SystemUI之ScreenShot

 2023-09-05 阅读 75 评论 0

摘要:ScreenShot流程 base/services/core/java/com/android/server/policy/PhoneWindowManager.java 物理截屏:按下power键和音量下键 private void initKeyCombinationRules() {mKeyCombinationManager = new KeyCombinationManager();final boolean screenshotChordEn

ScreenShot流程

base/services/core/java/com/android/server/policy/PhoneWindowManager.java

物理截屏:按下power键和音量下键

private void initKeyCombinationRules() {mKeyCombinationManager = new KeyCombinationManager();final boolean screenshotChordEnabled = mContext.getResources().getBoolean(com.android.internal.R.bool.config_enableScreenshotChord);if (screenshotChordEnabled) {mKeyCombinationManager.addRule(//按下电源键和音量下键new TwoKeysCombinationRule(KEYCODE_VOLUME_DOWN, KEYCODE_POWER) {@Overridevoid execute() {mPowerKeyHandled = true;interceptScreenshotChord();}@Overridevoid cancel() {cancelPendingScreenshotChordAction();}});}
}

收到截屏指令后,执行interceptScreenshotChord方法,

设置截屏类型

全屏:TAKE_SCREENSHOT_FULLSCREEN

用户选择区域:TAKE_SCREENSHOT_SELECTED_REGION

调用者提供的图像:TAKE_SCREENSHOT_PROVIDED_IMAGE

设置截屏来源

SCREENSHOT_KEY_CHORD

SCREENSHOT_KEY_OTHER

SCREENSHOT_OVERVIEW

SCREENSHOT_ACCESSIBILITY_ACTIONS

SCREENSHOT_OTHER

SCREENSHOT_VENDOR_GESTURE

private void interceptScreenshotChord() {mHandler.removeCallbacks(mScreenshotRunnable);mScreenshotRunnable.setScreenshotType(TAKE_SCREENSHOT_FULLSCREEN);mScreenshotRunnable.setScreenshotSource(SCREENSHOT_KEY_CHORD);mHandler.postDelayed(mScreenshotRunnable, getScreenshotChordLongPressDelay());}

执行ScreenRunnale.run()方法

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;}@Overridepublic void run() {mDefaultDisplayPolicy.takeScreenshot(mScreenshotType, mScreenshotSource);}}

截屏takeScreenshot()

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 */);}}

base/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java

创建一个 GlobalScreenshot 对象,通过GlobalScreenshot对象实现截屏
private final GlobalScreenshot mScreenshot;

在Handler中对三种截屏方式做处理

