blob: 80e17b5e8217d57c2e904aa2e4dab7a3b93ca0cc [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2006 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
17package android.widget;
18
Alan Viverettef6d87ec2016-03-11 10:09:14 -050019import android.annotation.NonNull;
Nader Jawad93aeba82019-02-04 16:42:26 -080020import android.annotation.Nullable;
Artur Satayeved5a6ae2019-12-10 17:47:54 +000021import android.compat.annotation.UnsupportedAppUsage;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080022import android.graphics.Canvas;
23import android.graphics.ColorFilter;
24import android.graphics.PixelFormat;
25import android.graphics.Rect;
26import android.graphics.drawable.Drawable;
Nader Jawad93aeba82019-02-04 16:42:26 -080027import android.os.Build;
28import android.view.View;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080029
Aurimas Liutikas99441c52016-10-11 16:48:32 -070030import com.android.internal.widget.ScrollBarUtils;
31
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080032/**
Alan Viverette029d0392015-01-21 15:41:53 -080033 * This is only used by View for displaying its scroll bars. It should probably
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080034 * be moved in to the view package since it is used in that lower-level layer.
35 * For now, we'll hide it so it can be cleaned up later.
Alan Viverette029d0392015-01-21 15:41:53 -080036 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080037 * {@hide}
38 */
Alan Viverette029d0392015-01-21 15:41:53 -080039public class ScrollBarDrawable extends Drawable implements Drawable.Callback {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080040 private Drawable mVerticalTrack;
41 private Drawable mHorizontalTrack;
Nader Jawad93aeba82019-02-04 16:42:26 -080042 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123768422)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080043 private Drawable mVerticalThumb;
44 private Drawable mHorizontalThumb;
Alan Viverette029d0392015-01-21 15:41:53 -080045
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080046 private int mRange;
47 private int mOffset;
48 private int mExtent;
Alan Viverette029d0392015-01-21 15:41:53 -080049
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080050 private boolean mVertical;
Alan Viverette029d0392015-01-21 15:41:53 -080051 private boolean mBoundsChanged;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080052 private boolean mRangeChanged;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080053 private boolean mAlwaysDrawHorizontalTrack;
54 private boolean mAlwaysDrawVerticalTrack;
Alan Viverettef8512ce2015-02-05 15:58:56 -080055 private boolean mMutated;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080056
Alan Viverette029d0392015-01-21 15:41:53 -080057 private int mAlpha = 255;
58 private boolean mHasSetAlpha;
59
60 private ColorFilter mColorFilter;
61 private boolean mHasSetColorFilter;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080062
Artur Satayev751e5512019-11-15 19:12:49 +000063 @UnsupportedAppUsage
64 public ScrollBarDrawable() {
65 }
66
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080067 /**
Alan Viverette029d0392015-01-21 15:41:53 -080068 * Indicate whether the horizontal scrollbar track should always be drawn
69 * regardless of the extent. Defaults to false.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080070 *
Alan Viverette029d0392015-01-21 15:41:53 -080071 * @param alwaysDrawTrack Whether the track should always be drawn
72 *
73 * @see #getAlwaysDrawHorizontalTrack()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080074 */
75 public void setAlwaysDrawHorizontalTrack(boolean alwaysDrawTrack) {
76 mAlwaysDrawHorizontalTrack = alwaysDrawTrack;
77 }
78
79 /**
Alan Viverette029d0392015-01-21 15:41:53 -080080 * Indicate whether the vertical scrollbar track should always be drawn
81 * regardless of the extent. Defaults to false.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080082 *
Alan Viverette029d0392015-01-21 15:41:53 -080083 * @param alwaysDrawTrack Whether the track should always be drawn
84 *
85 * @see #getAlwaysDrawVerticalTrack()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080086 */
87 public void setAlwaysDrawVerticalTrack(boolean alwaysDrawTrack) {
88 mAlwaysDrawVerticalTrack = alwaysDrawTrack;
89 }
90
91 /**
Alan Viverette029d0392015-01-21 15:41:53 -080092 * @return whether the vertical scrollbar track should always be drawn
93 * regardless of the extent.
94 *
95 * @see #setAlwaysDrawVerticalTrack(boolean)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080096 */
97 public boolean getAlwaysDrawVerticalTrack() {
98 return mAlwaysDrawVerticalTrack;
99 }
100
101 /**
Alan Viverette029d0392015-01-21 15:41:53 -0800102 * @return whether the horizontal scrollbar track should always be drawn
103 * regardless of the extent.
104 *
105 * @see #setAlwaysDrawHorizontalTrack(boolean)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800106 */
107 public boolean getAlwaysDrawHorizontalTrack() {
108 return mAlwaysDrawHorizontalTrack;
109 }
110
111 public void setParameters(int range, int offset, int extent, boolean vertical) {
112 if (mVertical != vertical) {
Alan Viverette029d0392015-01-21 15:41:53 -0800113 mVertical = vertical;
114
115 mBoundsChanged = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800116 }
117
118 if (mRange != range || mOffset != offset || mExtent != extent) {
Alan Viverette029d0392015-01-21 15:41:53 -0800119 mRange = range;
120 mOffset = offset;
121 mExtent = extent;
122
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800123 mRangeChanged = true;
124 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800125 }
126
127 @Override
128 public void draw(Canvas canvas) {
129 final boolean vertical = mVertical;
130 final int extent = mExtent;
131 final int range = mRange;
132
133 boolean drawTrack = true;
134 boolean drawThumb = true;
135 if (extent <= 0 || range <= extent) {
136 drawTrack = vertical ? mAlwaysDrawVerticalTrack : mAlwaysDrawHorizontalTrack;
137 drawThumb = false;
138 }
139
Alan Viverette029d0392015-01-21 15:41:53 -0800140 final Rect r = getBounds();
Romain Guy8fb95422010-08-17 18:38:51 -0700141 if (canvas.quickReject(r.left, r.top, r.right, r.bottom, Canvas.EdgeType.AA)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800142 return;
143 }
Alan Viverette029d0392015-01-21 15:41:53 -0800144
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800145 if (drawTrack) {
146 drawTrack(canvas, r, vertical);
147 }
148
149 if (drawThumb) {
Keisuke Kuroyanagid85bc502016-01-21 14:50:38 +0900150 final int scrollBarLength = vertical ? r.height() : r.width();
Alan Viverette029d0392015-01-21 15:41:53 -0800151 final int thickness = vertical ? r.width() : r.height();
Keisuke Kuroyanagid85bc502016-01-21 14:50:38 +0900152 final int thumbLength =
153 ScrollBarUtils.getThumbLength(scrollBarLength, thickness, extent, range);
154 final int thumbOffset =
155 ScrollBarUtils.getThumbOffset(scrollBarLength, thumbLength, extent, range,
156 mOffset);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800157
Keisuke Kuroyanagid85bc502016-01-21 14:50:38 +0900158 drawThumb(canvas, r, thumbOffset, thumbLength, vertical);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800159 }
160 }
161
162 @Override
163 protected void onBoundsChange(Rect bounds) {
164 super.onBoundsChange(bounds);
Alan Viverette029d0392015-01-21 15:41:53 -0800165 mBoundsChanged = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800166 }
167
Alan Viverette029d0392015-01-21 15:41:53 -0800168 @Override
169 public boolean isStateful() {
170 return (mVerticalTrack != null && mVerticalTrack.isStateful())
171 || (mVerticalThumb != null && mVerticalThumb.isStateful())
172 || (mHorizontalTrack != null && mHorizontalTrack.isStateful())
173 || (mHorizontalThumb != null && mHorizontalThumb.isStateful())
174 || super.isStateful();
175 }
176
177 @Override
178 protected boolean onStateChange(int[] state) {
179 boolean changed = super.onStateChange(state);
180 if (mVerticalTrack != null) {
181 changed |= mVerticalTrack.setState(state);
182 }
183 if (mVerticalThumb != null) {
184 changed |= mVerticalThumb.setState(state);
185 }
186 if (mHorizontalTrack != null) {
187 changed |= mHorizontalTrack.setState(state);
188 }
189 if (mHorizontalThumb != null) {
190 changed |= mHorizontalThumb.setState(state);
191 }
192 return changed;
193 }
194
195 private void drawTrack(Canvas canvas, Rect bounds, boolean vertical) {
196 final Drawable track;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800197 if (vertical) {
198 track = mVerticalTrack;
199 } else {
200 track = mHorizontalTrack;
201 }
Alan Viverette029d0392015-01-21 15:41:53 -0800202
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800203 if (track != null) {
Alan Viverette029d0392015-01-21 15:41:53 -0800204 if (mBoundsChanged) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800205 track.setBounds(bounds);
206 }
207 track.draw(canvas);
208 }
209 }
210
Alan Viverette029d0392015-01-21 15:41:53 -0800211 private void drawThumb(Canvas canvas, Rect bounds, int offset, int length, boolean vertical) {
212 final boolean changed = mRangeChanged || mBoundsChanged;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800213 if (vertical) {
Chet Haase6c8fef72014-06-27 16:49:05 -0700214 if (mVerticalThumb != null) {
215 final Drawable thumb = mVerticalThumb;
Alan Viverette029d0392015-01-21 15:41:53 -0800216 if (changed) {
217 thumb.setBounds(bounds.left, bounds.top + offset,
218 bounds.right, bounds.top + offset + length);
219 }
220
Chet Haase6c8fef72014-06-27 16:49:05 -0700221 thumb.draw(canvas);
222 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800223 } else {
Chet Haase6c8fef72014-06-27 16:49:05 -0700224 if (mHorizontalThumb != null) {
225 final Drawable thumb = mHorizontalThumb;
Alan Viverette029d0392015-01-21 15:41:53 -0800226 if (changed) {
227 thumb.setBounds(bounds.left + offset, bounds.top,
228 bounds.left + offset + length, bounds.bottom);
229 }
230
Chet Haase6c8fef72014-06-27 16:49:05 -0700231 thumb.draw(canvas);
232 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800233 }
234 }
235
Nader Jawad93aeba82019-02-04 16:42:26 -0800236 /**
237 * @see android.view.View#setVerticalThumbDrawable(Drawable)
238 */
239 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800240 public void setVerticalThumbDrawable(Drawable thumb) {
Alan Viverette029d0392015-01-21 15:41:53 -0800241 if (mVerticalThumb != null) {
242 mVerticalThumb.setCallback(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800243 }
Alan Viverette029d0392015-01-21 15:41:53 -0800244
245 propagateCurrentState(thumb);
246 mVerticalThumb = thumb;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800247 }
248
Nader Jawad93aeba82019-02-04 16:42:26 -0800249 /**
250 * @see View#getVerticalTrackDrawable()
251 */
252 public @Nullable Drawable getVerticalTrackDrawable() {
253 return mVerticalTrack;
254 }
255
256 /**
257 * @see View#getVerticalThumbDrawable()
258 */
259 public @Nullable Drawable getVerticalThumbDrawable() {
260 return mVerticalThumb;
261 }
262
263 /**
264 * @see View#getHorizontalTrackDrawable()
265 */
266 public @Nullable Drawable getHorizontalTrackDrawable() {
267 return mHorizontalTrack;
268 }
269
270 /**
271 * @see View#getHorizontalThumbDrawable()
272 */
273 public @Nullable Drawable getHorizontalThumbDrawable() {
274 return mHorizontalThumb;
275 }
276
277 /**
278 * @see android.view.View#setVerticalTrackDrawable(Drawable)
279 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800280 public void setVerticalTrackDrawable(Drawable track) {
Alan Viverette029d0392015-01-21 15:41:53 -0800281 if (mVerticalTrack != null) {
282 mVerticalTrack.setCallback(null);
Alan Viverette03748a52015-01-15 13:00:21 -0800283 }
Alan Viverette029d0392015-01-21 15:41:53 -0800284
285 propagateCurrentState(track);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800286 mVerticalTrack = track;
287 }
288
Nader Jawad93aeba82019-02-04 16:42:26 -0800289 /**
290 * @see android.view.View#setHorizontalThumbDrawable(Drawable)
291 */
292 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800293 public void setHorizontalThumbDrawable(Drawable thumb) {
Alan Viverette029d0392015-01-21 15:41:53 -0800294 if (mHorizontalThumb != null) {
295 mHorizontalThumb.setCallback(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800296 }
Alan Viverette029d0392015-01-21 15:41:53 -0800297
298 propagateCurrentState(thumb);
299 mHorizontalThumb = thumb;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800300 }
301
302 public void setHorizontalTrackDrawable(Drawable track) {
Alan Viverette029d0392015-01-21 15:41:53 -0800303 if (mHorizontalTrack != null) {
304 mHorizontalTrack.setCallback(null);
Alan Viverette03748a52015-01-15 13:00:21 -0800305 }
Alan Viverette029d0392015-01-21 15:41:53 -0800306
307 propagateCurrentState(track);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800308 mHorizontalTrack = track;
309 }
310
Alan Viverette029d0392015-01-21 15:41:53 -0800311 private void propagateCurrentState(Drawable d) {
312 if (d != null) {
Alan Viveretteb989c552015-02-05 17:10:47 -0800313 if (mMutated) {
314 d.mutate();
315 }
316
Alan Viverette029d0392015-01-21 15:41:53 -0800317 d.setState(getState());
318 d.setCallback(this);
319
320 if (mHasSetAlpha) {
321 d.setAlpha(mAlpha);
322 }
323
324 if (mHasSetColorFilter) {
325 d.setColorFilter(mColorFilter);
326 }
327 }
328 }
329
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800330 public int getSize(boolean vertical) {
331 if (vertical) {
Chet Haase6c8fef72014-06-27 16:49:05 -0700332 return mVerticalTrack != null ? mVerticalTrack.getIntrinsicWidth() :
333 mVerticalThumb != null ? mVerticalThumb.getIntrinsicWidth() : 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800334 } else {
Chet Haase6c8fef72014-06-27 16:49:05 -0700335 return mHorizontalTrack != null ? mHorizontalTrack.getIntrinsicHeight() :
336 mHorizontalThumb != null ? mHorizontalThumb.getIntrinsicHeight() : 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800337 }
338 }
339
340 @Override
Alan Viverettef8512ce2015-02-05 15:58:56 -0800341 public ScrollBarDrawable mutate() {
342 if (!mMutated && super.mutate() == this) {
343 if (mVerticalTrack != null) {
344 mVerticalTrack.mutate();
345 }
346 if (mVerticalThumb != null) {
347 mVerticalThumb.mutate();
348 }
349 if (mHorizontalTrack != null) {
350 mHorizontalTrack.mutate();
351 }
352 if (mHorizontalThumb != null) {
353 mHorizontalThumb.mutate();
354 }
355 mMutated = true;
356 }
357 return this;
358 }
359
360 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800361 public void setAlpha(int alpha) {
Alan Viverette029d0392015-01-21 15:41:53 -0800362 mAlpha = alpha;
363 mHasSetAlpha = true;
364
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800365 if (mVerticalTrack != null) {
366 mVerticalTrack.setAlpha(alpha);
367 }
Chet Haase6c8fef72014-06-27 16:49:05 -0700368 if (mVerticalThumb != null) {
369 mVerticalThumb.setAlpha(alpha);
370 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800371 if (mHorizontalTrack != null) {
372 mHorizontalTrack.setAlpha(alpha);
373 }
Chet Haase6c8fef72014-06-27 16:49:05 -0700374 if (mHorizontalThumb != null) {
375 mHorizontalThumb.setAlpha(alpha);
376 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800377 }
378
379 @Override
Chet Haaseb1af7f32013-03-08 14:02:04 -0800380 public int getAlpha() {
Alan Viverette029d0392015-01-21 15:41:53 -0800381 return mAlpha;
Chet Haaseb1af7f32013-03-08 14:02:04 -0800382 }
383
384 @Override
Chris Craikbd3bfc52015-03-02 10:43:29 -0800385 public void setColorFilter(ColorFilter colorFilter) {
386 mColorFilter = colorFilter;
Alan Viverette029d0392015-01-21 15:41:53 -0800387 mHasSetColorFilter = true;
388
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800389 if (mVerticalTrack != null) {
Chris Craikbd3bfc52015-03-02 10:43:29 -0800390 mVerticalTrack.setColorFilter(colorFilter);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800391 }
Chet Haase6c8fef72014-06-27 16:49:05 -0700392 if (mVerticalThumb != null) {
Chris Craikbd3bfc52015-03-02 10:43:29 -0800393 mVerticalThumb.setColorFilter(colorFilter);
Chet Haase6c8fef72014-06-27 16:49:05 -0700394 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800395 if (mHorizontalTrack != null) {
Chris Craikbd3bfc52015-03-02 10:43:29 -0800396 mHorizontalTrack.setColorFilter(colorFilter);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800397 }
Chet Haase6c8fef72014-06-27 16:49:05 -0700398 if (mHorizontalThumb != null) {
Chris Craikbd3bfc52015-03-02 10:43:29 -0800399 mHorizontalThumb.setColorFilter(colorFilter);
Chet Haase6c8fef72014-06-27 16:49:05 -0700400 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800401 }
402
403 @Override
Alan Viverette029d0392015-01-21 15:41:53 -0800404 public ColorFilter getColorFilter() {
405 return mColorFilter;
406 }
407
408 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800409 public int getOpacity() {
410 return PixelFormat.TRANSLUCENT;
411 }
412
413 @Override
Alan Viverettef6d87ec2016-03-11 10:09:14 -0500414 public void invalidateDrawable(@NonNull Drawable who) {
Alan Viverette029d0392015-01-21 15:41:53 -0800415 invalidateSelf();
416 }
417
418 @Override
Alan Viverettef6d87ec2016-03-11 10:09:14 -0500419 public void scheduleDrawable(@NonNull Drawable who, @NonNull Runnable what, long when) {
Alan Viverette029d0392015-01-21 15:41:53 -0800420 scheduleSelf(what, when);
421 }
422
423 @Override
Alan Viverettef6d87ec2016-03-11 10:09:14 -0500424 public void unscheduleDrawable(@NonNull Drawable who, @NonNull Runnable what) {
Alan Viverette029d0392015-01-21 15:41:53 -0800425 unscheduleSelf(what);
426 }
427
428 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800429 public String toString() {
430 return "ScrollBarDrawable: range=" + mRange + " offset=" + mOffset +
431 " extent=" + mExtent + (mVertical ? " V" : " H");
432 }
433}
434
435