Merge "PlaybackControlGlue: remove dependency on PlaybackControlsRowPresenter" into nyc-support-25.4-dev
diff --git a/api/current.txt b/api/current.txt
index eed38ed..62853ba 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -1859,6 +1859,7 @@
 
   public class DetailsFragmentBackgroundController {
     ctor public DetailsFragmentBackgroundController(android.support.v17.leanback.app.DetailsFragment);
+    method public boolean canNavigateToVideoFragment();
     method public void enableParallax();
     method public void enableParallax(android.graphics.drawable.Drawable, android.graphics.drawable.Drawable, android.support.v17.leanback.widget.ParallaxTarget.PropertyValuesHolderTarget);
     method public final android.app.Fragment findOrCreateVideoFragment();
@@ -1866,6 +1867,7 @@
     method public final android.graphics.Bitmap getCoverBitmap();
     method public final android.graphics.drawable.Drawable getCoverDrawable();
     method public final int getParallaxDrawableMaxOffset();
+    method public final android.support.v17.leanback.media.PlaybackGlue getPlaybackGlue();
     method public final int getSolidColor();
     method public android.support.v17.leanback.media.PlaybackGlueHost onCreateGlueHost();
     method public android.app.Fragment onCreateVideoFragment();
@@ -1873,6 +1875,8 @@
     method public final void setParallaxDrawableMaxOffset(int);
     method public final void setSolidColor(int);
     method public void setupVideoPlayback(android.support.v17.leanback.media.PlaybackGlue);
+    method public final void switchToRows();
+    method public final void switchToVideo();
   }
 
   public class DetailsSupportFragment extends android.support.v17.leanback.app.BrandedSupportFragment {
@@ -1900,6 +1904,7 @@
 
   public class DetailsSupportFragmentBackgroundController {
     ctor public DetailsSupportFragmentBackgroundController(android.support.v17.leanback.app.DetailsSupportFragment);
+    method public boolean canNavigateToVideoSupportFragment();
     method public void enableParallax();
     method public void enableParallax(android.graphics.drawable.Drawable, android.graphics.drawable.Drawable, android.support.v17.leanback.widget.ParallaxTarget.PropertyValuesHolderTarget);
     method public final android.support.v4.app.Fragment findOrCreateVideoSupportFragment();
@@ -1907,6 +1912,7 @@
     method public final android.graphics.Bitmap getCoverBitmap();
     method public final android.graphics.drawable.Drawable getCoverDrawable();
     method public final int getParallaxDrawableMaxOffset();
+    method public final android.support.v17.leanback.media.PlaybackGlue getPlaybackGlue();
     method public final int getSolidColor();
     method public android.support.v17.leanback.media.PlaybackGlueHost onCreateGlueHost();
     method public android.support.v4.app.Fragment onCreateVideoSupportFragment();
@@ -1914,6 +1920,8 @@
     method public final void setParallaxDrawableMaxOffset(int);
     method public final void setSolidColor(int);
     method public void setupVideoPlayback(android.support.v17.leanback.media.PlaybackGlue);
+    method public final void switchToRows();
+    method public final void switchToVideo();
   }
 
   public class ErrorFragment extends android.support.v17.leanback.app.BrandedFragment {
diff --git a/fragment/java/android/support/v4/app/Fragment.java b/fragment/java/android/support/v4/app/Fragment.java
index 8741ff6..698db20 100644
--- a/fragment/java/android/support/v4/app/Fragment.java
+++ b/fragment/java/android/support/v4/app/Fragment.java
@@ -1398,8 +1398,7 @@
             if (!mCheckedForLoaderManager) {
                 mCheckedForLoaderManager = true;
                 mLoaderManager = mHost.getLoaderManager(mWho, mLoadersStarted, false);
-            }
-            if (mLoaderManager != null) {
+            } else if (mLoaderManager != null) {
                 mLoaderManager.doStart();
             }
         }
diff --git a/v17/leanback/generatev4.py b/v17/leanback/generatev4.py
index ae695e50..4bd9550 100755
--- a/v17/leanback/generatev4.py
+++ b/v17/leanback/generatev4.py
@@ -100,6 +100,7 @@
     line = re.sub(r'FragmentUtil.getContext\(mFragment\)', 'mFragment.getContext()', line);
     line = line.replace('VideoFragment', 'VideoSupportFragment')
     line = line.replace('DetailsFragment', 'DetailsSupportFragment')
+    line = line.replace('RowsFragment', 'RowsSupportFragment')
     line = line.replace('VideoSupportFragmentGlueHost'.format(w), 'VideoSupportFragmentGlueHost'.format(w))
     line = line.replace('android.app.Fragment', 'android.support.v4.app.Fragment')
     outfile.write(line)
diff --git a/v17/leanback/src/android/support/v17/leanback/app/DetailsBackgroundVideoHelper.java b/v17/leanback/src/android/support/v17/leanback/app/DetailsBackgroundVideoHelper.java
index 5e2980d..c372888 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/DetailsBackgroundVideoHelper.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/DetailsBackgroundVideoHelper.java
@@ -56,6 +56,7 @@
     private ValueAnimator mBackgroundAnimator;
     private Drawable mBackgroundDrawable;
     private PlaybackGlue mPlaybackGlue;
+    private boolean mBackgroundDrawableVisible;
 
     /**
      * Constructor to setup a Helper for controlling video playback in DetailsFragment.
@@ -75,6 +76,7 @@
         this.mPlaybackGlue = playbackGlue;
         this.mDetailsParallax = detailsParallax;
         this.mBackgroundDrawable = backgroundDrawable;
+        mBackgroundDrawableVisible = true;
         startParallax();
     }
 
@@ -97,6 +99,9 @@
                         }
                     }
                 });
+        // In case the VideoHelper is created after RecyclerView is created: perform initial
+        // parallax effect.
+        mDetailsParallax.updateValues();
     }
 
     void stopParallax() {
@@ -112,24 +117,44 @@
             return;
         }
         mCurrentState = state;
-        switch (state) {
+        applyState();
+    }
+
+    private void applyState() {
+        switch (mCurrentState) {
             case PLAY_VIDEO:
-                if (mPlaybackGlue.isReadyForPlayback()) {
-                    internalStartPlayback();
+                if (mPlaybackGlue != null) {
+                    if (mPlaybackGlue.isReadyForPlayback()) {
+                        internalStartPlayback();
+                    } else {
+                        mPlaybackGlue.setPlayerCallback(mControlStateCallback);
+                    }
                 } else {
-                    mPlaybackGlue.setPlayerCallback(new PlaybackControlStateCallback());
+                    crossFadeBackgroundToVideo(false);
                 }
                 break;
             case NO_VIDEO:
                 crossFadeBackgroundToVideo(false);
-                mPlaybackGlue.setPlayerCallback(null);
-                mPlaybackGlue.pause();
+                if (mPlaybackGlue != null) {
+                    mPlaybackGlue.setPlayerCallback(null);
+                    mPlaybackGlue.pause();
+                }
                 break;
         }
     }
 
+    void setPlaybackGlue(PlaybackGlue playbackGlue) {
+        if (mPlaybackGlue != null) {
+            mPlaybackGlue.setPlayerCallback(null);
+        }
+        mPlaybackGlue = playbackGlue;
+        applyState();
+    }
+
     private void internalStartPlayback() {
-        mPlaybackGlue.play();
+        if (mPlaybackGlue != null) {
+            mPlaybackGlue.play();
+        }
         mDetailsParallax.getRecyclerView().postDelayed(new Runnable() {
             @Override
             public void run() {
@@ -139,6 +164,11 @@
     }
 
     private void crossFadeBackgroundToVideo(final boolean crossFadeToVideo) {
+        final boolean newVisible = !crossFadeToVideo;
+        if (mBackgroundDrawableVisible == newVisible) {
+            return;
+        }
+        mBackgroundDrawableVisible = newVisible;
         if (mBackgroundAnimator != null) {
             mBackgroundAnimator.cancel();
             mBackgroundAnimator = null;
@@ -189,4 +219,6 @@
             internalStartPlayback();
         }
     }
+
+    PlaybackControlStateCallback mControlStateCallback = new PlaybackControlStateCallback();
 }
diff --git a/v17/leanback/src/android/support/v17/leanback/app/DetailsFragment.java b/v17/leanback/src/android/support/v17/leanback/app/DetailsFragment.java
index 694384c..7e54146 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/DetailsFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/DetailsFragment.java
@@ -77,6 +77,11 @@
  * {@link FullWidthDetailsOverviewRowPresenter}.
  * </li>
  * </p>
+ *
+ * <p>
+ * DetailsFragment can use {@link DetailsFragmentBackgroundController} to add a parallax drawable
+ * background and embedded video playing fragment.
+ * </p>
  */
 public class DetailsFragment extends BaseFragment {
     static final String TAG = "DetailsFragment";
@@ -723,7 +728,9 @@
                 if (mRowsFragment.getVerticalGridView() != null
                         && mRowsFragment.getVerticalGridView().hasFocus()) {
                     if (direction == View.FOCUS_UP) {
-                        if (mVideoFragment != null && mVideoFragment.getView() != null) {
+                        if (mDetailsBackgroundController != null
+                                && mDetailsBackgroundController.canNavigateToVideoFragment()
+                                && mVideoFragment != null && mVideoFragment.getView() != null) {
                             return mVideoFragment.getView();
                         } else if (getTitleView() != null && getTitleView().hasFocusable()) {
                             return getTitleView();
diff --git a/v17/leanback/src/android/support/v17/leanback/app/DetailsFragmentBackgroundController.java b/v17/leanback/src/android/support/v17/leanback/app/DetailsFragmentBackgroundController.java
index ef09ae6..625a196 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/DetailsFragmentBackgroundController.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/DetailsFragmentBackgroundController.java
@@ -107,14 +107,14 @@
  */
 public class DetailsFragmentBackgroundController {
 
-    private final DetailsFragment mFragment;
-    private DetailsParallaxDrawable mParallaxDrawable;
-    private int mParallaxDrawableMaxOffset;
-    private PlaybackGlue mPlaybackGlue;
-    private DetailsBackgroundVideoHelper mVideoHelper;
-    private Bitmap mCoverBitmap;
-    private int mSolidColor;
-    private boolean mCanUseHost = false;
+    final DetailsFragment mFragment;
+    DetailsParallaxDrawable mParallaxDrawable;
+    int mParallaxDrawableMaxOffset;
+    PlaybackGlue mPlaybackGlue;
+    DetailsBackgroundVideoHelper mVideoHelper;
+    Bitmap mCoverBitmap;
+    int mSolidColor;
+    boolean mCanUseHost = false;
 
     /**
      * Creates a DetailsFragmentBackgroundController for a DetailsFragment. Note that
@@ -209,9 +209,13 @@
     /**
      * Enable video playback and set proper {@link PlaybackGlueHost}. This method by default
      * creates a VideoFragment and VideoFragmentGlueHost to host the PlaybackGlue.
-     * This method must be called after calling details Fragment super.onCreate().
+     * This method must be called after calling details Fragment super.onCreate(). This method
+     * can be called multiple times to replace existing PlaybackGlue or calling
+     * setupVideoPlayback(null) to clear. Note a typical {@link PlaybackGlue} subclass releases
+     * resources in {@link PlaybackGlue#onDetachedFromHost()}, when the {@link PlaybackGlue}
+     * subclass is not doing that, it's app's responsibility to release the resources.
      *
-     * @param playbackGlue
+     * @param playbackGlue The new PlaybackGlue to set as background or null to clear existing one.
      * @see #onCreateVideoFragment()
      * @see #onCreateGlueHost().
      */
@@ -219,15 +223,62 @@
         if (mPlaybackGlue == playbackGlue) {
             return;
         }
+        if (mPlaybackGlue != null) {
+            mPlaybackGlue.setHost(null);
+        }
         mPlaybackGlue = playbackGlue;
-        mVideoHelper = new DetailsBackgroundVideoHelper(mPlaybackGlue,
-                mFragment.getParallax(), mParallaxDrawable.getCoverDrawable());
-        if (mCanUseHost) {
+        if (mVideoHelper == null && mPlaybackGlue != null) {
+            mVideoHelper = new DetailsBackgroundVideoHelper(mPlaybackGlue,
+                    mFragment.getParallax(), mParallaxDrawable.getCoverDrawable());
+        } else if (mVideoHelper != null) {
+            mVideoHelper.setPlaybackGlue(mPlaybackGlue);
+        }
+        if (mCanUseHost && mPlaybackGlue != null) {
             mPlaybackGlue.setHost(onCreateGlueHost());
         }
     }
 
     /**
+     * Returns current PlaybackGlue or null if not set or cleared.
+     *
+     * @return Current PlaybackGlue or null
+     */
+    public final PlaybackGlue getPlaybackGlue() {
+        return mPlaybackGlue;
+    }
+
+    /**
+     * Precondition allows user navigate to video fragment using DPAD. Default implementation
+     * returns true if PlaybackGlue is not null. Subclass may override, e.g. only allow navigation
+     * when {@link PlaybackGlue#isReadyForPlayback()} is true. Note this method does not block
+     * app calls {@link #switchToVideo}.
+     *
+     * @return True allow to navigate to video fragment.
+     */
+    public boolean canNavigateToVideoFragment() {
+        return mPlaybackGlue != null;
+    }
+
+    /**
+     * Switch to video fragment, note that this method is not affected by result of
+     * {@link #canNavigateToVideoFragment()}.
+     */
+    public final void switchToVideo() {
+        if (mFragment.mVideoFragment != null && mFragment.mVideoFragment.getView() != null) {
+            mFragment.mVideoFragment.getView().requestFocus();
+        }
+    }
+
+    /**
+     * Switch to rows fragment.
+     */
+    public final void switchToRows() {
+        if (mFragment.mRowsFragment != null && mFragment.mRowsFragment.getView() != null) {
+            mFragment.mRowsFragment.getView().requestFocus();
+        }
+    }
+
+    /**
      * When fragment is started and no running transition. First set host if not yet set, second
      * start playing if it was paused before.
      */
diff --git a/v17/leanback/src/android/support/v17/leanback/app/DetailsSupportFragment.java b/v17/leanback/src/android/support/v17/leanback/app/DetailsSupportFragment.java
index 033ad0b..511a90b 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/DetailsSupportFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/DetailsSupportFragment.java
@@ -80,6 +80,11 @@
  * {@link FullWidthDetailsOverviewRowPresenter}.
  * </li>
  * </p>
+ *
+ * <p>
+ * DetailsSupportFragment can use {@link DetailsSupportFragmentBackgroundController} to add a parallax drawable
+ * background and embedded video playing fragment.
+ * </p>
  */
 public class DetailsSupportFragment extends BaseSupportFragment {
     static final String TAG = "DetailsSupportFragment";
@@ -726,7 +731,9 @@
                 if (mRowsSupportFragment.getVerticalGridView() != null
                         && mRowsSupportFragment.getVerticalGridView().hasFocus()) {
                     if (direction == View.FOCUS_UP) {
-                        if (mVideoSupportFragment != null && mVideoSupportFragment.getView() != null) {
+                        if (mDetailsBackgroundController != null
+                                && mDetailsBackgroundController.canNavigateToVideoSupportFragment()
+                                && mVideoSupportFragment != null && mVideoSupportFragment.getView() != null) {
                             return mVideoSupportFragment.getView();
                         } else if (getTitleView() != null && getTitleView().hasFocusable()) {
                             return getTitleView();
diff --git a/v17/leanback/src/android/support/v17/leanback/app/DetailsSupportFragmentBackgroundController.java b/v17/leanback/src/android/support/v17/leanback/app/DetailsSupportFragmentBackgroundController.java
index 071a04a..6149625 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/DetailsSupportFragmentBackgroundController.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/DetailsSupportFragmentBackgroundController.java
@@ -110,14 +110,14 @@
  */
 public class DetailsSupportFragmentBackgroundController {
 
-    private final DetailsSupportFragment mFragment;
-    private DetailsParallaxDrawable mParallaxDrawable;
-    private int mParallaxDrawableMaxOffset;
-    private PlaybackGlue mPlaybackGlue;
-    private DetailsBackgroundVideoHelper mVideoHelper;
-    private Bitmap mCoverBitmap;
-    private int mSolidColor;
-    private boolean mCanUseHost = false;
+    final DetailsSupportFragment mFragment;
+    DetailsParallaxDrawable mParallaxDrawable;
+    int mParallaxDrawableMaxOffset;
+    PlaybackGlue mPlaybackGlue;
+    DetailsBackgroundVideoHelper mVideoHelper;
+    Bitmap mCoverBitmap;
+    int mSolidColor;
+    boolean mCanUseHost = false;
 
     /**
      * Creates a DetailsSupportFragmentBackgroundController for a DetailsSupportFragment. Note that
@@ -212,9 +212,13 @@
     /**
      * Enable video playback and set proper {@link PlaybackGlueHost}. This method by default
      * creates a VideoSupportFragment and VideoSupportFragmentGlueHost to host the PlaybackGlue.
-     * This method must be called after calling details Fragment super.onCreate().
+     * This method must be called after calling details Fragment super.onCreate(). This method
+     * can be called multiple times to replace existing PlaybackGlue or calling
+     * setupVideoPlayback(null) to clear. Note a typical {@link PlaybackGlue} subclass releases
+     * resources in {@link PlaybackGlue#onDetachedFromHost()}, when the {@link PlaybackGlue}
+     * subclass is not doing that, it's app's responsibility to release the resources.
      *
-     * @param playbackGlue
+     * @param playbackGlue The new PlaybackGlue to set as background or null to clear existing one.
      * @see #onCreateVideoSupportFragment()
      * @see #onCreateGlueHost().
      */
@@ -222,15 +226,62 @@
         if (mPlaybackGlue == playbackGlue) {
             return;
         }
+        if (mPlaybackGlue != null) {
+            mPlaybackGlue.setHost(null);
+        }
         mPlaybackGlue = playbackGlue;
-        mVideoHelper = new DetailsBackgroundVideoHelper(mPlaybackGlue,
-                mFragment.getParallax(), mParallaxDrawable.getCoverDrawable());
-        if (mCanUseHost) {
+        if (mVideoHelper == null && mPlaybackGlue != null) {
+            mVideoHelper = new DetailsBackgroundVideoHelper(mPlaybackGlue,
+                    mFragment.getParallax(), mParallaxDrawable.getCoverDrawable());
+        } else if (mVideoHelper != null) {
+            mVideoHelper.setPlaybackGlue(mPlaybackGlue);
+        }
+        if (mCanUseHost && mPlaybackGlue != null) {
             mPlaybackGlue.setHost(onCreateGlueHost());
         }
     }
 
     /**
+     * Returns current PlaybackGlue or null if not set or cleared.
+     *
+     * @return Current PlaybackGlue or null
+     */
+    public final PlaybackGlue getPlaybackGlue() {
+        return mPlaybackGlue;
+    }
+
+    /**
+     * Precondition allows user navigate to video fragment using DPAD. Default implementation
+     * returns true if PlaybackGlue is not null. Subclass may override, e.g. only allow navigation
+     * when {@link PlaybackGlue#isReadyForPlayback()} is true. Note this method does not block
+     * app calls {@link #switchToVideo}.
+     *
+     * @return True allow to navigate to video fragment.
+     */
+    public boolean canNavigateToVideoSupportFragment() {
+        return mPlaybackGlue != null;
+    }
+
+    /**
+     * Switch to video fragment, note that this method is not affected by result of
+     * {@link #canNavigateToVideoSupportFragment()}.
+     */
+    public final void switchToVideo() {
+        if (mFragment.mVideoSupportFragment != null && mFragment.mVideoSupportFragment.getView() != null) {
+            mFragment.mVideoSupportFragment.getView().requestFocus();
+        }
+    }
+
+    /**
+     * Switch to rows fragment.
+     */
+    public final void switchToRows() {
+        if (mFragment.mRowsSupportFragment != null && mFragment.mRowsSupportFragment.getView() != null) {
+            mFragment.mRowsSupportFragment.getView().requestFocus();
+        }
+    }
+
+    /**
      * When fragment is started and no running transition. First set host if not yet set, second
      * start playing if it was paused before.
      */
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/RecyclerViewParallax.java b/v17/leanback/src/android/support/v17/leanback/widget/RecyclerViewParallax.java
index bdcf044..7253d01 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/RecyclerViewParallax.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/RecyclerViewParallax.java
@@ -41,6 +41,14 @@
         }
     };
 
+    View.OnLayoutChangeListener mOnLayoutChangeListener = new View.OnLayoutChangeListener() {
+        @Override
+        public void onLayoutChange(View view, int l, int t, int r, int b,
+                int oldL, int oldT, int oldR, int oldB) {
+            updateValues();
+        }
+    };
+
     /**
      * Subclass of {@link Parallax.IntProperty}. Using this Property, users can track a
      * RecylerView child's position inside recyclerview. i.e.
@@ -211,6 +219,7 @@
         }
         if (mRecylerView != null) {
             mRecylerView.removeOnScrollListener(mOnScrollListener);
+            mRecylerView.removeOnLayoutChangeListener(mOnLayoutChangeListener);
         }
         mRecylerView = recyclerView;
         if (mRecylerView != null) {
@@ -218,6 +227,7 @@
                     .getProperties(mRecylerView.getContext(), null, 0, 0);
             mIsVertical = properties.orientation == RecyclerView.VERTICAL;
             mRecylerView.addOnScrollListener(mOnScrollListener);
+            mRecylerView.addOnLayoutChangeListener(mOnLayoutChangeListener);
         }
     }
 
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/app/DetailsFragmentTest.java b/v17/leanback/tests/java/android/support/v17/leanback/app/DetailsFragmentTest.java
index 4356459..c8db4bd 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/app/DetailsFragmentTest.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/app/DetailsFragmentTest.java
@@ -30,6 +30,7 @@
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
 import android.os.Bundle;
+import android.os.SystemClock;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.LargeTest;
 import android.support.v17.leanback.R;
@@ -57,6 +58,11 @@
 
     static final int PARALLAX_VERTICAL_OFFSET = -300;
 
+    static int getCoverDrawableAlpha(DetailsFragmentBackgroundController controller) {
+        return ((FitWidthBitmapDrawable) controller.mParallaxDrawable.getCoverDrawable())
+                .getAlpha();
+    }
+
     public static class DetailsFragmentParallax extends DetailsTestFragment {
 
         private DetailsParallaxDrawable mParallaxDrawable;
@@ -386,6 +392,14 @@
         navigateBetweenRowsAndVideoUsingDPADInternal(DetailsFragmentWithVideo2.class);
     }
 
+    public static class EmptyFragmentClass extends Fragment {
+        @Override
+        public void onStart() {
+            super.onStart();
+            getActivity().finish();
+        }
+    }
+
     private void fragmentOnStartWithVideoInternal(Class cls) throws Throwable {
         launchAndWaitActivity(cls,
                 new Options().uiVisibility(
@@ -427,7 +441,7 @@
                     public void run() {
                         Intent intent = new Intent(mActivity, SingleFragmentTestActivity.class);
                         intent.putExtra(SingleFragmentTestActivity.EXTRA_FRAGMENT_NAME,
-                                Fragment.class.getName());
+                                EmptyFragmentClass.class.getName());
                         mActivity.startActivity(intent);
                     }
                 }
@@ -435,17 +449,6 @@
         PollingCheck.waitFor(2000, new PollingCheck.PollingCheckCondition() {
             @Override
             public boolean canProceed() {
-                return !detailsFragment.isResumed();
-            }
-        });
-        // pop empty activity, have to wait 1000 before sending BACK key or the key will lose
-        // nowhere.
-        Thread.sleep(1000);
-        sendKeys(KeyEvent.KEYCODE_BACK);
-
-        PollingCheck.waitFor(2000, new PollingCheck.PollingCheckCondition() {
-            @Override
-            public boolean canProceed() {
                 return detailsFragment.isResumed();
             }
         });
@@ -509,4 +512,272 @@
         assertTrue(firstRow.hasFocus());
         assertEquals(originalFirstRowTop, firstRow.getTop());
     }
+
+    public static class DetailsFragmentWithNoVideo extends DetailsTestFragment {
+
+        final DetailsFragmentBackgroundController mDetailsBackground =
+                new DetailsFragmentBackgroundController(this);
+
+        public DetailsFragmentWithNoVideo() {
+            mTimeToLoadOverviewRow = mTimeToLoadRelatedRow = 100;
+        }
+
+        @Override
+        public void onCreate(Bundle savedInstanceState) {
+            super.onCreate(savedInstanceState);
+            mDetailsBackground.enableParallax();
+
+            setItem(new PhotoItem("Hello world", "Fake content goes here",
+                    android.support.v17.leanback.test.R.drawable.spiderman));
+        }
+
+        @Override
+        public void onStart() {
+            super.onStart();
+            Bitmap bitmap = BitmapFactory.decodeResource(getActivity().getResources(),
+                    android.support.v17.leanback.test.R.drawable.spiderman);
+            mDetailsBackground.setCoverBitmap(bitmap);
+        }
+
+        @Override
+        public void onStop() {
+            mDetailsBackground.setCoverBitmap(null);
+            super.onStop();
+        }
+    }
+
+    @Test
+    public void lateSetupVideo() {
+        launchAndWaitActivity(DetailsFragmentWithNoVideo.class, new Options().uiVisibility(
+                View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_FULLSCREEN), 0);
+        final DetailsFragmentWithNoVideo detailsFragment =
+                (DetailsFragmentWithNoVideo) mActivity.getTestFragment();
+
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                detailsFragment.setItem(new PhotoItem("Hello world", "Fake content goes here",
+                        android.support.v17.leanback.test.R.drawable.spiderman));
+            }
+        });
+
+        PollingCheck.waitFor(4000, new PollingCheck.PollingCheckCondition() {
+            @Override
+            public boolean canProceed() {
+                return detailsFragment.getRowsFragment().getVerticalGridView().getChildCount() > 0;
+            }
+        });
+        final View firstRow = detailsFragment.getRowsFragment().getVerticalGridView().getChildAt(0);
+        final int screenHeight = detailsFragment.getRowsFragment().getVerticalGridView()
+                .getHeight();
+
+        assertTrue(firstRow.hasFocus());
+        assertTrue(detailsFragment.isShowingTitle());
+        assertTrue(firstRow.getTop() > 0 && firstRow.getTop() < screenHeight);
+
+        sendKeys(KeyEvent.KEYCODE_DPAD_UP);
+        assertTrue(firstRow.hasFocus());
+
+        SystemClock.sleep(1000);
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(
+                new Runnable() {
+                    @Override
+                    public void run() {
+                        final MediaPlayerGlue glue = new MediaPlayerGlue(mActivity);
+                        detailsFragment.mDetailsBackgroundController.setupVideoPlayback(glue);
+                        glue.setMode(MediaPlayerGlue.REPEAT_ALL);
+                        glue.setArtist("A Googleer");
+                        glue.setTitle("Diving with Sharks");
+                        glue.setMediaSource(Uri.parse(
+                                "android.resource://android.support.v17.leanback.test/raw/video"));
+                    }
+                }
+        );
+
+        // after setup Video Playback the DPAD up will navigate to Video Fragment.
+        sendKeys(KeyEvent.KEYCODE_DPAD_UP);
+        assertTrue(detailsFragment.mVideoFragment.getView().hasFocus());
+        PollingCheck.waitFor(4000, new PollingCheck.PollingCheckCondition() {
+            @Override
+            public boolean canProceed() {
+                return ((MediaPlayerGlue) detailsFragment.mDetailsBackgroundController
+                        .getPlaybackGlue()).isMediaPlaying();
+            }
+        });
+        PollingCheck.waitFor(4000, new PollingCheck.PollingCheckCondition() {
+            @Override
+            public boolean canProceed() {
+                return 0 == getCoverDrawableAlpha(detailsFragment.mDetailsBackgroundController);
+            }
+        });
+
+        // wait a little bit to replace with new Glue
+        SystemClock.sleep(1000);
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(
+                new Runnable() {
+                    @Override
+                    public void run() {
+                        final MediaPlayerGlue glue2 = new MediaPlayerGlue(mActivity);
+                        detailsFragment.mDetailsBackgroundController.setupVideoPlayback(glue2);
+                        glue2.setMode(MediaPlayerGlue.REPEAT_ALL);
+                        glue2.setArtist("A Googleer");
+                        glue2.setTitle("Diving with Sharks");
+                        glue2.setMediaSource(Uri.parse(
+                                "android.resource://android.support.v17.leanback.test/raw/video"));
+                    }
+                }
+        );
+
+        // test switchToRows() and switchToVideo()
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(
+                new Runnable() {
+                    @Override
+                    public void run() {
+                        detailsFragment.mDetailsBackgroundController.switchToRows();
+                    }
+                }
+        );
+        assertTrue(detailsFragment.mRowsFragment.getView().hasFocus());
+        PollingCheck.waitFor(new PollingCheck.ViewStableOnScreen(firstRow));
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(
+                new Runnable() {
+                    @Override
+                    public void run() {
+                        detailsFragment.mDetailsBackgroundController.switchToVideo();
+                    }
+                }
+        );
+        assertTrue(detailsFragment.mVideoFragment.getView().hasFocus());
+        PollingCheck.waitFor(new PollingCheck.ViewStableOnScreen(firstRow));
+    }
+
+    @Test
+    public void clearVideo() {
+        launchAndWaitActivity(DetailsFragmentWithNoVideo.class, new Options().uiVisibility(
+                View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_FULLSCREEN), 0);
+        final DetailsFragmentWithNoVideo detailsFragment =
+                (DetailsFragmentWithNoVideo) mActivity.getTestFragment();
+
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                detailsFragment.setItem(new PhotoItem("Hello world", "Fake content goes here",
+                        android.support.v17.leanback.test.R.drawable.spiderman));
+            }
+        });
+
+        PollingCheck.waitFor(4000, new PollingCheck.PollingCheckCondition() {
+            @Override
+            public boolean canProceed() {
+                return detailsFragment.getRowsFragment().getVerticalGridView().getChildCount() > 0;
+            }
+        });
+        final View firstRow = detailsFragment.getRowsFragment().getVerticalGridView().getChildAt(0);
+        final int screenHeight = detailsFragment.getRowsFragment().getVerticalGridView()
+                .getHeight();
+
+        assertTrue(firstRow.hasFocus());
+        assertTrue(detailsFragment.isShowingTitle());
+        assertTrue(firstRow.getTop() > 0 && firstRow.getTop() < screenHeight);
+
+        SystemClock.sleep(1000);
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(
+                new Runnable() {
+                    @Override
+                    public void run() {
+                        final MediaPlayerGlue glue = new MediaPlayerGlue(mActivity);
+                        detailsFragment.mDetailsBackgroundController.setupVideoPlayback(glue);
+                        glue.setMode(MediaPlayerGlue.REPEAT_ALL);
+                        glue.setArtist("A Googleer");
+                        glue.setTitle("Diving with Sharks");
+                        glue.setMediaSource(Uri.parse(
+                                "android.resource://android.support.v17.leanback.test/raw/video"));
+                    }
+                }
+        );
+
+        PollingCheck.waitFor(4000, new PollingCheck.PollingCheckCondition() {
+            @Override
+            public boolean canProceed() {
+                return ((MediaPlayerGlue) detailsFragment.mDetailsBackgroundController
+                        .getPlaybackGlue()).isMediaPlaying();
+            }
+        });
+        PollingCheck.waitFor(4000, new PollingCheck.PollingCheckCondition() {
+            @Override
+            public boolean canProceed() {
+                return 0 == getCoverDrawableAlpha(detailsFragment.mDetailsBackgroundController);
+            }
+        });
+
+        // wait a little bit then clear glue
+        SystemClock.sleep(1000);
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(
+                new Runnable() {
+                    @Override
+                    public void run() {
+                        detailsFragment.mDetailsBackgroundController.setupVideoPlayback(null);
+                    }
+                }
+        );
+        // background should fade in upon clear playback
+        PollingCheck.waitFor(4000, new PollingCheck.PollingCheckCondition() {
+            @Override
+            public boolean canProceed() {
+                return 255 == getCoverDrawableAlpha(detailsFragment.mDetailsBackgroundController);
+            }
+        });
+    }
+
+    public static class DetailsFragmentWithNoItem extends DetailsTestFragment {
+
+        final DetailsFragmentBackgroundController mDetailsBackground =
+                new DetailsFragmentBackgroundController(this);
+
+        public DetailsFragmentWithNoItem() {
+            mTimeToLoadOverviewRow = mTimeToLoadRelatedRow = 100;
+        }
+
+        @Override
+        public void onCreate(Bundle savedInstanceState) {
+            super.onCreate(savedInstanceState);
+            mDetailsBackground.enableParallax();
+        }
+
+        @Override
+        public void onStart() {
+            super.onStart();
+            Bitmap bitmap = BitmapFactory.decodeResource(getActivity().getResources(),
+                    android.support.v17.leanback.test.R.drawable.spiderman);
+            mDetailsBackground.setCoverBitmap(bitmap);
+        }
+
+        @Override
+        public void onStop() {
+            mDetailsBackground.setCoverBitmap(null);
+            super.onStop();
+        }
+    }
+
+    @Test
+    public void noInitialItem() {
+        launchAndWaitActivity(DetailsFragmentWithNoItem.class, new Options().uiVisibility(
+                View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_FULLSCREEN), 0);
+        final DetailsFragmentWithNoItem detailsFragment =
+                (DetailsFragmentWithNoItem) mActivity.getTestFragment();
+
+        final int recyclerViewHeight = detailsFragment.getRowsFragment().getVerticalGridView()
+                .getHeight();
+        assertTrue(recyclerViewHeight > 0);
+
+        assertEquals(255, getCoverDrawableAlpha(detailsFragment.mDetailsBackgroundController));
+        assertEquals(255, detailsFragment.mDetailsBackgroundController.mParallaxDrawable
+                .getAlpha());
+        Drawable coverDrawable = detailsFragment.mDetailsBackgroundController.getCoverDrawable();
+        assertEquals(0, coverDrawable.getBounds().top);
+        assertEquals(recyclerViewHeight, coverDrawable.getBounds().bottom);
+        Drawable bottomDrawable = detailsFragment.mDetailsBackgroundController.getBottomDrawable();
+        assertEquals(recyclerViewHeight, bottomDrawable.getBounds().top);
+        assertEquals(recyclerViewHeight, bottomDrawable.getBounds().bottom);
+    }
 }
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/app/DetailsSupportFragmentTest.java b/v17/leanback/tests/java/android/support/v17/leanback/app/DetailsSupportFragmentTest.java
index f90eb1b..03277bd 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/app/DetailsSupportFragmentTest.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/app/DetailsSupportFragmentTest.java
@@ -33,6 +33,7 @@
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
 import android.os.Bundle;
+import android.os.SystemClock;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.LargeTest;
 import android.support.v17.leanback.R;
@@ -60,6 +61,11 @@
 
     static final int PARALLAX_VERTICAL_OFFSET = -300;
 
+    static int getCoverDrawableAlpha(DetailsSupportFragmentBackgroundController controller) {
+        return ((FitWidthBitmapDrawable) controller.mParallaxDrawable.getCoverDrawable())
+                .getAlpha();
+    }
+
     public static class DetailsSupportFragmentParallax extends DetailsTestSupportFragment {
 
         private DetailsParallaxDrawable mParallaxDrawable;
@@ -389,6 +395,14 @@
         navigateBetweenRowsAndVideoUsingDPADInternal(DetailsSupportFragmentWithVideo2.class);
     }
 
+    public static class EmptyFragmentClass extends Fragment {
+        @Override
+        public void onStart() {
+            super.onStart();
+            getActivity().finish();
+        }
+    }
+
     private void fragmentOnStartWithVideoInternal(Class cls) throws Throwable {
         launchAndWaitActivity(cls,
                 new Options().uiVisibility(
@@ -430,7 +444,7 @@
                     public void run() {
                         Intent intent = new Intent(mActivity, SingleSupportFragmentTestActivity.class);
                         intent.putExtra(SingleSupportFragmentTestActivity.EXTRA_FRAGMENT_NAME,
-                                Fragment.class.getName());
+                                EmptyFragmentClass.class.getName());
                         mActivity.startActivity(intent);
                     }
                 }
@@ -438,17 +452,6 @@
         PollingCheck.waitFor(2000, new PollingCheck.PollingCheckCondition() {
             @Override
             public boolean canProceed() {
-                return !detailsFragment.isResumed();
-            }
-        });
-        // pop empty activity, have to wait 1000 before sending BACK key or the key will lose
-        // nowhere.
-        Thread.sleep(1000);
-        sendKeys(KeyEvent.KEYCODE_BACK);
-
-        PollingCheck.waitFor(2000, new PollingCheck.PollingCheckCondition() {
-            @Override
-            public boolean canProceed() {
                 return detailsFragment.isResumed();
             }
         });
@@ -512,4 +515,272 @@
         assertTrue(firstRow.hasFocus());
         assertEquals(originalFirstRowTop, firstRow.getTop());
     }
+
+    public static class DetailsSupportFragmentWithNoVideo extends DetailsTestSupportFragment {
+
+        final DetailsSupportFragmentBackgroundController mDetailsBackground =
+                new DetailsSupportFragmentBackgroundController(this);
+
+        public DetailsSupportFragmentWithNoVideo() {
+            mTimeToLoadOverviewRow = mTimeToLoadRelatedRow = 100;
+        }
+
+        @Override
+        public void onCreate(Bundle savedInstanceState) {
+            super.onCreate(savedInstanceState);
+            mDetailsBackground.enableParallax();
+
+            setItem(new PhotoItem("Hello world", "Fake content goes here",
+                    android.support.v17.leanback.test.R.drawable.spiderman));
+        }
+
+        @Override
+        public void onStart() {
+            super.onStart();
+            Bitmap bitmap = BitmapFactory.decodeResource(getActivity().getResources(),
+                    android.support.v17.leanback.test.R.drawable.spiderman);
+            mDetailsBackground.setCoverBitmap(bitmap);
+        }
+
+        @Override
+        public void onStop() {
+            mDetailsBackground.setCoverBitmap(null);
+            super.onStop();
+        }
+    }
+
+    @Test
+    public void lateSetupVideo() {
+        launchAndWaitActivity(DetailsSupportFragmentWithNoVideo.class, new Options().uiVisibility(
+                View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_FULLSCREEN), 0);
+        final DetailsSupportFragmentWithNoVideo detailsFragment =
+                (DetailsSupportFragmentWithNoVideo) mActivity.getTestFragment();
+
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                detailsFragment.setItem(new PhotoItem("Hello world", "Fake content goes here",
+                        android.support.v17.leanback.test.R.drawable.spiderman));
+            }
+        });
+
+        PollingCheck.waitFor(4000, new PollingCheck.PollingCheckCondition() {
+            @Override
+            public boolean canProceed() {
+                return detailsFragment.getRowsSupportFragment().getVerticalGridView().getChildCount() > 0;
+            }
+        });
+        final View firstRow = detailsFragment.getRowsSupportFragment().getVerticalGridView().getChildAt(0);
+        final int screenHeight = detailsFragment.getRowsSupportFragment().getVerticalGridView()
+                .getHeight();
+
+        assertTrue(firstRow.hasFocus());
+        assertTrue(detailsFragment.isShowingTitle());
+        assertTrue(firstRow.getTop() > 0 && firstRow.getTop() < screenHeight);
+
+        sendKeys(KeyEvent.KEYCODE_DPAD_UP);
+        assertTrue(firstRow.hasFocus());
+
+        SystemClock.sleep(1000);
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(
+                new Runnable() {
+                    @Override
+                    public void run() {
+                        final MediaPlayerGlue glue = new MediaPlayerGlue(mActivity);
+                        detailsFragment.mDetailsBackgroundController.setupVideoPlayback(glue);
+                        glue.setMode(MediaPlayerGlue.REPEAT_ALL);
+                        glue.setArtist("A Googleer");
+                        glue.setTitle("Diving with Sharks");
+                        glue.setMediaSource(Uri.parse(
+                                "android.resource://android.support.v17.leanback.test/raw/video"));
+                    }
+                }
+        );
+
+        // after setup Video Playback the DPAD up will navigate to Video Fragment.
+        sendKeys(KeyEvent.KEYCODE_DPAD_UP);
+        assertTrue(detailsFragment.mVideoSupportFragment.getView().hasFocus());
+        PollingCheck.waitFor(4000, new PollingCheck.PollingCheckCondition() {
+            @Override
+            public boolean canProceed() {
+                return ((MediaPlayerGlue) detailsFragment.mDetailsBackgroundController
+                        .getPlaybackGlue()).isMediaPlaying();
+            }
+        });
+        PollingCheck.waitFor(4000, new PollingCheck.PollingCheckCondition() {
+            @Override
+            public boolean canProceed() {
+                return 0 == getCoverDrawableAlpha(detailsFragment.mDetailsBackgroundController);
+            }
+        });
+
+        // wait a little bit to replace with new Glue
+        SystemClock.sleep(1000);
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(
+                new Runnable() {
+                    @Override
+                    public void run() {
+                        final MediaPlayerGlue glue2 = new MediaPlayerGlue(mActivity);
+                        detailsFragment.mDetailsBackgroundController.setupVideoPlayback(glue2);
+                        glue2.setMode(MediaPlayerGlue.REPEAT_ALL);
+                        glue2.setArtist("A Googleer");
+                        glue2.setTitle("Diving with Sharks");
+                        glue2.setMediaSource(Uri.parse(
+                                "android.resource://android.support.v17.leanback.test/raw/video"));
+                    }
+                }
+        );
+
+        // test switchToRows() and switchToVideo()
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(
+                new Runnable() {
+                    @Override
+                    public void run() {
+                        detailsFragment.mDetailsBackgroundController.switchToRows();
+                    }
+                }
+        );
+        assertTrue(detailsFragment.mRowsSupportFragment.getView().hasFocus());
+        PollingCheck.waitFor(new PollingCheck.ViewStableOnScreen(firstRow));
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(
+                new Runnable() {
+                    @Override
+                    public void run() {
+                        detailsFragment.mDetailsBackgroundController.switchToVideo();
+                    }
+                }
+        );
+        assertTrue(detailsFragment.mVideoSupportFragment.getView().hasFocus());
+        PollingCheck.waitFor(new PollingCheck.ViewStableOnScreen(firstRow));
+    }
+
+    @Test
+    public void clearVideo() {
+        launchAndWaitActivity(DetailsSupportFragmentWithNoVideo.class, new Options().uiVisibility(
+                View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_FULLSCREEN), 0);
+        final DetailsSupportFragmentWithNoVideo detailsFragment =
+                (DetailsSupportFragmentWithNoVideo) mActivity.getTestFragment();
+
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                detailsFragment.setItem(new PhotoItem("Hello world", "Fake content goes here",
+                        android.support.v17.leanback.test.R.drawable.spiderman));
+            }
+        });
+
+        PollingCheck.waitFor(4000, new PollingCheck.PollingCheckCondition() {
+            @Override
+            public boolean canProceed() {
+                return detailsFragment.getRowsSupportFragment().getVerticalGridView().getChildCount() > 0;
+            }
+        });
+        final View firstRow = detailsFragment.getRowsSupportFragment().getVerticalGridView().getChildAt(0);
+        final int screenHeight = detailsFragment.getRowsSupportFragment().getVerticalGridView()
+                .getHeight();
+
+        assertTrue(firstRow.hasFocus());
+        assertTrue(detailsFragment.isShowingTitle());
+        assertTrue(firstRow.getTop() > 0 && firstRow.getTop() < screenHeight);
+
+        SystemClock.sleep(1000);
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(
+                new Runnable() {
+                    @Override
+                    public void run() {
+                        final MediaPlayerGlue glue = new MediaPlayerGlue(mActivity);
+                        detailsFragment.mDetailsBackgroundController.setupVideoPlayback(glue);
+                        glue.setMode(MediaPlayerGlue.REPEAT_ALL);
+                        glue.setArtist("A Googleer");
+                        glue.setTitle("Diving with Sharks");
+                        glue.setMediaSource(Uri.parse(
+                                "android.resource://android.support.v17.leanback.test/raw/video"));
+                    }
+                }
+        );
+
+        PollingCheck.waitFor(4000, new PollingCheck.PollingCheckCondition() {
+            @Override
+            public boolean canProceed() {
+                return ((MediaPlayerGlue) detailsFragment.mDetailsBackgroundController
+                        .getPlaybackGlue()).isMediaPlaying();
+            }
+        });
+        PollingCheck.waitFor(4000, new PollingCheck.PollingCheckCondition() {
+            @Override
+            public boolean canProceed() {
+                return 0 == getCoverDrawableAlpha(detailsFragment.mDetailsBackgroundController);
+            }
+        });
+
+        // wait a little bit then clear glue
+        SystemClock.sleep(1000);
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(
+                new Runnable() {
+                    @Override
+                    public void run() {
+                        detailsFragment.mDetailsBackgroundController.setupVideoPlayback(null);
+                    }
+                }
+        );
+        // background should fade in upon clear playback
+        PollingCheck.waitFor(4000, new PollingCheck.PollingCheckCondition() {
+            @Override
+            public boolean canProceed() {
+                return 255 == getCoverDrawableAlpha(detailsFragment.mDetailsBackgroundController);
+            }
+        });
+    }
+
+    public static class DetailsSupportFragmentWithNoItem extends DetailsTestSupportFragment {
+
+        final DetailsSupportFragmentBackgroundController mDetailsBackground =
+                new DetailsSupportFragmentBackgroundController(this);
+
+        public DetailsSupportFragmentWithNoItem() {
+            mTimeToLoadOverviewRow = mTimeToLoadRelatedRow = 100;
+        }
+
+        @Override
+        public void onCreate(Bundle savedInstanceState) {
+            super.onCreate(savedInstanceState);
+            mDetailsBackground.enableParallax();
+        }
+
+        @Override
+        public void onStart() {
+            super.onStart();
+            Bitmap bitmap = BitmapFactory.decodeResource(getActivity().getResources(),
+                    android.support.v17.leanback.test.R.drawable.spiderman);
+            mDetailsBackground.setCoverBitmap(bitmap);
+        }
+
+        @Override
+        public void onStop() {
+            mDetailsBackground.setCoverBitmap(null);
+            super.onStop();
+        }
+    }
+
+    @Test
+    public void noInitialItem() {
+        launchAndWaitActivity(DetailsSupportFragmentWithNoItem.class, new Options().uiVisibility(
+                View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_FULLSCREEN), 0);
+        final DetailsSupportFragmentWithNoItem detailsFragment =
+                (DetailsSupportFragmentWithNoItem) mActivity.getTestFragment();
+
+        final int recyclerViewHeight = detailsFragment.getRowsSupportFragment().getVerticalGridView()
+                .getHeight();
+        assertTrue(recyclerViewHeight > 0);
+
+        assertEquals(255, getCoverDrawableAlpha(detailsFragment.mDetailsBackgroundController));
+        assertEquals(255, detailsFragment.mDetailsBackgroundController.mParallaxDrawable
+                .getAlpha());
+        Drawable coverDrawable = detailsFragment.mDetailsBackgroundController.getCoverDrawable();
+        assertEquals(0, coverDrawable.getBounds().top);
+        assertEquals(recyclerViewHeight, coverDrawable.getBounds().bottom);
+        Drawable bottomDrawable = detailsFragment.mDetailsBackgroundController.getBottomDrawable();
+        assertEquals(recyclerViewHeight, bottomDrawable.getBounds().top);
+        assertEquals(recyclerViewHeight, bottomDrawable.getBounds().bottom);
+    }
 }