1 // Copyright 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 package org.chromium.chrome.browser.feed.shared.stream;
6 
7 import android.view.View;
8 
9 import androidx.annotation.IntDef;
10 import androidx.annotation.Nullable;
11 
12 import java.lang.annotation.Retention;
13 import java.lang.annotation.RetentionPolicy;
14 import java.util.List;
15 
16 /** Interface used for interacting with the Stream library in order to render a stream of cards. */
17 public interface Stream {
18     /** Constant used to notify host that a view's position on screen is not known. */
19     int POSITION_NOT_KNOWN = Integer.MIN_VALUE;
20 
21     @IntDef({FeedFirstCardDensity.UNKNOWN, FeedFirstCardDensity.NOT_DENSE,
22             FeedFirstCardDensity.DENSE})
23     @Retention(RetentionPolicy.SOURCE)
24     @interface FeedFirstCardDensity {
25         int UNKNOWN = 0;
26         int NOT_DENSE = 1;
27         int DENSE = 2;
28     }
29 
30     /**
31      * Called when the Stream is being created. {@code savedInstanceState} should be a previous
32      * string returned from {@link #getSavedInstanceStateString()}.
33      *
34      * @param savedInstanceState state to restore to.
35      * @throws IllegalStateException if method is called multiple times.
36      */
onCreate(@ullable String savedInstanceState)37     void onCreate(@Nullable String savedInstanceState);
38 
39     /**
40      * Called when the Stream is visible on the screen, may be partially obscured or about to be
41      * displayed. This maps similarly to {@link android.app.Activity#onStart()}.
42      *
43      * <p>This will cause the Stream to start pre-warming feed services.
44      */
onShow()45     void onShow();
46 
47     /**
48      * Called when the Stream is no longer visible on screen. This should act similarly to {@link
49      * android.app.Activity#onStop()}.
50      */
onHide()51     void onHide();
52 
53     /**
54      * Called when the Stream is destroyed. This should act similarly to {@link
55      * android.app.Activity#onDestroy()}.
56      */
onDestroy()57     void onDestroy();
58 
59     /**
60      * The returned string should be passed to {@link #onCreate(String)} when the activity is
61      * recreated and the stream needs to be recreated.
62      */
getSavedInstanceStateString()63     String getSavedInstanceStateString();
64 
65     /**
66      * Return the root view which holds all card stream views. The Feed library builds Views when
67      * this method is called (caches as needed). This must be called after {@link
68      * #onCreate()}. Multiple calls to this method will return the same View.
69      *
70      * @throws IllegalStateException when called before {@link #onCreate()}.
71      */
getView()72     View getView();
73 
74     /**
75      * Set headers on the stream. Headers will be added to the top of the stream in the order they
76      * are in the list. The headers are not sticky and will scroll with content. Headers can be
77      * cleared by passing in an empty list.
78      */
setHeaderViews(List<Header> headers)79     void setHeaderViews(List<Header> headers);
80 
81     /**
82      * Sets whether or not the Stream should show Feed content. Header views will still be shown if
83      * set.
84      */
setStreamContentVisibility(boolean visible)85     void setStreamContentVisibility(boolean visible);
86 
87     /**
88      * Notifies the Stream to purge unnecessary memory. This just purges recycling pools for now.
89      * Can expand out as needed.
90      */
trim()91     void trim();
92 
93     /**
94      * Called by the host to scroll the Stream by a certain amount. If the Stream is unable to
95      * scroll the desired amount, it will scroll as much as possible.
96      *
97      * @param dx amount in pixels for Stream to scroll horizontally
98      * @param dy amount in pixels for Stream to scroll vertically
99      */
smoothScrollBy(int dx, int dy)100     void smoothScrollBy(int dx, int dy);
101 
102     /**
103      * Returns the top position in pixels of the View at the {@code position} in the vertical
104      * hierarchy. This should act similarly to {@code RecyclerView.getChildAt(position).getTop()}.
105      *
106      * <p>Returns {@link #POSITION_NOT_KNOWN} if position is not known. This could be returned if
107      * {@code position} it not a valid position or the actual child has not been placed on screen
108      * and rendered.
109      */
getChildTopAt(int position)110     int getChildTopAt(int position);
111 
112     /**
113      * Returns true if the child at the position is visible on screen. The view could be partially
114      * visible and this would still return true.
115      */
isChildAtPositionVisible(int position)116     boolean isChildAtPositionVisible(int position);
117 
addScrollListener(ScrollListener listener)118     void addScrollListener(ScrollListener listener);
119 
removeScrollListener(ScrollListener listener)120     void removeScrollListener(ScrollListener listener);
121 
addOnContentChangedListener(ContentChangedListener listener)122     void addOnContentChangedListener(ContentChangedListener listener);
123 
removeOnContentChangedListener(ContentChangedListener listener)124     void removeOnContentChangedListener(ContentChangedListener listener);
125 
126     /**
127      * Allow the container to trigger a refresh of the stream.
128      *
129      * <p>Note: this will assume {@link RequestReason.HOST_REQUESTED}.
130      */
triggerRefresh()131     void triggerRefresh();
132 
133     /**
134      * @return Whether the placeholder is shown.
135      */
isPlaceholderShown()136     boolean isPlaceholderShown();
137 
138     /**
139      * Called when the placeholder is shown and the first batch of articles are about to show.
140      */
hidePlaceholder()141     void hidePlaceholder();
142 
143     /**
144      * Get whether the first card of Feed is dense in portrait mode.
145      */
getFirstCardDensity()146     default int getFirstCardDensity() {
147         return FeedFirstCardDensity.UNKNOWN;
148     };
149 
150     /**
151      * Interface users can implement to know when content in the Stream has changed content on
152      * screen.
153      */
154     interface ContentChangedListener {
155         /**
156          * Called by Stream when content being shown has changed. This could be new cards being
157          * created, the content of a card changing, etc...
158          */
onContentChanged()159         void onContentChanged();
160 
161         /**
162          * Called by Stream when an
163          * {@link androidx.recyclerview.widget.SimpleItemAnimator#onAddFinished} event is received.
164          */
onAddFinished()165         default void onAddFinished(){};
166 
167         /**
168          * Called by Stream when an
169          * {@link androidx.recyclerview.widget.SimpleItemAnimator#onAddStarting} event is received.
170          */
onAddStarting()171         default void onAddStarting(){};
172     }
173 
174     /** Interface users can implement to be told about changes to scrolling in the Stream. */
175     interface ScrollListener {
176         /**
177          * Constant used to denote that a scroll was performed but scroll delta could not be
178          * calculated. This normally maps to a programmatic scroll.
179          */
180         int UNKNOWN_SCROLL_DELTA = Integer.MIN_VALUE;
181 
onScrollStateChanged(@crollState int state)182         void onScrollStateChanged(@ScrollState int state);
183 
184         /**
185          * Called when a scroll happens and provides the amount of pixels scrolled. {@link
186          * #UNKNOWN_SCROLL_DELTA} will be specified if scroll delta would not be determined. An
187          * example of this would be a scroll initiated programmatically.
188          */
onScrolled(int dx, int dy)189         void onScrolled(int dx, int dy);
190 
191         /**
192          * Possible scroll states.
193          *
194          * <p>When adding new values, the value of {@link ScrollState#NEXT_VALUE} should be used and
195          * incremented. When removing values, {@link ScrollState#NEXT_VALUE} should not be changed,
196          * and those values should not be reused.
197          */
198         @IntDef({ScrollState.IDLE, ScrollState.DRAGGING, ScrollState.SETTLING,
199                 ScrollState.NEXT_VALUE})
200         @interface ScrollState {
201             /** Stream is not scrolling */
202             int IDLE = 0;
203 
204             /** Stream is currently scrolling through external means such as user input. */
205             int DRAGGING = 1;
206 
207             /** Stream is animating to a final position. */
208             int SETTLING = 2;
209 
210             /** The next value that should be used when adding additional values to the IntDef. */
211             int NEXT_VALUE = 3;
212         }
213     }
214 }
215