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:
@@ -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;
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user