简单介绍:

截屏一般有三种方法:

1.直接获取到一个view,然后通过ViewCache来获取一个bitmap对象,然后将bitmap对象写到图像文件。

2.ddmslib截屏,ddmslibandroid内置的一个库,在pc端的截屏都是使用的这种方式,但在网上找不到使用这种方法的资料。

3.framebuffer截屏,网上流传的都是这种方法,不过只有root后的设备能使用

根据各种方法的特点,我们选择的是framebuffer的方式,View的方式也简单介绍一下。由于截屏需要一定的处理时间,而且需要在后台运行,用service来实现是比较好的选择。

View截屏的简单实现

使用view截屏的话首先要获取当前的界面的view

Activity中获取view是非常容易的,但是仅限于当前Activityview,这种方法截屏是有限制的,截取的图像没有状态栏。在Activity中截屏的代码如下:

取得bitmap

View view = v.getRootView();

view.setDrawingCacheEnabled(true);

view.buildDrawingCache();

Bitmap bitmap = view.getDrawingCache();

然后将bitmap保存为png格式:

FileOutputStreamout = new FileOutputStream(file_name);

bitmap.compress(Bitmap.CompressFormat.PNG, 100,out);

framebuffer截屏的实现

framebufferlinux内核对显示的最底层驱动。在一般的linux文件系统中,通过/dev/fb0设备文件来提供给应用程序对framebuffer进行读写的访问。这里,如果有多个显示设备,就将依次出现fb1,fb2,…等文件。而在我们所说的android系统中,这个设备文件被放在了/dev/graphics/fb0,而且往往只有这一个。

这种方法使用的最为普遍,linux系统中经常使用这种方法实现截屏,一般步骤是:

1.读取framebuffer

2.Framebuffer转换为bitmap

3.bitmap生成图像文件

读取framebuffer

android上使用这种方法第一个难题是获取framebuffer,因为默认的配置中framebuffer的读取权限是“root”,而Apk的权限最高只能提升到“system”,framework工作的权限也是“system”,也因此网上提供的截屏软件都只能在root过的手机上使用。对拥有源码的人来说,最简单的方法是直接改变framebuffer的权限,普通用户也有权限读取framebuffer

然后就可以通过读文件的方式直接读取framebuffer,利用如下代码打开一个指向framebuffer的输入流就可以读取了。

publicstatic InputStreamgetInputStream() throws Exception {

FileInputStream buf =newFileInputStream(

new File("/dev/graphics/fb0"));

return buf;

}//get the InputStream from framebuffer

framebufferbitmap的转换

framebuffer的数据是直接送入显示设备的,这些数据没有文件头,而且由于framebuffer读到数据跟显示方式关系很大,在不同设备上framebuffer的大小和数据格式不一样,读取前确定framebuffer的数据格式。

获取屏幕大小:

DisplayMetrics metrics =new DisplayMetrics();

WindowManager WM = (WindowManager)mContext

.getSystemService(Context.WINDOW_SERVICE);

Display display = WM.getDefaultDisplay();

display.getMetrics(metrics);

int height = metrics.heightPixels; //屏幕高

int with = metrics.widthPixels;//屏幕的宽

获取显示方式

int pixelformat = display.getPixelFormat();

PixelFormat localPixelFormat1 =new PixelFormat();

PixelFormat.getPixelFormatInfo(pixelformat, localPixelFormat1);

int deepth = localPixelFormat1.bytesPerPixel;//位深

pixelformat代表的意义是在PixelFormat.java定义的:

public static final int RGBA_8888= 1;

public static final int RGBX_8888= 2;

public static final int RGB_888= 3;

public static final int RGB_565= 4;

public static final int RGBA_5551= 6;

public static final int RGBA_4444= 7;

public static final int A_8= 8;

public static final int L_8= 9;

public static final int LA_88= 0xA;

public static final int RGB_332= 0xB;

pixelformat是下面进行判断处理的依据,根据pixelformat计算出实际的深度。

