Loading core/java/com/android/internal/view/ListViewCaptureHelper.java +8 −4 Original line number Diff line number Diff line Loading @@ -23,10 +23,13 @@ import static com.android.internal.view.ScrollCaptureViewSupport.transformFromRe import android.annotation.NonNull; import android.graphics.Rect; import android.os.CancellationSignal; import android.util.Log; import android.view.View; import android.widget.ListView; import java.util.function.Consumer; /** * Scroll capture support for ListView. * Loading Loading @@ -56,8 +59,8 @@ public class ListViewCaptureHelper implements ScrollCaptureViewHelper<ListView> } @Override public ScrollResult onScrollRequested(@NonNull ListView listView, Rect scrollBounds, Rect requestRect) { public void onScrollRequested(@NonNull ListView listView, Rect scrollBounds, Rect requestRect, CancellationSignal signal, Consumer<ScrollResult> resultConsumer) { Log.d(TAG, "-----------------------------------------------------------"); Log.d(TAG, "onScrollRequested(scrollBounds=" + scrollBounds + ", " + "requestRect=" + requestRect + ")"); Loading @@ -69,7 +72,8 @@ public class ListViewCaptureHelper implements ScrollCaptureViewHelper<ListView> if (!listView.isVisibleToUser() || listView.getChildCount() == 0) { Log.w(TAG, "listView is empty or not visible, cannot continue"); return result; // result.availableArea == empty Rect resultConsumer.accept(result); // result.availableArea == empty Rect return; } // Make requestRect relative to RecyclerView (from scrollBounds) Loading Loading @@ -117,7 +121,7 @@ public class ListViewCaptureHelper implements ScrollCaptureViewHelper<ListView> mScrollDelta, scrollBounds, requestedContainerBounds); } Log.d(TAG, "-----------------------------------------------------------"); return result; resultConsumer.accept(result); } @Override Loading core/java/com/android/internal/view/RecyclerViewCaptureHelper.java +12 −6 Original line number Diff line number Diff line Loading @@ -18,11 +18,14 @@ package com.android.internal.view; import android.annotation.NonNull; import android.graphics.Rect; import android.os.CancellationSignal; import android.util.Log; import android.view.View; import android.view.ViewGroup; import android.view.ViewParent; import java.util.function.Consumer; /** * ScrollCapture for RecyclerView and <i>RecyclerView-like</i> ViewGroups. * <p> Loading Loading @@ -61,8 +64,8 @@ public class RecyclerViewCaptureHelper implements ScrollCaptureViewHelper<ViewGr } @Override public ScrollResult onScrollRequested(@NonNull ViewGroup recyclerView, Rect scrollBounds, Rect requestRect) { public void onScrollRequested(@NonNull ViewGroup recyclerView, Rect scrollBounds, Rect requestRect, CancellationSignal signal, Consumer<ScrollResult> resultConsumer) { ScrollResult result = new ScrollResult(); result.requestedArea = new Rect(requestRect); result.scrollDelta = mScrollDelta; Loading @@ -70,7 +73,8 @@ public class RecyclerViewCaptureHelper implements ScrollCaptureViewHelper<ViewGr if (!recyclerView.isVisibleToUser() || recyclerView.getChildCount() == 0) { Log.w(TAG, "recyclerView is empty or not visible, cannot continue"); return result; // result.availableArea == empty Rect resultConsumer.accept(result); // result.availableArea == empty Rect return; } // move from scrollBounds-relative to parent-local coordinates Loading @@ -83,7 +87,8 @@ public class RecyclerViewCaptureHelper implements ScrollCaptureViewHelper<ViewGr View anchor = findChildNearestTarget(recyclerView, requestedContainerBounds); if (anchor == null) { Log.w(TAG, "Failed to locate anchor view"); return result; // result.availableArea == empty rect resultConsumer.accept(result); // result.availableArea == empty rect return; } Rect requestedContentBounds = new Rect(requestedContainerBounds); Loading Loading @@ -113,13 +118,14 @@ public class RecyclerViewCaptureHelper implements ScrollCaptureViewHelper<ViewGr if (!requestedContainerBounds.intersect(recyclerLocalVisible)) { // Requested area is still not visible return result; resultConsumer.accept(result); return; } Rect available = new Rect(requestedContainerBounds); available.offset(-scrollBounds.left, -scrollBounds.top); available.offset(0, mScrollDelta); result.availableArea = available; return result; resultConsumer.accept(result); } /** Loading core/java/com/android/internal/view/ScrollCaptureViewHelper.java +11 −7 Original line number Diff line number Diff line Loading @@ -18,9 +18,12 @@ package com.android.internal.view; import android.annotation.NonNull; import android.graphics.Rect; import android.os.CancellationSignal; import android.view.View; import android.view.ViewGroup; import java.util.function.Consumer; /** * Provides view-specific handling to ScrollCaptureViewSupport. * Loading Loading @@ -102,17 +105,18 @@ public interface ScrollCaptureViewHelper<V extends View> { * necessary to bring the content within the rectangle into the visible area of the view if * needed and return the resulting rectangle describing the position and bounds of the area * which is visible. * * @param view the view being captured * @param scrollBounds the area in which scrolling content moves, local to the {@code containing * view} * @param requestRect the area relative to {@code scrollBounds} which describes the location of * content to capture for the request * @return the result of the request as a {@link ScrollResult} * @param cancellationSignal allows for the request to be cancelled by the caller * @param resultConsumer accepts the result of the request as a {@link ScrollResult} */ @NonNull ScrollResult onScrollRequested(@NonNull V view, @NonNull Rect scrollBounds, @NonNull Rect requestRect); void onScrollRequested(@NonNull V view, @NonNull Rect scrollBounds, @NonNull Rect requestRect, CancellationSignal cancellationSignal, Consumer<ScrollResult> resultConsumer); /** * Restore the target after capture. Loading core/java/com/android/internal/view/ScrollCaptureViewSupport.java +23 −31 Original line number Diff line number Diff line Loading @@ -249,46 +249,38 @@ public class ScrollCaptureViewSupport<V extends View> implements ScrollCaptureCa } // Ask the view to scroll as needed to bring this area into view. ScrollResult scrollResult = mViewHelper.onScrollRequested(view, session.getScrollBounds(), requestRect); mViewHelper.onScrollRequested(view, session.getScrollBounds(), requestRect, signal, (result) -> onScrollResult(result, view, signal, onComplete)); } private void onScrollResult(ScrollResult scrollResult, V view, CancellationSignal signal, Consumer<Rect> onComplete) { if (signal.isCanceled()) { Log.w(TAG, "onScrollCaptureImageRequest: cancelled! skipping render."); return; } if (scrollResult.availableArea.isEmpty()) { onComplete.accept(scrollResult.availableArea); return; } // For image capture, shift back by scrollDelta to arrive at the location within the view // where the requested content will be drawn // 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); Runnable captureAction = () -> { if (signal.isCanceled()) { Log.w(TAG, "onScrollCaptureImageRequest: cancelled! skipping render."); } else { int result = mRenderer.renderView(view, viewCaptureArea); switch (result) { case HardwareRenderer.SYNC_OK: case HardwareRenderer.SYNC_REDRAW_REQUESTED: if (result == HardwareRenderer.SYNC_OK || result == HardwareRenderer.SYNC_REDRAW_REQUESTED) { /* Frame synced, buffer will be produced... notify client. */ onComplete.accept(new Rect(scrollResult.availableArea)); return; case HardwareRenderer.SYNC_FRAME_DROPPED: Log.e(TAG, "syncAndDraw(): SYNC_FRAME_DROPPED !"); break; case HardwareRenderer.SYNC_LOST_SURFACE_REWARD_IF_FOUND: Log.e(TAG, "syncAndDraw(): SYNC_LOST_SURFACE !"); break; case HardwareRenderer.SYNC_CONTEXT_IS_STOPPED: Log.e(TAG, "syncAndDraw(): SYNC_CONTEXT_IS_STOPPED !"); break; } } else { // No buffer will be produced. Log.e(TAG, "syncAndDraw(): SyncAndDrawResult = " + result); onComplete.accept(new Rect(/* empty */)); } }; view.postOnAnimationDelayed(captureAction, mPostScrollDelayMillis); } @Override Loading core/java/com/android/internal/view/ScrollViewCaptureHelper.java +10 −5 Original line number Diff line number Diff line Loading @@ -19,10 +19,13 @@ package com.android.internal.view; import android.annotation.NonNull; import android.graphics.Point; import android.graphics.Rect; import android.os.CancellationSignal; import android.view.View; import android.view.ViewGroup; import android.view.ViewParent; import java.util.function.Consumer; /** * ScrollCapture for ScrollView and <i>ScrollView-like</i> ViewGroups. * <p> Loading Loading @@ -60,8 +63,8 @@ public class ScrollViewCaptureHelper implements ScrollCaptureViewHelper<ViewGrou } } public ScrollResult onScrollRequested(@NonNull ViewGroup view, Rect scrollBounds, Rect requestRect) { public void onScrollRequested(@NonNull ViewGroup view, Rect scrollBounds, Rect requestRect, CancellationSignal signal, Consumer<ScrollResult> resultConsumer) { /* +---------+ <----+ Content [25,25 - 275,1025] (w=250,h=1000) | | Loading Loading @@ -105,7 +108,8 @@ public class ScrollViewCaptureHelper implements ScrollCaptureViewHelper<ViewGrou final View contentView = view.getChildAt(0); // returns null, does not throw IOOBE if (contentView == null) { // No child view? Cannot continue. return result; resultConsumer.accept(result); return; } // 1) Translate request rect to make it relative to container view Loading Loading @@ -155,7 +159,8 @@ public class ScrollViewCaptureHelper implements ScrollCaptureViewHelper<ViewGrou if (!view.getChildVisibleRect(contentView, available, offset)) { available.setEmpty(); result.availableArea = available; return result; resultConsumer.accept(result); return; } // Transform back from global to content-view local available.offset(-offset.x, -offset.y); Loading @@ -174,7 +179,7 @@ public class ScrollViewCaptureHelper implements ScrollCaptureViewHelper<ViewGrou available.offset(0, scrollDelta); result.availableArea = new Rect(available); return result; resultConsumer.accept(result); } public void onPrepareForEnd(@NonNull ViewGroup view) { Loading Loading
core/java/com/android/internal/view/ListViewCaptureHelper.java +8 −4 Original line number Diff line number Diff line Loading @@ -23,10 +23,13 @@ import static com.android.internal.view.ScrollCaptureViewSupport.transformFromRe import android.annotation.NonNull; import android.graphics.Rect; import android.os.CancellationSignal; import android.util.Log; import android.view.View; import android.widget.ListView; import java.util.function.Consumer; /** * Scroll capture support for ListView. * Loading Loading @@ -56,8 +59,8 @@ public class ListViewCaptureHelper implements ScrollCaptureViewHelper<ListView> } @Override public ScrollResult onScrollRequested(@NonNull ListView listView, Rect scrollBounds, Rect requestRect) { public void onScrollRequested(@NonNull ListView listView, Rect scrollBounds, Rect requestRect, CancellationSignal signal, Consumer<ScrollResult> resultConsumer) { Log.d(TAG, "-----------------------------------------------------------"); Log.d(TAG, "onScrollRequested(scrollBounds=" + scrollBounds + ", " + "requestRect=" + requestRect + ")"); Loading @@ -69,7 +72,8 @@ public class ListViewCaptureHelper implements ScrollCaptureViewHelper<ListView> if (!listView.isVisibleToUser() || listView.getChildCount() == 0) { Log.w(TAG, "listView is empty or not visible, cannot continue"); return result; // result.availableArea == empty Rect resultConsumer.accept(result); // result.availableArea == empty Rect return; } // Make requestRect relative to RecyclerView (from scrollBounds) Loading Loading @@ -117,7 +121,7 @@ public class ListViewCaptureHelper implements ScrollCaptureViewHelper<ListView> mScrollDelta, scrollBounds, requestedContainerBounds); } Log.d(TAG, "-----------------------------------------------------------"); return result; resultConsumer.accept(result); } @Override Loading
core/java/com/android/internal/view/RecyclerViewCaptureHelper.java +12 −6 Original line number Diff line number Diff line Loading @@ -18,11 +18,14 @@ package com.android.internal.view; import android.annotation.NonNull; import android.graphics.Rect; import android.os.CancellationSignal; import android.util.Log; import android.view.View; import android.view.ViewGroup; import android.view.ViewParent; import java.util.function.Consumer; /** * ScrollCapture for RecyclerView and <i>RecyclerView-like</i> ViewGroups. * <p> Loading Loading @@ -61,8 +64,8 @@ public class RecyclerViewCaptureHelper implements ScrollCaptureViewHelper<ViewGr } @Override public ScrollResult onScrollRequested(@NonNull ViewGroup recyclerView, Rect scrollBounds, Rect requestRect) { public void onScrollRequested(@NonNull ViewGroup recyclerView, Rect scrollBounds, Rect requestRect, CancellationSignal signal, Consumer<ScrollResult> resultConsumer) { ScrollResult result = new ScrollResult(); result.requestedArea = new Rect(requestRect); result.scrollDelta = mScrollDelta; Loading @@ -70,7 +73,8 @@ public class RecyclerViewCaptureHelper implements ScrollCaptureViewHelper<ViewGr if (!recyclerView.isVisibleToUser() || recyclerView.getChildCount() == 0) { Log.w(TAG, "recyclerView is empty or not visible, cannot continue"); return result; // result.availableArea == empty Rect resultConsumer.accept(result); // result.availableArea == empty Rect return; } // move from scrollBounds-relative to parent-local coordinates Loading @@ -83,7 +87,8 @@ public class RecyclerViewCaptureHelper implements ScrollCaptureViewHelper<ViewGr View anchor = findChildNearestTarget(recyclerView, requestedContainerBounds); if (anchor == null) { Log.w(TAG, "Failed to locate anchor view"); return result; // result.availableArea == empty rect resultConsumer.accept(result); // result.availableArea == empty rect return; } Rect requestedContentBounds = new Rect(requestedContainerBounds); Loading Loading @@ -113,13 +118,14 @@ public class RecyclerViewCaptureHelper implements ScrollCaptureViewHelper<ViewGr if (!requestedContainerBounds.intersect(recyclerLocalVisible)) { // Requested area is still not visible return result; resultConsumer.accept(result); return; } Rect available = new Rect(requestedContainerBounds); available.offset(-scrollBounds.left, -scrollBounds.top); available.offset(0, mScrollDelta); result.availableArea = available; return result; resultConsumer.accept(result); } /** Loading
core/java/com/android/internal/view/ScrollCaptureViewHelper.java +11 −7 Original line number Diff line number Diff line Loading @@ -18,9 +18,12 @@ package com.android.internal.view; import android.annotation.NonNull; import android.graphics.Rect; import android.os.CancellationSignal; import android.view.View; import android.view.ViewGroup; import java.util.function.Consumer; /** * Provides view-specific handling to ScrollCaptureViewSupport. * Loading Loading @@ -102,17 +105,18 @@ public interface ScrollCaptureViewHelper<V extends View> { * necessary to bring the content within the rectangle into the visible area of the view if * needed and return the resulting rectangle describing the position and bounds of the area * which is visible. * * @param view the view being captured * @param scrollBounds the area in which scrolling content moves, local to the {@code containing * view} * @param requestRect the area relative to {@code scrollBounds} which describes the location of * content to capture for the request * @return the result of the request as a {@link ScrollResult} * @param cancellationSignal allows for the request to be cancelled by the caller * @param resultConsumer accepts the result of the request as a {@link ScrollResult} */ @NonNull ScrollResult onScrollRequested(@NonNull V view, @NonNull Rect scrollBounds, @NonNull Rect requestRect); void onScrollRequested(@NonNull V view, @NonNull Rect scrollBounds, @NonNull Rect requestRect, CancellationSignal cancellationSignal, Consumer<ScrollResult> resultConsumer); /** * Restore the target after capture. Loading
core/java/com/android/internal/view/ScrollCaptureViewSupport.java +23 −31 Original line number Diff line number Diff line Loading @@ -249,46 +249,38 @@ public class ScrollCaptureViewSupport<V extends View> implements ScrollCaptureCa } // Ask the view to scroll as needed to bring this area into view. ScrollResult scrollResult = mViewHelper.onScrollRequested(view, session.getScrollBounds(), requestRect); mViewHelper.onScrollRequested(view, session.getScrollBounds(), requestRect, signal, (result) -> onScrollResult(result, view, signal, onComplete)); } private void onScrollResult(ScrollResult scrollResult, V view, CancellationSignal signal, Consumer<Rect> onComplete) { if (signal.isCanceled()) { Log.w(TAG, "onScrollCaptureImageRequest: cancelled! skipping render."); return; } if (scrollResult.availableArea.isEmpty()) { onComplete.accept(scrollResult.availableArea); return; } // For image capture, shift back by scrollDelta to arrive at the location within the view // where the requested content will be drawn // 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); Runnable captureAction = () -> { if (signal.isCanceled()) { Log.w(TAG, "onScrollCaptureImageRequest: cancelled! skipping render."); } else { int result = mRenderer.renderView(view, viewCaptureArea); switch (result) { case HardwareRenderer.SYNC_OK: case HardwareRenderer.SYNC_REDRAW_REQUESTED: if (result == HardwareRenderer.SYNC_OK || result == HardwareRenderer.SYNC_REDRAW_REQUESTED) { /* Frame synced, buffer will be produced... notify client. */ onComplete.accept(new Rect(scrollResult.availableArea)); return; case HardwareRenderer.SYNC_FRAME_DROPPED: Log.e(TAG, "syncAndDraw(): SYNC_FRAME_DROPPED !"); break; case HardwareRenderer.SYNC_LOST_SURFACE_REWARD_IF_FOUND: Log.e(TAG, "syncAndDraw(): SYNC_LOST_SURFACE !"); break; case HardwareRenderer.SYNC_CONTEXT_IS_STOPPED: Log.e(TAG, "syncAndDraw(): SYNC_CONTEXT_IS_STOPPED !"); break; } } else { // No buffer will be produced. Log.e(TAG, "syncAndDraw(): SyncAndDrawResult = " + result); onComplete.accept(new Rect(/* empty */)); } }; view.postOnAnimationDelayed(captureAction, mPostScrollDelayMillis); } @Override Loading
core/java/com/android/internal/view/ScrollViewCaptureHelper.java +10 −5 Original line number Diff line number Diff line Loading @@ -19,10 +19,13 @@ package com.android.internal.view; import android.annotation.NonNull; import android.graphics.Point; import android.graphics.Rect; import android.os.CancellationSignal; import android.view.View; import android.view.ViewGroup; import android.view.ViewParent; import java.util.function.Consumer; /** * ScrollCapture for ScrollView and <i>ScrollView-like</i> ViewGroups. * <p> Loading Loading @@ -60,8 +63,8 @@ public class ScrollViewCaptureHelper implements ScrollCaptureViewHelper<ViewGrou } } public ScrollResult onScrollRequested(@NonNull ViewGroup view, Rect scrollBounds, Rect requestRect) { public void onScrollRequested(@NonNull ViewGroup view, Rect scrollBounds, Rect requestRect, CancellationSignal signal, Consumer<ScrollResult> resultConsumer) { /* +---------+ <----+ Content [25,25 - 275,1025] (w=250,h=1000) | | Loading Loading @@ -105,7 +108,8 @@ public class ScrollViewCaptureHelper implements ScrollCaptureViewHelper<ViewGrou final View contentView = view.getChildAt(0); // returns null, does not throw IOOBE if (contentView == null) { // No child view? Cannot continue. return result; resultConsumer.accept(result); return; } // 1) Translate request rect to make it relative to container view Loading Loading @@ -155,7 +159,8 @@ public class ScrollViewCaptureHelper implements ScrollCaptureViewHelper<ViewGrou if (!view.getChildVisibleRect(contentView, available, offset)) { available.setEmpty(); result.availableArea = available; return result; resultConsumer.accept(result); return; } // Transform back from global to content-view local available.offset(-offset.x, -offset.y); Loading @@ -174,7 +179,7 @@ public class ScrollViewCaptureHelper implements ScrollCaptureViewHelper<ViewGrou available.offset(0, scrollDelta); result.availableArea = new Rect(available); return result; resultConsumer.accept(result); } public void onPrepareForEnd(@NonNull ViewGroup view) { Loading