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