// CHECKSTYLE:OFF Generated code
/* This file is auto-generated from PlaybackSupportFragmentTest.java.  DO NOT MODIFY. */

/*
 * Copyright (C) 2016 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package androidx.leanback.app;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;

import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.support.test.filters.FlakyTest;
import android.support.test.filters.MediumTest;
import android.support.test.filters.Suppress;
import android.support.test.runner.AndroidJUnit4;
import android.view.KeyEvent;
import android.view.View;

import androidx.leanback.media.PlaybackControlGlue;
import androidx.leanback.media.PlaybackGlue;
import androidx.leanback.testutils.PollingCheck;
import androidx.leanback.widget.ControlButtonPresenterSelector;
import androidx.leanback.widget.ListRow;
import androidx.leanback.widget.OnItemViewClickedListener;
import androidx.leanback.widget.OnItemViewSelectedListener;
import androidx.leanback.widget.PlaybackControlsRow;
import androidx.leanback.widget.PlaybackControlsRowPresenter;
import androidx.leanback.widget.Presenter;
import androidx.leanback.widget.Row;
import androidx.leanback.widget.RowPresenter;
import androidx.leanback.widget.SparseArrayObjectAdapter;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mockito;

@MediumTest
@RunWith(AndroidJUnit4.class)
public class PlaybackFragmentTest extends SingleFragmentTestBase {

    private static final String TAG = "PlaybackFragmentTest";
    private static final long TRANSITION_LENGTH = 1000;

    @Test
    public void testDetachCalledWhenDestroyFragment() throws Throwable {
        final SingleFragmentTestActivity activity =
                launchAndWaitActivity(PlaybackTestFragment.class, 1000);
        final PlaybackTestFragment fragment = (PlaybackTestFragment) activity.getTestFragment();
        PlaybackGlue glue = fragment.getGlue();
        activityTestRule.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                activity.finish();
            }
        });
        PollingCheck.waitFor(new PollingCheck.PollingCheckCondition() {
            @Override
            public boolean canProceed() {
                return fragment.mDestroyCalled;
            }
        });
        assertNull(glue.getHost());
    }

    @Test
    public void testSelectedListener() throws Throwable {
        SingleFragmentTestActivity activity =
                launchAndWaitActivity(PlaybackTestFragment.class, 1000);
        PlaybackTestFragment fragment = (PlaybackTestFragment) activity.getTestFragment();

        assertTrue(fragment.getView().hasFocus());

        OnItemViewSelectedListener selectedListener = Mockito.mock(
                OnItemViewSelectedListener.class);
        fragment.setOnItemViewSelectedListener(selectedListener);


        PlaybackControlsRow controlsRow = fragment.getGlue().getControlsRow();
        SparseArrayObjectAdapter primaryActionsAdapter = (SparseArrayObjectAdapter)
                controlsRow.getPrimaryActionsAdapter();

        PlaybackControlsRow.MultiAction playPause = (PlaybackControlsRow.MultiAction)
                primaryActionsAdapter.lookup(PlaybackControlGlue.ACTION_PLAY_PAUSE);

        PlaybackControlsRow.MultiAction rewind = (PlaybackControlsRow.MultiAction)
                primaryActionsAdapter.lookup(PlaybackControlGlue.ACTION_REWIND);

        PlaybackControlsRow.MultiAction thumbsUp = (PlaybackControlsRow.MultiAction)
                primaryActionsAdapter.lookup(PlaybackControlGlue.ACTION_CUSTOM_LEFT_FIRST);

        ArgumentCaptor<Presenter.ViewHolder> itemVHCaptor =
                ArgumentCaptor.forClass(Presenter.ViewHolder.class);
        ArgumentCaptor<Object> itemCaptor = ArgumentCaptor.forClass(Object.class);
        ArgumentCaptor<RowPresenter.ViewHolder> rowVHCaptor =
                ArgumentCaptor.forClass(RowPresenter.ViewHolder.class);
        ArgumentCaptor<Row> rowCaptor = ArgumentCaptor.forClass(Row.class);


        // First navigate left within PlaybackControlsRow items.
        verify(selectedListener, times(0)).onItemSelected(any(Presenter.ViewHolder.class),
                any(Object.class), any(RowPresenter.ViewHolder.class), any(Row.class));
        sendKeys(KeyEvent.KEYCODE_DPAD_LEFT);
        verify(selectedListener, times(1)).onItemSelected(itemVHCaptor.capture(),
                itemCaptor.capture(), rowVHCaptor.capture(), rowCaptor.capture());
        assertSame("Same controls row should be passed to the listener", controlsRow,
                rowCaptor.getValue());
        assertSame("The selected action should be rewind", rewind, itemCaptor.getValue());

        sendKeys(KeyEvent.KEYCODE_DPAD_LEFT);
        verify(selectedListener, times(2)).onItemSelected(itemVHCaptor.capture(),
                itemCaptor.capture(), rowVHCaptor.capture(), rowCaptor.capture());
        assertSame("Same controls row should be passed to the listener", controlsRow,
                rowCaptor.getValue());
        assertSame("The selected action should be thumbsUp", thumbsUp, itemCaptor.getValue());

        // Now navigate down to a ListRow item.
        ListRow listRow0 = (ListRow) fragment.getAdapter().get(1);

        sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
        waitForScrollIdle(fragment.getVerticalGridView());
        verify(selectedListener, times(3)).onItemSelected(itemVHCaptor.capture(),
                itemCaptor.capture(), rowVHCaptor.capture(), rowCaptor.capture());
        assertSame("Same list row should be passed to the listener", listRow0,
                rowCaptor.getValue());
        // Depending on the focusSearch algorithm, one of the items in the first ListRow must be
        // selected.
        boolean listRowItemPassed = (itemCaptor.getValue() == listRow0.getAdapter().get(0)
                || itemCaptor.getValue() == listRow0.getAdapter().get(1));
        assertTrue("None of the items in the first ListRow are passed to the selected listener.",
                listRowItemPassed);
    }

    @Test
    public void testClickedListener() throws Throwable {
        SingleFragmentTestActivity activity =
                launchAndWaitActivity(PlaybackTestFragment.class, 1000);
        PlaybackTestFragment fragment = (PlaybackTestFragment) activity.getTestFragment();

        assertTrue(fragment.getView().hasFocus());

        OnItemViewClickedListener clickedListener = Mockito.mock(OnItemViewClickedListener.class);
        fragment.setOnItemViewClickedListener(clickedListener);


        PlaybackControlsRow controlsRow = fragment.getGlue().getControlsRow();
        SparseArrayObjectAdapter primaryActionsAdapter = (SparseArrayObjectAdapter)
                controlsRow.getPrimaryActionsAdapter();

        PlaybackControlsRow.MultiAction playPause = (PlaybackControlsRow.MultiAction)
                primaryActionsAdapter.lookup(PlaybackControlGlue.ACTION_PLAY_PAUSE);

        PlaybackControlsRow.MultiAction rewind = (PlaybackControlsRow.MultiAction)
                primaryActionsAdapter.lookup(PlaybackControlGlue.ACTION_REWIND);

        PlaybackControlsRow.MultiAction thumbsUp = (PlaybackControlsRow.MultiAction)
                primaryActionsAdapter.lookup(PlaybackControlGlue.ACTION_CUSTOM_LEFT_FIRST);

        ArgumentCaptor<Presenter.ViewHolder> itemVHCaptor =
                ArgumentCaptor.forClass(Presenter.ViewHolder.class);
        ArgumentCaptor<Object> itemCaptor = ArgumentCaptor.forClass(Object.class);
        ArgumentCaptor<RowPresenter.ViewHolder> rowVHCaptor =
                ArgumentCaptor.forClass(RowPresenter.ViewHolder.class);
        ArgumentCaptor<Row> rowCaptor = ArgumentCaptor.forClass(Row.class);


        // First navigate left within PlaybackControlsRow items.
        verify(clickedListener, times(0)).onItemClicked(any(Presenter.ViewHolder.class),
                any(Object.class), any(RowPresenter.ViewHolder.class), any(Row.class));
        sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
        verify(clickedListener, times(1)).onItemClicked(itemVHCaptor.capture(),
                itemCaptor.capture(), rowVHCaptor.capture(), rowCaptor.capture());
        assertSame("Same controls row should be passed to the listener", controlsRow,
                rowCaptor.getValue());
        assertSame("The clicked action should be playPause", playPause, itemCaptor.getValue());

        sendKeys(KeyEvent.KEYCODE_DPAD_LEFT);
        verify(clickedListener, times(1)).onItemClicked(any(Presenter.ViewHolder.class),
                any(Object.class), any(RowPresenter.ViewHolder.class), any(Row.class));
        sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
        verify(clickedListener, times(2)).onItemClicked(itemVHCaptor.capture(),
                itemCaptor.capture(), rowVHCaptor.capture(), rowCaptor.capture());
        assertSame("Same controls row should be passed to the listener", controlsRow,
                rowCaptor.getValue());
        assertSame("The clicked action should be rewind", rewind, itemCaptor.getValue());

        sendKeys(KeyEvent.KEYCODE_DPAD_LEFT);
        verify(clickedListener, times(2)).onItemClicked(any(Presenter.ViewHolder.class),
                any(Object.class), any(RowPresenter.ViewHolder.class), any(Row.class));
        sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
        verify(clickedListener, times(3)).onItemClicked(itemVHCaptor.capture(),
                itemCaptor.capture(), rowVHCaptor.capture(), rowCaptor.capture());
        assertSame("Same controls row should be passed to the listener", controlsRow,
                rowCaptor.getValue());
        assertSame("The clicked action should be thumbsUp", thumbsUp, itemCaptor.getValue());

        // Now navigate down to a ListRow item.
        ListRow listRow0 = (ListRow) fragment.getAdapter().get(1);

        sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
        waitForScrollIdle(fragment.getVerticalGridView());
        verify(clickedListener, times(3)).onItemClicked(any(Presenter.ViewHolder.class),
                any(Object.class), any(RowPresenter.ViewHolder.class), any(Row.class));
        sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
        verify(clickedListener, times(4)).onItemClicked(itemVHCaptor.capture(),
                itemCaptor.capture(), rowVHCaptor.capture(), rowCaptor.capture());
        assertSame("Same list row should be passed to the listener", listRow0,
                rowCaptor.getValue());
        boolean listRowItemPassed = (itemCaptor.getValue() == listRow0.getAdapter().get(0)
                || itemCaptor.getValue() == listRow0.getAdapter().get(1));
        assertTrue("None of the items in the first ListRow are passed to the click listener.",
                listRowItemPassed);
    }

    @FlakyTest
    @Suppress
    @Test
    public void alignmentRowToBottom() throws Throwable {
        SingleFragmentTestActivity activity =
                launchAndWaitActivity(PlaybackTestFragment.class, 1000);
        final PlaybackTestFragment fragment = (PlaybackTestFragment) activity.getTestFragment();

        assertTrue(fragment.getAdapter().size() > 2);

        View playRow = fragment.getVerticalGridView().getChildAt(0);
        assertTrue(playRow.hasFocus());
        assertEquals(playRow.getResources().getDimensionPixelSize(
                androidx.leanback.test.R.dimen.lb_playback_controls_padding_bottom),
                fragment.getVerticalGridView().getHeight() - playRow.getBottom());

        activityTestRule.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                fragment.getVerticalGridView().setSelectedPositionSmooth(
                        fragment.getAdapter().size() - 1);
            }
        });
        waitForScrollIdle(fragment.getVerticalGridView());

        View lastRow = fragment.getVerticalGridView().getChildAt(
                fragment.getVerticalGridView().getChildCount() - 1);
        assertEquals(fragment.getAdapter().size() - 1,
                fragment.getVerticalGridView().getChildAdapterPosition(lastRow));
        assertTrue(lastRow.hasFocus());
        assertEquals(lastRow.getResources().getDimensionPixelSize(
                androidx.leanback.test.R.dimen.lb_playback_controls_padding_bottom),
                fragment.getVerticalGridView().getHeight() - lastRow.getBottom());
    }

    public static class PurePlaybackFragment extends PlaybackFragment {
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setFadingEnabled(false);
            PlaybackControlsRow row = new PlaybackControlsRow();
            SparseArrayObjectAdapter primaryAdapter = new SparseArrayObjectAdapter(
                    new ControlButtonPresenterSelector());
            primaryAdapter.set(0, new PlaybackControlsRow.SkipPreviousAction(getActivity()));
            primaryAdapter.set(1, new PlaybackControlsRow.PlayPauseAction(getActivity()));
            primaryAdapter.set(2, new PlaybackControlsRow.SkipNextAction(getActivity()));
            row.setPrimaryActionsAdapter(primaryAdapter);
            row.setSecondaryActionsAdapter(null);
            setPlaybackRow(row);
            setPlaybackRowPresenter(new PlaybackControlsRowPresenter());
        }
    }

    @Test
    public void setupRowAndPresenterWithoutGlue() {
        SingleFragmentTestActivity activity =
                launchAndWaitActivity(PurePlaybackFragment.class, 1000);
        final PurePlaybackFragment fragment = (PurePlaybackFragment)
                activity.getTestFragment();

        assertTrue(fragment.getAdapter().size() == 1);
        View playRow = fragment.getVerticalGridView().getChildAt(0);
        assertTrue(playRow.hasFocus());
        assertEquals(playRow.getResources().getDimensionPixelSize(
                androidx.leanback.test.R.dimen.lb_playback_controls_padding_bottom),
                fragment.getVerticalGridView().getHeight() - playRow.getBottom());
    }

    public static class ControlGlueFragment extends PlaybackFragment {
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            int[] ffspeeds = new int[] {PlaybackControlGlue.PLAYBACK_SPEED_FAST_L0,
                    PlaybackControlGlue.PLAYBACK_SPEED_FAST_L1};
            PlaybackGlue glue = new PlaybackControlGlue(
                    getActivity(), ffspeeds) {
                @Override
                public boolean hasValidMedia() {
                    return true;
                }

                @Override
                public boolean isMediaPlaying() {
                    return false;
                }

                @Override
                public CharSequence getMediaTitle() {
                    return "Title";
                }

                @Override
                public CharSequence getMediaSubtitle() {
                    return "SubTitle";
                }

                @Override
                public int getMediaDuration() {
                    return 100;
                }

                @Override
                public Drawable getMediaArt() {
                    return null;
                }

                @Override
                public long getSupportedActions() {
                    return PlaybackControlGlue.ACTION_PLAY_PAUSE;
                }

                @Override
                public int getCurrentSpeedId() {
                    return PlaybackControlGlue.PLAYBACK_SPEED_PAUSED;
                }

                @Override
                public int getCurrentPosition() {
                    return 50;
                }
            };
            glue.setHost(new PlaybackFragmentGlueHost(this));
        }
    }

    @Test
    public void setupWithControlGlue() throws Throwable {
        SingleFragmentTestActivity activity =
                launchAndWaitActivity(ControlGlueFragment.class, 1000);
        final ControlGlueFragment fragment = (ControlGlueFragment)
                activity.getTestFragment();

        assertTrue(fragment.getAdapter().size() == 1);

        View playRow = fragment.getVerticalGridView().getChildAt(0);
        assertTrue(playRow.hasFocus());
        assertEquals(playRow.getResources().getDimensionPixelSize(
                androidx.leanback.test.R.dimen.lb_playback_controls_padding_bottom),
                fragment.getVerticalGridView().getHeight() - playRow.getBottom());
    }
}
