Fixed playback row callback not notified in updateRowMetaData
am: 8f2df00092

Change-Id: Iaf95186605ec3af1291be0b786acf3c3ef463d29
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackControlHelper.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackControlHelper.java
index df6995e..a6752eb 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackControlHelper.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackControlHelper.java
@@ -55,6 +55,9 @@
     private PlaybackControlsRow.PictureInPictureAction mPipAction;
 
     private Handler mHandler = new Handler();
+    // simulating whether the media is yet prepared and ready to play
+    private boolean mInitialized = true;
+
     private final Runnable mUpdateProgressRunnable = new Runnable() {
         @Override
         public void run() {
@@ -159,7 +162,7 @@
 
     @Override
     public boolean hasValidMedia() {
-        return true;
+        return mInitialized;
     }
 
     @Override
@@ -179,7 +182,7 @@
 
     @Override
     public int getMediaDuration() {
-        return FAUX_DURATION;
+        return mInitialized ? FAUX_DURATION : 0;
     }
 
     @Override
@@ -280,4 +283,16 @@
             mUpdateProgressRunnable.run();
         }
     }
+
+    public boolean isInitialized() {
+        return mInitialized;
+    }
+
+    public void setInitialized(boolean initialized) {
+        if (mInitialized != initialized) {
+            mInitialized = initialized;
+            onMetadataChanged();
+            onStateChanged();
+        }
+    }
 };
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackControlSupportHelper.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackControlSupportHelper.java
index e7afb27..0425e60 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackControlSupportHelper.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackControlSupportHelper.java
@@ -58,6 +58,9 @@
     private PlaybackControlsRow.PictureInPictureAction mPipAction;
 
     private Handler mHandler = new Handler();
+    // simulating whether the media is yet prepared and ready to play
+    private boolean mInitialized = true;
+
     private final Runnable mUpdateProgressRunnable = new Runnable() {
         @Override
         public void run() {
@@ -162,7 +165,7 @@
 
     @Override
     public boolean hasValidMedia() {
-        return true;
+        return mInitialized;
     }
 
     @Override
@@ -182,7 +185,7 @@
 
     @Override
     public int getMediaDuration() {
-        return FAUX_DURATION;
+        return mInitialized ? FAUX_DURATION : 0;
     }
 
     @Override
@@ -283,4 +286,16 @@
             mUpdateProgressRunnable.run();
         }
     }
+
+    public boolean isInitialized() {
+        return mInitialized;
+    }
+
+    public void setInitialized(boolean initialized) {
+        if (mInitialized != initialized) {
+            mInitialized = initialized;
+            onMetadataChanged();
+            onStateChanged();
+        }
+    }
 };
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackOverlayFragment.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackOverlayFragment.java
index 1531d14..bca057f 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackOverlayFragment.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackOverlayFragment.java
@@ -15,6 +15,7 @@
 
 import android.content.Context;
 import android.os.Bundle;
+import android.os.Handler;
 import android.support.v17.leanback.widget.Action;
 import android.support.v17.leanback.widget.ArrayObjectAdapter;
 import android.support.v17.leanback.widget.HeaderItem;
@@ -56,6 +57,11 @@
     private PlaybackControlHelper mGlue;
     private PlaybackControlsRowPresenter mPlaybackControlsRowPresenter;
     private ListRowPresenter mListRowPresenter;
+    final Handler mHandler = new Handler();
+
+    // Artificial delay to simulate a media being prepared. The onRowChanged callback should be
+    // called and the playback row UI should be updated after this delay.
+    private static final int MEDIA_PREPARATION_DELAY = 500;
 
     private OnItemViewClickedListener mOnItemViewClickedListener = new OnItemViewClickedListener() {
         @Override
@@ -124,6 +130,13 @@
             }
         };
 
+        mGlue.setInitialized(false);
+        mHandler.postDelayed(new Runnable() {
+            @Override
+            public void run() {
+                mGlue.setInitialized(true);
+            }
+        }, MEDIA_PREPARATION_DELAY);
         mGlue.setOnItemViewClickedListener(mOnItemViewClickedListener);
 
         mPlaybackControlsRowPresenter = mGlue.createControlsRowAndPresenter();
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackOverlaySupportFragment.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackOverlaySupportFragment.java
index 7a33493..f51513c 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackOverlaySupportFragment.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackOverlaySupportFragment.java
@@ -18,6 +18,7 @@
 
 import android.content.Context;
 import android.os.Bundle;
