android4.3截屏源碼,【android4.3】记一次完整的android源码截屏事件的捕获(不同于网上的老版本)...

---------------------------------------------------------------------------------------------------------------------

1.背景

我们知道android提供了一个系统截屏功能,就是按住电源键和音量减的按键0.5秒,系统将执行截屏功能。所以要实现系统截屏的功能,就是要捕获系统的这两个组合键下面的函数,然后一层一层的向下挖掘。现在网上找到的版本是在Surface.java文件下存在ScreenShot()函数,是@hide的。但是这是之前版本的办法,在android4.3之后已经是不适用的,因为在/frameworks/base/core/java/android/view/的Surface.java下并没有ScreenShot()函数,我猜google不会这么绝情,一定会在framework层给开发者留了接口,只不过写到了别的地方。所以博主按照前任的思路自行挖掘,最后找到了新版本的ScreenShot函数,在这与大家分享。

2.挖掘过程

(1)Android源码中对按键的捕获位于文件PhoneWindowManager.java(\frameworks\base\policy\src\com\android\internal\policy\impl)中

ase KeyEvent.KEYCODE_VOLUME_UP:

case KeyEvent.KEYCODE_VOLUME_MUTE: {

if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) {

if (down) {

if (isScreenOn && !mVolumeDownKeyTriggered

&& (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {

mVolumeDownKeyTriggered = true;

mVolumeDownKeyTime = event.getDownTime();

mVolumeDownKeyConsumedByScreenshotChord = false;

cancelPendingPowerKeyAction();

interceptScreenshotChord();

}

} else {

mVolumeDownKeyTriggered = false;

cancelPendingScreenshotChordAction();

}

我们看到了,如果同时按下电源键与音量减会启动函数,

interceptScreenshotChord();

我们来看下着个函数

private void interceptScreenshotChord() {

if (mVolumeDownKeyTriggered && mPowerKeyTriggered && !mVolumeUpKeyTriggered) {

final long now = SystemClock.uptimeMillis();

if (now <= mVolumeDownKeyTime + SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS

&& now <= mPowerKeyTime + SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS) {

mVolumeDownKeyConsumedByScreenshotChord = true;

cancelPendingPowerKeyAction();

mHandler.postDelayed(mScreenshotChordLongPress,

ViewConfiguration.getGlobalActionKeyTimeout());

}

}

}

我们看到handle中的这个函数,应该就是我们要执行的截屏功能

mScreenshotChordLongPress

我们进入这个函数

private final Runnable mScreenshotChordLongPress = new Runnable() {

public void run() {

takeScreenshot();

}

};

终于让我们找到了takeScreenShot,不过别急,我们转到这个函数

private void takeScreenshot() {

synchronized (mScreenshotLock) {

if (mScreenshotConnection != null) {

return;

}

ComponentName cn = new ComponentName("com.android.systemui",

"com.android.systemui.screenshot.TakeScreenshotService");

Intent intent = new Intent();

intent.setComponent(cn);

ServiceConnection conn = new ServiceConnection() {

@Override

public void onServiceConnected(ComponentName name, IBinder service) {

synchronized (mScreenshotLock) {

if (mScreenshotConnection != this) {

return;

}

Messenger messenger = new Messenger(service);

Message msg = Message.obtain(null, 1);

final ServiceConnection myConn = this;

Handler h = new Handler(mHandler.getLooper()) {

@Override

public void handleMessage(Message msg) {

synchronized (mScreenshotLock) {

if (mScreenshotConnection == myConn) {

mContext.unbindService(mScreenshotConnection);

mScreenshotConnection = null;

mHandler.removeCallbacks(mScreenshotTimeout);

}

}

}

};

msg.replyTo = new Messenger(h);

msg.arg1 = msg.arg2 = 0;

if (mStatusBar != null && mStatusBar.isVisibleLw())

msg.arg1 = 1;

if (mNavigationBar != null && mNavigationBar.isVisibleLw())

msg.arg2 = 1;

try {

messenger.send(msg);

} catch (RemoteException e) {

}

}

}

@Override

public void onServiceDisconnected(ComponentName name) {}

};

if (mContext.bindService(intent, conn, Context.BIND_AUTO_CREATE)) {

mScreenshotConnection = conn;

mHandler.postDelayed(mScreenshotTimeout, 10000);

}

}

}

我们看到它启动了一个截图的service( "com.android.systemui.screenshot.TakeScreenshotService")。

(这也印证了我一个猜想,android的一切功能都是handle通过sendmessage然后通过service实现的)

(2)找到那个service

public class TakeScreenshotService extends Service {

private static final String TAG = "TakeScreenshotService";

private static GlobalScreenshot mScreenshot;

private Handler mHandler = new Handler() {

@Override

public void handleMessage(Message msg) {

switch (msg.what) {

case 1:

final Messenger callback = msg.replyTo;

if (mScreenshot == null) {

mScreenshot = new GlobalScreenshot(TakeScreenshotService.this);

}

mScreenshot.takeScreenshot(new Runnable() {

@Override public void run() {

Message reply = Message.obtain(null, 1);

try {

callback.send(reply);

} catch (RemoteException e) {

}

}

}, msg.arg1 > 0, msg.arg2 > 0);

}

}

};

@Override

public IBinder onBind(Intent intent) {

return new Messenger(mHandler).getBinder();

}

}

我们看到类GlobalScreenshot的对象执行了截图的功能。

(3)打开GlobalScreenshot

/**

* Takes a screenshot of the current display and shows an animation.

*/

void takeScreenshot(Runnable finisher, boolean statusBarVisible, boolean navBarVisible) {

// 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]);

}

// Take the screenshot

mScreenBitmap = SurfaceControl.screenshot((int) dims[0], (int) dims[1]);

if (mScreenBitmap == null) {

notifyScreenshotError(mContext, mNotificationManager);

finisher.run();

return;

}

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();

// Start the post-screenshot animation

startAnimation(finisher, mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels,

statusBarVisible, navBarVisible);

}

我们主要看这句,我们终于找到了screenshot(),这个地方跟低版本的android源码是有改动的,之前的surface操作是写到surface类里,现在增加了这个surfacecontrol类来控制surface。

// Take the screenshot

mScreenBitmap = SurfaceControl.screenshot((int) dims[0], (int) dims[1]);

(4)现在我们打开surfacecontrol类,位于/frameworks/base/core/java/android/view

代码开头我们可以看到,这个类是被google隐藏了,所以不能直接调用,若是想用截屏功能要在源码中编译才行,至于如何调用这个功能以后会讲,have fun!

/**

* SurfaceControl

* @hide

*/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值