前言
一般截屏都是电源键+音量减键,而这些按键的处理都是在 PhoneWindowManager 中进行的,但在该类中有两个主要处理按键的方法:
- interceptKeyBeforeQueueing():主要处理音量键、电源键(Power键)、耳机键等。
- interceptKeyBeforeDispatching():处理一般性的按键和动作。
参数含义:
- interactive:是否亮屏
- KeyEvent.FLAG_FALLBACK:不被应用处理的按键事件或一些在 键值映射中不被处理的事件(例:轨迹球事件等)。
这里我们直接看 PhoneWindowManager#interceptKeyBeforeQueueing() 方法:
frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| @Override public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) { final int keyCode = event.getKeyCode(); final boolean down = event.getAction() == KeyEvent.ACTION_DOWN; boolean isWakeKey = (policyFlags & WindowManagerPolicy.FLAG_WAKE) != 0 || event.isWakeKey(); if (!mSystemBooted) { return 0; } final boolean isDefaultDisplayOn = Display.isOnState(mDefaultDisplay.getState()); final boolean interactiveAndOn = interactive && isDefaultDisplayOn; if ((event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) { handleKeyGesture(event, interactiveAndOn); } switch (keyCode) { return result; }
|
上述代码里说的组合键添加,在 initKeyCombinationRules() 方法中,并在PhoneWindowManager的 init() 方法中初始化。关于 initKeyCombinationRules() 方法,下文会有讲述。
下面接着看 PhoneWindowManager#handleKeyGesture() 方法:
frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| private void handleKeyGesture(KeyEvent event, boolean interactive) { if (mKeyCombinationManager.interceptKey(event, interactive)) { mSingleKeyGestureDetector.reset(); return; } if (event.getKeyCode() == KEYCODE_POWER && event.getAction() == KeyEvent.ACTION_DOWN) { mPowerKeyHandled = handleCameraGesture(event, interactive); if (mPowerKeyHandled) { mSingleKeyGestureDetector.reset(); return; } } mSingleKeyGestureDetector.interceptKey(event, interactive); }
|
这里我们主要看 mKeyCombinationManager.interceptKey(event, interactive) 方法就行了;
KeyCombinationManager#interceptKey():
frameworks/base/services/core/java/com/android/server/policy/KeyCombinationManager.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| boolean interceptKey(KeyEvent event, boolean interactive) { synchronized (mLock) { return interceptKeyLocked(event, interactive); } } private boolean interceptKeyLocked(KeyEvent event, boolean interactive) { final boolean down = event.getAction() == KeyEvent.ACTION_DOWN; final int keyCode = event.getKeyCode(); final int count = mActiveRules.size(); final long eventTime = event.getEventTime(); if (interactive && down) { if (mDownTimes.size() == 1) { } else { if (mTriggeredRule != null) { return true; } forAllActiveRules((rule) -> { if (!rule.shouldInterceptKeys(mDownTimes)) { return false; } Log.v(TAG, "Performing combination rule : " + rule); mHandler.post(rule::execute); mTriggeredRule = rule; return true; }); mActiveRules.clear(); if (mTriggeredRule != null) { mActiveRules.add(mTriggeredRule); return true; } } } else { } return false; }
|
这里我们看下组合键添加,及触发回调。
initKeyCombinationRules()
frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| private void initKeyCombinationRules() { mKeyCombinationManager = new KeyCombinationManager(mHandler); final boolean screenshotChordEnabled = mContext.getResources().getBoolean( com.android.internal.R.bool.config_enableScreenshotChord); if (screenshotChordEnabled) { mKeyCombinationManager.addRule( new TwoKeysCombinationRule(KEYCODE_VOLUME_DOWN, KEYCODE_POWER) { @Override void execute() { mPowerKeyHandled = true; interceptScreenshotChord(TAKE_SCREENSHOT_FULLSCREEN, SCREENSHOT_KEY_CHORD, getScreenshotChordLongPressDelay()); } @Override void cancel() { cancelPendingScreenshotChordAction(); } }); } }
|
上面通过 handle 发了一个消息,将会调用 handleScreenShot() 方法,处理截屏:
PhoneWindowManager# handleScreenShot()
frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java
1 2 3 4 5
| private void handleScreenShot(@WindowManager.ScreenshotType int type, @WindowManager.ScreenshotSource int source) { mDefaultDisplayPolicy.takeScreenshot(type, source); }
|
DisplayPolicy#takeScreenshot()
frameworks/base/services/core/java/com/android/server/wm/DisplayPolicy.java
1 2 3 4 5 6 7 8 9
| public void takeScreenshot(int screenshotType, int source) { if (mScreenshotHelper != null) { mScreenshotHelper.takeScreenshot(screenshotType, getStatusBar() != null && getStatusBar().isVisible(), getNavigationBar() != null && getNavigationBar().isVisible(), source, mHandler, null ); } }
|
继续往下看 ScreenshotHelper#takeScreenshot()
frameworks/base/core/java/com/android/internal/util/ScreenshotHelper.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
| 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); }
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(); } } if (completionConsumer != null) { completionConsumer.accept(null); } }; Message msg = Message.obtain(null, screenshotType, screenshotRequest); Handler h = new Handler(handler.getLooper()) { @Override public void handleMessage(Message msg) { switch (msg.what) { case SCREENSHOT_MSG_URI: if (completionConsumer != null) { completionConsumer.accept((Uri) msg.obj); } handler.removeCallbacks(mScreenshotTimeout); break; case SCREENSHOT_MSG_PROCESS_COMPLETE: synchronized (mScreenshotLock) { resetConnection(); } break; } } }; msg.replyTo = new Messenger(h); if (mScreenshotConnection == null || mScreenshotService == null) { final ComponentName serviceComponent = ComponentName.unflattenFromString( mContext.getResources().getString( com.android.internal.R.string.config_screenshotServiceComponent)); final Intent serviceIntent = new Intent(); serviceIntent.setComponent(serviceComponent); ServiceConnection conn = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { synchronized (mScreenshotLock) { if (mScreenshotConnection != this) { return; } mScreenshotService = service; Messenger messenger = new Messenger(mScreenshotService); try { messenger.send(msg); } catch (RemoteException e) { Log.e(TAG, "Couldn't take screenshot: " + e); if (completionConsumer != null) { completionConsumer.accept(null); } } } } @Override public void onServiceDisconnected(ComponentName name) { synchronized (mScreenshotLock) { if (mScreenshotConnection != null) { resetConnection(); if (handler.hasCallbacks(mScreenshotTimeout)) { handler.removeCallbacks(mScreenshotTimeout); notifyScreenshotError(); } } } } }; if (mContext.bindServiceAsUser(serviceIntent, conn, Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE, UserHandle.CURRENT)) { mScreenshotConnection = conn; handler.postDelayed(mScreenshotTimeout, timeoutMs); } } else { Messenger messenger = new Messenger(mScreenshotService); try { messenger.send(msg); } catch (RemoteException e) { Log.e(TAG, "Couldn't take screenshot: " + e); if (completionConsumer != null) { completionConsumer.accept(null); } } handler.postDelayed(mScreenshotTimeout, timeoutMs); } } }
|
客户端通过向服务端发送 message 来将截屏任务交给 service,由 service 处理后面的操作。
frameworks/base/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
| @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()) { mNotificationsController.notifyScreenshotError( R.string.screenshot_failed_to_save_user_locked_text); requestCallback.reportError(); return true; } if (mDevicePolicyManager.getScreenCaptureDisabled(null, UserHandle.USER_ALL)) { mBgExecutor.execute(() -> { String blockedByAdminText = mDevicePolicyManager.getResources().getString( SCREENSHOT_BLOCKED_BY_ADMIN, () -> mContext.getString(R.string.screenshot_blocked_by_admin)); mHandler.post(() -> Toast.makeText(mContext, blockedByAdminText, Toast.LENGTH_SHORT).show()); requestCallback.reportError(); }); return true; } ScreenshotHelper.ScreenshotRequest screenshotRequest = (ScreenshotHelper.ScreenshotRequest) msg.obj; ComponentName topComponent = screenshotRequest.getTopComponent(); mUiEventLogger.log(ScreenshotEvent.getScreenshotSource(screenshotRequest.getSource()), 0, topComponent == null ? "" : topComponent.getPackageName()); switch (msg.what) { case WindowManager.TAKE_SCREENSHOT_FULLSCREEN: mScreenshot.takeScreenshotFullscreen(topComponent, uriConsumer, requestCallback); break; case WindowManager.TAKE_SCREENSHOT_SELECTED_REGION: mScreenshot.takeScreenshotPartial(topComponent, uriConsumer, requestCallback); break; case WindowManager.TAKE_SCREENSHOT_PROVIDED_IMAGE: Bitmap screenshot = ScreenshotHelper.HardwareBitmapBundler.bundleToHardwareBitmap( screenshotRequest.getBitmapBundle()); Rect screenBounds = screenshotRequest.getBoundsInScreen(); Insets insets = screenshotRequest.getInsets(); int taskId = screenshotRequest.getTaskId(); int userId = screenshotRequest.getUserId(); if (screenshot == null) { 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; }
|
TakeScreenshotService 调用 ScreenshotController.java 的 takeScreenshotFullscreen() ;
ScreenshotController#takeScreenshotFullscreen()
frameworks/base/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| void takeScreenshotFullscreen(ComponentName topComponent, Consumer<Uri> finisher, RequestCallback requestCallback) { Assert.isMainThread(); mCurrentRequestCallback = requestCallback; DisplayMetrics displayMetrics = new DisplayMetrics(); getDefaultDisplay().getRealMetrics(displayMetrics); takeScreenshotInternal( topComponent, finisher, new Rect(0, 0, displayMetrics.widthPixels, displayMetrics.heightPixels)); }
private void takeScreenshotInternal(ComponentName topComponent, Consumer<Uri> finisher, Rect crop) { mScreenshotTakenInPortrait = mContext.getResources().getConfiguration().orientation == ORIENTATION_PORTRAIT; Rect screenRect = new Rect(crop); Bitmap screenshot = captureScreenshot(crop); if (screenshot == null) { mNotificationsController.notifyScreenshotError( R.string.screenshot_failed_to_capture_text); if (mCurrentRequestCallback != null) { mCurrentRequestCallback.reportError(); } return; } saveScreenshot(screenshot, finisher, screenRect, Insets.NONE, topComponent, true); mBroadcastSender.sendBroadcast(new Intent(ClipboardOverlayController.SCREENSHOT_ACTION), ClipboardOverlayController.SELF_PERMISSION); }
|
如何截图的呢?这里我们看 captureScreenshot() 方法;
ScreenshotController#captureScreenshot()
frameworks/base/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| private Bitmap captureScreenshot(Rect crop) { int width = crop.width(); int height = crop.height(); Bitmap screenshot = null; final Display display = getDefaultDisplay(); final DisplayAddress address = display.getAddress(); if (!(address instanceof DisplayAddress.Physical)) { Log.e(TAG, "Skipping Screenshot - Default display does not have a physical address: " + display); } else { final DisplayAddress.Physical physicalAddress = (DisplayAddress.Physical) address; final IBinder displayToken = SurfaceControl.getPhysicalDisplayToken( physicalAddress.getPhysicalDisplayId()); final SurfaceControl.DisplayCaptureArgs captureArgs = new SurfaceControl.DisplayCaptureArgs.Builder(displayToken) .setSourceCrop(crop) .setSize(width, height) .build(); final SurfaceControl.ScreenshotHardwareBuffer screenshotBuffer = SurfaceControl.captureDisplay(captureArgs); screenshot = screenshotBuffer == null ? null : screenshotBuffer.asBitmap(); } return screenshot; }
|
上面是捕获图片的过程,里面到底如何捕获的。这点我目前还没弄清。
接着拿到截屏的 Bitmap 后就可以进行图片保存,显示等等一些操作。
接着看 ScreenshotController#saveScreenshot()
frameworks/base/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
| private void saveScreenshot(Bitmap screenshot, Consumer<Uri> finisher, Rect screenRect, Insets screenInsets, ComponentName topComponent, boolean showFlash) { withWindowAttached(() -> mScreenshotView.announceForAccessibility( mContext.getResources().getString(R.string.screenshot_saving_title))); if (mScreenshotView.isAttachedToWindow()) { if (!mScreenshotView.isDismissing()) { mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_REENTERED, 0, mPackageName); } if (DEBUG_WINDOW) { Log.d(TAG, "saveScreenshot: screenshotView is already attached, resetting. " + "(dismissing=" + mScreenshotView.isDismissing() + ")"); } mScreenshotView.reset(); } saveScreenshotInWorkerThread(finisher, this::showUiOnActionsReady, this::showUiOnQuickShareActionReady); setWindowFocusable(true); withWindowAttached(() -> { requestScrollCapture(); mWindow.peekDecorView().getViewRootImpl().setActivityConfigCallback( new ViewRootImpl.ActivityConfigCallback() { @Override public void onConfigurationChanged(Configuration overrideConfig, int newDisplayId) { } @Override public void requestCompatCameraControl(boolean showControl, boolean transformationApplied, ICompatCameraControlCallback callback) { } }); }); attachWindow(); mScreenshotView.setScreenshot(mScreenBitmap, screenInsets); setContentView(mScreenshotView); }
|
截屏布局 screenshot_static.xml :
frameworks/base/packages/SystemUI/res/layout/screenshot_static.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
| <com.android.systemui.screenshot.DraggableConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent"> <ImageView android:id="@+id/actions_container_background" android:visibility="gone" android:layout_height="0dp" android:layout_width="0dp" android:elevation="4dp" android:background="@drawable/action_chip_container_background" android:layout_marginStart="@dimen/overlay_action_container_margin_horizontal" app:layout_constraintBottom_toBottomOf="@+id/actions_container" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="@+id/actions_container" app:layout_constraintEnd_toEndOf="@+id/actions_container"/> <HorizontalScrollView android:id="@+id/actions_container" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginEnd="@dimen/overlay_action_container_margin_horizontal" android:layout_marginBottom="4dp" android:paddingEnd="@dimen/overlay_action_container_padding_right" android:paddingVertical="@dimen/overlay_action_container_padding_vertical" android:elevation="4dp" android:scrollbars="none" app:layout_constraintHorizontal_bias="0" app:layout_constraintWidth_percent="1.0" app:layout_constraintWidth_max="wrap" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintStart_toEndOf="@+id/screenshot_preview_border" app:layout_constraintEnd_toEndOf="parent"> <LinearLayout android:id="@+id/screenshot_actions" android:layout_width="wrap_content" android:layout_height="wrap_content"> <include layout="@layout/overlay_action_chip" android:id="@+id/screenshot_share_chip"/> <include layout="@layout/overlay_action_chip" android:id="@+id/screenshot_edit_chip"/> <include layout="@layout/overlay_action_chip" android:id="@+id/screenshot_scroll_chip" android:visibility="gone" /> </LinearLayout> </HorizontalScrollView> <View android:id="@+id/screenshot_preview_border" android:layout_width="0dp" android:layout_height="0dp" android:layout_marginStart="@dimen/overlay_offset_x" android:layout_marginBottom="12dp" android:elevation="7dp" android:alpha="0" android:background="@drawable/overlay_border" app:layout_constraintStart_toStartOf="parent" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="@id/screenshot_preview_end" app:layout_constraintTop_toTopOf="@id/screenshot_preview_top"/> <androidx.constraintlayout.widget.Barrier android:id="@+id/screenshot_preview_end" android:layout_width="wrap_content" android:layout_height="wrap_content" app:barrierMargin="@dimen/overlay_border_width" app:barrierDirection="end" app:constraint_referenced_ids="screenshot_preview"/> <androidx.constraintlayout.widget.Barrier android:id="@+id/screenshot_preview_top" android:layout_width="wrap_content" android:layout_height="wrap_content" app:barrierDirection="top" app:barrierMargin="@dimen/overlay_border_width_neg" app:constraint_referenced_ids="screenshot_preview"/> <ImageView android:id="@+id/screenshot_preview" android:visibility="invisible" android:layout_width="@dimen/overlay_x_scale" android:layout_margin="@dimen/overlay_border_width" android:layout_height="wrap_content" android:layout_gravity="center" android:elevation="7dp" android:contentDescription="@string/screenshot_edit_description" android:scaleType="fitEnd" android:background="@drawable/overlay_preview_background" android:adjustViewBounds="true" android:clickable="true" app:layout_constraintBottom_toBottomOf="@id/screenshot_preview_border" app:layout_constraintStart_toStartOf="@id/screenshot_preview_border" app:layout_constraintEnd_toEndOf="@id/screenshot_preview_border" app:layout_constraintTop_toTopOf="@id/screenshot_preview_border"> </ImageView> <FrameLayout android:id="@+id/screenshot_dismiss_button" android:layout_width="@dimen/overlay_dismiss_button_tappable_size" android:layout_height="@dimen/overlay_dismiss_button_tappable_size" android:elevation="10dp" app:layout_constraintStart_toEndOf="@id/screenshot_preview" app:layout_constraintEnd_toEndOf="@id/screenshot_preview" app:layout_constraintTop_toTopOf="@id/screenshot_preview" app:layout_constraintBottom_toTopOf="@id/screenshot_preview" android:contentDescription="@string/screenshot_dismiss_description"> <ImageView android:id="@+id/screenshot_dismiss_image" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_margin="@dimen/overlay_dismiss_button_margin" android:src="@drawable/overlay_cancel"/> </FrameLayout> <ImageView android:id="@+id/screenshot_scrollable_preview" android:layout_width="wrap_content" android:layout_height="wrap_content" android:scaleType="matrix" android:visibility="gone" app:layout_constraintStart_toStartOf="@id/screenshot_preview" app:layout_constraintTop_toTopOf="@id/screenshot_preview" android:elevation="7dp"/> </com.android.systemui.screenshot.DraggableConstraintLayout>
|
至此,全截屏流程就到此结束,saveScreenshotInWorkerThread() 这里不做分析。
下面分析长截屏:
在上述代码中,有讲到 requestScrollCapture() ,请求滚动捕获,即长截屏。
ScreenshotController#requestScrollCapture()
frameworks/base/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| private void requestScrollCapture() { if (!allowLongScreenshots()) { Log.d(TAG, "Long screenshots not supported on this device"); return; } mScrollCaptureClient.setHostWindowToken(mWindow.getDecorView().getWindowToken()); if (mLastScrollCaptureRequest != null) { mLastScrollCaptureRequest.cancel(true); } final ListenableFuture<ScrollCaptureResponse> future = mScrollCaptureClient.request(DEFAULT_DISPLAY); mLastScrollCaptureRequest = future; mLastScrollCaptureRequest.addListener(() -> onScrollCaptureResponseReady(future), mMainExecutor); }
|
长截图捕获流程: mScrollCaptureClient.request() 请求捕获 →mWindowManagerService.requestScrollCapture()→ViewRootImpl#requestScrollCapture()→ViewRootImpl#handleScrollCaptureRequest() 处理滚动捕获请求,拿到捕获目标。 →ViewGroup#dispatchScrollCaptureSearch() 通过检查此视图,处理滚动捕获搜索请求,然后检查每个子视图。该隐藏的隐藏,设置视图偏移等等。
走完上述流程,才会继续往下执行;
接着看 ScreenshotController#onScrollCaptureResponseReady()
frameworks/base/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| private void onScrollCaptureResponseReady(Future<ScrollCaptureResponse> responseFuture) { try { if (mLastScrollCaptureResponse != null) { mLastScrollCaptureResponse.close(); mLastScrollCaptureResponse = null; } if (responseFuture != null) { if (responseFuture.isCancelled()) { return; } mLastScrollCaptureResponse = responseFuture.get(); } else { Log.e(TAG, "onScrollCaptureResponseReady responseFuture is null!"); } if (mLastScrollCaptureResponse != null && !mLastScrollCaptureResponse.isConnected()) { Log.d(TAG, "ScrollCapture: " + mLastScrollCaptureResponse.getDescription() + " [" + mLastScrollCaptureResponse.getWindowTitle() + "]"); return; } Log.d(TAG, "ScrollCapture: connected to window [" + mLastScrollCaptureResponse.getWindowTitle() + "]"); final ScrollCaptureResponse response = mLastScrollCaptureResponse; mScreenshotView.showScrollChip(response.getPackageName(), () -> { DisplayMetrics displayMetrics = new DisplayMetrics(); getDefaultDisplay().getRealMetrics(displayMetrics); Bitmap newScreenshot = captureScreenshot( new Rect(0, 0, displayMetrics.widthPixels, displayMetrics.heightPixels)); mScreenshotView.prepareScrollingTransition(response, mScreenBitmap, newScreenshot, mScreenshotTakenInPortrait); mScreenshotView.post(() -> runBatchScrollCapture(response)); }); } catch (InterruptedException | ExecutionException e) { Log.e(TAG, "requestScrollCapture failed", e); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| private void runBatchScrollCapture(ScrollCaptureResponse response) { mLastScrollCaptureResponse = null; if (mLongScreenshotFuture != null) { mLongScreenshotFuture.cancel(true); } mLongScreenshotFuture = mScrollCaptureController.run(response); mLongScreenshotFuture.addListener(() -> { ScrollCaptureController.LongScreenshot longScreenshot; try { longScreenshot = mLongScreenshotFuture.get(); } catch (CancellationException e) { Log.e(TAG, "Long screenshot cancelled"); return; } catch (InterruptedException | ExecutionException e) { Log.e(TAG, "Exception", e); mScreenshotView.restoreNonScrollingUi(); return; } if (longScreenshot.getHeight() == 0) { mScreenshotView.restoreNonScrollingUi(); return; } mLongScreenshotHolder.setLongScreenshot(longScreenshot); mLongScreenshotHolder.setTransitionDestinationCallback( (transitionDestination, onTransitionEnd) -> mScreenshotView.startLongScreenshotTransition( transitionDestination, onTransitionEnd, longScreenshot)); final Intent intent = new Intent(mContext, LongScreenshotActivity.class); intent.setFlags( Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); mContext.startActivity(intent, ActivityOptions.makeCustomAnimation(mContext, 0, 0).toBundle()); RemoteAnimationAdapter runner = new RemoteAnimationAdapter( SCREENSHOT_REMOTE_RUNNER, 0, 0); try { WindowManagerGlobal.getWindowManagerService() .overridePendingAppTransitionRemote(runner, DEFAULT_DISPLAY); } catch (Exception e) { Log.e(TAG, "Error overriding screenshot app transition", e); } }, mMainExecutor); }
|
本文链接:
http://longzhiye.top/2024/02/10/2024-02-10/