+import android.os.Handler;
 import android.support.v17.leanback.widget.Action;
 import android.support.v17.leanback.widget.ArrayObjectAdapter;
 import android.support.v17.leanback.widget.HeaderItem;
@@ -59,6 +60,11 @@
     private PlaybackControlSupportHelper mGlue;
     private PlaybackControlsRowPresenter mPlaybackControlsRowPresenter;
     private ListRowPresenter mListRowPresenter;
+    final Handler mHandler = new Handler();
+
+    // Artificial delay to simulate a media being prepared. The onRowChanged callback should be
+    // called and the playback row UI should be updated after this delay.
+    private static final int MEDIA_PREPARATION_DELAY = 500;
 
     private OnItemViewClickedListener mOnItemViewClickedListener = new OnItemViewClickedListener() {
         @Override
@@ -127,6 +133,14 @@
             }
         };
 
+        mGlue.setInitialized(false);
+        mHandler.postDelayed(new Runnable() {
+            @Override
+            public void run() {
+                mGlue.setInitialized(true);
+            }
+        }, MEDIA_PREPARATION_DELAY);
+
         mGlue.setOnItemViewClickedListener(mOnItemViewClickedListener);
 
         mPlaybackControlsRowPresenter = mGlue.createControlsRowAndPresenter();
