Android 4.0 截屏(Screenshot)代码流程小结

参考文档:Android 4.0 截屏(Screenshot)代码流程小结:http://blog.csdn.net/hk_256/article/details/7306590

Apk签名相关:http://blog.csdn.net/electricity/article/details/6449998

用Android自带的signapk.jar + .x509.pem + .pk8签名应用程序http://mysuperbaby.iteye.com/blog/1420612

一、基本介绍

在Android 4.0 之前,Android手机上如果要使用截屏功能,只能通过Root手机,且使用第3方截图软件来实现截屏功能。

Android4.0中,系统自带了截屏功能,使用方法是音量下(VOLUME_DOWN)键+电源(Power)键。

在同时按下2键并保持0.5s左右后,会听到咔嚓一声响声,并弹出一个浮动动画,显示截图效果。

二、代码调用流程

Policy(PhoneWindowManager.java):在此处完成Key的捕获,当VOLUME_DOWN和Power键被几乎同时按下后,向

SystemUI发送Message开始截图。

SystemUI(TakeScreenshotService.java和GlobalScreenshot.java):收到来自Client端的截屏请求后,开始调用Surface的API

截屏,并将截取到的图片通过WindowManager以浮动窗口的形式显示给用户查看。

Surface(Surface.java和android_view_Surface.cpp):Framework层的Surface.java只是提供一个native方法,实际实现在JNI

处的android_view_Surface.cpp中的doScreenshot(...)方法。

由上分析得知:真正完成截屏工作的是在Surface类中的screenshot()方法,这个调用JNI的doScreenshot()方法。

注:在SurfceFlinger.cpp的onTransact方法中,有对截屏的操作进行权限认证,所以需要为app使用system的shareUserId。

三、App端如何使用截屏功能

以目前代码情况看,Surface.java中的screenshot方法是有@hide标记的,即在默认的SDK中是没有此方法的,暂不支持App端

直接使用。

有如下解决方案:

1、自己将源代码中的@hide去掉,然后编译一个sdk来替换默认的sdk

在linux上使用  make PRODUCT-sdk-sdk 命令,编译一个新的sdk出来,注意编译后其实我们不需要整个sdk,只需要android.jar

这个文件替换掉sdk里的android.jar,例如:笔者的sdk里的jar对应的目录为:

F:/Program Files/Android/android-sdk-windows/platforms/android-8/android.jar

具体编译sdk的方法是,在linux编译环境下用命令 make PRODUCT-sdk-sdk ,成功后,会有如下提示:
                 Package SDK: out/host/linux-x86/sdk/android-sdk_eng.stevewang_linux-x86.zip

我们进入到 linux编译环境的 out/host/linux-x86/sdk/android-sdk_eng.stevewang_linux-x86/platforms/android-2.2/目录下可以看

到android.jar 文件。使用此文件替换   F:\Program Files\Android\android-sdk-windows\platforms\android-8\android.jar 即可,替换前

记得备份。

注:此方法较为麻烦,上面的内容是从网络摘抄的,自己也未实际操作过,个人推荐使用第二种方法。

2、添加framework 编译出来的class.jar文件到 eclipse的build path

其实在编译android的时候,我们将framework 编译到一个临时的jar包中了,这个jar包的路径一般为:

out\target\common\obj\JAVA_LIBRARIES\framework_intermediates\classes.jar

我们只需要在linux上android源代码目录下使用make 命令即可生成此文件。

由于这个jar文件中的api 还没有重新打包,里面被@hide掉的api并没有被去掉。所以我们依然能够引用里面被@hide的api 。而

sdk 中的android.jar文件时重新打包生成的,其里标记有@hide的api已经被去掉了。

我们把out\target\common\obj\JAVA_LIBRARIES\framework_intermediates\classes.jar 拷贝到本地一个目录下,然后在工程中添加此jar包。

具体方法:

1)拷贝linux编译生成的  out\target\common\obj\JAVA_LIBRARIES\framework_intermediates\classes.jar到本机PC

2)在eclipse的Android项目中,选择项目属性->Java Build Path->Libraries->Add Library->User Library->Next-> UserLibraries进入

到User Libraries管理界面,点击New新建一个User Library,比如android_framework,点击Add Jars把Jar包加入到建立的User

Library中,最后点击OK。

3)选择项目属性->Java Build Path->Order and Export,把所建立的User Libraries移到Android SDK的上面。
如下图:

到此编译问题已解决。下面是此后进行的步骤(这些是关键步骤):

1) 在AndroidManifest.xml中加入android:sharedUserId="android.uid.system" 属性

