WindowAlignment.java revision 79b86b227e6794937ec311522b50e727f8eec263
1/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5 * in compliance with the License. You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software distributed under the License
10 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11 * or implied. See the License for the specific language governing permissions and limitations under
12 * the License.
13 */
14
15package android.support.v17.leanback.widget;
16
17import static android.support.v17.leanback.widget.BaseGridView.WINDOW_ALIGN_LOW_EDGE;
18import static android.support.v17.leanback.widget.BaseGridView.WINDOW_ALIGN_HIGH_EDGE;
19import static android.support.v17.leanback.widget.BaseGridView.WINDOW_ALIGN_BOTH_EDGE;
20import static android.support.v17.leanback.widget.BaseGridView.WINDOW_ALIGN_OFFSET_PERCENT_DISABLED;
21
22import static android.support.v7.widget.RecyclerView.HORIZONTAL;
23
24/**
25 * Maintains Window Alignment information of two axis.
26 */
27class WindowAlignment {
28
29    /**
30     * Maintains alignment information in one direction.
31     */
32    public static class Axis {
33        /**
34         * mScrollCenter is used to calculate dynamic transformation based on how far a view
35         * is from the mScrollCenter. For example, the views with center close to mScrollCenter
36         * will be scaled up.
37         */
38        private float mScrollCenter;
39        /**
40         * Right or bottom edge of last child.
41         */
42        private int mMaxEdge;
43        /**
44         * Left or top edge of first child, typically should be zero.
45         */
46        private int mMinEdge;
47        /**
48         * Max Scroll value
49         */
50        private int mMaxScroll;
51        /**
52         * Min Scroll value
53         */
54        private int mMinScroll;
55
56        private int mWindowAlignment = WINDOW_ALIGN_BOTH_EDGE;
57
58        private int mWindowAlignmentOffset = 0;
59
60        private float mWindowAlignmentOffsetPercent = 50f;
61
62        private int mSize;
63
64        private int mPaddingLow;
65
66        private int mPaddingHigh;
67
68        private String mName; // for debugging
69
70        public Axis(String name) {
71            reset();
72            mName = name;
73        }
74
75        final public int getWindowAlignment() {
76            return mWindowAlignment;
77        }
78
79        final public void setWindowAlignment(int windowAlignment) {
80            mWindowAlignment = windowAlignment;
81        }
82
83        final public int getWindowAlignmentOffset() {
84            return mWindowAlignmentOffset;
85        }
86
87        final public void setWindowAlignmentOffset(int offset) {
88            mWindowAlignmentOffset = offset;
89        }
90
91        final public void setWindowAlignmentOffsetPercent(float percent) {
92            if ((percent < 0 || percent > 100)
93                    && percent != WINDOW_ALIGN_OFFSET_PERCENT_DISABLED) {
94                throw new IllegalArgumentException();
95            }
96            mWindowAlignmentOffsetPercent = percent;
97        }
98
99        final public float getWindowAlignmentOffsetPercent() {
100            return mWindowAlignmentOffsetPercent;
101        }
102
103        final public int getScrollCenter() {
104            return (int) mScrollCenter;
105        }
106
107        /** set minEdge,  Integer.MIN_VALUE means unknown*/
108        final public void setMinEdge(int minEdge) {
109            mMinEdge = minEdge;
110        }
111
112        /** set minScroll,  Integer.MIN_VALUE means unknown*/
113        final public void setMinScroll(int minScroll) {
114            mMinScroll = minScroll;
115        }
116
117        final public int getMinScroll() {
118            return mMinScroll;
119        }
120
121        final public void invalidateScrollMin() {
122            mMinEdge = Integer.MIN_VALUE;
123            mMinScroll = Integer.MIN_VALUE;
124        }
125
126        /** update max edge,  Integer.MAX_VALUE means unknown*/
127        final public void setMaxEdge(int maxEdge) {
128            mMaxEdge = maxEdge;
129        }
130
131        /** update max scroll,  Integer.MAX_VALUE means unknown*/
132        final public void setMaxScroll(int maxScroll) {
133            mMaxScroll = maxScroll;
134        }
135
136        final public int getMaxScroll() {
137            return mMaxScroll;
138        }
139
140        final public void invalidateScrollMax() {
141            mMaxEdge = Integer.MAX_VALUE;
142            mMaxScroll = Integer.MAX_VALUE;
143        }
144
145        final public float updateScrollCenter(float scrollTarget) {
146            mScrollCenter = scrollTarget;
147            return scrollTarget;
148        }
149
150        private void reset() {
151            mScrollCenter = Integer.MIN_VALUE;
152            mMinEdge = Integer.MIN_VALUE;
153            mMaxEdge = Integer.MAX_VALUE;
154        }
155
156        final public boolean isMinUnknown() {
157            return mMinEdge == Integer.MIN_VALUE;
158        }
159
160        final public boolean isMaxUnknown() {
161            return mMaxEdge == Integer.MAX_VALUE;
162        }
163
164        final public void setSize(int size) {
165            mSize = size;
166        }
167
168        final public int getSize() {
169            return mSize;
170        }
171
172        final public void setPadding(int paddingLow, int paddingHigh) {
173            mPaddingLow = paddingLow;
174            mPaddingHigh = paddingHigh;
175        }
176
177        final public int getPaddingLow() {
178            return mPaddingLow;
179        }
180
181        final public int getPaddingHigh() {
182            return mPaddingHigh;
183        }
184
185        final public int getClientSize() {
186            return mSize - mPaddingLow - mPaddingHigh;
187        }
188
189        final public int getSystemScrollPos() {
190            return getSystemScrollPos((int) mScrollCenter);
191        }
192
193        final public int getSystemScrollPos(int scrollCenter) {
194            int middlePosition;
195            if (mWindowAlignmentOffset >= 0) {
196                middlePosition = mWindowAlignmentOffset - mPaddingLow;
197            } else {
198                middlePosition = mSize + mWindowAlignmentOffset - mPaddingLow;
199            }
200            if (mWindowAlignmentOffsetPercent != WINDOW_ALIGN_OFFSET_PERCENT_DISABLED) {
201                middlePosition += (int) (mSize * mWindowAlignmentOffsetPercent / 100);
202            }
203            int clientSize = getClientSize();
204            int afterMiddlePosition = clientSize - middlePosition;
205            boolean isMinUnknown = isMinUnknown();
206            boolean isMaxUnknown = isMaxUnknown();
207            if (!isMinUnknown && !isMaxUnknown &&
208                    (mWindowAlignment & WINDOW_ALIGN_BOTH_EDGE) == WINDOW_ALIGN_BOTH_EDGE) {
209                if (mMaxEdge - mMinEdge <= clientSize) {
210                    // total children size is less than view port and we want to align
211                    // both edge:  align first child to left edge of view port
212                    return mMinEdge - mPaddingLow;
213                }
214            }
215            if (!isMinUnknown) {
216                if ((mWindowAlignment & WINDOW_ALIGN_LOW_EDGE) != 0 &&
217                        scrollCenter - mMinEdge <= middlePosition) {
218                    // scroll center is within half of view port size: align the left edge
219                    // of first child to the left edge of view port
220                    return mMinEdge - mPaddingLow;
221                }
222            }
223            if (!isMaxUnknown) {
224                if ((mWindowAlignment & WINDOW_ALIGN_HIGH_EDGE) != 0 &&
225                        mMaxEdge - scrollCenter <= afterMiddlePosition) {
226                    // scroll center is very close to the right edge of view port : align the
227                    // right edge of last children (plus expanded size) to view port's right
228                    return mMaxEdge -mPaddingLow - (clientSize);
229                }
230            }
231            // else put scroll center in middle of view port
232            return scrollCenter - middlePosition - mPaddingLow;
233        }
234
235        @Override
236        public String toString() {
237            return "center: " + mScrollCenter + " min:" + mMinEdge +
238                    " max:" + mMaxEdge;
239        }
240
241    }
242
243    private int mOrientation = HORIZONTAL;
244
245    final public Axis vertical = new Axis("vertical");
246
247    final public Axis horizontal = new Axis("horizontal");
248
249    private Axis mMainAxis = horizontal;
250
251    private Axis mSecondAxis = vertical;
252
253    final public Axis mainAxis() {
254        return mMainAxis;
255    }
256
257    final public Axis secondAxis() {
258        return mSecondAxis;
259    }
260
261    final public void setOrientation(int orientation) {
262        mOrientation = orientation;
263        if (mOrientation == HORIZONTAL) {
264            mMainAxis = horizontal;
265            mSecondAxis = vertical;
266        } else {
267            mMainAxis = vertical;
268            mSecondAxis = horizontal;
269        }
270    }
271
272    final public int getOrientation() {
273        return mOrientation;
274    }
275
276    final public void reset() {
277        mainAxis().reset();
278    }
279
280    @Override
281    public String toString() {
282        return new StringBuffer().append("horizontal=")
283                .append(horizontal.toString())
284                .append("vertical=")
285                .append(vertical.toString())
286                .toString();
287    }
288
289}
290