android 截屏源码分析,android 截图功能源码解析

本文从源码角度分析Android系统中截图功能的实现。首先,按键事件通过PhoneWindowManager的dispatchUnhandledKey方法分发,接着关注到interceptFallback方法,此方法触发截屏操作。当音量减小键和电源键同时按下时,系统开始执行截屏。通过TakeScreenshotService服务,使用SurfaceControl的nativeScreenshot方法进行实际截图,成功后展示截图动画,并发送截屏成功的通知。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一般没有修改rom的android原生系统截图功能的组合键是音量减+开机键;今天我们从源码角度来分析截图功能是如何在源码中实现的。

在android系统中,由于我们的每一个Android界面都是一个Activity,而界面的显示都是通过Window对象实现的,每个Window对象实际上都是PhoneWindow的实例,而每个PhoneWindow对象都对应一个PhoneWindowManager对象,当我们在Activity界面执行按键操作的时候,在将按键的处理操作分发到App之前,首先会回调PhoneWindowManager中的dispatchUnhandledKey方法,该方法主要用于执行当前App处理按键之前的操作,我们具体看一下该方法的实现。

/** {@inheritDoc} */

@Override

public KeyEvent dispatchUnhandledKey(WindowState win, KeyEvent event, int policyFlags) {

...

KeyEvent fallbackEvent = null;

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

final KeyCharacterMap kcm = event.getKeyCharacterMap();

final int keyCode = event.getKeyCode();

final int metaState = event.getMetaState();

final boolean initialDown = event.getAction() == KeyEvent.ACTION_DOWN

&& event.getRepeatCount() == 0;

// Check for fallback actions specified by the key character map.

final FallbackAction fallbackAction;

if (initialDown) {

fallbackAction = kcm.getFallbackAction(keyCode, metaState);

} else {

fallbackAction = mFallbackActions.get(keyCode);

}

if (fallbackAction != null) {

...

final int flags = event.getFlags() | KeyEvent.FLAG_FALLBACK;

fallbackEvent = KeyEvent.obtain(

event.getDownTime(), event.getEventTime(),

event.getAction(), fallbackAction.keyCode,

event.getRepeatCount(), fallbackAction.metaState,

event.getDeviceId(), event.getScanCode(),

flags, event.getSource(), null);

if (!interceptFallback(win, fallbackEvent, policyFlags)) {

fallbackEvent.recycle();

fallbackEvent = null;

}

if (initialDown) {

mFallbackActions.put(keyCode, fallbackAction);

} else if (event.getAction() == KeyEvent.ACTION_UP) {

mFallbackActions.remove(keyCode);

fallbackAction.recycle();

}

}

}

...

return fallbackEvent;

}

这里我们关注一下方法体中调用的:interceptFallback方法,通过调用该方法将处理按键的操作下发到该方法中,我们继续看一下该方法的实现逻辑。

private boolean interceptFallback(WindowState win, KeyEvent fallbackEvent, int policyFlags) {

int actions = interceptKeyBeforeQueueing(fallbackEvent, policyFlags);

if ((actions & ACTION_PASS_TO_USER) != 0) {

long delayMillis = interceptKeyBeforeDispatching(

win, fallbackEvent, policyFlags);

if (delayMillis == 0) {

return true;

}

}

return false;

}

然后我们看到在interceptFallback方法中我们调用了interceptKeyBeforeQueueing方法,通过阅读我们我们知道该方法主要实现了对截屏按键的处理流程,这样我们继续看一下interceptKeyBeforeWueueing方法的处理:

@Override

public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {

if (!mSystemBooted) {

// If we have not yet booted, don't let key events do anything.

return 0;

}

...

// Handle special keys.

switch (keyCode) {

case KeyEvent.KEYCODE_VOLUME_DOWN:

case KeyEvent.KEYCODE_VOLUME_UP:

case KeyEvent.KEYCODE_VOLUME_MUTE: {

if (mUseTvRouting) {

// On TVs volume keys never go to the foreground app

result &= ~ACTION_PASS_TO_USER;

}

if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) {

if (down) {

if (interactive && !mScreenshotChordVolumeDownKeyTriggered

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

mScreenshotChordVolumeDownKeyTriggered = true;

mScreenshotChordVolumeDownKeyTime = event.getDownTime();

mScreenshotChordVolumeDownKeyConsumed = false;

cancelPendingPowerKeyAction();

interceptScreenshotChord();

}

} else {

mScreenshotChordVolumeDownKeyTriggered = false;

cancelPendingScreenshotChordAction();

}

}

...

return result;

}

可以发现这里首先判断当前系统是否已经boot完毕,若尚未启动完毕,则所有的按键操作都将失效,若启动完成,则执行后续的操作,这里我们只是关注音量减少按键和电源按键组

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值