1 /*
2  * Copyright (C) 2008 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.widget.cts;
18 
19 import static org.junit.Assert.assertEquals;
20 import static org.junit.Assert.assertFalse;
21 import static org.junit.Assert.assertSame;
22 import static org.junit.Assert.assertTrue;
23 import static org.mockito.Mockito.atLeastOnce;
24 import static org.mockito.Mockito.reset;
25 import static org.mockito.Mockito.spy;
26 import static org.mockito.Mockito.times;
27 import static org.mockito.Mockito.verify;
28 
29 import android.app.Activity;
30 import android.app.Instrumentation;
31 import android.content.Context;
32 import android.content.res.ColorStateList;
33 import android.graphics.Color;
34 import android.graphics.PorterDuff;
35 import android.graphics.drawable.ColorDrawable;
36 import android.graphics.drawable.Drawable;
37 import android.support.test.InstrumentationRegistry;
38 import android.support.test.annotation.UiThreadTest;
39 import android.support.test.filters.SmallTest;
40 import android.support.test.rule.ActivityTestRule;
41 import android.support.test.runner.AndroidJUnit4;
42 import android.util.AttributeSet;
43 import android.view.KeyEvent;
44 import android.widget.AbsSeekBar;
45 import android.widget.SeekBar;
46 import android.widget.cts.util.TestUtils;
47 
48 import com.android.compatibility.common.util.PollingCheck;
49 import com.android.compatibility.common.util.WidgetTestUtils;
50 
51 import org.junit.Before;
52 import org.junit.Rule;
53 import org.junit.Test;
54 import org.junit.runner.RunWith;
55 import org.mockito.ArgumentCaptor;
56 
57 import java.util.List;
58 
59 /**
60  * Test {@link AbsSeekBar}.
61  */
62 @SmallTest
63 @RunWith(AndroidJUnit4.class)
64 public class AbsSeekBarTest {
65     private Instrumentation mInstrumentation;
66     private Activity mActivity;
67 
68     @Rule
69     public ActivityTestRule<AbsSeekBarCtsActivity> mActivityRule =
70             new ActivityTestRule<>(AbsSeekBarCtsActivity.class);
71 
72     @Before
setup()73     public void setup() {
74         mInstrumentation = InstrumentationRegistry.getInstrumentation();
75         mActivity = mActivityRule.getActivity();
76     }
77 
78     @Test
testConstructor()79     public void testConstructor() {
80         new MyAbsSeekBar(mActivity);
81 
82         new MyAbsSeekBar(mActivity, null);
83 
84         new MyAbsSeekBar(mActivity, null, android.R.attr.progressBarStyle);
85 
86         new MyAbsSeekBar(mActivity, null, 0, android.R.style.Widget_Material_Light_ProgressBar);
87     }
88 
89     @Test
testAccessThumbOffset()90     public void testAccessThumbOffset() {
91         AbsSeekBar myAbsSeekBar = new MyAbsSeekBar(mActivity);
92         final int positive = 5;
93         final int negative = -5;
94         final int zero = 0;
95 
96         myAbsSeekBar.setThumbOffset(positive);
97         assertEquals(positive, myAbsSeekBar.getThumbOffset());
98 
99         myAbsSeekBar.setThumbOffset(zero);
100         assertEquals(zero, myAbsSeekBar.getThumbOffset());
101 
102         myAbsSeekBar.setThumbOffset(negative);
103         assertEquals(negative, myAbsSeekBar.getThumbOffset());
104     }
105 
106     @Test
testAccessThumb()107     public void testAccessThumb() {
108         // Both are pointing to the same object. This works around current limitation in CTS
109         // coverage report tool for properly reporting coverage of base class method calls.
110         final MyAbsSeekBar myAbsSeekBar = new MyAbsSeekBar(mActivity);
111         final AbsSeekBar absSeekBar = myAbsSeekBar;
112 
113         Drawable drawable1 = mActivity.getDrawable(R.drawable.scenery);
114         Drawable drawable2 = mActivity.getDrawable(R.drawable.pass);
115 
116         assertFalse(myAbsSeekBar.verifyDrawable(drawable1));
117         assertFalse(myAbsSeekBar.verifyDrawable(drawable2));
118 
119         absSeekBar.setThumb(drawable1);
120         assertSame(drawable1, absSeekBar.getThumb());
121         assertTrue(myAbsSeekBar.verifyDrawable(drawable1));
122         assertFalse(myAbsSeekBar.verifyDrawable(drawable2));
123 
124         absSeekBar.setThumb(drawable2);
125         assertSame(drawable2, absSeekBar.getThumb());
126         assertFalse(myAbsSeekBar.verifyDrawable(drawable1));
127         assertTrue(myAbsSeekBar.verifyDrawable(drawable2));
128     }
129 
130     @Test
testAccessTickMark()131     public void testAccessTickMark() {
132         // Both are pointing to the same object. This works around current limitation in CTS
133         // coverage report tool for properly reporting coverage of base class method calls.
134         final MyAbsSeekBar myAbsSeekBar = new MyAbsSeekBar(mActivity);
135         final AbsSeekBar absSeekBar = myAbsSeekBar;
136 
137         Drawable drawable1 = mActivity.getDrawable(R.drawable.black);
138         Drawable drawable2 = mActivity.getDrawable(R.drawable.black);
139 
140         assertFalse(myAbsSeekBar.verifyDrawable(drawable1));
141         assertFalse(myAbsSeekBar.verifyDrawable(drawable2));
142 
143         absSeekBar.setTickMark(drawable1);
144         assertSame(drawable1, absSeekBar.getTickMark());
145         assertTrue(myAbsSeekBar.verifyDrawable(drawable1));
146         assertFalse(myAbsSeekBar.verifyDrawable(drawable2));
147 
148         absSeekBar.setTickMark(drawable2);
149         assertSame(drawable2, absSeekBar.getTickMark());
150         assertFalse(myAbsSeekBar.verifyDrawable(drawable1));
151         assertTrue(myAbsSeekBar.verifyDrawable(drawable2));
152     }
153 
154     @Test
testDrawableStateChanged()155     public void testDrawableStateChanged() {
156         MyAbsSeekBar myAbsSeekBar = new MyAbsSeekBar(mActivity);
157         Drawable mockProgressDrawable = spy(new ColorDrawable(Color.YELLOW));
158         myAbsSeekBar.setProgressDrawable(mockProgressDrawable);
159 
160         ArgumentCaptor<Integer> alphaCaptor = ArgumentCaptor.forClass(Integer.class);
161         myAbsSeekBar.setEnabled(false);
162         myAbsSeekBar.drawableStateChanged();
163         verify(mockProgressDrawable, atLeastOnce()).setAlpha(alphaCaptor.capture());
164         // Verify that the last call to setAlpha was with argument 0x00
165         List<Integer> alphaCaptures = alphaCaptor.getAllValues();
166         assertTrue(!alphaCaptures.isEmpty());
167         assertEquals(Integer.valueOf(0x00), alphaCaptures.get(alphaCaptures.size() - 1));
168 
169         alphaCaptor = ArgumentCaptor.forClass(Integer.class);
170         myAbsSeekBar.setEnabled(true);
171         myAbsSeekBar.drawableStateChanged();
172         verify(mockProgressDrawable, atLeastOnce()).setAlpha(alphaCaptor.capture());
173         // Verify that the last call to setAlpha was with argument 0xFF
174         alphaCaptures = alphaCaptor.getAllValues();
175         assertTrue(!alphaCaptures.isEmpty());
176         assertEquals(Integer.valueOf(0xFF), alphaCaptures.get(alphaCaptures.size() - 1));
177     }
178 
179     @Test
testVerifyDrawable()180     public void testVerifyDrawable() {
181         MyAbsSeekBar myAbsSeekBar = new MyAbsSeekBar(mActivity);
182         Drawable drawable1 = mActivity.getDrawable(R.drawable.scenery);
183         Drawable drawable2 = mActivity.getDrawable(R.drawable.pass);
184         Drawable drawable3 = mActivity.getDrawable(R.drawable.blue);
185         Drawable drawable4 = mActivity.getDrawable(R.drawable.black);
186 
187         assertFalse(myAbsSeekBar.verifyDrawable(drawable1));
188         assertFalse(myAbsSeekBar.verifyDrawable(drawable2));
189         assertFalse(myAbsSeekBar.verifyDrawable(drawable3));
190         assertFalse(myAbsSeekBar.verifyDrawable(drawable4));
191 
192         myAbsSeekBar.setThumb(drawable1);
193         assertTrue(myAbsSeekBar.verifyDrawable(drawable1));
194         assertFalse(myAbsSeekBar.verifyDrawable(drawable2));
195         assertFalse(myAbsSeekBar.verifyDrawable(drawable3));
196         assertFalse(myAbsSeekBar.verifyDrawable(drawable4));
197 
198         myAbsSeekBar.setThumb(drawable2);
199         assertFalse(myAbsSeekBar.verifyDrawable(drawable1));
200         assertTrue(myAbsSeekBar.verifyDrawable(drawable2));
201         assertFalse(myAbsSeekBar.verifyDrawable(drawable3));
202         assertFalse(myAbsSeekBar.verifyDrawable(drawable4));
203 
204         myAbsSeekBar.setBackgroundDrawable(drawable2);
205         myAbsSeekBar.setProgressDrawable(drawable3);
206         myAbsSeekBar.setIndeterminateDrawable(drawable4);
207         assertFalse(myAbsSeekBar.verifyDrawable(drawable1));
208         assertTrue(myAbsSeekBar.verifyDrawable(drawable2));
209         assertTrue(myAbsSeekBar.verifyDrawable(drawable3));
210         assertTrue(myAbsSeekBar.verifyDrawable(drawable4));
211     }
212 
213     @Test
testAccessKeyProgressIncrement()214     public void testAccessKeyProgressIncrement() throws Throwable {
215         // AbsSeekBar is an abstract class, use its subclass: SeekBar to do this test.
216         mActivityRule.runOnUiThread(() -> mActivity.setContentView(R.layout.seekbar_layout));
217         mInstrumentation.waitForIdleSync();
218 
219         final SeekBar seekBar = (SeekBar) mActivity.findViewById(R.id.seekBar);
220         final int keyProgressIncrement = 2;
221         mActivityRule.runOnUiThread(() -> {
222             seekBar.setKeyProgressIncrement(keyProgressIncrement);
223             seekBar.setFocusable(true);
224             seekBar.requestFocus();
225         });
226         PollingCheck.waitFor(1000, seekBar::hasWindowFocus);
227         assertEquals(keyProgressIncrement, seekBar.getKeyProgressIncrement());
228 
229         int oldProgress = seekBar.getProgress();
230         KeyEvent keyEvent = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_RIGHT);
231         mInstrumentation.sendKeySync(keyEvent);
232         assertEquals(oldProgress + keyProgressIncrement, seekBar.getProgress());
233         oldProgress = seekBar.getProgress();
234         keyEvent = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_LEFT);
235         mInstrumentation.sendKeySync(keyEvent);
236         assertEquals(oldProgress - keyProgressIncrement, seekBar.getProgress());
237     }
238 
239     @Test
testAccessMax()240     public void testAccessMax() {
241         AbsSeekBar myAbsSeekBar = new MyAbsSeekBar(mActivity, null, R.style.TestProgressBar);
242 
243         int progress = 10;
244         myAbsSeekBar.setProgress(progress);
245         int max = progress + 1;
246         myAbsSeekBar.setMax(max);
247         assertEquals(max, myAbsSeekBar.getMax());
248         assertEquals(progress, myAbsSeekBar.getProgress());
249         assertEquals(1, myAbsSeekBar.getKeyProgressIncrement());
250 
251         max = progress - 1;
252         myAbsSeekBar.setMax(max);
253         assertEquals(max, myAbsSeekBar.getMax());
254         assertEquals(max, myAbsSeekBar.getProgress());
255         assertEquals(1, myAbsSeekBar.getKeyProgressIncrement());
256 
257         int keyProgressIncrement = 10;
258         myAbsSeekBar.setKeyProgressIncrement(keyProgressIncrement);
259         assertEquals(keyProgressIncrement, myAbsSeekBar.getKeyProgressIncrement());
260         max = (keyProgressIncrement - 1) * 20;
261         myAbsSeekBar.setMax(max);
262         assertEquals(keyProgressIncrement, myAbsSeekBar.getKeyProgressIncrement());
263         max = (keyProgressIncrement + 1) * 20;
264         myAbsSeekBar.setMax(max);
265         assertEquals(keyProgressIncrement + 1, myAbsSeekBar.getKeyProgressIncrement());
266     }
267 
268     @Test
testAccessMin()269     public void testAccessMin() {
270         AbsSeekBar myAbsSeekBar = new MyAbsSeekBar(mActivity, null, R.style.TestProgressBar);
271 
272         int progress = -5;
273         int min = progress - 1;
274         int max = 5;
275         myAbsSeekBar.setMax(max);
276         myAbsSeekBar.setMin(min);
277         myAbsSeekBar.setProgress(progress);
278         assertEquals(min, myAbsSeekBar.getMin());
279         assertEquals(progress, myAbsSeekBar.getProgress());
280         assertEquals(1, myAbsSeekBar.getKeyProgressIncrement());
281 
282         min = progress + 1;
283         myAbsSeekBar.setMin(min);
284         assertEquals(min, myAbsSeekBar.getMin());
285         assertEquals(min, myAbsSeekBar.getProgress());
286         assertEquals(1, myAbsSeekBar.getKeyProgressIncrement());
287 
288         int keyProgressIncrement = 10;
289         myAbsSeekBar.setKeyProgressIncrement(keyProgressIncrement);
290         assertEquals(keyProgressIncrement, myAbsSeekBar.getKeyProgressIncrement());
291         max = (keyProgressIncrement - 1) * 10;
292         min = -1 * keyProgressIncrement * 10;
293         myAbsSeekBar.setMax(max);
294         myAbsSeekBar.setMin(min);
295         assertEquals(keyProgressIncrement, myAbsSeekBar.getKeyProgressIncrement());
296 
297         max += 20;
298         myAbsSeekBar.setMax(max);
299         assertEquals(keyProgressIncrement + 1, myAbsSeekBar.getKeyProgressIncrement());
300         assertEquals(min, myAbsSeekBar.getMin());
301         assertEquals(max, myAbsSeekBar.getMax());
302     }
303 
304     @UiThreadTest
305     @Test
testThumbTint()306     public void testThumbTint() {
307         AbsSeekBar inflatedView = (AbsSeekBar) mActivity.findViewById(R.id.thumb_tint);
308 
309         assertEquals("Thumb tint inflated correctly",
310                 Color.WHITE, inflatedView.getThumbTintList().getDefaultColor());
311         assertEquals("Thumb tint mode inflated correctly",
312                 PorterDuff.Mode.SRC_OVER, inflatedView.getThumbTintMode());
313 
314         Drawable mockThumb = spy(new ColorDrawable(Color.BLUE));
315 
316         inflatedView.setThumb(mockThumb);
317         verify(mockThumb, times(1)).setTintList(TestUtils.colorStateListOf(Color.WHITE));
318 
319         reset(mockThumb);
320         inflatedView.setThumbTintList(ColorStateList.valueOf(Color.RED));
321         verify(mockThumb, times(1)).setTintList(TestUtils.colorStateListOf(Color.RED));
322 
323         inflatedView.setThumbTintMode(PorterDuff.Mode.DST_ATOP);
324         assertEquals("Thumb tint mode changed correctly",
325                 PorterDuff.Mode.DST_ATOP, inflatedView.getThumbTintMode());
326 
327         reset(mockThumb);
328         inflatedView.setThumb(null);
329         inflatedView.setThumb(mockThumb);
330         verify(mockThumb, times(1)).setTintList(TestUtils.colorStateListOf(Color.RED));
331     }
332 
333     @UiThreadTest
334     @Test
testTickMarkTint()335     public void testTickMarkTint() {
336         AbsSeekBar inflatedView = (AbsSeekBar) mActivity.findViewById(R.id.tick_mark_tint);
337 
338         assertEquals("TickMark tint inflated correctly",
339                 Color.WHITE, inflatedView.getTickMarkTintList().getDefaultColor());
340         assertEquals("TickMark tint mode inflated correctly",
341                 PorterDuff.Mode.SRC_OVER, inflatedView.getTickMarkTintMode());
342 
343         Drawable mockTickMark = spy(new ColorDrawable(Color.BLUE));
344 
345         inflatedView.setTickMark(mockTickMark);
346         verify(mockTickMark, times(1)).setTintList(TestUtils.colorStateListOf(Color.WHITE));
347 
348         reset(mockTickMark);
349         inflatedView.setTickMarkTintList(ColorStateList.valueOf(Color.RED));
350         verify(mockTickMark, times(1)).setTintList(TestUtils.colorStateListOf(Color.RED));
351 
352         inflatedView.setTickMarkTintMode(PorterDuff.Mode.DARKEN);
353         assertEquals("TickMark tint mode changed correctly",
354                 PorterDuff.Mode.DARKEN, inflatedView.getTickMarkTintMode());
355 
356         reset(mockTickMark);
357         inflatedView.setTickMark(null);
358         inflatedView.setTickMark(mockTickMark);
359         verify(mockTickMark, times(1)).setTintList(TestUtils.colorStateListOf(Color.RED));
360     }
361 
362     @Test
testAccessSplitTrack()363     public void testAccessSplitTrack() throws Throwable {
364         AbsSeekBar inflatedView = (AbsSeekBar) mActivity.findViewById(R.id.tick_mark_tint);
365 
366         WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, inflatedView,
367                 () -> inflatedView.setSplitTrack(true));
368         assertTrue(inflatedView.getSplitTrack());
369 
370         WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, inflatedView,
371                 () -> inflatedView.setSplitTrack(false));
372         assertFalse(inflatedView.getSplitTrack());
373     }
374 
375     private static class MyAbsSeekBar extends AbsSeekBar {
MyAbsSeekBar(Context context)376         public MyAbsSeekBar(Context context) {
377             super(context);
378         }
379 
MyAbsSeekBar(Context context, AttributeSet attrs)380         public MyAbsSeekBar(Context context, AttributeSet attrs) {
381             super(context, attrs);
382         }
383 
MyAbsSeekBar(Context context, AttributeSet attrs, int defStyle)384         public MyAbsSeekBar(Context context, AttributeSet attrs, int defStyle) {
385             super(context, attrs, defStyle);
386         }
387 
MyAbsSeekBar(Context context, AttributeSet attrs, int defStyle, int defStyleRes)388         public MyAbsSeekBar(Context context, AttributeSet attrs, int defStyle, int defStyleRes) {
389             super(context, attrs, defStyle, defStyleRes);
390         }
391 
392         @Override
drawableStateChanged()393         protected void drawableStateChanged() {
394             super.drawableStateChanged();
395         }
396 
397         @Override
verifyDrawable(Drawable who)398         protected boolean verifyDrawable(Drawable who) {
399             return super.verifyDrawable(who);
400         }
401     }
402 }
403