2)使用eclipse生成.apk程序:在eclipse的Android项目中,选择项目属性->Android Tools->Export Unsigned Application

Package...,会弹出一个对话框,选择.apk文件存放的路径,点击OK后,在相应的路径下生成.apk文件

这时候我们会发现:无论是用 eclipse直接运行aplication还是用adb push命令都无法安装apk应用程序,这是为什么呢?

通过eclipse编译android源码中,如果编译Settings或者android manifest XML中 shared user id 包含android.uid.shared等系统权

限的时候,则会报以下错误:

INSTALL_FAILED_SHARED_USER_INCOMPATIBLE

3)由上面的发现可知,主要是使用了android.uid.shared导致的问题。解决方案如下:

(1)第一个方法简单点,不过需要在Android系统源码的环境下用make来编译:

a. 修改Android.mk文件,加入LOCAL_CERTIFICATE := platform这一行

b. 使用mm命令来编译,生成的apk就可以在安装运行了

注:这种方法我尝试了,不知道为什么老是提示说上面提到@hide方法找不到,望哪位大侠支招,不慎感激

(2)第二个方法麻烦点,不过不用开虚拟机跑到源码环境下用make来编译:

使用eclipse编译出apk文件,但是这个apk文件是不能用的。使用目标系统的platform密钥来重新给apk文件签名。这步比较麻烦,

a.首先找到密钥文件,在我的Android源码目录中的位置是"build/target/product/security"的下面的platform.pk8和

platform.x509.pem 两个文件,将这两个文件拷贝至上面提到的.apk文件存放路径下(当然不放在目录也是可以的,不过在生成新的apk时需要指出绝对路径)

b.然后用Android提供的Signapk工具来签名,signapk的源代码在"build/tools/signapk"目录下,我们编译源码会在/out/host

/linux-x86/framework/目录下生成signapk.jar。将这个jar文件拷贝至之前提到的路径下

c.最后是增加签名:使用java -jar signapk.jar platform.x509.pem platform.pk8 input.apk ouput.apk 得到具有对应权限的APK

d.安装apk

四、范例

下面我们写一个简单的android apllication程序来说明如何实现截图

1、 Activity文件

package com.arvinhe.testscreenshot;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.view.Display;
import android.view.Surface;
import android.view.View;
import android.view.WindowManager;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;
public class TestScreenShotActivity extends Activity implements OnClickListener{
private ImageView img_display;
private Button bt_screenshot;
private Display mDisplay;
private DisplayMetrics mDisplayMetrics;
private Matrix mDisplayMatrix;
private Bitmap mScreenBitmap;
private WindowManager mWindowManager;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
bt_screenshot = (Button)findViewById(R.id.bt_screenshot);
img_display = (ImageView)findViewById(R.id.img_display);
bt_screenshot.setOnClickListener(this);
mDisplayMatrix = new Matrix();
mWindowManager = (WindowManager) this.getSystemService(Context.WINDOW_SERVICE);
mDisplay = mWindowManager.getDefaultDisplay();
mDisplayMetrics = new DisplayMetrics();
mDisplay.getRealMetrics(mDisplayMetrics);            //这个类可获取当前手机的分辨率
}
@Override
public void onClick(View v) {
if(v.equals(bt_screenshot)){
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]);
}
mScreenBitmap = Surface.screenshot((int) dims[0], (int) dims[1]);
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);
mScreenBitmap = ss;
}
// If we couldn't take the screenshot, notify the user
if (mScreenBitmap == null) {
return;
}
// Optimizations
mScreenBitmap.setHasAlpha(false);
mScreenBitmap.prepareToDraw();
img_display.setImageBitmap(mScreenBitmap);
}
}
/**
* @return the current display rotation in degrees
*/
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;
}
}

2、 AndroidManifest.xml文件

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.arvinhe.testscreenshot"
android:versionCode="1"
android:versionName="1.0"
android:sharedUserId="android.uid.system">
<uses-sdk android:minSdkVersion="15" />
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name" >
<activity
android:name=".TestScreenShotActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>

3、 Layout文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello" />
<Button
android:id="@+id/bt_screenshot"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Screen Shot"
/>
<ImageView
android:id="@+id/img_display"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:src="@drawable/ic_launcher"/>
</LinearLayout>

