1// CHECKSTYLE:OFF Generated code
2/* This file is auto-generated from PlaybackSupportFragmentTest.java.  DO NOT MODIFY. */
3
4/*
5 * Copyright (C) 2016 The Android Open Source Project
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 *      http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 */
19package androidx.leanback.app;
20
21import static org.junit.Assert.assertEquals;
22import static org.junit.Assert.assertNull;
23import static org.junit.Assert.assertSame;
24import static org.junit.Assert.assertTrue;
25import static org.mockito.Matchers.any;
26import static org.mockito.Mockito.times;
27import static org.mockito.Mockito.verify;
28
29import android.graphics.drawable.Drawable;
30import android.os.Bundle;
31import android.support.test.filters.FlakyTest;
32import android.support.test.filters.MediumTest;
33import android.support.test.filters.Suppress;
34import android.support.test.runner.AndroidJUnit4;
35import android.view.KeyEvent;
36import android.view.View;
37
38import androidx.leanback.media.PlaybackControlGlue;
39import androidx.leanback.media.PlaybackGlue;
40import androidx.leanback.testutils.PollingCheck;
41import androidx.leanback.widget.ControlButtonPresenterSelector;
42import androidx.leanback.widget.ListRow;
43import androidx.leanback.widget.OnItemViewClickedListener;
44import androidx.leanback.widget.OnItemViewSelectedListener;
45import androidx.leanback.widget.PlaybackControlsRow;
46import androidx.leanback.widget.PlaybackControlsRowPresenter;
47import androidx.leanback.widget.Presenter;
48import androidx.leanback.widget.Row;
49import androidx.leanback.widget.RowPresenter;
50import androidx.leanback.widget.SparseArrayObjectAdapter;
51
52import org.junit.Test;
53import org.junit.runner.RunWith;
54import org.mockito.ArgumentCaptor;
55import org.mockito.Mockito;
56
57@MediumTest
58@RunWith(AndroidJUnit4.class)
59public class PlaybackFragmentTest extends SingleFragmentTestBase {
60
61    private static final String TAG = "PlaybackFragmentTest";
62    private static final long TRANSITION_LENGTH = 1000;
63
64    @Test
65    public void testDetachCalledWhenDestroyFragment() throws Throwable {
66        final SingleFragmentTestActivity activity =
67                launchAndWaitActivity(PlaybackTestFragment.class, 1000);
68        final PlaybackTestFragment fragment = (PlaybackTestFragment) activity.getTestFragment();
69        PlaybackGlue glue = fragment.getGlue();
70        activityTestRule.runOnUiThread(new Runnable() {
71            @Override
72            public void run() {
73                activity.finish();
74            }
75        });
76        PollingCheck.waitFor(new PollingCheck.PollingCheckCondition() {
77            @Override
78            public boolean canProceed() {
79                return fragment.mDestroyCalled;
80            }
81        });
82        assertNull(glue.getHost());
83    }
84
85    @Test
86    public void testSelectedListener() throws Throwable {
87        SingleFragmentTestActivity activity =
88                launchAndWaitActivity(PlaybackTestFragment.class, 1000);
89        PlaybackTestFragment fragment = (PlaybackTestFragment) activity.getTestFragment();
90
91        assertTrue(fragment.getView().hasFocus());
92
93        OnItemViewSelectedListener selectedListener = Mockito.mock(
94                OnItemViewSelectedListener.class);
95        fragment.setOnItemViewSelectedListener(selectedListener);
96
97
98        PlaybackControlsRow controlsRow = fragment.getGlue().getControlsRow();
99        SparseArrayObjectAdapter primaryActionsAdapter = (SparseArrayObjectAdapter)
100                controlsRow.getPrimaryActionsAdapter();
101
102        PlaybackControlsRow.MultiAction playPause = (PlaybackControlsRow.MultiAction)
103                primaryActionsAdapter.lookup(PlaybackControlGlue.ACTION_PLAY_PAUSE);
104
105        PlaybackControlsRow.MultiAction rewind = (PlaybackControlsRow.MultiAction)
106                primaryActionsAdapter.lookup(PlaybackControlGlue.ACTION_REWIND);
107
108        PlaybackControlsRow.MultiAction thumbsUp = (PlaybackControlsRow.MultiAction)
109                primaryActionsAdapter.lookup(PlaybackControlGlue.ACTION_CUSTOM_LEFT_FIRST);
110
111        ArgumentCaptor<Presenter.ViewHolder> itemVHCaptor =
112                ArgumentCaptor.forClass(Presenter.ViewHolder.class);
113        ArgumentCaptor<Object> itemCaptor = ArgumentCaptor.forClass(Object.class);
114        ArgumentCaptor<RowPresenter.ViewHolder> rowVHCaptor =
115                ArgumentCaptor.forClass(RowPresenter.ViewHolder.class);
116        ArgumentCaptor<Row> rowCaptor = ArgumentCaptor.forClass(Row.class);
117
118
119        // First navigate left within PlaybackControlsRow items.
120        verify(selectedListener, times(0)).onItemSelected(any(Presenter.ViewHolder.class),
121                any(Object.class), any(RowPresenter.ViewHolder.class), any(Row.class));
122        sendKeys(KeyEvent.KEYCODE_DPAD_LEFT);
123        verify(selectedListener, times(1)).onItemSelected(itemVHCaptor.capture(),
124                itemCaptor.capture(), rowVHCaptor.capture(), rowCaptor.capture());
125        assertSame("Same controls row should be passed to the listener", controlsRow,
126                rowCaptor.getValue());
127        assertSame("The selected action should be rewind", rewind, itemCaptor.getValue());
128
129        sendKeys(KeyEvent.KEYCODE_DPAD_LEFT);
130        verify(selectedListener, times(2)).onItemSelected(itemVHCaptor.capture(),
131                itemCaptor.capture(), rowVHCaptor.capture(), rowCaptor.capture());
132        assertSame("Same controls row should be passed to the listener", controlsRow,
133                rowCaptor.getValue());
134        assertSame("The selected action should be thumbsUp", thumbsUp, itemCaptor.getValue());
135
136        // Now navigate down to a ListRow item.
137        ListRow listRow0 = (ListRow) fragment.getAdapter().get(1);
138
139        sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
140        waitForScrollIdle(fragment.getVerticalGridView());
141        verify(selectedListener, times(3)).onItemSelected(itemVHCaptor.capture(),
142                itemCaptor.capture(), rowVHCaptor.capture(), rowCaptor.capture());
143        assertSame("Same list row should be passed to the listener", listRow0,
144                rowCaptor.getValue());
145        // Depending on the focusSearch algorithm, one of the items in the first ListRow must be
146        // selected.
147        boolean listRowItemPassed = (itemCaptor.getValue() == listRow0.getAdapter().get(0)
148                || itemCaptor.getValue() == listRow0.getAdapter().get(1));
149        assertTrue("None of the items in the first ListRow are passed to the selected listener.",
150                listRowItemPassed);
151    }
152
153    @Test
154    public void testClickedListener() throws Throwable {
155        SingleFragmentTestActivity activity =
156                launchAndWaitActivity(PlaybackTestFragment.class, 1000);
157        PlaybackTestFragment fragment = (PlaybackTestFragment) activity.getTestFragment();
158
159        assertTrue(fragment.getView().hasFocus());
160
161        OnItemViewClickedListener clickedListener = Mockito.mock(OnItemViewClickedListener.class);
162        fragment.setOnItemViewClickedListener(clickedListener);
163
164
165        PlaybackControlsRow controlsRow = fragment.getGlue().getControlsRow();
166        SparseArrayObjectAdapter primaryActionsAdapter = (SparseArrayObjectAdapter)
167                controlsRow.getPrimaryActionsAdapter();
168
169        PlaybackControlsRow.MultiAction playPause = (PlaybackControlsRow.MultiAction)
170                primaryActionsAdapter.lookup(PlaybackControlGlue.ACTION_PLAY_PAUSE);
171
172        PlaybackControlsRow.MultiAction rewind = (PlaybackControlsRow.MultiAction)
173                primaryActionsAdapter.lookup(PlaybackControlGlue.ACTION_REWIND);
174
175        PlaybackControlsRow.MultiAction thumbsUp = (PlaybackControlsRow.MultiAction)
176                primaryActionsAdapter.lookup(PlaybackControlGlue.ACTION_CUSTOM_LEFT_FIRST);
177
178        ArgumentCaptor<Presenter.ViewHolder> itemVHCaptor =
179                ArgumentCaptor.forClass(Presenter.ViewHolder.class);
180        ArgumentCaptor<Object> itemCaptor = ArgumentCaptor.forClass(Object.class);
181        ArgumentCaptor<RowPresenter.ViewHolder> rowVHCaptor =
182                ArgumentCaptor.forClass(RowPresenter.ViewHolder.class);
183        ArgumentCaptor<Row> rowCaptor = ArgumentCaptor.forClass(Row.class);
184
185
186        // First navigate left within PlaybackControlsRow items.
187        verify(clickedListener, times(0)).onItemClicked(any(Presenter.ViewHolder.class),
188                any(Object.class), any(RowPresenter.ViewHolder.class), any(Row.class));
189        sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
190        verify(clickedListener, times(1)).onItemClicked(itemVHCaptor.capture(),
191                itemCaptor.capture(), rowVHCaptor.capture(), rowCaptor.capture());
192        assertSame("Same controls row should be passed to the listener", controlsRow,
193                rowCaptor.getValue());
194        assertSame("The clicked action should be playPause", playPause, itemCaptor.getValue());
195
196        sendKeys(KeyEvent.KEYCODE_DPAD_LEFT);
197        verify(clickedListener, times(1)).onItemClicked(any(Presenter.ViewHolder.class),
198                any(Object.class), any(RowPresenter.ViewHolder.class), any(Row.class));
199        sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
200        verify(clickedListener, times(2)).onItemClicked(itemVHCaptor.capture(),
201                itemCaptor.capture(), rowVHCaptor.capture(), rowCaptor.capture());
202        assertSame("Same controls row should be passed to the listener", controlsRow,
203                rowCaptor.getValue());
204        assertSame("The clicked action should be rewind", rewind, itemCaptor.getValue());
205
206        sendKeys(KeyEvent.KEYCODE_DPAD_LEFT);
207        verify(clickedListener, times(2)).onItemClicked(any(Presenter.ViewHolder.class),
208                any(Object.class), any(RowPresenter.ViewHolder.class), any(Row.class));
209        sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
210        verify(clickedListener, times(3)).onItemClicked(itemVHCaptor.capture(),
211                itemCaptor.capture(), rowVHCaptor.capture(), rowCaptor.capture());
212        assertSame("Same controls row should be passed to the listener", controlsRow,
213                rowCaptor.getValue());
214        assertSame("The clicked action should be thumbsUp", thumbsUp, itemCaptor.getValue());
215
216        // Now navigate down to a ListRow item.
217        ListRow listRow0 = (ListRow) fragment.getAdapter().get(1);
218
219        sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
220        waitForScrollIdle(fragment.getVerticalGridView());
221        verify(clickedListener, times(3)).onItemClicked(any(Presenter.ViewHolder.class),
222                any(Object.class), any(RowPresenter.ViewHolder.class), any(Row.class));
223        sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
224        verify(clickedListener, times(4)).onItemClicked(itemVHCaptor.capture(),
225                itemCaptor.capture(), rowVHCaptor.capture(), rowCaptor.capture());
226        assertSame("Same list row should be passed to the listener", listRow0,
227                rowCaptor.getValue());
228        boolean listRowItemPassed = (itemCaptor.getValue() == listRow0.getAdapter().get(0)
229                || itemCaptor.getValue() == listRow0.getAdapter().get(1));
230        assertTrue("None of the items in the first ListRow are passed to the click listener.",
231                listRowItemPassed);
232    }
233
234    @FlakyTest
235    @Suppress
236    @Test
237    public void alignmentRowToBottom() throws Throwable {
238        SingleFragmentTestActivity activity =
239                launchAndWaitActivity(PlaybackTestFragment.class, 1000);
240        final PlaybackTestFragment fragment = (PlaybackTestFragment) activity.getTestFragment();
241
242        assertTrue(fragment.getAdapter().size() > 2);
243
244        View playRow = fragment.getVerticalGridView().getChildAt(0);
245        assertTrue(playRow.hasFocus());
246        assertEquals(playRow.getResources().getDimensionPixelSize(
247                androidx.leanback.test.R.dimen.lb_playback_controls_padding_bottom),
248                fragment.getVerticalGridView().getHeight() - playRow.getBottom());
249
250        activityTestRule.runOnUiThread(new Runnable() {
251            @Override
252            public void run() {
253                fragment.getVerticalGridView().setSelectedPositionSmooth(
254                        fragment.getAdapter().size() - 1);
255            }
256        });
257        waitForScrollIdle(fragment.getVerticalGridView());
258
259        View lastRow = fragment.getVerticalGridView().getChildAt(
260                fragment.getVerticalGridView().getChildCount() - 1);
261        assertEquals(fragment.getAdapter().size() - 1,
262                fragment.getVerticalGridView().getChildAdapterPosition(lastRow));
263        assertTrue(lastRow.hasFocus());
264        assertEquals(lastRow.getResources().getDimensionPixelSize(
265                androidx.leanback.test.R.dimen.lb_playback_controls_padding_bottom),
266                fragment.getVerticalGridView().getHeight() - lastRow.getBottom());
267    }
268
269    public static class PurePlaybackFragment extends PlaybackFragment {
270        @Override
271        public void onCreate(Bundle savedInstanceState) {
272            super.onCreate(savedInstanceState);
273            setFadingEnabled(false);
274            PlaybackControlsRow row = new PlaybackControlsRow();
275            SparseArrayObjectAdapter primaryAdapter = new SparseArrayObjectAdapter(
276                    new ControlButtonPresenterSelector());
277            primaryAdapter.set(0, new PlaybackControlsRow.SkipPreviousAction(getActivity()));
278            primaryAdapter.set(1, new PlaybackControlsRow.PlayPauseAction(getActivity()));
279            primaryAdapter.set(2, new PlaybackControlsRow.SkipNextAction(getActivity()));
280            row.setPrimaryActionsAdapter(primaryAdapter);
281            row.setSecondaryActionsAdapter(null);
282            setPlaybackRow(row);
283            setPlaybackRowPresenter(new PlaybackControlsRowPresenter());
284        }
285    }
286
287    @Test
288    public void setupRowAndPresenterWithoutGlue() {
289        SingleFragmentTestActivity activity =
290                launchAndWaitActivity(PurePlaybackFragment.class, 1000);
291        final PurePlaybackFragment fragment = (PurePlaybackFragment)
292                activity.getTestFragment();
293
294        assertTrue(fragment.getAdapter().size() == 1);
295        View playRow = fragment.getVerticalGridView().getChildAt(0);
296        assertTrue(playRow.hasFocus());
297        assertEquals(playRow.getResources().getDimensionPixelSize(
298                androidx.leanback.test.R.dimen.lb_playback_controls_padding_bottom),
299                fragment.getVerticalGridView().getHeight() - playRow.getBottom());
300    }
301
302    public static class ControlGlueFragment extends PlaybackFragment {
303        @Override
304        public void onCreate(Bundle savedInstanceState) {
305            super.onCreate(savedInstanceState);
306            int[] ffspeeds = new int[] {PlaybackControlGlue.PLAYBACK_SPEED_FAST_L0,
307                    PlaybackControlGlue.PLAYBACK_SPEED_FAST_L1};
308            PlaybackGlue glue = new PlaybackControlGlue(
309                    getActivity(), ffspeeds) {
310                @Override
311                public boolean hasValidMedia() {
312                    return true;
313                }
314
315                @Override
316                public boolean isMediaPlaying() {
317                    return false;
318                }
319
320                @Override
321                public CharSequence getMediaTitle() {
322                    return "Title";
323                }
324
325                @Override
326                public CharSequence getMediaSubtitle() {
327                    return "SubTitle";
328                }
329
330                @Override
331                public int getMediaDuration() {
332                    return 100;
333                }
334
335                @Override
336                public Drawable getMediaArt() {
337                    return null;
338                }
339
340                @Override
341                public long getSupportedActions() {
342                    return PlaybackControlGlue.ACTION_PLAY_PAUSE;
343                }
344
345                @Override
346                public int getCurrentSpeedId() {
347                    return PlaybackControlGlue.PLAYBACK_SPEED_PAUSED;
348                }
349
350                @Override
351                public int getCurrentPosition() {
352                    return 50;
353                }
354            };
355            glue.setHost(new PlaybackFragmentGlueHost(this));
356        }
357    }
358
359    @Test
360    public void setupWithControlGlue() throws Throwable {
361        SingleFragmentTestActivity activity =
362                launchAndWaitActivity(ControlGlueFragment.class, 1000);
363        final ControlGlueFragment fragment = (ControlGlueFragment)
364                activity.getTestFragment();
365
366        assertTrue(fragment.getAdapter().size() == 1);
367
368        View playRow = fragment.getVerticalGridView().getChildAt(0);
369        assertTrue(playRow.hasFocus());
370        assertEquals(playRow.getResources().getDimensionPixelSize(
371                androidx.leanback.test.R.dimen.lb_playback_controls_padding_bottom),
372                fragment.getVerticalGridView().getHeight() - playRow.getBottom());
373    }
374}
375