1. 监听按键手势
[frameworks](http://aospxref.com/android-12.0.0_r3/xref/frameworks/)/[base](http://aospxref.com/android-12.0.0_r3/xref/frameworks/base/)/[services](http://aospxref.com/android-12.0.0_r3/xref/frameworks/base/services/)/[core](http://aospxref.com/android-12.0.0_r3/xref/frameworks/base/services/core/)/[java](http://aospxref.com/android-12.0.0_r3/xref/frameworks/base/services/core/java/)/[com](http://aospxref.com/android-12.0.0_r3/xref/frameworks/base/services/core/java/com/)/[android](http://aospxref.com/android-12.0.0_r3/xref/frameworks/base/services/core/java/com/android/)/[server](http://aospxref.com/android-12.0.0_r3/xref/frameworks/base/services/core/java/com/android/server/)/[policy](http://aospxref.com/android-12.0.0_r3/xref/frameworks/base/services/core/java/com/android/server/policy/)/[PhoneWindowManager.java](http://aospxref.com/android-12.0.0_r3/xref/frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java)
private void initKeyCombinationRules() {
mKeyCombinationManager = new KeyCombinationManager();
final boolean screenshotChordEnabled = mContext.getResources().getBoolean(
com.android.internal.R.bool.config_enableScreenshotChord);
// 监听音量下键与power键是否同时按下
if (screenshotChordEnabled) {
mKeyCombinationManager.addRule(
new TwoKeysCombinationRule(KEYCODE_VOLUME_DOWN, KEYCODE_POWER) {
@Override
void execute() {
mPowerKeyHandled = true;
interceptScreenshotChord();
}
@Override
void cancel() {
cancelPendingScreenshotChordAction();
}
});
}
........
}
.....
**private void interceptScreenshotChord() {
mHandler.removeCallbacks(mScreenshotRunnable);
//** **使用全屏截图
mScreenshotRunnable.setScreenshotType(TAKE_SCREENSHOT_FULLSCREEN);
mScreenshotRunnable.setScreenshotSource(SCREENSHOT_KEY_CHORD);
mHandler.postDelayed(mScreenshotRunnable, getScreenshotChordLongPressDelay());
}**
2. 当截屏动作被监听到后,调用 PhoneWindowManager.java 中的内部类 ScreenshotRunnable
[frameworks](http://aospxref.com/android-12.0.0_r3/xref/frameworks/)/[base](http://aospxref.com/android-12.0.0_r3/xref/frameworks/base/)/[services](http://aospxref.com/android-12.0.0_r3/xref/frameworks/base/services/)/[core](http://aospxref.com/android-12.0.0_r3/xref/frameworks/base/services/core/)/[java](http://aospxref.com/android-12.0.0_r3/xref/frameworks/base/services/core/java/)/[com](http://aospxref.com/android-12.0.0_r3/xref/frameworks/base/services/core/java/com/)/[android](http://aospxref.com/android-12.0.0_r3/xref/frameworks/base/services/core/java/com/android/)/[server](http://aospxref.com/android-12.0.0_r3/xref/frameworks/base/services/core/java/com/android/server/)/[policy](http://aospxref.com/android-12.0.0_r3/xref/frameworks/base/services/core/java/com/android/server/policy/)/[PhoneWindowManager.java](http://aospxref.com/android-12.0.0_r3/xref/frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java)
private class ScreenshotRunnable implements Runnable {
private int mScreenshotType = TAKE_SCREENSHOT_FULLSCREEN;
private int mScreenshotSource = SCREENSHOT_KEY_OTHER;
public void setScreenshotType(int screenshotType) {
mScreenshotType = screenshotType;
}
public void setScreenshotSource(int screenshotSource) {
mScreenshotSource = screenshotSource;
}
// 向下调用至DisplayPolicy.java
@Override
public void run() {
mDefaultDisplayPolicy.takeScreenshot(mScreenshotType, mScreenshotSource);
}
}
3. 向下调用至 DisplayPolicy.java
[frameworks](http://aospxref.com/android-12.0.0_r3/xref/frameworks/)/[base](http://aospxref.com/android-12.0.0_r3/xref/frameworks/base/)/[services](http://aospxref.com/android-12.0.0_r3/xref/frameworks/base/services/)/[core](http://aospxref.com/android-12.0.0_r3/xref/frameworks/base/services/core/)/[java](http://aospxref.com/android-12.0.0_r3/xref/frameworks/base/services/core/java/)/[com](http://aospxref.com/android-12.0.0_r3/xref/frameworks/base/services/core/java/com/)/[android](http://aospxref.com/android-12.0.0_r3/xref/frameworks/base/services/core/java/com/android/)/[server](http://aospxref.com/android-12.0.0_r3/xref/frameworks/base/services/core/java/com/android/server/)/[wm](http://aospxref.com/android-12.0.0_r3/xref/frameworks/base/services/core/java/com/android/server/wm/)/[DisplayPolicy.java](http://aospxref.com/android-12.0.0_r3/xref/frameworks/base/services/core/java/com/android/server/wm/DisplayPolicy.java)
public void takeScreenshot(int screenshotType, int source) {
if (mScreenshotHelper != null) {
mScreenshotHelper.takeScreenshot(screenshotType,
getStatusBar() != null && getStatusBar().isVisible(),
getNavigationBar() != null && getNavigationBar().isVisible(),
source, mHandler, null /* completionConsumer */);
}
}
4. 继续向下至 ScreenshotHelper.java
[frameworks](http://aospxref.com/android-12.0.0_r3/xref/frameworks/)/[base](http://aospxref.com/android-12.0.0_r3/xref/frameworks/base/)/[core](http://aospxref.com/android-12.0.0_r3/xref/frameworks/base/core/)/[java](http://aospxref.com/android-12.0.0_r3/xref/frameworks/base/core/java/)/[com](http://aospxref.com/android-12.0.0_r3/xref/frameworks/base/core/java/com/)/[android](http://aospxref.com/android-12.0.0_r3/xref/frameworks/base/core/java/com/android/)/[internal](http://aospxref.com/android-12.0.0_r3/xref/frameworks/base/core/java/com/android/internal/)/[util](http://aospxref.com/android-12.0.0_r3/xref/frameworks/base/core/java/com/android/internal/util/)/[ScreenshotHelper.java](http://aospxref.com/android-12.0.0_r3/xref/frameworks/base/core/java/com/android/internal/util/ScreenshotHelper.java)
public void takeScreenshot(final int screenshotType, final boolean hasStatus,
final boolean hasNav, int source, @NonNull Handler handler,
@Nullable Consumer<Uri> completionConsumer) {
ScreenshotRequest screenshotRequest = new ScreenshotRequest(source, hasStatus, hasNav);
takeScreenshot(screenshotType, SCREENSHOT_TIMEOUT_MS, handler, screenshotRequest,
completionConsumer);
}
5. 发送截屏指令
private void takeScreenshot(final int screenshotType, long timeoutMs, @NonNull Handler handler,
ScreenshotRequest screenshotRequest, @Nullable Consumer<Uri> completionConsumer) {
synchronized (mScreenshotLock) {
final Runnable mScreenshotTimeout = () -> {
synchronized (mScreenshotLock) {
if (mScreenshotConnection != null) {
Log.e(TAG, "Timed out before getting screenshot capture response");
resetConnection();
notifyScreenshotError();
}
}
6.TakeScreenshotService.java 接收 msg 信息并开始处理截屏
[frameworks](http://aospxref.com/android-12.0.0_r3/xref/frameworks/)/[base](http://aospxref.com/android-12.0.0_r3/xref/frameworks/base/)/[packages](http://aospxref.com/android-12.0.0_r3/xref/frameworks/base/packages/)/[SystemUI](http://aospxref.com/android-12.0.0_r3/xref/frameworks/base/packages/SystemUI/)/[src](http://aospxref.com/android-12.0.0_r3/xref/frameworks/base/packages/SystemUI/src/)/[com](http://aospxref.com/android-12.0.0_r3/xref/frameworks/base/packages/SystemUI/src/com/)/[android](http://aospxref.com/android-12.0.0_r3/xref/frameworks/base/packages/SystemUI/src/com/android/)/[systemui](http://aospxref.com/android-12.0.0_r3/xref/frameworks/base/packages/SystemUI/src/com/android/systemui/)/[screenshot](http://aospxref.com/android-12.0.0_r3/xref/frameworks/base/packages/SystemUI/src/com/android/systemui/screenshot/)/[TakeScreenshotService.java](http://aospxref.com/android-12.0.0_r3/xref/frameworks/base/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java)
@MainThread
private boolean handleMessage(Message msg) {
final Messenger replyTo = msg.replyTo;
final Consumer<Uri> uriConsumer = (uri) -> reportUri(replyTo, uri);
RequestCallback requestCallback = new RequestCallbackImpl(replyTo);
// 判断用户设备是否解锁,如未解锁,跳出截屏
if (!mUserManager.isUserUnlocked()) {
Log.w(TAG, "Skipping screenshot because storage is locked!");
mNotificationsController.notifyScreenshotError(
R.string.screenshot_failed_to_save_user_locked_text);
requestCallback.reportError();
return true;
}
ScreenshotHelper.ScreenshotRequest screenshotRequest =
(ScreenshotHelper.ScreenshotRequest) msg.obj;
mUiEventLogger.log(ScreenshotEvent.getScreenshotSource(screenshotRequest.getSource()));
switch (msg.what) {
// 全屏截屏
case WindowManager.TAKE_SCREENSHOT_FULLSCREEN:
if (DEBUG_SERVICE) {
Log.d(TAG, "handleMessage: TAKE_SCREENSHOT_FULLSCREEN");
}
mScreenshot.takeScreenshotFullscreen(uriConsumer, requestCallback);
break;
case WindowManager.TAKE_SCREENSHOT_SELECTED_REGION:
if (DEBUG_SERVICE) {
Log.d(TAG, "handleMessage: TAKE_SCREENSHOT_SELECTED_REGION");
}
mScreenshot.takeScreenshotPartial(uriConsumer, requestCallback);
break;
case WindowManager.TAKE_SCREENSHOT_PROVIDED_IMAGE:
if (DEBUG_SERVICE) {
Log.d(TAG, "handleMessage: TAKE_SCREENSHOT_PROVIDED_IMAGE");
}
Bitmap screenshot = BitmapUtil.bundleToHardwareBitmap(
screenshotRequest.getBitmapBundle());
Rect screenBounds = screenshotRequest.getBoundsInScreen();
Insets insets = screenshotRequest.getInsets();
int taskId = screenshotRequest.getTaskId();
int userId = screenshotRequest.getUserId();
ComponentName topComponent = screenshotRequest.getTopComponent();
if (screenshot == null) {
Log.e(TAG, "Got null bitmap from screenshot message");
mNotificationsController.notifyScreenshotError(
R.string.screenshot_failed_to_capture_text);
requestCallback.reportError();
} else {
mScreenshot.handleImageAsScreenshot(screenshot, screenBounds, insets,
taskId, userId, topComponent, uriConsumer, requestCallback);
}
break;
default:
Log.w(TAG, "Invalid screenshot option: " + msg.what);
return false;
}
return true;
};
7.TakeScreenshotService.java 调用ScreenshotController.java来完成截屏
[frameworks](http://aospxref.com/android-12.0.0_r3/xref/frameworks/)/[base](http://aospxref.com/android-12.0.0_r3/xref/frameworks/base/)/[packages](http://aospxref.com/android-12.0.0_r3/xref/frameworks/base/packages/)/[SystemUI](http://aospxref.com/android-12.0.0_r3/xref/frameworks/base/packages/SystemUI/)/[src](http://aospxref.com/android-12.0.0_r3/xref/frameworks/base/packages/SystemUI/src/)/[com](http://aospxref.com/android-12.0.0_r3/xref/frameworks/base/packages/SystemUI/src/com/)/[android](http://aospxref.com/android-12.0.0_r3/xref/frameworks/base/packages/SystemUI/src/com/android/)/[systemui](http://aospxref.com/android-12.0.0_r3/xref/frameworks/base/packages/SystemUI/src/com/android/systemui/)/[screenshot](http://aospxref.com/android-12.0.0_r3/xref/frameworks/base/packages/SystemUI/src/com/android/systemui/screenshot/)/[ScreenshotController.java](http://aospxref.com/android-12.0.0_r3/xref/frameworks/base/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java)
void takeScreenshotFullscreen(Consumer<Uri> finisher, RequestCallback requestCallback) {
mCurrentRequestCallback = requestCallback;
DisplayMetrics displayMetrics = new DisplayMetrics();
getDefaultDisplay().getRealMetrics(displayMetrics);
takeScreenshotInternal(
finisher,
new Rect(0, 0, displayMetrics.widthPixels, displayMetrics.heightPixels));
}
private void takeScreenshotInternal(Consumer<Uri> finisher, Rect crop) {
mScreenshotTakenInPortrait =
mContext.getResources().getConfiguration().orientation == ORIENTATION_PORTRAIT;
// copy the input Rect, since SurfaceControl.screenshot can mutate it
Rect screenRect = new Rect(crop);
Bitmap screenshot = captureScreenshot(crop);
if (screenshot == null) {
Log.e(TAG, "takeScreenshotInternal: Screenshot bitmap was null");
mNotificationsController.notifyScreenshotError(
R.string.screenshot_failed_to_capture_text);
if (mCurrentRequestCallback != null) {
mCurrentRequestCallback.reportError();
}
return;
}
// 调用saveScreenshot完成截屏
// showFlag控制截屏动画
saveScreenshot(screenshot, finisher, screenRect, Insets.NONE, true);
}