diff --git a/v17/leanback/src/android/support/v17/leanback/app/PlaybackControlGlue.java b/v17/leanback/src/android/support/v17/leanback/app/PlaybackControlGlue.java
index b16f432..190ce22 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/PlaybackControlGlue.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/PlaybackControlGlue.java
@@ -211,9 +211,6 @@
      * containing this row should be notified.
      */
     protected void onRowChanged(PlaybackControlsRow row) {
-        if (getHost() != null) {
-            getHost().notifyPlaybackRowChanged();
-        }
     }
 
     /**
@@ -330,5 +327,10 @@
         public void fadeOut() {
             mFragment.fadeOut();
         }
+
+        @Override
+        public void notifyPlaybackRowChanged() {
+            mGlue.onRowChanged(mGlue.getControlsRow());
+        }
     }
 }
diff --git a/v17/leanback/src/android/support/v17/leanback/app/PlaybackControlSupportGlue.java b/v17/leanback/src/android/support/v17/leanback/app/PlaybackControlSupportGlue.java
index 55ce89e..b3d19ae 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/PlaybackControlSupportGlue.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/PlaybackControlSupportGlue.java
@@ -193,5 +193,10 @@
         public void fadeOut() {
             mFragment.fadeOut();
         }
+
+        @Override
+        public void notifyPlaybackRowChanged() {
+            mGlue.onRowChanged(mGlue.getControlsRow());
+        }
     }
 }
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/app/PlaybackControlGlueTest.java b/v17/leanback/tests/java/android/support/v17/leanback/app/PlaybackControlGlueTest.java
index f26c60c..326d2be 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/app/PlaybackControlGlueTest.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/app/PlaybackControlGlueTest.java
@@ -50,6 +50,8 @@
 
     static class PlayControlGlueImpl extends PlaybackControlGlue {
         int mSpeedId = PLAYBACK_SPEED_PAUSED;
+        // number of times onRowChanged callback is called
+        int mOnRowChangedCallCount = 0;
 
         PlayControlGlueImpl(Context context, int[] seekSpeeds) {
             super(context, seekSpeeds);
@@ -59,6 +61,11 @@
             super(context, ffSpeeds, rwSpeeds);
         }
 
+        PlayControlGlueImpl(Context context, PlaybackOverlayFragment fragment,
+                                   int[] seekSpeeds) {
+            super(context, fragment, seekSpeeds);
+        }
+
         @Override
         public boolean hasValidMedia() {
             return true;
@@ -124,6 +131,16 @@
 
         @Override
         protected void onRowChanged(PlaybackControlsRow row) {
+            mOnRowChangedCallCount++;
+        }
+
+        public void notifyMetaDataChanged() {
+            onMetadataChanged();
+            onStateChanged();
+        }
+
+        public int getOnRowChangedCallCount() {
+            return mOnRowChangedCallCount;
         }
     }
 
@@ -557,4 +574,32 @@
         assertEquals(PlaybackControlGlue.PLAYBACK_SPEED_NORMAL, glue.getCurrentSpeedId());
     }
 
+    @Test
+    public void testOnRowChangedCallback() throws Exception {
+        final PlaybackOverlayFragment[] fragmentResult = new
+                PlaybackOverlayFragment[1];
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                fragmentResult[0] = new PlaybackOverlayFragment();
+            }
+        });
+        PlaybackOverlayFragment fragment = fragmentResult[0];
+        PlayControlGlueImpl playbackGlue = new PlayControlGlueImpl(context, fragment,
+                new int[]{
+                        PlaybackControlGlue.PLAYBACK_SPEED_FAST_L0,
+                        PlaybackControlGlue.PLAYBACK_SPEED_FAST_L1,
+                        PlaybackControlGlue.PLAYBACK_SPEED_FAST_L2
+                });
+
+        // before any controls row is created the count is zero
+        assertEquals(playbackGlue.getOnRowChangedCallCount(), 0);
+        playbackGlue.createControlsRowAndPresenter();
+        // after a controls row is created, onRowChanged() call back is called once
+        assertEquals(playbackGlue.getOnRowChangedCallCount(), 1);
+        playbackGlue.notifyMetaDataChanged();
+        // onMetaDataChanged() calls updateRowMetadata which ends up calling
+        // notifyPlaybackRowChanged on the old host and finally onRowChanged on the glue.
+        assertEquals(playbackGlue.getOnRowChangedCallCount(), 2);
+    }
 }
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/app/PlaybackControlSupportGlueTest.java b/v17/leanback/tests/java/android/support/v17/leanback/app/PlaybackControlSupportGlueTest.java
index 211b42c..748a39f 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/app/PlaybackControlSupportGlueTest.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/app/PlaybackControlSupportGlueTest.java
@@ -51,8 +51,10 @@
 public class PlaybackControlSupportGlueTest {
 
 
-    static class PlayControlGlueImpl extends PlaybackControlSupportGlue {
+    public  static class PlayControlGlueImpl extends PlaybackControlSupportGlue {
         int mSpeedId = PLAYBACK_SPEED_PAUSED;
+        // number of times onRowChanged callback is called
+        int mOnRowChangedCallCount = 0;
 
         PlayControlGlueImpl(Context context, int[] seekSpeeds) {
             super(context, seekSpeeds);
@@ -62,6 +64,11 @@
             super(context, ffSpeeds, rwSpeeds);
         }
 
+        PlayControlGlueImpl(Context context, PlaybackOverlaySupportFragment fragment,
+                int[] seekSpeeds) {
+            super(context, fragment, seekSpeeds);
+        }
+
         @Override
         public boolean hasValidMedia() {
             return true;
@@ -127,6 +134,16 @@
 
         @Override
         protected void onRowChanged(PlaybackControlsRow row) {
+            mOnRowChangedCallCount++;
+        }
+
+        public void notifyMetaDataChanged() {
+            onMetadataChanged();
+            onStateChanged();
+        }
+
+        public int getOnRowChangedCallCount() {
+            return mOnRowChangedCallCount;
         }
     }
 
@@ -560,4 +577,33 @@
         assertEquals(PlaybackControlSupportGlue.PLAYBACK_SPEED_NORMAL, glue.getCurrentSpeedId());
     }
 
+    @Test
+    public void testOnRowChangedCallback() throws Exception {
+        final PlaybackOverlaySupportFragment[] fragmentResult = new
+                PlaybackOverlaySupportFragment[1];
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                fragmentResult[0] = new PlaybackOverlaySupportFragment();
+            }
+        });
+        PlaybackOverlaySupportFragment fragment = fragmentResult[0];
+        PlayControlGlueImpl playbackGlue = new PlayControlGlueImpl(context, fragment,
+                new int[]{
+                        PlaybackControlSupportGlue.PLAYBACK_SPEED_FAST_L0,
+                        PlaybackControlSupportGlue.PLAYBACK_SPEED_FAST_L1,
+                        PlaybackControlSupportGlue.PLAYBACK_SPEED_FAST_L2
+                });
+
+        // before any controls row is created the count is zero
+        assertEquals(playbackGlue.getOnRowChangedCallCount(), 0);
+        playbackGlue.createControlsRowAndPresenter();
+        // after a controls row is created, onRowChanged() call back is called once
+        assertEquals(playbackGlue.getOnRowChangedCallCount(), 1);
+        playbackGlue.notifyMetaDataChanged();
+        // onMetaDataChanged() calls updateRowMetadata which ends up calling
+        // notifyPlaybackRowChanged on the old host and finally onRowChanged on the glue.
+        assertEquals(playbackGlue.getOnRowChangedCallCount(), 2);
+    }
+
 }