| /* |
| * Copyright (C) 2017 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.widget; |
| |
| 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.Matchers.anyInt; |
| import static org.mockito.Matchers.eq; |
| import static org.mockito.Mockito.times; |
| import static org.mockito.Mockito.verify; |
| import static org.mockito.Mockito.when; |
| |
| import android.content.Context; |
| import android.graphics.Bitmap; |
| import android.graphics.drawable.ColorDrawable; |
| import android.support.test.InstrumentationRegistry; |
| import android.support.test.filters.SmallTest; |
| import android.view.ContextThemeWrapper; |
| import android.view.KeyEvent; |
| import android.view.View; |
| import android.view.ViewParent; |
| |
| import androidx.leanback.media.PlaybackTransportControlGlue; |
| import androidx.leanback.media.PlayerAdapter; |
| import androidx.leanback.widget.PlaybackSeekDataProvider.ResultCallback; |
| |
| import org.junit.Before; |
| import org.junit.Test; |
| import org.mockito.Mockito; |
| |
| import java.util.Arrays; |
| |
| @SmallTest |
| public class PlaybackTransportRowPresenterTest { |
| |
| Context mContext; |
| PlaybackTransportControlGlue mGlue; |
| PlaybackGlueHostImplWithViewHolder mHost; |
| PlayerAdapter mImpl; |
| PlaybackTransportRowPresenter.ViewHolder mViewHolder; |
| AbstractDetailsDescriptionPresenter.ViewHolder mDescriptionViewHolder; |
| int mNumbThumbs; |
| |
| @Before |
| public void setUp() { |
| mContext = new ContextThemeWrapper( |
| InstrumentationRegistry.getInstrumentation().getTargetContext(), |
| androidx.leanback.test.R.style.Theme_Leanback); |
| mHost = new PlaybackGlueHostImplWithViewHolder(mContext); |
| mImpl = Mockito.mock(PlayerAdapter.class); |
| InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() { |
| @Override |
| public void run() { |
| mGlue = new PlaybackTransportControlGlue(mContext, mImpl) { |
| @Override |
| protected void onCreatePrimaryActions(ArrayObjectAdapter |
| primaryActionsAdapter) { |
| super.onCreatePrimaryActions(primaryActionsAdapter); |
| primaryActionsAdapter.add( |
| new PlaybackControlsRow.ClosedCaptioningAction(mContext)); |
| } |
| |
| @Override |
| protected void onCreateSecondaryActions(ArrayObjectAdapter |
| secondaryActionsAdapter) { |
| secondaryActionsAdapter.add( |
| new PlaybackControlsRow.HighQualityAction(mContext)); |
| secondaryActionsAdapter.add( |
| new PlaybackControlsRow.PictureInPictureAction(mContext)); |
| } |
| }; |
| mGlue.setHost(mHost); |
| |
| } |
| }); |
| mViewHolder = (PlaybackTransportRowPresenter.ViewHolder) mHost.mViewHolder; |
| mDescriptionViewHolder = (AbstractDetailsDescriptionPresenter.ViewHolder) |
| mViewHolder.mDescriptionViewHolder; |
| mNumbThumbs = mViewHolder.mThumbsBar.getChildCount(); |
| assertTrue((mNumbThumbs & 1) != 0); |
| } |
| |
| void sendKeyUIThread(int keyCode) { |
| sendKeyUIThread(keyCode, 1); |
| } |
| |
| void sendKeyUIThread(final int keyCode, final int repeat) { |
| InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() { |
| @Override |
| public void run() { |
| mHost.sendKeyDownUp(keyCode, repeat); |
| } |
| }); |
| } |
| |
| void verifyGetThumbCalls(int firstHeroIndex, int lastHeroIndex, |
| PlaybackSeekDataProvider provider, long[] positions) { |
| int firstThumbIndex = Math.max(firstHeroIndex - (mNumbThumbs / 2), 0); |
| int lastThumbIndex = Math.min(lastHeroIndex + (mNumbThumbs / 2), positions.length - 1); |
| for (int i = firstThumbIndex; i <= lastThumbIndex; i++) { |
| Mockito.verify(provider, times(1)).getThumbnail(eq(i), any(ResultCallback.class)); |
| } |
| Mockito.verify(provider, times(0)).getThumbnail( |
| eq(firstThumbIndex - 1), any(ResultCallback.class)); |
| Mockito.verify(provider, times(0)).getThumbnail( |
| eq(firstThumbIndex - 2), any(ResultCallback.class)); |
| Mockito.verify(provider, times(0)).getThumbnail( |
| eq(lastThumbIndex + 1), any(ResultCallback.class)); |
| Mockito.verify(provider, times(0)).getThumbnail( |
| eq(lastThumbIndex + 2), any(ResultCallback.class)); |
| } |
| |
| void verifyAtHeroIndexWithDifferentPosition(long position, int heroIndex) { |
| assertEquals(position, mGlue.getControlsRow().getCurrentPosition()); |
| assertEquals(mViewHolder.mThumbHeroIndex, heroIndex); |
| } |
| |
| void verifyAtHeroIndex(long[] positions, int heroIndex) { |
| verifyAtHeroIndex(positions, heroIndex, null); |
| } |
| |
| void verifyAtHeroIndex(long[] positions, int heroIndex, Bitmap[] thumbs) { |
| assertEquals(positions[heroIndex], mGlue.getControlsRow().getCurrentPosition()); |
| assertEquals(mViewHolder.mThumbHeroIndex, heroIndex); |
| if (thumbs != null) { |
| int start = Math.max(0, mViewHolder.mThumbHeroIndex - mNumbThumbs / 2); |
| int end = Math.min(positions.length - 1, mViewHolder.mThumbHeroIndex + mNumbThumbs / 2); |
| verifyThumbBitmaps(thumbs, start, end, |
| mViewHolder.mThumbsBar, start + mNumbThumbs / 2 - mViewHolder.mThumbHeroIndex, |
| end + mNumbThumbs / 2 - mViewHolder.mThumbHeroIndex); |
| } |
| } |
| |
| void verifyThumbBitmaps(Bitmap[] thumbs, int start, int end, |
| ThumbsBar thumbsBar, int childStart, int childEnd) { |
| assertEquals(end - start, childEnd - childStart); |
| for (int i = start; i <= end; i++) { |
| assertSame(thumbs[i], thumbsBar.getThumbBitmap(childStart + (i - start))); |
| } |
| for (int i = 0; i < childStart; i++) { |
| assertNull(thumbsBar.getThumbBitmap(i)); |
| } |
| for (int i = childEnd + 1; i < mNumbThumbs; i++) { |
| assertNull(thumbsBar.getThumbBitmap(i)); |
| } |
| } |
| |
| @Test |
| public void progressUpdating() { |
| when(mImpl.isPrepared()).thenReturn(true); |
| when(mImpl.getCurrentPosition()).thenReturn(123L); |
| when(mImpl.getDuration()).thenReturn(20000L); |
| when(mImpl.getBufferedPosition()).thenReturn(321L); |
| |
| mGlue.play(); |
| Mockito.verify(mImpl, times(1)).play(); |
| mGlue.pause(); |
| Mockito.verify(mImpl, times(1)).pause(); |
| mGlue.seekTo(1231); |
| Mockito.verify(mImpl, times(1)).seekTo(1231); |
| mImpl.getCallback().onCurrentPositionChanged(mImpl); |
| mImpl.getCallback().onDurationChanged(mImpl); |
| mImpl.getCallback().onBufferedPositionChanged(mImpl); |
| assertEquals(123L, mGlue.getCurrentPosition()); |
| assertEquals(20000L, mGlue.getDuration()); |
| assertEquals(321L, mGlue.getBufferedPosition()); |
| assertEquals(123L, mViewHolder.mCurrentTimeInMs); |
| assertEquals(20000L, mViewHolder.mTotalTimeInMs); |
| assertEquals(321L, mViewHolder.mSecondaryProgressInMs); |
| |
| when(mImpl.getCurrentPosition()).thenReturn(124L); |
| mImpl.getCallback().onCurrentPositionChanged(mImpl); |
| assertEquals(124L, mGlue.getControlsRow().getCurrentPosition()); |
| assertEquals(124L, mViewHolder.mCurrentTimeInMs); |
| when(mImpl.getBufferedPosition()).thenReturn(333L); |
| mImpl.getCallback().onBufferedPositionChanged(mImpl); |
| assertEquals(333L, mGlue.getControlsRow().getBufferedPosition()); |
| assertEquals(333L, mViewHolder.mSecondaryProgressInMs); |
| when(mImpl.getDuration()).thenReturn((long) (Integer.MAX_VALUE) * 2); |
| mImpl.getCallback().onDurationChanged(mImpl); |
| assertEquals((long) (Integer.MAX_VALUE) * 2, mGlue.getControlsRow().getDuration()); |
| assertEquals((long) (Integer.MAX_VALUE) * 2, mViewHolder.mTotalTimeInMs); |
| } |
| |
| @Test |
| public void mediaInfo() { |
| final ColorDrawable art = new ColorDrawable(); |
| InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() { |
| @Override |
| public void run() { |
| mGlue.setTitle("xyz"); |
| mGlue.setSubtitle("zyx"); |
| mGlue.setArt(art); |
| } |
| }); |
| assertEquals("xyz", mDescriptionViewHolder.mTitle.getText()); |
| assertEquals("zyx", mDescriptionViewHolder.mSubtitle.getText()); |
| assertSame(art, mViewHolder.mImageView.getDrawable()); |
| } |
| |
| static boolean isDescendant(View view, View descendant) { |
| while (descendant != view) { |
| ViewParent p = descendant.getParent(); |
| if (!(p instanceof View)) { |
| return false; |
| } |
| descendant = (View) p; |
| } |
| return true; |
| } |
| |
| @Test |
| public void navigateRightInPrimary() { |
| InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() { |
| @Override |
| public void run() { |
| mViewHolder.mControlsVh.mControlBar.getChildAt(0).requestFocus(); |
| } |
| }); |
| View view = mViewHolder.view.findFocus(); |
| assertTrue(isDescendant(mViewHolder.mControlsVh.mControlBar.getChildAt(0), view)); |
| assertTrue(isDescendant(mViewHolder.mControlsVh.mControlBar.getChildAt(1), |
| view.focusSearch(View.FOCUS_RIGHT))); |
| } |
| |
| @Test |
| public void navigateRightInSecondary() { |
| InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() { |
| @Override |
| public void run() { |
| mViewHolder.mSecondaryControlsVh.mControlBar.getChildAt(0).requestFocus(); |
| } |
| }); |
| View view = mViewHolder.view.findFocus(); |
| assertTrue(isDescendant(mViewHolder.mSecondaryControlsVh.mControlBar.getChildAt(0), view)); |
| assertTrue(isDescendant(mViewHolder.mSecondaryControlsVh.mControlBar.getChildAt(1), |
| view.focusSearch(View.FOCUS_RIGHT))); |
| } |
| |
| @Test |
| public void navigatePrimaryDownToProgress() { |
| InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() { |
| @Override |
| public void run() { |
| mViewHolder.mControlsVh.mControlBar.getChildAt(0).requestFocus(); |
| } |
| }); |
| View view = mViewHolder.view.findFocus(); |
| assertTrue(isDescendant(mViewHolder.mControlsVh.mControlBar.getChildAt(0), view)); |
| assertSame(mViewHolder.mProgressBar, view.focusSearch(View.FOCUS_DOWN)); |
| } |
| |
| @Test |
| public void navigateProgressUpToPrimary() { |
| InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() { |
| @Override |
| public void run() { |
| mViewHolder.mProgressBar.requestFocus(); |
| } |
| }); |
| InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() { |
| @Override |
| public void run() { |
| mViewHolder.mProgressBar.focusSearch(View.FOCUS_UP).requestFocus(); |
| } |
| }); |
| View view = mViewHolder.view.findFocus(); |
| assertTrue(isDescendant(mViewHolder.mControlsVh.mControlBar.getChildAt(0), view)); |
| } |
| |
| @Test |
| public void navigateProgressDownToSecondary() { |
| InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() { |
| @Override |
| public void run() { |
| mViewHolder.mProgressBar.requestFocus(); |
| } |
| }); |
| InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() { |
| @Override |
| public void run() { |
| mViewHolder.mProgressBar.focusSearch(View.FOCUS_DOWN).requestFocus(); |
| } |
| }); |
| View view = mViewHolder.view.findFocus(); |
| assertTrue(isDescendant(mViewHolder.mSecondaryControlsVh.mControlBar.getChildAt(0), view)); |
| } |
| |
| @Test |
| public void navigateSecondaryUpToProgress() { |
| InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() { |
| @Override |
| public void run() { |
| mViewHolder.mSecondaryControlsVh.mControlBar.getChildAt(0).requestFocus(); |
| } |
| }); |
| View view = mViewHolder.view.findFocus(); |
| assertTrue(isDescendant(mViewHolder.mSecondaryControlsVh.mControlBar.getChildAt(0), view)); |
| assertSame(mViewHolder.mProgressBar, view.focusSearch(View.FOCUS_UP)); |
| } |
| |
| @Test |
| public void seekAndConfirm() { |
| when(mImpl.isPrepared()).thenReturn(true); |
| when(mImpl.getCurrentPosition()).thenReturn(0L); |
| when(mImpl.getDuration()).thenReturn(20000L); |
| when(mImpl.getBufferedPosition()).thenReturn(321L); |
| mImpl.getCallback().onCurrentPositionChanged(mImpl); |
| mImpl.getCallback().onDurationChanged(mImpl); |
| mImpl.getCallback().onBufferedPositionChanged(mImpl); |
| |
| PlaybackSeekProviderSample provider = Mockito.spy( |
| new PlaybackSeekProviderSample(10000L, 101)); |
| final long[] positions = provider.getSeekPositions(); |
| mGlue.setSeekProvider(provider); |
| mViewHolder.mProgressBar.requestFocus(); |
| assertTrue(mViewHolder.mProgressBar.hasFocus()); |
| |
| sendKeyUIThread(KeyEvent.KEYCODE_DPAD_RIGHT); |
| verifyAtHeroIndex(positions, 1); |
| sendKeyUIThread(KeyEvent.KEYCODE_DPAD_RIGHT); |
| verifyAtHeroIndex(positions, 2); |
| |
| sendKeyUIThread(KeyEvent.KEYCODE_DPAD_CENTER); |
| Mockito.verify(mImpl).seekTo(positions[2]); |
| |
| verifyGetThumbCalls(1, 2, provider, positions); |
| } |
| |
| @Test |
| public void playSeekToZero() { |
| when(mImpl.isPrepared()).thenReturn(true); |
| when(mImpl.getCurrentPosition()).thenReturn(0L); |
| when(mImpl.getDuration()).thenReturn(20000L); |
| when(mImpl.getBufferedPosition()).thenReturn(321L); |
| mImpl.getCallback().onCurrentPositionChanged(mImpl); |
| mImpl.getCallback().onDurationChanged(mImpl); |
| mImpl.getCallback().onBufferedPositionChanged(mImpl); |
| |
| PlaybackSeekProviderSample provider = Mockito.spy( |
| new PlaybackSeekProviderSample(10000L, 101)); |
| final long[] positions = provider.getSeekPositions(); |
| mGlue.setSeekProvider(provider); |
| |
| // start play |
| mGlue.play(); |
| verify(mImpl).play(); |
| |
| // focus to seek bar |
| mViewHolder.mProgressBar.requestFocus(); |
| assertTrue(mViewHolder.mProgressBar.hasFocus()); |
| |
| // using DPAD_RIGHT to initiate seeking |
| sendKeyUIThread(KeyEvent.KEYCODE_DPAD_RIGHT); |
| sendKeyUIThread(KeyEvent.KEYCODE_DPAD_RIGHT); |
| verifyAtHeroIndex(positions, 2); |
| // press DPAD_CENTER to seek to new position and continue play |
| sendKeyUIThread(KeyEvent.KEYCODE_DPAD_CENTER); |
| verify(mImpl).seekTo(positions[2]); |
| verify(mImpl).play(); |
| |
| // press DPAD_LEFT seek to 0 |
| sendKeyUIThread(KeyEvent.KEYCODE_DPAD_LEFT); |
| sendKeyUIThread(KeyEvent.KEYCODE_DPAD_LEFT); |
| verifyAtHeroIndex(positions, 0); |
| // press DPAD_CENTER to continue play from 0 |
| sendKeyUIThread(KeyEvent.KEYCODE_DPAD_CENTER); |
| verify(mImpl).seekTo(0); |
| verify(mImpl).play(); |
| } |
| |
| @Test |
| public void playSeekAndCancel() { |
| when(mImpl.isPrepared()).thenReturn(true); |
| when(mImpl.getCurrentPosition()).thenReturn(0L); |
| when(mImpl.getDuration()).thenReturn(20000L); |
| when(mImpl.getBufferedPosition()).thenReturn(321L); |
| mImpl.getCallback().onCurrentPositionChanged(mImpl); |
| mImpl.getCallback().onDurationChanged(mImpl); |
| mImpl.getCallback().onBufferedPositionChanged(mImpl); |
| |
| PlaybackSeekProviderSample provider = Mockito.spy( |
| new PlaybackSeekProviderSample(10000L, 101)); |
| final long[] positions = provider.getSeekPositions(); |
| mGlue.setSeekProvider(provider); |
| |
| // start play |
| mGlue.play(); |
| verify(mImpl).play(); |
| |
| // focus to seek bar |
| mViewHolder.mProgressBar.requestFocus(); |
| assertTrue(mViewHolder.mProgressBar.hasFocus()); |
| |
| // using DPAD_RIGHT to initiate seeking |
| sendKeyUIThread(KeyEvent.KEYCODE_DPAD_RIGHT); |
| sendKeyUIThread(KeyEvent.KEYCODE_DPAD_RIGHT); |
| verifyAtHeroIndex(positions, 2); |
| // press DPAD_CENTER to seek to new position and continue play |
| sendKeyUIThread(KeyEvent.KEYCODE_DPAD_CENTER); |
| verify(mImpl).seekTo(positions[2]); |
| verify(mImpl).play(); |
| |
| // press DPAD_LEFT seek to 0 |
| sendKeyUIThread(KeyEvent.KEYCODE_DPAD_LEFT); |
| sendKeyUIThread(KeyEvent.KEYCODE_DPAD_LEFT); |
| verifyAtHeroIndex(positions, 0); |
| // press BACK to cancel and continue play from position before seek |
| sendKeyUIThread(KeyEvent.KEYCODE_BACK); |
| verify(mImpl).seekTo(positions[2]); |
| verify(mImpl).play(); |
| } |
| |
| @Test |
| public void seekHoldKeyDown() { |
| when(mImpl.isPrepared()).thenReturn(true); |
| when(mImpl.getCurrentPosition()).thenReturn(4489L); |
| when(mImpl.getDuration()).thenReturn(20000L); |
| when(mImpl.getBufferedPosition()).thenReturn(4489L); |
| mImpl.getCallback().onCurrentPositionChanged(mImpl); |
| mImpl.getCallback().onDurationChanged(mImpl); |
| mImpl.getCallback().onBufferedPositionChanged(mImpl); |
| |
| PlaybackSeekProviderSample provider = Mockito.spy( |
| new PlaybackSeekProviderSample(10000L, 101)); |
| final long[] positions = provider.getSeekPositions(); |
| mGlue.setSeekProvider(provider); |
| mViewHolder.mProgressBar.requestFocus(); |
| assertTrue(mViewHolder.mProgressBar.hasFocus()); |
| |
| int insertPosition = -1 - Arrays.binarySearch(positions, 4489L); |
| sendKeyUIThread(KeyEvent.KEYCODE_DPAD_RIGHT, 5); |
| verifyAtHeroIndex(positions, insertPosition + 4); |
| verifyGetThumbCalls(insertPosition, insertPosition + 4, provider, positions); |
| |
| sendKeyUIThread(KeyEvent.KEYCODE_DPAD_LEFT, 5); |
| verifyAtHeroIndex(positions, insertPosition - 1); |
| } |
| |
| @Test |
| public void seekAndCancel() { |
| when(mImpl.isPrepared()).thenReturn(true); |
| when(mImpl.getCurrentPosition()).thenReturn(0L); |
| when(mImpl.getDuration()).thenReturn(20000L); |
| when(mImpl.getBufferedPosition()).thenReturn(321L); |
| mImpl.getCallback().onCurrentPositionChanged(mImpl); |
| mImpl.getCallback().onDurationChanged(mImpl); |
| mImpl.getCallback().onBufferedPositionChanged(mImpl); |
| |
| PlaybackSeekProviderSample provider = Mockito.spy( |
| new PlaybackSeekProviderSample(10000L, 101)); |
| final long[] positions = provider.getSeekPositions(); |
| mGlue.setSeekProvider(provider); |
| mViewHolder.mProgressBar.requestFocus(); |
| assertTrue(mViewHolder.mProgressBar.hasFocus()); |
| |
| sendKeyUIThread(KeyEvent.KEYCODE_DPAD_RIGHT); |
| verifyAtHeroIndex(positions, 1); |
| |
| sendKeyUIThread(KeyEvent.KEYCODE_DPAD_RIGHT); |
| verifyAtHeroIndex(positions, 2); |
| |
| sendKeyUIThread(KeyEvent.KEYCODE_BACK); |
| Mockito.verify(mImpl, times(0)).seekTo(anyInt()); |
| verifyGetThumbCalls(1, 2, provider, positions); |
| } |
| |
| @Test |
| public void seekUpBetweenTwoKeyPosition() { |
| PlaybackSeekProviderSample provider = Mockito.spy( |
| new PlaybackSeekProviderSample(10000L, 101)); |
| final long[] positions = provider.getSeekPositions(); |
| |
| // initially select between 0 and 1 |
| when(mImpl.isPrepared()).thenReturn(true); |
| when(mImpl.getCurrentPosition()).thenReturn((positions[0] + positions[1]) / 2); |
| mImpl.getCallback().onCurrentPositionChanged(mImpl); |
| when(mImpl.getDuration()).thenReturn(20000L); |
| when(mImpl.getBufferedPosition()).thenReturn(321L); |
| mImpl.getCallback().onDurationChanged(mImpl); |
| mImpl.getCallback().onBufferedPositionChanged(mImpl); |
| |
| mGlue.setSeekProvider(provider); |
| mViewHolder.mProgressBar.requestFocus(); |
| assertTrue(mViewHolder.mProgressBar.hasFocus()); |
| |
| sendKeyUIThread(KeyEvent.KEYCODE_DPAD_RIGHT); |
| verifyAtHeroIndex(positions, 1); |
| verifyGetThumbCalls(1, 1, provider, positions); |
| } |
| |
| @Test |
| public void seekDownBetweenTwoKeyPosition() { |
| PlaybackSeekProviderSample provider = Mockito.spy( |
| new PlaybackSeekProviderSample(10000L, 101)); |
| final long[] positions = provider.getSeekPositions(); |
| assertTrue(positions[0] == 0); |
| |
| // initially select between 0 and 1 |
| when(mImpl.isPrepared()).thenReturn(true); |
| when(mImpl.getCurrentPosition()).thenReturn((positions[0] + positions[1]) / 2); |
| mImpl.getCallback().onCurrentPositionChanged(mImpl); |
| when(mImpl.getDuration()).thenReturn(20000L); |
| when(mImpl.getBufferedPosition()).thenReturn(321L); |
| mImpl.getCallback().onDurationChanged(mImpl); |
| mImpl.getCallback().onBufferedPositionChanged(mImpl); |
| |
| mGlue.setSeekProvider(provider); |
| mViewHolder.mProgressBar.requestFocus(); |
| assertTrue(mViewHolder.mProgressBar.hasFocus()); |
| |
| sendKeyUIThread(KeyEvent.KEYCODE_DPAD_LEFT); |
| verifyAtHeroIndex(positions, 0); |
| verifyGetThumbCalls(0, 0, provider, positions); |
| } |
| |
| @Test |
| public void seekDownOutOfKeyPositions() { |
| PlaybackSeekProviderSample provider = Mockito.spy( |
| new PlaybackSeekProviderSample(1000L, 10000L, 101)); |
| final long[] positions = provider.getSeekPositions(); |
| assertTrue(positions[0] > 0); |
| |
| // initially select between 0 and 1 |
| when(mImpl.isPrepared()).thenReturn(true); |
| when(mImpl.getCurrentPosition()).thenReturn((positions[0] + positions[1]) / 2); |
| mImpl.getCallback().onCurrentPositionChanged(mImpl); |
| when(mImpl.getDuration()).thenReturn(20000L); |
| when(mImpl.getBufferedPosition()).thenReturn(321L); |
| mImpl.getCallback().onDurationChanged(mImpl); |
| mImpl.getCallback().onBufferedPositionChanged(mImpl); |
| |
| mGlue.setSeekProvider(provider); |
| mViewHolder.mProgressBar.requestFocus(); |
| assertTrue(mViewHolder.mProgressBar.hasFocus()); |
| |
| sendKeyUIThread(KeyEvent.KEYCODE_DPAD_LEFT); |
| verifyAtHeroIndex(positions, 0); |
| sendKeyUIThread(KeyEvent.KEYCODE_DPAD_LEFT); |
| verifyAtHeroIndexWithDifferentPosition(0, 0); |
| sendKeyUIThread(KeyEvent.KEYCODE_DPAD_LEFT); |
| verifyAtHeroIndexWithDifferentPosition(0, 0); |
| verifyGetThumbCalls(0, 0, provider, positions); |
| } |
| |
| @Test |
| public void seekDownAheadOfKeyPositions() { |
| PlaybackSeekProviderSample provider = Mockito.spy( |
| new PlaybackSeekProviderSample(1000L, 10000L, 101)); |
| final long[] positions = provider.getSeekPositions(); |
| assertTrue(positions[0] > 0); |
| |
| // initially select between 0 and 1 |
| when(mImpl.isPrepared()).thenReturn(true); |
| when(mImpl.getCurrentPosition()).thenReturn(positions[0] / 2); |
| mImpl.getCallback().onCurrentPositionChanged(mImpl); |
| when(mImpl.getDuration()).thenReturn(20000L); |
| when(mImpl.getBufferedPosition()).thenReturn(321L); |
| mImpl.getCallback().onDurationChanged(mImpl); |
| mImpl.getCallback().onBufferedPositionChanged(mImpl); |
| |
| mGlue.setSeekProvider(provider); |
| mViewHolder.mProgressBar.requestFocus(); |
| assertTrue(mViewHolder.mProgressBar.hasFocus()); |
| |
| sendKeyUIThread(KeyEvent.KEYCODE_DPAD_LEFT); |
| verifyAtHeroIndexWithDifferentPosition(0, 0); |
| sendKeyUIThread(KeyEvent.KEYCODE_DPAD_RIGHT); |
| verifyAtHeroIndex(positions, 0); |
| verifyGetThumbCalls(0, 0, provider, positions); |
| } |
| |
| @Test |
| public void seekUpAheadOfKeyPositions() { |
| PlaybackSeekProviderSample provider = Mockito.spy( |
| new PlaybackSeekProviderSample(1000L, 10000L, 101)); |
| final long[] positions = provider.getSeekPositions(); |
| assertTrue(positions[0] > 0); |
| |
| // initially select between 0 and 1 |
| when(mImpl.isPrepared()).thenReturn(true); |
| when(mImpl.getCurrentPosition()).thenReturn(positions[0] / 2); |
| mImpl.getCallback().onCurrentPositionChanged(mImpl); |
| when(mImpl.getDuration()).thenReturn(20000L); |
| when(mImpl.getBufferedPosition()).thenReturn(321L); |
| mImpl.getCallback().onDurationChanged(mImpl); |
| mImpl.getCallback().onBufferedPositionChanged(mImpl); |
| |
| mGlue.setSeekProvider(provider); |
| mViewHolder.mProgressBar.requestFocus(); |
| assertTrue(mViewHolder.mProgressBar.hasFocus()); |
| |
| sendKeyUIThread(KeyEvent.KEYCODE_DPAD_RIGHT); |
| verifyAtHeroIndex(positions, 0); |
| sendKeyUIThread(KeyEvent.KEYCODE_DPAD_LEFT); |
| verifyAtHeroIndexWithDifferentPosition(0, 0); |
| verifyGetThumbCalls(0, 0, provider, positions); |
| } |
| |
| @Test |
| public void seekUpOutOfKeyPositions() { |
| PlaybackSeekProviderSample provider = Mockito.spy( |
| new PlaybackSeekProviderSample(10000L, 101)); |
| final long[] positions = provider.getSeekPositions(); |
| |
| // initially select between nth-1 and nth |
| when(mImpl.isPrepared()).thenReturn(true); |
| when(mImpl.getCurrentPosition()).thenReturn((positions[positions.length - 2] |
| + positions[positions.length - 1]) / 2); |
| mImpl.getCallback().onCurrentPositionChanged(mImpl); |
| when(mImpl.getDuration()).thenReturn(20000L); |
| when(mImpl.getBufferedPosition()).thenReturn(321L); |
| mImpl.getCallback().onDurationChanged(mImpl); |
| mImpl.getCallback().onBufferedPositionChanged(mImpl); |
| |
| mGlue.setSeekProvider(provider); |
| mViewHolder.mProgressBar.requestFocus(); |
| assertTrue(mViewHolder.mProgressBar.hasFocus()); |
| |
| sendKeyUIThread(KeyEvent.KEYCODE_DPAD_RIGHT); |
| verifyAtHeroIndex(positions, positions.length - 1); |
| sendKeyUIThread(KeyEvent.KEYCODE_DPAD_LEFT); |
| verifyAtHeroIndex(positions, positions.length - 2); |
| sendKeyUIThread(KeyEvent.KEYCODE_DPAD_RIGHT); |
| verifyAtHeroIndex(positions, positions.length - 1); |
| sendKeyUIThread(KeyEvent.KEYCODE_DPAD_RIGHT); |
| verifyAtHeroIndexWithDifferentPosition(20000L, positions.length - 1); |
| sendKeyUIThread(KeyEvent.KEYCODE_DPAD_RIGHT); |
| verifyAtHeroIndexWithDifferentPosition(20000L, positions.length - 1); |
| verifyGetThumbCalls(positions.length - 2, positions.length - 1, provider, positions); |
| } |
| |
| @Test |
| public void seekUpAfterKeyPositions() { |
| PlaybackSeekProviderSample provider = Mockito.spy( |
| new PlaybackSeekProviderSample(10000L, 101)); |
| final long[] positions = provider.getSeekPositions(); |
| |
| // initially select after last item |
| when(mImpl.isPrepared()).thenReturn(true); |
| when(mImpl.getCurrentPosition()).thenReturn(positions[positions.length - 1] + 100); |
| mImpl.getCallback().onCurrentPositionChanged(mImpl); |
| when(mImpl.getDuration()).thenReturn(20000L); |
| when(mImpl.getBufferedPosition()).thenReturn(321L); |
| mImpl.getCallback().onDurationChanged(mImpl); |
| mImpl.getCallback().onBufferedPositionChanged(mImpl); |
| |
| mGlue.setSeekProvider(provider); |
| mViewHolder.mProgressBar.requestFocus(); |
| assertTrue(mViewHolder.mProgressBar.hasFocus()); |
| |
| sendKeyUIThread(KeyEvent.KEYCODE_DPAD_RIGHT); |
| verifyAtHeroIndexWithDifferentPosition(20000L, positions.length - 1); |
| sendKeyUIThread(KeyEvent.KEYCODE_DPAD_LEFT); |
| verifyAtHeroIndex(positions, positions.length - 1); |
| verifyGetThumbCalls(positions.length - 1, positions.length - 1, provider, positions); |
| } |
| |
| @Test |
| public void seekDownAfterKeyPositions() { |
| PlaybackSeekProviderSample provider = Mockito.spy( |
| new PlaybackSeekProviderSample(10000L, 101)); |
| final long[] positions = provider.getSeekPositions(); |
| |
| // initially select after last item |
| when(mImpl.isPrepared()).thenReturn(true); |
| when(mImpl.getCurrentPosition()).thenReturn(positions[positions.length - 1] + 100); |
| mImpl.getCallback().onCurrentPositionChanged(mImpl); |
| when(mImpl.getDuration()).thenReturn(20000L); |
| when(mImpl.getBufferedPosition()).thenReturn(321L); |
| mImpl.getCallback().onDurationChanged(mImpl); |
| mImpl.getCallback().onBufferedPositionChanged(mImpl); |
| |
| mGlue.setSeekProvider(provider); |
| mViewHolder.mProgressBar.requestFocus(); |
| assertTrue(mViewHolder.mProgressBar.hasFocus()); |
| |
| sendKeyUIThread(KeyEvent.KEYCODE_DPAD_LEFT); |
| verifyAtHeroIndex(positions, positions.length - 1); |
| sendKeyUIThread(KeyEvent.KEYCODE_DPAD_RIGHT); |
| verifyAtHeroIndexWithDifferentPosition(20000L, positions.length - 1); |
| verifyGetThumbCalls(positions.length - 1, positions.length - 1, provider, positions); |
| } |
| |
| @Test |
| public void thumbLoadedInCallback() { |
| when(mImpl.isPrepared()).thenReturn(true); |
| when(mImpl.getCurrentPosition()).thenReturn(0L); |
| when(mImpl.getDuration()).thenReturn(20000L); |
| when(mImpl.getBufferedPosition()).thenReturn(321L); |
| mImpl.getCallback().onCurrentPositionChanged(mImpl); |
| mImpl.getCallback().onDurationChanged(mImpl); |
| mImpl.getCallback().onBufferedPositionChanged(mImpl); |
| |
| final Bitmap[] thumbs = new Bitmap[101]; |
| for (int i = 0; i < 101; i++) { |
| thumbs[i] = Bitmap.createBitmap(16, 16, Bitmap.Config.ARGB_8888); |
| } |
| PlaybackSeekProviderSample provider = new PlaybackSeekProviderSample(10000L, 101) { |
| @Override |
| public void getThumbnail(int index, ResultCallback callback) { |
| callback.onThumbnailLoaded(thumbs[index], index); |
| } |
| }; |
| final long[] positions = provider.getSeekPositions(); |
| mGlue.setSeekProvider(provider); |
| mViewHolder.mProgressBar.requestFocus(); |
| assertTrue(mViewHolder.mProgressBar.hasFocus()); |
| |
| sendKeyUIThread(KeyEvent.KEYCODE_DPAD_RIGHT); |
| verifyAtHeroIndex(positions, 1, thumbs); |
| } |
| |
| } |