Android 4.0 截屏(Screenshot)相关推荐

  1. Android 4.0 截屏(Screenshot)代码流程小结

    Android 4.0 截屏 在Android 4.0 之前,Android手机上如果要使用截屏功能,只能通过Root手机,且使用第3方截图软件来实现截屏功能. Android4.0中,系统自带了截屏 ...

  2. android模拟器后台截屏,【Android】Android模拟器下截屏及格式转换

    一,模拟器信息 Android 模拟器手机的色深是16bit, 即R/G/B=5/6/5. 故需要一些特殊处理才能获得其屏幕图像. 我们可以adb登录进入Android模拟器,先dump出/dev/f ...

  3. android 8.1 截屏,Android8.1 MTK平台 截屏功能分析

    前言 涉及到的源码有 frameworksbaseservicescorejavacomandroidserverpolicyPhoneWindowManager.java vendormediate ...

  4. android长截图工具下载,Android实现长截屏功能

    本文实例为大家分享了Android实现长截屏功能的具体代码,供大家参考,具体内容如下 1.MainActivity public class MainActivity extends AppCompa ...

  5. Android App内截屏监控及涂鸦功能实现

    Android App内截屏监控及涂鸦功能实现 Android截屏功能是一个常用的功能,可以方便的用来分享或者发送给好友,本文介绍了如何实现app内截屏监控功能,当发现用户在我们的app内进行了截屏操 ...

  6. android 禁止截屏录屏功能,android 应用禁止截屏录屏

    更新记录 1.0.0(2021-02-01) Android 应用禁止截屏录屏 平台兼容性 Android iOS 适用版本区间:4.4 - 11.0 × 原生插件通用使用流程: 购买插件,选择该插件 ...

  7. android解锁界面分析,Android 7.0 锁屏解锁之向上滑动显示解锁界面分析

    Android 7.0 锁屏解锁之向上滑动显示解锁界面分析 by jing.chen 锁屏的解锁操作是在锁屏界面向上滑动实现的,通过向上滑动调出解锁界面(如图案.PIN.密码解锁界面),在解锁界面输入 ...

  8. android 实现手机录屏功能,基于MediaProjection实现Android移动手机截屏和录屏功能

    Android软件应用经常要求实现截屏和录屏的功能,那么如何实现Android软件截屏和录屏功能呢?本文将介绍基于MediaProjection实现Android移动手机截屏和录屏功能. MediaP ...

  9. Android 截屏(Screenshot)代码流程小结

    一.基本介绍 在Android 4.0 之前,Android手机上如果要使用截屏功能,只能通过Root手机,且使用第3方截图软件来实现截屏功能. Android4.0中,系统自带了截屏功能,使用方法是 ...

最新文章

  1. 零知识证明实践教程,第一部分
  2. “饶毅举报”事件尘埃落定,裴钢表示未发现裴钢造假。网友:我有信心一年发20篇SCI...
  3. 在ctex环境下利用Metapost作图
  4. 切片分析报告格式_疫情舆情分析研判报告怎么撰写?2020舆情报告格式
  5. pandas 如何删掉第一行_Python:Pandas – 按组删除第一行
  6. 手把手教你全家桶之React(一)
  7. java铝轮_为速度而生 JAVA Fuoco铝合金气动公路
  8. Java 使用反射处理注解
  9. java课程总结_Java课程总结 - osc_uyb9f22c的个人空间 - OSCHINA - 中文开源技术交流社区...
  10. 【实践】飞猪交通个性化搜索推荐技术的实践与创新(附PPT下载链接)
  11. vue+echarts 实时跟新数据 仪表盘多个渲染
  12. Socket服务器分类与流程总结
  13. Sqlite3相关函数返回值及其含义
  14. 短视频剪辑APP开发快速开发
  15. 数学管理联考-无限循环小数如何转化为分数
  16. 论微服务架构及其应用
  17. ESP8266恒温控制器
  18. Power bi 3.12 瀑布图
  19. pythoneducoder苹果梨子煮水的功效_荸荠和梨子一起煮的好处
  20. 大厂Java面试过程中如何介绍自己的项目经历?

热门文章

  1. 学python多久能上线部署网站_从开发到上线,实战持续交付
  2. python可以在哪些系统运行_Python 语言可以在哪些操作系统上运行?
  3. STI比赛任务一:【智能问答baseline】
  4. 打开同一网络下的电脑摄像头
  5. 2017CS231n笔记_S13生成模型
  6. 常用的数据采集工具有哪些-免费获取数据信息的工具有哪些
  7. 今天第五人格服务器维护,更新公告《第五人格》2021年5月8日维护公告
  8. 《影视特效镜头跟踪技术精粹(第2版)》即将上市
  9. java输出字体_ITEXT输出中文调用windows字体
  10. HDU 6208【假AC自动机+string方法】