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 android.view;
18 
19 import static java.util.Objects.requireNonNull;
20 
21 import android.annotation.NonNull;
22 import android.annotation.Nullable;
23 import android.annotation.UiThread;
24 import android.graphics.Point;
25 import android.graphics.Rect;
26 import android.os.CancellationSignal;
27 
28 import java.io.PrintWriter;
29 import java.util.function.Consumer;
30 
31 /**
32  * A target collects the set of contextual information for a ScrollCaptureHandler discovered during
33  * a {@link View#dispatchScrollCaptureSearch scroll capture search}.
34  */
35 public final class ScrollCaptureTarget {
36     private final View mContainingView;
37     private final ScrollCaptureCallback mCallback;
38     private final Rect mLocalVisibleRect;
39     private final Point mPositionInWindow;
40     private final int mHint;
41     private Rect mScrollBounds;
42 
43     private final int[] mTmpIntArr = new int[2];
44 
ScrollCaptureTarget(@onNull View scrollTarget, @NonNull Rect localVisibleRect, @NonNull Point positionInWindow, @NonNull ScrollCaptureCallback callback)45     public ScrollCaptureTarget(@NonNull View scrollTarget, @NonNull Rect localVisibleRect,
46             @NonNull Point positionInWindow, @NonNull ScrollCaptureCallback callback) {
47         mContainingView = requireNonNull(scrollTarget);
48         mHint = mContainingView.getScrollCaptureHint();
49         mCallback = requireNonNull(callback);
50         mLocalVisibleRect = requireNonNull(localVisibleRect);
51         mPositionInWindow = requireNonNull(positionInWindow);
52     }
53 
54     /**
55      * @return the hint that the {@code containing view} had during the scroll capture search
56      * @see View#getScrollCaptureHint()
57      */
58     @View.ScrollCaptureHint
getHint()59     public int getHint() {
60         return mHint;
61     }
62 
63     /** @return the {@link ScrollCaptureCallback} for this target */
64     @NonNull
getCallback()65     public ScrollCaptureCallback getCallback() {
66         return mCallback;
67     }
68 
69     /** @return the {@code containing view} for this {@link ScrollCaptureCallback callback} */
70     @NonNull
getContainingView()71     public View getContainingView() {
72         return mContainingView;
73     }
74 
75     /**
76      * Returns the visible bounds of the containing view.
77      *
78      * @return the visible bounds of the {@code containing view} in view-local coordinates
79      */
80     @NonNull
getLocalVisibleRect()81     public Rect getLocalVisibleRect() {
82         return mLocalVisibleRect;
83     }
84 
85     /** @return the position of the visible bounds of the containing view within the window */
86     @NonNull
getPositionInWindow()87     public Point getPositionInWindow() {
88         return mPositionInWindow;
89     }
90 
91     /**
92      * @return the {@code scroll bounds} for this {@link ScrollCaptureCallback callback}
93      *
94      * @see ScrollCaptureCallback#onScrollCaptureSearch(CancellationSignal, Consumer)
95      */
96     @Nullable
getScrollBounds()97     public Rect getScrollBounds() {
98         return mScrollBounds;
99     }
100 
101     /**
102      * Sets the scroll bounds rect to the intersection of provided rect and the current bounds of
103      * the {@code containing view}.
104      */
setScrollBounds(@ullable Rect scrollBounds)105     public void setScrollBounds(@Nullable Rect scrollBounds) {
106         mScrollBounds = Rect.copyOrNull(scrollBounds);
107         if (mScrollBounds == null) {
108             return;
109         }
110         if (!mScrollBounds.intersect(0, 0,
111                 mContainingView.getWidth(), mContainingView.getHeight())) {
112             mScrollBounds.setEmpty();
113         }
114     }
115 
116     /**
117      * Refresh the local visible bounds and its offset within the window, based on the current
118      * state of the {@code containing view}.
119      */
120     @UiThread
updatePositionInWindow()121     public void updatePositionInWindow() {
122         mContainingView.getLocationInWindow(mTmpIntArr);
123         mPositionInWindow.x = mTmpIntArr[0];
124         mPositionInWindow.y = mTmpIntArr[1];
125     }
126 
toString()127     public String toString() {
128         return "ScrollCaptureTarget{" + "view=" + mContainingView
129                 + ", callback=" + mCallback
130                 + ", scrollBounds=" + mScrollBounds
131                 + ", localVisibleRect=" + mLocalVisibleRect
132                 + ", positionInWindow=" + mPositionInWindow
133                 + "}";
134     }
135 
dump(@onNull PrintWriter writer)136     void dump(@NonNull PrintWriter writer) {
137         View view = getContainingView();
138         writer.println("view: " + view);
139         writer.println("hint: " + mHint);
140         writer.println("callback: " + mCallback);
141         writer.println("scrollBounds: "
142                 + (mScrollBounds == null ? "null" : mScrollBounds.toShortString()));
143         Point inWindow = getPositionInWindow();
144         writer.println("positionInWindow: "
145                 + ((inWindow == null) ? "null" : "[" + inWindow.x + "," + inWindow.y + "]"));
146         Rect localVisible = getLocalVisibleRect();
147         writer.println("localVisibleRect: "
148                 + (localVisible == null ? "null" : localVisible.toShortString()));
149     }
150 }
151