DetailsFragmentTest.java revision 6525e063fbbd691a8553f4fc77f3960f93bea34d
1/* 2 * Copyright (C) 2016 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 */ 16package android.support.v17.leanback.app; 17 18import static junit.framework.TestCase.assertFalse; 19 20import static org.junit.Assert.assertEquals; 21import static org.junit.Assert.assertTrue; 22 23import android.animation.PropertyValuesHolder; 24import android.app.Fragment; 25import android.content.Intent; 26import android.graphics.Bitmap; 27import android.graphics.BitmapFactory; 28import android.graphics.Rect; 29import android.graphics.drawable.ColorDrawable; 30import android.graphics.drawable.Drawable; 31import android.net.Uri; 32import android.os.Bundle; 33import android.support.test.InstrumentationRegistry; 34import android.support.test.filters.LargeTest; 35import android.support.v17.leanback.R; 36import android.support.v17.leanback.graphics.FitWidthBitmapDrawable; 37import android.support.v17.leanback.media.MediaPlayerGlue; 38import android.support.v17.leanback.testutils.PollingCheck; 39import android.support.v17.leanback.widget.DetailsParallax; 40import android.support.v17.leanback.widget.DetailsParallaxDrawable; 41import android.support.v17.leanback.widget.ParallaxTarget; 42import android.support.v17.leanback.widget.RecyclerViewParallax; 43import android.support.v17.leanback.widget.VerticalGridView; 44import android.view.KeyEvent; 45import android.view.View; 46 47import org.junit.Test; 48import org.junit.runner.RunWith; 49import org.junit.runners.JUnit4; 50 51/** 52 * Unit tests for {@link DetailsFragment}. 53 */ 54@RunWith(JUnit4.class) 55@LargeTest 56public class DetailsFragmentTest extends SingleFragmentTestBase { 57 58 static final int PARALLAX_VERTICAL_OFFSET = -300; 59 60 public static class DetailsFragmentParallax extends DetailsTestFragment { 61 62 private DetailsParallaxDrawable mParallaxDrawable; 63 64 public DetailsFragmentParallax() { 65 super(); 66 mMinVerticalOffset = PARALLAX_VERTICAL_OFFSET; 67 } 68 69 @Override 70 public void onCreate(Bundle savedInstanceState) { 71 super.onCreate(savedInstanceState); 72 Drawable coverDrawable = new FitWidthBitmapDrawable(); 73 mParallaxDrawable = new DetailsParallaxDrawable( 74 getActivity(), 75 getParallax(), 76 coverDrawable, 77 new ParallaxTarget.PropertyValuesHolderTarget( 78 coverDrawable, 79 PropertyValuesHolder.ofInt("verticalOffset", 0, mMinVerticalOffset) 80 ) 81 ); 82 83 BackgroundManager backgroundManager = BackgroundManager.getInstance(getActivity()); 84 backgroundManager.attach(getActivity().getWindow()); 85 backgroundManager.setDrawable(mParallaxDrawable); 86 } 87 88 @Override 89 public void onStart() { 90 super.onStart(); 91 setItem(new PhotoItem("Hello world", "Fake content goes here", 92 android.support.v17.leanback.test.R.drawable.spiderman)); 93 } 94 95 @Override 96 public void onResume() { 97 super.onResume(); 98 Bitmap bitmap = BitmapFactory.decodeResource(getActivity().getResources(), 99 android.support.v17.leanback.test.R.drawable.spiderman); 100 ((FitWidthBitmapDrawable) mParallaxDrawable.getCoverDrawable()).setBitmap(bitmap); 101 } 102 103 DetailsParallaxDrawable getParallaxDrawable() { 104 return mParallaxDrawable; 105 } 106 } 107 108 @Test 109 public void parallaxSetupTest() { 110 launchAndWaitActivity(DetailsFragmentTest.DetailsFragmentParallax.class, 111 new SingleFragmentTestBase.Options().uiVisibility( 112 View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_FULLSCREEN), 0); 113 114 double delta = 0.0002; 115 DetailsParallax dpm = ((DetailsFragment) mActivity.getTestFragment()).getParallax(); 116 117 RecyclerViewParallax.ChildPositionProperty frameTop = 118 (RecyclerViewParallax.ChildPositionProperty) dpm.getOverviewRowTop(); 119 assertEquals(0f, frameTop.getFraction(), delta); 120 assertEquals(0f, frameTop.getAdapterPosition(), delta); 121 122 123 RecyclerViewParallax.ChildPositionProperty frameBottom = 124 (RecyclerViewParallax.ChildPositionProperty) dpm.getOverviewRowBottom(); 125 assertEquals(1f, frameBottom.getFraction(), delta); 126 assertEquals(0f, frameBottom.getAdapterPosition(), delta); 127 } 128 129 @Test 130 public void parallaxTest() throws Throwable { 131 launchAndWaitActivity(DetailsFragmentParallax.class, 132 new Options().uiVisibility( 133 View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_FULLSCREEN), 0); 134 135 final DetailsFragmentParallax detailsFragment = 136 (DetailsFragmentParallax) mActivity.getTestFragment(); 137 DetailsParallaxDrawable drawable = 138 detailsFragment.getParallaxDrawable(); 139 final FitWidthBitmapDrawable bitmapDrawable = (FitWidthBitmapDrawable) 140 drawable.getCoverDrawable(); 141 142 PollingCheck.waitFor(4000, new PollingCheck.PollingCheckCondition() { 143 @Override 144 public boolean canProceed() { 145 return detailsFragment.getRowsFragment().getAdapter() != null 146 && detailsFragment.getRowsFragment().getAdapter().size() > 1; 147 } 148 }); 149 150 final VerticalGridView verticalGridView = detailsFragment.getRowsFragment() 151 .getVerticalGridView(); 152 final int windowHeight = verticalGridView.getHeight(); 153 final int windowWidth = verticalGridView.getWidth(); 154 // make sure background manager attached to window is same size as VerticalGridView 155 // i.e. no status bar. 156 assertEquals(windowHeight, mActivity.getWindow().getDecorView().getHeight()); 157 assertEquals(windowWidth, mActivity.getWindow().getDecorView().getWidth()); 158 159 final View detailsFrame = verticalGridView.findViewById(R.id.details_frame); 160 161 assertEquals(windowWidth, bitmapDrawable.getBounds().width()); 162 163 final Rect detailsFrameRect = new Rect(); 164 detailsFrameRect.set(0, 0, detailsFrame.getWidth(), detailsFrame.getHeight()); 165 verticalGridView.offsetDescendantRectToMyCoords(detailsFrame, detailsFrameRect); 166 167 assertEquals(Math.min(windowHeight, detailsFrameRect.top), 168 bitmapDrawable.getBounds().height()); 169 assertEquals(0, bitmapDrawable.getVerticalOffset()); 170 171 assertTrue("TitleView is visible", detailsFragment.getView() 172 .findViewById(R.id.browse_title_group).getVisibility() == View.VISIBLE); 173 174 activityTestRule.runOnUiThread(new Runnable() { 175 @Override 176 public void run() { 177 verticalGridView.scrollToPosition(1); 178 } 179 }); 180 181 PollingCheck.waitFor(4000, new PollingCheck.PollingCheckCondition() { 182 @Override 183 public boolean canProceed() { 184 return bitmapDrawable.getVerticalOffset() == PARALLAX_VERTICAL_OFFSET 185 && detailsFragment.getView() 186 .findViewById(R.id.browse_title_group).getVisibility() != View.VISIBLE; 187 } 188 }); 189 190 detailsFrameRect.set(0, 0, detailsFrame.getWidth(), detailsFrame.getHeight()); 191 verticalGridView.offsetDescendantRectToMyCoords(detailsFrame, detailsFrameRect); 192 193 assertEquals(0, bitmapDrawable.getBounds().top); 194 assertEquals(Math.max(detailsFrameRect.top, 0), bitmapDrawable.getBounds().bottom); 195 assertEquals(windowWidth, bitmapDrawable.getBounds().width()); 196 197 ColorDrawable colorDrawable = (ColorDrawable) (drawable.getChildAt(1).getDrawable()); 198 assertEquals(windowWidth, colorDrawable.getBounds().width()); 199 assertEquals(detailsFrameRect.bottom, colorDrawable.getBounds().top); 200 assertEquals(windowHeight, colorDrawable.getBounds().bottom); 201 } 202 203 public static class DetailsFragmentWithVideo extends DetailsTestFragment { 204 205 final DetailsFragmentBackgroundController mDetailsBackground = 206 new DetailsFragmentBackgroundController(this); 207 MediaPlayerGlue mGlue; 208 209 public DetailsFragmentWithVideo() { 210 mTimeToLoadOverviewRow = mTimeToLoadRelatedRow = 100; 211 } 212 213 @Override 214 public void onCreate(Bundle savedInstanceState) { 215 super.onCreate(savedInstanceState); 216 mDetailsBackground.enableParallax(); 217 mGlue = new MediaPlayerGlue(getActivity()); 218 mDetailsBackground.setupVideoPlayback(mGlue); 219 220 mGlue.setMode(MediaPlayerGlue.REPEAT_ALL); 221 mGlue.setArtist("A Googleer"); 222 mGlue.setTitle("Diving with Sharks"); 223 mGlue.setMediaSource( 224 Uri.parse("android.resource://android.support.v17.leanback.test/raw/video")); 225 } 226 227 @Override 228 public void onStart() { 229 super.onStart(); 230 Bitmap bitmap = BitmapFactory.decodeResource(getActivity().getResources(), 231 android.support.v17.leanback.test.R.drawable.spiderman); 232 mDetailsBackground.setCoverBitmap(bitmap); 233 } 234 235 @Override 236 public void onStop() { 237 mDetailsBackground.setCoverBitmap(null); 238 super.onStop(); 239 } 240 } 241 242 public static class DetailsFragmentWithVideo1 extends DetailsFragmentWithVideo { 243 244 @Override 245 public void onCreate(Bundle savedInstanceState) { 246 super.onCreate(savedInstanceState); 247 setItem(new PhotoItem("Hello world", "Fake content goes here", 248 android.support.v17.leanback.test.R.drawable.spiderman)); 249 } 250 } 251 252 public static class DetailsFragmentWithVideo2 extends DetailsFragmentWithVideo { 253 254 @Override 255 public void onStart() { 256 super.onStart(); 257 setItem(new PhotoItem("Hello world", "Fake content goes here", 258 android.support.v17.leanback.test.R.drawable.spiderman)); 259 } 260 } 261 262 private void navigateBetweenRowsAndVideoUsingRequestFocusInternal(Class cls) 263 throws Throwable { 264 launchAndWaitActivity(cls, 265 new Options().uiVisibility( 266 View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_FULLSCREEN), 0); 267 268 final DetailsFragmentWithVideo detailsFragment = 269 (DetailsFragmentWithVideo) mActivity.getTestFragment(); 270 PollingCheck.waitFor(4000, new PollingCheck.PollingCheckCondition() { 271 @Override 272 public boolean canProceed() { 273 return detailsFragment.mVideoFragment != null 274 && detailsFragment.mVideoFragment.getView() != null 275 && detailsFragment.mGlue.isMediaPlaying(); 276 } 277 }); 278 279 final int screenHeight = detailsFragment.getRowsFragment().getVerticalGridView() 280 .getHeight(); 281 final View firstRow = detailsFragment.getRowsFragment().getVerticalGridView().getChildAt(0); 282 final int originalFirstRowTop = firstRow.getTop(); 283 assertTrue(firstRow.hasFocus()); 284 assertTrue(firstRow.getTop() > 0 && firstRow.getTop() < screenHeight); 285 assertTrue(detailsFragment.isShowingTitle()); 286 287 InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() { 288 @Override 289 public void run() { 290 detailsFragment.mVideoFragment.getView().requestFocus(); 291 } 292 }); 293 PollingCheck.waitFor(4000, new PollingCheck.PollingCheckCondition() { 294 @Override 295 public boolean canProceed() { 296 return firstRow.getTop() >= screenHeight; 297 } 298 }); 299 assertFalse(detailsFragment.isShowingTitle()); 300 301 InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() { 302 @Override 303 public void run() { 304 detailsFragment.getRowsFragment().getVerticalGridView().requestFocus(); 305 } 306 }); 307 PollingCheck.waitFor(4000, new PollingCheck.PollingCheckCondition() { 308 @Override 309 public boolean canProceed() { 310 return firstRow.getTop() == originalFirstRowTop; 311 } 312 }); 313 assertTrue(detailsFragment.isShowingTitle()); 314 } 315 316 @Test 317 public void navigateBetweenRowsAndVideoUsingRequestFocus1() throws Throwable { 318 navigateBetweenRowsAndVideoUsingRequestFocusInternal(DetailsFragmentWithVideo1.class); 319 } 320 321 @Test 322 public void navigateBetweenRowsAndVideoUsingRequestFocus2() throws Throwable { 323 navigateBetweenRowsAndVideoUsingRequestFocusInternal(DetailsFragmentWithVideo2.class); 324 } 325 326 private void navigateBetweenRowsAndVideoUsingDPADInternal(Class cls) throws Throwable { 327 launchAndWaitActivity(cls, 328 new Options().uiVisibility( 329 View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_FULLSCREEN), 0); 330 331 final DetailsFragmentWithVideo detailsFragment = 332 (DetailsFragmentWithVideo) mActivity.getTestFragment(); 333 // wait video playing 334 PollingCheck.waitFor(4000, new PollingCheck.PollingCheckCondition() { 335 @Override 336 public boolean canProceed() { 337 return detailsFragment.mVideoFragment != null 338 && detailsFragment.mVideoFragment.getView() != null 339 && detailsFragment.mGlue.isMediaPlaying(); 340 } 341 }); 342 343 final int screenHeight = detailsFragment.getRowsFragment().getVerticalGridView() 344 .getHeight(); 345 final View firstRow = detailsFragment.getRowsFragment().getVerticalGridView().getChildAt(0); 346 final int originalFirstRowTop = firstRow.getTop(); 347 assertTrue(firstRow.hasFocus()); 348 assertTrue(firstRow.getTop() > 0 && firstRow.getTop() < screenHeight); 349 assertTrue(detailsFragment.isShowingTitle()); 350 351 // navigate to video 352 sendKeys(KeyEvent.KEYCODE_DPAD_UP); 353 PollingCheck.waitFor(4000, new PollingCheck.PollingCheckCondition() { 354 @Override 355 public boolean canProceed() { 356 return firstRow.getTop() >= screenHeight; 357 } 358 }); 359 360 // wait auto hide play controls done: 361 PollingCheck.waitFor(8000, new PollingCheck.PollingCheckCondition() { 362 @Override 363 public boolean canProceed() { 364 return ((PlaybackFragment) detailsFragment.mVideoFragment).mBgAlpha == 0; 365 } 366 }); 367 368 // navigate to details 369 sendKeys(KeyEvent.KEYCODE_BACK); 370 PollingCheck.waitFor(4000, new PollingCheck.PollingCheckCondition() { 371 @Override 372 public boolean canProceed() { 373 return firstRow.getTop() == originalFirstRowTop; 374 } 375 }); 376 assertTrue(detailsFragment.isShowingTitle()); 377 } 378 379 @Test 380 public void navigateBetweenRowsAndVideoUsingDPAD1() throws Throwable { 381 navigateBetweenRowsAndVideoUsingDPADInternal(DetailsFragmentWithVideo1.class); 382 } 383 384 @Test 385 public void navigateBetweenRowsAndVideoUsingDPAD2() throws Throwable { 386 navigateBetweenRowsAndVideoUsingDPADInternal(DetailsFragmentWithVideo2.class); 387 } 388 389 private void fragmentOnStartWithVideoInternal(Class cls) throws Throwable { 390 launchAndWaitActivity(cls, 391 new Options().uiVisibility( 392 View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_FULLSCREEN), 0); 393 394 final DetailsFragmentWithVideo detailsFragment = 395 (DetailsFragmentWithVideo) mActivity.getTestFragment(); 396 // wait video playing 397 PollingCheck.waitFor(4000, new PollingCheck.PollingCheckCondition() { 398 @Override 399 public boolean canProceed() { 400 return detailsFragment.mVideoFragment != null 401 && detailsFragment.mVideoFragment.getView() != null 402 && detailsFragment.mGlue.isMediaPlaying(); 403 } 404 }); 405 406 final int screenHeight = detailsFragment.getRowsFragment().getVerticalGridView() 407 .getHeight(); 408 final View firstRow = detailsFragment.getRowsFragment().getVerticalGridView().getChildAt(0); 409 final int originalFirstRowTop = firstRow.getTop(); 410 assertTrue(firstRow.hasFocus()); 411 assertTrue(firstRow.getTop() > 0 && firstRow.getTop() < screenHeight); 412 assertTrue(detailsFragment.isShowingTitle()); 413 414 // navigate to video 415 sendKeys(KeyEvent.KEYCODE_DPAD_UP); 416 PollingCheck.waitFor(4000, new PollingCheck.PollingCheckCondition() { 417 @Override 418 public boolean canProceed() { 419 return firstRow.getTop() >= screenHeight; 420 } 421 }); 422 423 // start an empty activity 424 InstrumentationRegistry.getInstrumentation().runOnMainSync( 425 new Runnable() { 426 @Override 427 public void run() { 428 Intent intent = new Intent(mActivity, SingleFragmentTestActivity.class); 429 intent.putExtra(SingleFragmentTestActivity.EXTRA_FRAGMENT_NAME, 430 Fragment.class.getName()); 431 mActivity.startActivity(intent); 432 } 433 } 434 ); 435 PollingCheck.waitFor(2000, new PollingCheck.PollingCheckCondition() { 436 @Override 437 public boolean canProceed() { 438 return !detailsFragment.isResumed(); 439 } 440 }); 441 // pop empty activity, have to wait 1000 before sending BACK key or the key will lose 442 // nowhere. 443 Thread.sleep(1000); 444 sendKeys(KeyEvent.KEYCODE_BACK); 445 446 PollingCheck.waitFor(2000, new PollingCheck.PollingCheckCondition() { 447 @Override 448 public boolean canProceed() { 449 return detailsFragment.isResumed(); 450 } 451 }); 452 assertTrue(detailsFragment.mVideoFragment.getView().hasFocus()); 453 } 454 455 @Test 456 public void fragmentOnStartWithVideo1() throws Throwable { 457 fragmentOnStartWithVideoInternal(DetailsFragmentWithVideo1.class); 458 } 459 460 @Test 461 public void fragmentOnStartWithVideo2() throws Throwable { 462 fragmentOnStartWithVideoInternal(DetailsFragmentWithVideo2.class); 463 } 464 465 @Test 466 public void navigateBetweenRowsAndTitle() throws Throwable { 467 launchAndWaitActivity(DetailsTestFragment.class, new Options().uiVisibility( 468 View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_FULLSCREEN), 0); 469 final DetailsTestFragment detailsFragment = 470 (DetailsTestFragment) mActivity.getTestFragment(); 471 472 InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() { 473 @Override 474 public void run() { 475 detailsFragment.setOnSearchClickedListener(new View.OnClickListener() { 476 @Override 477 public void onClick(View view) { 478 } 479 }); 480 detailsFragment.setItem(new PhotoItem("Hello world", "Fake content goes here", 481 android.support.v17.leanback.test.R.drawable.spiderman)); 482 } 483 }); 484 485 PollingCheck.waitFor(4000, new PollingCheck.PollingCheckCondition() { 486 @Override 487 public boolean canProceed() { 488 return detailsFragment.getRowsFragment().getVerticalGridView().getChildCount() > 0; 489 } 490 }); 491 final View firstRow = detailsFragment.getRowsFragment().getVerticalGridView().getChildAt(0); 492 final int originalFirstRowTop = firstRow.getTop(); 493 final int screenHeight = detailsFragment.getRowsFragment().getVerticalGridView() 494 .getHeight(); 495 496 assertTrue(firstRow.hasFocus()); 497 assertTrue(detailsFragment.isShowingTitle()); 498 assertTrue(firstRow.getTop() > 0 && firstRow.getTop() < screenHeight); 499 500 sendKeys(KeyEvent.KEYCODE_DPAD_UP); 501 PollingCheck.waitFor(new PollingCheck.ViewStableOnScreen(firstRow)); 502 assertTrue(detailsFragment.isShowingTitle()); 503 assertTrue(detailsFragment.getTitleView().hasFocus()); 504 assertEquals(originalFirstRowTop, firstRow.getTop()); 505 506 sendKeys(KeyEvent.KEYCODE_DPAD_DOWN); 507 PollingCheck.waitFor(new PollingCheck.ViewStableOnScreen(firstRow)); 508 assertTrue(detailsFragment.isShowingTitle()); 509 assertTrue(firstRow.hasFocus()); 510 assertEquals(originalFirstRowTop, firstRow.getTop()); 511 } 512} 513