1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.internal.view;
18 
19 import android.annotation.NonNull;
20 import android.graphics.Rect;
21 import android.view.View;
22 import android.view.ViewGroup;
23 
24 /**
25  * Provides view-specific handling to ScrollCaptureViewSupport.
26  *
27  * @param <V> the View subclass
28  */
29 public interface ScrollCaptureViewHelper<V extends View> {
30     int UP = -1;
31     int DOWN = 1;
32 
33     /**
34      * Contains the result of a scroll request.
35      */
36     class ScrollResult {
37         /**
38          * The area requested in pixels, within {@link #onComputeScrollBounds scroll bounds}, with
39          * top/bottom relative to the scroll position at the start of capture.
40          */
41         public Rect requestedArea;
42         /**
43          * The area, in pixels of the request which is visible and available for capture. In the
44          * same coordinate space as {@link #requestedArea}.
45          */
46         public Rect availableArea;
47         /**
48          * The updated scroll delta (the relative distance, in pixels that the scroll position has
49          * moved from the starting position since capture started).
50          */
51         public int scrollDelta; // visible top offset from start
52 
53         @Override
toString()54         public String toString() {
55             return "ScrollResult{"
56                     + "requestedArea=" + requestedArea
57                     + ", availableArea=" + availableArea
58                     + ", scrollDelta=" + scrollDelta
59                     + '}';
60         }
61     }
62 
63     /**
64      * Verifies that the view is still visible and scrollable. If true is returned here, expect a
65      * call to {@link #onComputeScrollBounds(View)} to follow.
66      *
67      * @param view the view being captured
68      * @return true if the callback should respond to a request with scroll bounds
69      */
onAcceptSession(@onNull V view)70     default boolean onAcceptSession(@NonNull V view) {
71         return view.isVisibleToUser()
72                 && (view.canScrollVertically(UP) || view.canScrollVertically(DOWN));
73     }
74 
75     /**
76      * Given a scroll capture request for a view, adjust the provided rect to cover the scrollable
77      * content area. The default implementation returns the padded content area of {@code view}.
78      *
79      * @param view the view being captured
80      */
onComputeScrollBounds(@onNull V view)81     @NonNull default Rect onComputeScrollBounds(@NonNull V view) {
82         Rect bounds = new Rect(0, 0, view.getWidth(), view.getHeight());
83         if (view instanceof ViewGroup && ((ViewGroup) view).getClipToPadding()) {
84             bounds.inset(view.getPaddingLeft(), view.getPaddingTop(),
85                     view.getPaddingRight(), view.getPaddingBottom());
86         }
87         return bounds;
88     }
89 
90     /**
91      * Adjust the target for capture.
92      * <p>
93      * Do not touch anything that may change layout positions or sizes on screen. Anything else may
94      * be adjusted as long as it can be reversed in {@link #onPrepareForEnd(View)}.
95      *
96      * @param view         the view being captured
97      * @param scrollBounds the bounds within {@code view} where content scrolls
98      */
onPrepareForStart(@onNull V view, @NonNull Rect scrollBounds)99     void onPrepareForStart(@NonNull V view, @NonNull Rect scrollBounds);
100 
101     /**
102      * Map the request onto the screen.
103      * <p>
104      * Given a  rect describing the area to capture, relative to scrollBounds, take actions
105      * necessary to bring the content within the rectangle into the visible area of the view if
106      * needed and return the resulting rectangle describing the position and bounds of the area
107      * which is visible.
108      *
109      * @param view the view being captured
110      * @param scrollBounds the area in which scrolling content moves, local to the {@code containing
111      *                     view}
112      * @param requestRect  the area relative to {@code scrollBounds} which describes the location of
113      *                     content to capture for the request
114      * @return the result of the request as a {@link ScrollResult}
115      */
116     @NonNull
onScrollRequested(@onNull V view, @NonNull Rect scrollBounds, @NonNull Rect requestRect)117     ScrollResult onScrollRequested(@NonNull V view, @NonNull Rect scrollBounds,
118             @NonNull Rect requestRect);
119 
120     /**
121      * Restore the target after capture.
122      * <p>
123      * Put back anything that was changed in {@link #onPrepareForStart(View, Rect)}.
124      *
125      * @param view the view being captured
126      */
onPrepareForEnd(@onNull V view)127     void onPrepareForEnd(@NonNull V view);
128 }
129