Merge changes I3a11ac86,I84e0b1fd into sc-dev

* changes:
  ScrollCaptureConnection: fix npe on close() when active
  Scroll Capture: Add configurable post-scroll capture delay
This commit is contained in:
Mark Renouf
2021-04-15 19:19:27 +00:00
committed by Android (Google) Code Review
3 changed files with 36 additions and 10 deletions

View File

@@ -185,7 +185,8 @@ public class ScrollCaptureConnection extends IScrollCaptureConnection.Stub {
} }
Log.w(TAG, "close(): capture session still active! Ending now."); Log.w(TAG, "close(): capture session still active! Ending now.");
// -> UiThread // -> UiThread
mUiThread.execute(() -> mLocal.onScrollCaptureEnd(() -> { /* ignore */ })); final ScrollCaptureCallback callback = mLocal;
mUiThread.execute(() -> callback.onScrollCaptureEnd(() -> { /* ignore */ }));
mActive = false; mActive = false;
} }
mActive = false; mActive = false;

View File

@@ -17,6 +17,7 @@
package com.android.internal.view; package com.android.internal.view;
import android.annotation.UiThread; import android.annotation.UiThread;
import android.content.ContentResolver;
import android.content.Context; import android.content.Context;
import android.content.pm.ActivityInfo; import android.content.pm.ActivityInfo;
import android.graphics.HardwareRenderer; import android.graphics.HardwareRenderer;
@@ -26,6 +27,7 @@ import android.graphics.Rect;
import android.graphics.RectF; import android.graphics.RectF;
import android.graphics.RenderNode; import android.graphics.RenderNode;
import android.os.CancellationSignal; import android.os.CancellationSignal;
import android.provider.Settings;
import android.util.DisplayMetrics; import android.util.DisplayMetrics;
import android.util.Log; import android.util.Log;
import android.view.Display.ColorMode; import android.view.Display.ColorMode;
@@ -53,11 +55,14 @@ public class ScrollCaptureViewSupport<V extends View> implements ScrollCaptureCa
private static final String TAG = "ScrollCaptureViewSupport"; 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<V> mWeakView; private final WeakReference<V> mWeakView;
private final ScrollCaptureViewHelper<V> mViewHelper; private final ScrollCaptureViewHelper<V> mViewHelper;
private final ViewRenderer mRenderer; private final ViewRenderer mRenderer;
private final long mPostScrollDelayMillis;
private boolean mStarted; private boolean mStarted;
private boolean mEnded; private boolean mEnded;
@@ -66,6 +71,10 @@ public class ScrollCaptureViewSupport<V extends View> implements ScrollCaptureCa
mRenderer = new ViewRenderer(); mRenderer = new ViewRenderer();
// TODO(b/177649144): provide access to color space from android.media.Image // TODO(b/177649144): provide access to color space from android.media.Image
mViewHelper = viewHelper; 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 */ /** Based on ViewRootImpl#updateColorModeIfNeeded */
@@ -120,37 +129,41 @@ public class ScrollCaptureViewSupport<V extends View> implements ScrollCaptureCa
public final void onScrollCaptureImageRequest(ScrollCaptureSession session, public final void onScrollCaptureImageRequest(ScrollCaptureSession session,
CancellationSignal signal, Rect requestRect, Consumer<Rect> onComplete) { CancellationSignal signal, Rect requestRect, Consumer<Rect> onComplete) {
if (signal.isCanceled()) { if (signal.isCanceled()) {
Log.w(TAG, "onScrollCaptureImageRequest: cancelled!");
return; return;
} }
V view = mWeakView.get(); V view = mWeakView.get();
if (view == null || !view.isVisibleToUser()) { if (view == null || !view.isVisibleToUser()) {
// Signal to the controller that we have a problem and can't continue. // Signal to the controller that we have a problem and can't continue.
onComplete.accept(new Rect()); onComplete.accept(new Rect());
return; return;
} }
// Ask the view to scroll as needed to bring this area into view. // Ask the view to scroll as needed to bring this area into view.
ScrollResult scrollResult = mViewHelper.onScrollRequested(view, session.getScrollBounds(), ScrollResult scrollResult = mViewHelper.onScrollRequested(view, session.getScrollBounds(),
requestRect); requestRect);
if (scrollResult.availableArea.isEmpty()) { if (scrollResult.availableArea.isEmpty()) {
onComplete.accept(scrollResult.availableArea); onComplete.accept(scrollResult.availableArea);
return; return;
} }
view.invalidate(); // don't wait for vsync
// For image capture, shift back by scrollDelta to arrive at the location within the view // For image capture, shift back by scrollDelta to arrive at the location within the view
// where the requested content will be drawn // where the requested content will be drawn
Rect viewCaptureArea = new Rect(scrollResult.availableArea); Rect viewCaptureArea = new Rect(scrollResult.availableArea);
viewCaptureArea.offset(0, -scrollResult.scrollDelta); viewCaptureArea.offset(0, -scrollResult.scrollDelta);
if (WAIT_FOR_ANIMATION) { Runnable captureAction = () -> {
view.postOnAnimation(() -> { if (signal.isCanceled()) {
Log.w(TAG, "onScrollCaptureImageRequest: cancelled! skipping render.");
} else {
mRenderer.renderView(view, viewCaptureArea); mRenderer.renderView(view, viewCaptureArea);
onComplete.accept(new Rect(scrollResult.availableArea)); onComplete.accept(new Rect(scrollResult.availableArea));
}); }
} else { };
mRenderer.renderView(view, viewCaptureArea);
onComplete.accept(new Rect(scrollResult.availableArea)); view.postOnAnimationDelayed(captureAction, mPostScrollDelayMillis);
}
} }
@Override @Override

View File

@@ -32,6 +32,7 @@ import android.graphics.Point;
import android.graphics.Rect; import android.graphics.Rect;
import android.os.Handler; import android.os.Handler;
import android.os.ICancellationSignal; import android.os.ICancellationSignal;
import android.os.RemoteException;
import android.platform.test.annotations.Presubmit; import android.platform.test.annotations.Presubmit;
import androidx.test.filters.SmallTest; import androidx.test.filters.SmallTest;
@@ -189,4 +190,15 @@ public class ScrollCaptureConnectionTest {
verifyNoMoreInteractions(mRemote); 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());
}
} }