一般

Framebuffer大小 =height* with* deepth*2

之所以“*2”,是因为Framebuffer包含两帧画面,我们使用任何一帧都可以。

piex =newbyte[height * with * deepth];

InputStream stream =getInputStream(

new File("/dev/graphics/fb0"));

DataInputStream dStream =new DataInputStream(stream);

dStream.readFully(piex);

这样framebuffer的数据就被写进了piex

piex生成bitmap

bitmap = Bitmap.createBitmap(data,mwidth,mheight,config);

data:像素数据,data的一个元素表示一个像素,所以这里不能直接使用piex,必须经过转换。

mwidth,mheight:图像大小

config:图像格式,可以取以下数值

Bitmap.Config.ALPHA_8(2),

Bitmap.Config.RGB_565(4),

Bitmap.Config.ARGB_4444(5),

Bitmap.Config.ARGB_8888(6);

bitmap保存为png格式

这是跟上面一样的

FileOutputStreamout = new FileOutputStream(file_name);

bitmap.compress(Bitmap.CompressFormat.PNG, 100,out);

这样截取的一幅图片就被保存到了固定位置。

快捷键的添加

由于快捷键是全局的,所以要在PhoneWindowManager中添加

public int interceptKeyBeforeQueueing(

long whenNanos, int action, int flags,

int keyCode, int scanCode, int policyFlags,

boolean isScreenOn)

这个函数是在按键事件进入消息队列之前调用的,所以先与所有app相应事件。但是在这个函数对于每个按键事件是单独处理的,组合键需要我们自己来识别。

下图分别是power键和volumedown键的按键处理,黄色区域为新增加代码。由于现在power键的长按和短按都是有事件响应的,所以设计的关键在于必须在长按和短按的间隙处理截屏事件,而且截屏后保证power的长按不在响应。

service设计:

这个服务的功能比较单一,只在启动时响应请求就可以,不需要驻留在后台,也不需要调用接口,所以不需要AIDL,也不需要远程连接。

客户端,使用intent启动服务

Intent intent = new Intent();

intent.setAction("com.android.ScreenServer.SHOT");

mContext.startService(intent);

在应用程序端

声明权限使用SD

<uses-permissionandroid:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

Intentfilter过滤事件

<application

android:icon="@drawable/ic_launcher"

android:label="@string/app_name">

<service

android:name="shotservice">

<intent-filter>

<actionandroid:name="com.android.ScreenServer.SHOT"/>

</intent-filter>

</service>

</application>

程序代码:

publicvoid onStart(Intent intent,int startId) {

//TODO Auto-generated method stub

super.onStart(intent, startId);

mContext =this;

。。。

使用framebuffer截屏

。。。

}

这样截屏结束后,Service的生命周期就结束了,系统会自动销毁Service

更多相关文章

  1. Android之Retrofit和RxJava的结合使用
  2. Android(安卓)如何从SD卡中读取数据?
  3. Android(安卓)四种加载方式详解(standard singleTop singleTask s
  4. Android编程基础之简单Button事件响应综合提示控件Toast应用示例
  5. Android一个支持竖向滚动的ViewPager实现
  6. android利用post方式与web服务器通信
  7. Broadcast 广播 的接收 和发送 -- Android(安卓)学习之路
  8. 【Android(安卓)开发】 : Activity之间传递数据的几种方式
  9. android中的5个布局方式

随机推荐

  1. 针对Sqlserver大数据量插入速度慢或丢失
  2. ms sql server中实现的unix时间戳函数(含
  3. sql 判断函数、存储过程是否存在的代码整
  4. SQL SERVER 2000通讯管道后复用劫持
  5. SQL Server 2000安全配置详解
  6. SQL Server出现System.OutOfMemoryExcept
  7. SQL Server中检查字段的值是否为数字的方
  8. SQL Server数据类型char、nchar、varchar
  9. SQLServer行转列实现思路记录
  10. .net+mssql制作抽奖程序思路及源码