diff --git a/core/java/android/view/ScrollCaptureConnection.java b/core/java/android/view/ScrollCaptureConnection.java index a6d786e1db21a..5fcb011c76f1b 100644 --- a/core/java/android/view/ScrollCaptureConnection.java +++ b/core/java/android/view/ScrollCaptureConnection.java @@ -185,7 +185,8 @@ public class ScrollCaptureConnection extends IScrollCaptureConnection.Stub { } Log.w(TAG, "close(): capture session still active! Ending now."); // -> UiThread - mUiThread.execute(() -> mLocal.onScrollCaptureEnd(() -> { /* ignore */ })); + final ScrollCaptureCallback callback = mLocal; + mUiThread.execute(() -> callback.onScrollCaptureEnd(() -> { /* ignore */ })); mActive = false; } mActive = false; diff --git a/core/java/com/android/internal/view/ScrollCaptureViewSupport.java b/core/java/com/android/internal/view/ScrollCaptureViewSupport.java index a41511b74a7d6..8aa2d57e8ea66 100644 --- a/core/java/com/android/internal/view/ScrollCaptureViewSupport.java +++ b/core/java/com/android/internal/view/ScrollCaptureViewSupport.java @@ -17,6 +17,7 @@ package com.android.internal.view; import android.annotation.UiThread; +import android.content.ContentResolver; import android.content.Context; import android.content.pm.ActivityInfo; import android.graphics.HardwareRenderer; @@ -26,6 +27,7 @@ import android.graphics.Rect; import android.graphics.RectF; import android.graphics.RenderNode; import android.os.CancellationSignal; +import android.provider.Settings; import android.util.DisplayMetrics; import android.util.Log; import android.view.Display.ColorMode; @@ -53,11 +55,14 @@ public class ScrollCaptureViewSupport implements ScrollCaptureCa private static final String TAG = "ScrollCaptureViewSupport"; - private static final boolean WAIT_FOR_ANIMATION = true; + private static final String SETTING_CAPTURE_DELAY = "screenshot.scroll_capture_delay"; + private static final long SETTING_CAPTURE_DELAY_DEFAULT = 60L; // millis private final WeakReference mWeakView; private final ScrollCaptureViewHelper mViewHelper; private final ViewRenderer mRenderer; + private final long mPostScrollDelayMillis; + private boolean mStarted; private boolean mEnded; @@ -66,6 +71,10 @@ public class ScrollCaptureViewSupport implements ScrollCaptureCa mRenderer = new ViewRenderer(); // TODO(b/177649144): provide access to color space from android.media.Image mViewHelper = viewHelper; + Context context = containingView.getContext(); + ContentResolver contentResolver = context.getContentResolver(); + mPostScrollDelayMillis = Settings.Global.getLong(contentResolver, + SETTING_CAPTURE_DELAY, SETTING_CAPTURE_DELAY_DEFAULT); } /** Based on ViewRootImpl#updateColorModeIfNeeded */ @@ -120,37 +129,41 @@ public class ScrollCaptureViewSupport implements ScrollCaptureCa public final void onScrollCaptureImageRequest(ScrollCaptureSession session, CancellationSignal signal, Rect requestRect, Consumer onComplete) { if (signal.isCanceled()) { + Log.w(TAG, "onScrollCaptureImageRequest: cancelled!"); return; } + V view = mWeakView.get(); if (view == null || !view.isVisibleToUser()) { // Signal to the controller that we have a problem and can't continue. onComplete.accept(new Rect()); return; } + // Ask the view to scroll as needed to bring this area into view. ScrollResult scrollResult = mViewHelper.onScrollRequested(view, session.getScrollBounds(), requestRect); + if (scrollResult.availableArea.isEmpty()) { onComplete.accept(scrollResult.availableArea); return; } - view.invalidate(); // don't wait for vsync // For image capture, shift back by scrollDelta to arrive at the location within the view // where the requested content will be drawn Rect viewCaptureArea = new Rect(scrollResult.availableArea); viewCaptureArea.offset(0, -scrollResult.scrollDelta); - if (WAIT_FOR_ANIMATION) { - view.postOnAnimation(() -> { + Runnable captureAction = () -> { + if (signal.isCanceled()) { + Log.w(TAG, "onScrollCaptureImageRequest: cancelled! skipping render."); + } else { mRenderer.renderView(view, viewCaptureArea); onComplete.accept(new Rect(scrollResult.availableArea)); - }); - } else { - mRenderer.renderView(view, viewCaptureArea); - onComplete.accept(new Rect(scrollResult.availableArea)); - } + } + }; + + view.postOnAnimationDelayed(captureAction, mPostScrollDelayMillis); } @Override diff --git a/core/tests/coretests/src/android/view/ScrollCaptureConnectionTest.java b/core/tests/coretests/src/android/view/ScrollCaptureConnectionTest.java index 22c71b527d480..e7b88c8df3936 100644 --- a/core/tests/coretests/src/android/view/ScrollCaptureConnectionTest.java +++ b/core/tests/coretests/src/android/view/ScrollCaptureConnectionTest.java @@ -32,6 +32,7 @@ import android.graphics.Point; import android.graphics.Rect; import android.os.Handler; import android.os.ICancellationSignal; +import android.os.RemoteException; import android.platform.test.annotations.Presubmit; import androidx.test.filters.SmallTest; @@ -189,4 +190,15 @@ public class ScrollCaptureConnectionTest { verifyNoMoreInteractions(mRemote); } + @Test + public void testClose_whileActive() throws RemoteException { + mConnection.startCapture(mSurface, mRemote); + + mCallback.completeStartRequest(); + assertTrue(mConnection.isActive()); + + mConnection.close(); + mCallback.completeEndRequest(); + assertFalse(mConnection.isActive()); + } }