private Handler mHandler = new Handler(Looper.myLooper()) {@Overridepublic void handleMessage(Message msg) {final Messenger callback = msg.replyTo;Consumer<Uri> uriConsumer = uri -> {Message reply = Message.obtain(null, SCREENSHOT_MSG_URI, uri);try {callback.send(reply);} catch (RemoteException e) {}};Runnable onComplete = () -> {Message reply = Message.obtain(null, SCREENSHOT_MSG_PROCESS_COMPLETE);try {callback.send(reply);} catch (RemoteException e) {}};// If the storage for this user is locked, we have no place to store// the screenshot, so skip taking it instead of showing a misleading// animation and error notification.if (!mUserManager.isUserUnlocked()) {Log.w(TAG, "Skipping screenshot because storage is locked!");post(() -> uriConsumer.accept(null));post(onComplete);return;}ScreenshotHelper.ScreenshotRequest screenshotRequest =(ScreenshotHelper.ScreenshotRequest) msg.obj;mUiEventLogger.log(ScreenshotEvent.getScreenshotSource(screenshotRequest.getSource()));switch (msg.what) {case WindowManager.TAKE_SCREENSHOT_FULLSCREEN:mScreenshot.takeScreenshot(uriConsumer, onComplete);break;case WindowManager.TAKE_SCREENSHOT_SELECTED_REGION:mScreenshot.takeScreenshotPartial(uriConsumer, onComplete);break;case WindowManager.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();mScreenshot.handleImageAsScreenshot(screenshot, screenBounds, insets,taskId, userId, topComponent, uriConsumer, onComplete);break;default:Log.d(TAG, "Invalid screenshot option: " + msg.what);}}};

当截取全屏时

base/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java

private void takeScreenshot(Consumer<Uri> finisher, Rect crop) {// copy the input Rect, since SurfaceControl.screenshot can mutate itRect screenRect = new Rect(crop);int rot = mDisplay.getRotation();int width = crop.width();int height = crop.height();takeScreenshot(SurfaceControl.screenshot(crop, width, height, rot), finisher, screenRect,Insets.NONE, true);}private void takeScreenshot(Bitmap screenshot, Consumer<Uri> finisher, Rect screenRect,Insets screenInsets, boolean showFlash) {dismissScreenshot("new screenshot requested", true);mScreenBitmap = screenshot;if (mScreenBitmap == null) {mNotificationsController.notifyScreenshotError(R.string.screenshot_failed_to_capture_text);finisher.accept(null);mOnCompleteRunnable.run();return;}if (!isUserSetupComplete()) {// User setup isn't complete, so we don't want to show any UI beyond a toast, as editing// and sharing shouldn't be exposed to the user.saveScreenshotAndToast(finisher);return;}// OptimizationsmScreenBitmap.setHasAlpha(false);mScreenBitmap.prepareToDraw();onConfigChanged(mContext.getResources().getConfiguration());if (mDismissAnimation != null && mDismissAnimation.isRunning()) {mDismissAnimation.cancel();}// The window is focusable by defaultsetWindowFocusable(true);// Start the post-screenshot animationstartAnimation(finisher, screenRect, screenInsets, showFlash);}

截屏之后开始截屏动画

private void startAnimation(final Consumer<Uri> finisher, Rect screenRect, Insets screenInsets,boolean showFlash) {// If power save is on, show a toast so there is some visual indication that a// screenshot has been taken.PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);if (powerManager.isPowerSaveMode()) {Toast.makeText(mContext, R.string.screenshot_saved_title, Toast.LENGTH_SHORT).show();}mScreenshotHandler.post(() -> {if (!mScreenshotLayout.isAttachedToWindow()) {mWindowManager.addView(mScreenshotLayout, mWindowLayoutParams);}mScreenshotAnimatedView.setImageDrawable(createScreenDrawable(mScreenBitmap, screenInsets));setAnimatedViewSize(screenRect.width(), screenRect.height());// Show when the animation startsmScreenshotAnimatedView.setVisibility(View.GONE);mScreenshotPreview.setImageDrawable(createScreenDrawable(mScreenBitmap, screenInsets));// make static preview invisible (from gone) so we can query its location on screenmScreenshotPreview.setVisibility(View.INVISIBLE);mScreenshotHandler.post(() -> {mScreenshotLayout.getViewTreeObserver().addOnComputeInternalInsetsListener(this);mScreenshotAnimation =createScreenshotDropInAnimation(screenRect, showFlash);saveScreenshotInWorkerThread(finisher, new ActionsReadyListener() {@Overridevoid onActionsReady(SavedImageData imageData) {showUiOnActionsReady(imageData);}});// Play the shutter sound to notify that we've taken a screenshotmCameraSound.play(MediaActionSound.SHUTTER_CLICK);mScreenshotPreview.setLayerType(View.LAYER_TYPE_HARDWARE, null);mScreenshotPreview.buildLayer();mScreenshotAnimation.start();});});}

版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。

原文链接:https://808629.com/786.html

发表评论:

本站为非赢利网站,部分文章来源或改编自互联网及其他公众平台,主要目的在于分享信息,版权归原作者所有,内容仅供读者参考,如有侵权请联系我们删除!

Copyright © 2022 86后生记录生活 Inc. 保留所有权利。

底部版权信息