Fix PlaybackOverlayFragment sample not work.
am: ef05d5494f

Change-Id: Ifc4003000f810b1726ae5cffc92d548d13b2f9e4
diff --git a/samples/SupportLeanbackDemos/AndroidManifest.xml b/samples/SupportLeanbackDemos/AndroidManifest.xml
index e1acf45..1dba568 100644
--- a/samples/SupportLeanbackDemos/AndroidManifest.xml
+++ b/samples/SupportLeanbackDemos/AndroidManifest.xml
@@ -59,6 +59,22 @@
             android:theme="@style/Theme.Example.Leanback.Rows"
             android:exported="true" />
 
+        <activity android:name="PlaybackActivity"
+            android:configChanges=
+                "screenSize|smallestScreenSize|screenLayout|orientation"
+            android:resizeableActivity="true"
+            android:supportsPictureInPicture="true"
+            android:launchMode="singleTask"
+            android:exported="true" />
+
+        <activity android:name="PlaybackSupportActivity"
+            android:configChanges=
+                "screenSize|smallestScreenSize|screenLayout|orientation"
+            android:resizeableActivity="true"
+            android:supportsPictureInPicture="true"
+            android:launchMode="singleTask"
+            android:exported="true" />
+
         <activity android:name="PlaybackOverlayActivity"
             android:configChanges=
                 "screenSize|smallestScreenSize|screenLayout|orientation"
diff --git a/samples/SupportLeanbackDemos/generatev4.py b/samples/SupportLeanbackDemos/generatev4.py
index efaf0b4..d4b3f22 100755
--- a/samples/SupportLeanbackDemos/generatev4.py
+++ b/samples/SupportLeanbackDemos/generatev4.py
@@ -300,16 +300,58 @@
 file.close()
 outfile.close()
 
+file = open('src/com/example/android/leanback/PlaybackFragment.java', 'r')
+outfile = open('src/com/example/android/leanback/PlaybackSupportFragment.java', 'w')
+write_java_head(outfile, "PlaybackFragment")
+for line in file:
+    line = line.replace('PlaybackFragment', 'PlaybackSupportFragment')
+    line = line.replace('PlaybackActivity', 'PlaybackSupportActivity')
+    outfile.write(line)
+file.close()
+outfile.close()
+
+file = open('src/com/example/android/leanback/PlaybackActivity.java', 'r')
+outfile = open('src/com/example/android/leanback/PlaybackSupportActivity.java', 'w')
+write_java_head(outfile, "PlaybackActivity")
+for line in file:
+    line = line.replace('PlaybackActivity', 'PlaybackSupportActivity')
+    line = line.replace('extends Activity', 'extends FragmentActivity')
+    line = line.replace('R.layout.playback_activity', 'R.layout.playback_activity_support')
+    line = line.replace('android.app.Activity', 'android.support.v4.app.FragmentActivity')
+    outfile.write(line)
+file.close()
+outfile.close()
+
+file = open('res/layout/playback_activity.xml', 'r')
+outfile = open('res/layout/playback_activity_support.xml', 'w')
+for line in file:
+    line = replace_xml_head(line, "playback_controls")
+    line = line.replace('com.example.android.leanback.PlaybackFragment', 'com.example.android.leanback.PlaybackSupportFragment')
+    outfile.write(line)
+file.close()
+outfile.close()
+
+
 
 file = open('src/com/example/android/leanback/PlaybackOverlayFragment.java', 'r')
 outfile = open('src/com/example/android/leanback/PlaybackOverlaySupportFragment.java', 'w')
 write_java_head(outfile, "PlaybackOverlayFragment")
 for line in file:
     line = line.replace('PlaybackOverlayFragment', 'PlaybackOverlaySupportFragment')
+    line = line.replace('PlaybackControlHelper', 'PlaybackControlSupportHelper')
     line = line.replace('PlaybackOverlayActivity', 'PlaybackOverlaySupportActivity')
-    line = line.replace('PlaybackFragmentGlueHost', 'PlaybackSupportFragmentGlueHost')
-    line = line.replace('VideoFragment', 'VideoSupportFragment')
-    line = line.replace('PlaybackFragment', 'PlaybackSupportFragment')
+    outfile.write(line)
+file.close()
+outfile.close()
+
+
+file = open('src/com/example/android/leanback/PlaybackControlHelper.java', 'r')
+outfile = open('src/com/example/android/leanback/PlaybackControlSupportHelper.java', 'w')
+write_java_head(outfile, "PlaybackControlHelper")
+for line in file:
+    line = line.replace('PlaybackControlHelper', 'PlaybackControlSupportHelper')
+    line = line.replace('PlaybackControlGlue', 'PlaybackControlSupportGlue')
+    line = line.replace('PlaybackOverlayFragment', 'PlaybackOverlaySupportFragment')
     outfile.write(line)
 file.close()
 outfile.close()
diff --git a/samples/SupportLeanbackDemos/res/layout/playback_activity.xml b/samples/SupportLeanbackDemos/res/layout/playback_activity.xml
new file mode 100644
index 0000000..91754ff
--- /dev/null
+++ b/samples/SupportLeanbackDemos/res/layout/playback_activity.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2014 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.
+-->
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <fragment
+        android:id="@+id/playback_controls_fragment"
+        android:name="com.example.android.leanback.PlaybackFragment"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent" />
+
+</FrameLayout>
\ No newline at end of file
diff --git a/samples/SupportLeanbackDemos/res/layout/playback_activity_support.xml b/samples/SupportLeanbackDemos/res/layout/playback_activity_support.xml
new file mode 100644
index 0000000..0f2cbc1
--- /dev/null
+++ b/samples/SupportLeanbackDemos/res/layout/playback_activity_support.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- This file is auto-generated from playback_controls.xml.  DO NOT MODIFY. -->
+
+<!--
+     Copyright (C) 2014 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.
+-->
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <fragment
+        android:id="@+id/playback_controls_fragment"
+        android:name="com.example.android.leanback.PlaybackSupportFragment"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent" />
+
+</FrameLayout>
\ No newline at end of file
diff --git a/samples/SupportLeanbackDemos/res/values/strings.xml b/samples/SupportLeanbackDemos/res/values/strings.xml
index 6a9b4a3..3774ebf 100644
--- a/samples/SupportLeanbackDemos/res/values/strings.xml
+++ b/samples/SupportLeanbackDemos/res/values/strings.xml
@@ -35,12 +35,16 @@
     <string name="search_details_description">Search style DetailsFragment test</string>
     <string name="search_details_support">Search Details(support version)</string>
     <string name="search_details_support_description">Search style DetailsSupportFragment test</string>
-    <string name="playback">Playback</string>
     <string name="video_playback">Video Playback</string>
     <string name="video_playback_support">Video Playback(support version)</string>
-    <string name="playback_description">PlaybackOverlayFragment test</string>
+    <string name="playback">Playback</string>
+    <string name="playback_description">PlaybackFragment test</string>
     <string name="playback_support">Playback(support version)</string>
-    <string name="playback_support_description">PlaybackOverlaySupportFragment test</string>
+    <string name="playback_support_description">PlaybackSupportFragment test</string>
+    <string name="playbackoverlay">PlaybackOverlay</string>
+    <string name="playbackoverlay_description">PlaybackOverlayFragment test</string>
+    <string name="playbackoverlay_support">PlaybackOverlay(support version)</string>
+    <string name="playbackoverlay_support_description">PlaybackOverlaySupportFragment test</string>
     <string name="hgrid">Horizontal Grid</string>
     <string name="hgrid_description">HorizontalGridView test</string>
     <string name="vgrid">Vertical Grid</string>
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/MainActivity.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/MainActivity.java
index eab5bbe..83e56d6 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/MainActivity.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/MainActivity.java
@@ -26,6 +26,7 @@
 import android.support.v17.leanback.widget.GuidedAction;
 import android.support.v4.app.ActivityOptionsCompat;
 import android.support.v4.content.res.ResourcesCompat;
+
 import java.util.List;
 
 /**
@@ -91,10 +92,14 @@
                     R.string.browseerror_description);
             addAction(actions, BrowseErrorSupportActivity.class, R.string.browseerror_support,
                     R.string.browseerror_support_description);
-            addAction(actions, PlaybackOverlayActivity.class, R.string.playback,
+            addAction(actions, PlaybackActivity.class, R.string.playback,
                     R.string.playback_description);
-            addAction(actions, PlaybackOverlaySupportActivity.class, R.string.playback_support,
+            addAction(actions, PlaybackSupportActivity.class, R.string.playback_support,
                     R.string.playback_support_description);
+            addAction(actions, PlaybackOverlayActivity.class, R.string.playbackoverlay,
+                    R.string.playbackoverlay_description);
+            addAction(actions, PlaybackOverlaySupportActivity.class,
+                    R.string.playbackoverlay_support, R.string.playbackoverlay_support_description);
             addAction(actions, VideoActivity.class, R.string.video_playback,
                     R.string.playback_description);
             addAction(actions, VideoSupportActivity.class, R.string.video_playback_support,
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackActivity.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackActivity.java
new file mode 100644
index 0000000..14a13cd
--- /dev/null
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackActivity.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.leanback;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Host PlaybackFragment and provide PIP events.
+ */
+public class PlaybackActivity extends Activity {
+    private List<PictureInPictureListener> mListeners = new ArrayList<>();
+
+    /** Called when the activity is first created. */
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.playback_activity);
+    }
+
+    @Override
+    public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode) {
+        for (PictureInPictureListener listener : mListeners) {
+            listener.onPictureInPictureModeChanged(isInPictureInPictureMode);
+        }
+    }
+
+    /**
+     * Register a PIP listener.
+     */
+    public void registerPictureInPictureListener(PictureInPictureListener listener) {
+        mListeners.add(listener);
+    }
+
+    /**
+     * Unregister a PIP listener.
+     */
+    public void unregisterPictureInPictureListener(PictureInPictureListener listener) {
+        mListeners.remove(listener);
+    }
+
+    /**
+     * Interface of PIP event on Activity.
+     */
+    public interface PictureInPictureListener {
+        /**
+         * Called when Activity's PIP mode is changed.
+         */
+        void onPictureInPictureModeChanged(boolean isInPictureInPictureMode);
+    }
+}
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackControlGlue.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackControlGlue.java
new file mode 100644
index 0000000..e04fa46
--- /dev/null
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackControlGlue.java
@@ -0,0 +1,269 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.leanback;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.os.Handler;
+import android.support.v17.leanback.widget.Action;
+import android.support.v17.leanback.widget.ArrayObjectAdapter;
+import android.support.v17.leanback.widget.PlaybackControlsRow;
+import android.support.v17.leanback.widget.SparseArrayObjectAdapter;
+import android.view.KeyEvent;
+import android.view.View;
+import android.widget.Toast;
+
+abstract class PlaybackControlGlue extends android.support.v17.leanback.media.PlaybackControlGlue {
+    /**
+     * Change the location of the thumbs up/down controls
+     */
+    private static final boolean THUMBS_PRIMARY = true;
+
+    private static final String FAUX_TITLE = "A short song of silence";
+    private static final String FAUX_SUBTITLE = "2014";
+    private static final int FAUX_DURATION = 33 * 1000;
+
+    // These should match the playback service FF behavior
+    private static int[] sFastForwardSpeeds = { 2, 3, 4, 5 };
+
+    private boolean mIsPlaying;
+    private int mSpeed = PlaybackControlGlue.PLAYBACK_SPEED_PAUSED;
+    private long mStartTime;
+    private long mStartPosition = 0;
+
+    private PlaybackControlsRow.RepeatAction mRepeatAction;
+    private PlaybackControlsRow.ThumbsUpAction mThumbsUpAction;
+    private PlaybackControlsRow.ThumbsDownAction mThumbsDownAction;
+    private PlaybackControlsRow.PictureInPictureAction mPipAction;
+
+    private Handler mHandler = new Handler();
+    private final Runnable mUpdateProgressRunnable = new Runnable() {
+        @Override
+        public void run() {
+            updateProgress();
+            mHandler.postDelayed(this, getUpdatePeriod());
+        }
+    };
+
+    PlaybackControlGlue(Context context) {
+        super(context, sFastForwardSpeeds);
+        mThumbsUpAction = new PlaybackControlsRow.ThumbsUpAction(context);
+        mThumbsUpAction.setIndex(PlaybackControlsRow.ThumbsUpAction.OUTLINE);
+        mThumbsDownAction = new PlaybackControlsRow.ThumbsDownAction(context);
+        mThumbsDownAction.setIndex(PlaybackControlsRow.ThumbsDownAction.OUTLINE);
+        mRepeatAction = new PlaybackControlsRow.RepeatAction(context);
+        mPipAction = new PlaybackControlsRow.PictureInPictureAction(context);
+    }
+
+    @Override
+    protected void onCreateSecondaryActions(ArrayObjectAdapter adapter) {
+        if (!THUMBS_PRIMARY) {
+            adapter.add(mThumbsDownAction);
+        }
+        if (android.os.Build.VERSION.SDK_INT > 23) {
+            adapter.add(mPipAction);
+        }
+        adapter.add(mRepeatAction);
+        if (!THUMBS_PRIMARY) {
+            adapter.add(mThumbsUpAction);
+        }
+    }
+
+    @Override
+    protected void onCreatePrimaryActions(SparseArrayObjectAdapter adapter) {
+        if (THUMBS_PRIMARY) {
+            adapter.set(PlaybackControlGlue.ACTION_CUSTOM_LEFT_FIRST, mThumbsUpAction);
+            adapter.set(PlaybackControlGlue.ACTION_CUSTOM_RIGHT_FIRST, mThumbsDownAction);
+        }
+    }
+
+    @Override
+    public void onActionClicked(Action action) {
+        if (shouldDispatchAction(action)) {
+            dispatchAction(action);
+            return;
+        }
+        super.onActionClicked(action);
+    }
+
+    @Override
+    public boolean onKey(View view, int keyCode, KeyEvent keyEvent) {
+        if (keyEvent.getAction() == KeyEvent.ACTION_DOWN) {
+            Action action = getControlsRow().getActionForKeyCode(keyEvent.getKeyCode());
+            if (shouldDispatchAction(action)) {
+                dispatchAction(action);
+                return true;
+            }
+        }
+        return super.onKey(view, keyCode, keyEvent);
+    }
+
+    private boolean shouldDispatchAction(Action action) {
+        return action == mRepeatAction || action == mThumbsUpAction || action == mThumbsDownAction;
+    }
+
+    private void dispatchAction(Action action) {
+        Toast.makeText(getContext(), action.toString(), Toast.LENGTH_SHORT).show();
+        PlaybackControlsRow.MultiAction multiAction = (PlaybackControlsRow.MultiAction) action;
+        multiAction.nextIndex();
+        notifyActionChanged(multiAction);
+    }
+
+    private void notifyActionChanged(PlaybackControlsRow.MultiAction action) {
+        int index;
+        index = getPrimaryActionsAdapter().indexOf(action);
+        if (index >= 0) {
+            getPrimaryActionsAdapter().notifyArrayItemRangeChanged(index, 1);
+        } else {
+            index = getSecondaryActionsAdapter().indexOf(action);
+            if (index >= 0) {
+                getSecondaryActionsAdapter().notifyArrayItemRangeChanged(index, 1);
+            }
+        }
+    }
+
+    private SparseArrayObjectAdapter getPrimaryActionsAdapter() {
+        return (SparseArrayObjectAdapter) getControlsRow().getPrimaryActionsAdapter();
+    }
+
+    private ArrayObjectAdapter getSecondaryActionsAdapter() {
+        return (ArrayObjectAdapter) getControlsRow().getSecondaryActionsAdapter();
+    }
+
+    @Override
+    public boolean hasValidMedia() {
+        return true;
+    }
+
+    @Override
+    public boolean isMediaPlaying() {
+        return mIsPlaying;
+    }
+
+    @Override
+    public CharSequence getMediaTitle() {
+        return FAUX_TITLE;
+    }
+
+    @Override
+    public CharSequence getMediaSubtitle() {
+        return FAUX_SUBTITLE;
+    }
+
+    @Override
+    public int getMediaDuration() {
+        return FAUX_DURATION;
+    }
+
+    @Override
+    public Drawable getMediaArt() {
+        return null;
+    }
+
+    @Override
+    public long getSupportedActions() {
+        return PlaybackControlGlue.ACTION_PLAY_PAUSE
+                | PlaybackControlGlue.ACTION_FAST_FORWARD
+                | PlaybackControlGlue.ACTION_REWIND;
+    }
+
+    @Override
+    public int getCurrentSpeedId() {
+        return mSpeed;
+    }
+
+    @Override
+    public int getCurrentPosition() {
+        int speed;
+        if (mSpeed == PlaybackControlGlue.PLAYBACK_SPEED_PAUSED) {
+            speed = 0;
+        } else if (mSpeed == PlaybackControlGlue.PLAYBACK_SPEED_NORMAL) {
+            speed = 1;
+        } else if (mSpeed >= PlaybackControlGlue.PLAYBACK_SPEED_FAST_L0) {
+            int index = mSpeed - PlaybackControlGlue.PLAYBACK_SPEED_FAST_L0;
+            speed = getFastForwardSpeeds()[index];
+        } else if (mSpeed <= -PlaybackControlGlue.PLAYBACK_SPEED_FAST_L0) {
+            int index = -mSpeed - PlaybackControlGlue.PLAYBACK_SPEED_FAST_L0;
+            speed = -getRewindSpeeds()[index];
+        } else {
+            return -1;
+        }
+        long position = mStartPosition + (System.currentTimeMillis() - mStartTime) * speed;
+        if (position > getMediaDuration()) {
+            position = getMediaDuration();
+            onPlaybackComplete(true);
+        } else if (position < 0) {
+            position = 0;
+            onPlaybackComplete(false);
+        }
+        return (int) position;
+    }
+
+    void onPlaybackComplete(final boolean ended) {
+        mHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                if (mRepeatAction.getIndex() == PlaybackControlsRow.RepeatAction.NONE) {
+                    pause();
+                } else {
+                    play(PlaybackControlGlue.PLAYBACK_SPEED_NORMAL);
+                }
+                mStartPosition = 0;
+                onStateChanged();
+            }
+        });
+    }
+
+    @Override
+    public void play(int speed) {
+        if (speed == mSpeed) {
+            return;
+        }
+        mStartPosition = getCurrentPosition();
+        mSpeed = speed;
+        mIsPlaying = true;
+        mStartTime = System.currentTimeMillis();
+    }
+
+    @Override
+    public void pause() {
+        if (mSpeed == PlaybackControlGlue.PLAYBACK_SPEED_PAUSED) {
+            return;
+        }
+        mStartPosition = getCurrentPosition();
+        mSpeed = PlaybackControlGlue.PLAYBACK_SPEED_PAUSED;
+        mIsPlaying = false;
+    }
+
+    @Override
+    public void next() {
+        // Not supported
+    }
+
+    @Override
+    public void previous() {
+        // Not supported
+    }
+
+    @Override
+    public void enableProgressUpdating(boolean enable) {
+        mHandler.removeCallbacks(mUpdateProgressRunnable);
+        if (enable) {
+            mUpdateProgressRunnable.run();
+        }
+    }
+}
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackControlHelper.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackControlHelper.java
index 09892da..df6995e 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackControlHelper.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackControlHelper.java
@@ -19,17 +19,19 @@
 import android.content.Context;
 import android.graphics.drawable.Drawable;
 import android.os.Handler;
-import android.support.v17.leanback.media.MediaPlayerGlue;
-import android.support.v17.leanback.media.PlaybackControlGlue;
+import android.support.v17.leanback.app.PlaybackControlGlue;
 import android.support.v17.leanback.widget.Action;
 import android.support.v17.leanback.widget.ArrayObjectAdapter;
+import android.support.v17.leanback.widget.ControlButtonPresenterSelector;
 import android.support.v17.leanback.widget.PlaybackControlsRow;
+import android.support.v17.leanback.widget.PlaybackControlsRowPresenter;
+import android.support.v17.leanback.widget.PresenterSelector;
 import android.support.v17.leanback.widget.SparseArrayObjectAdapter;
 import android.view.KeyEvent;
 import android.view.View;
 import android.widget.Toast;
 
-abstract class PlaybackControlHelper extends MediaPlayerGlue {
+abstract class PlaybackControlHelper extends PlaybackControlGlue {
     /**
      * Change the location of the thumbs up/down controls
      */
@@ -52,17 +54,17 @@
     private PlaybackControlsRow.ThumbsDownAction mThumbsDownAction;
     private PlaybackControlsRow.PictureInPictureAction mPipAction;
 
-    private static Handler sHandler = new Handler();
+    private Handler mHandler = new Handler();
     private final Runnable mUpdateProgressRunnable = new Runnable() {
         @Override
         public void run() {
             updateProgress();
-            sHandler.postDelayed(this, getUpdatePeriod());
+            mHandler.postDelayed(this, getUpdatePeriod());
         }
     };
 
-    PlaybackControlHelper(Context context) {
-        super(context, sFastForwardSpeeds, sFastForwardSpeeds);
+    PlaybackControlHelper(Context context, PlaybackOverlayFragment fragment) {
+        super(context, fragment, sFastForwardSpeeds);
         mThumbsUpAction = new PlaybackControlsRow.ThumbsUpAction(context);
         mThumbsUpAction.setIndex(PlaybackControlsRow.ThumbsUpAction.OUTLINE);
         mThumbsDownAction = new PlaybackControlsRow.ThumbsDownAction(context);
@@ -72,26 +74,34 @@
     }
 
     @Override
-    protected void onCreateSecondaryActions(ArrayObjectAdapter secondaryActionsAdapter) {
+    public PlaybackControlsRowPresenter createControlsRowAndPresenter() {
+        PlaybackControlsRowPresenter presenter = super.createControlsRowAndPresenter();
+
+        ArrayObjectAdapter adapter = new ArrayObjectAdapter(new ControlButtonPresenterSelector());
+        getControlsRow().setSecondaryActionsAdapter(adapter);
         if (!THUMBS_PRIMARY) {
-            secondaryActionsAdapter.add(mThumbsDownAction);
+            adapter.add(mThumbsDownAction);
         }
         if (android.os.Build.VERSION.SDK_INT > 23) {
-            secondaryActionsAdapter.add(mPipAction);
+            adapter.add(mPipAction);
         }
-        secondaryActionsAdapter.add(mRepeatAction);
+        adapter.add(mRepeatAction);
         if (!THUMBS_PRIMARY) {
-            secondaryActionsAdapter.add(mThumbsUpAction);
+            adapter.add(mThumbsUpAction);
         }
+
+        return presenter;
     }
 
     @Override
-    protected void onCreatePrimaryActions(SparseArrayObjectAdapter adapter) {
-        super.onCreatePrimaryActions(adapter);
+    protected SparseArrayObjectAdapter createPrimaryActionsAdapter(
+            PresenterSelector presenterSelector) {
+        SparseArrayObjectAdapter adapter = new SparseArrayObjectAdapter(presenterSelector);
         if (THUMBS_PRIMARY) {
             adapter.set(PlaybackControlGlue.ACTION_CUSTOM_LEFT_FIRST, mThumbsUpAction);
             adapter.set(PlaybackControlGlue.ACTION_CUSTOM_RIGHT_FIRST, mThumbsDownAction);
         }
+        return adapter;
     }
 
     @Override
@@ -218,13 +228,13 @@
     }
 
     void onPlaybackComplete(final boolean ended) {
-        sHandler.post(new Runnable() {
+        mHandler.post(new Runnable() {
             @Override
             public void run() {
                 if (mRepeatAction.getIndex() == PlaybackControlsRow.RepeatAction.NONE) {
-                    pause();
+                    pausePlayback();
                 } else {
-                    play(PlaybackControlGlue.PLAYBACK_SPEED_NORMAL);
+                    startPlayback(PlaybackControlGlue.PLAYBACK_SPEED_NORMAL);
                 }
                 mStartPosition = 0;
                 onStateChanged();
@@ -233,7 +243,7 @@
     }
 
     @Override
-    public void play(int speed) {
+    protected void startPlayback(int speed) {
         if (speed == mSpeed) {
             return;
         }
@@ -244,7 +254,7 @@
     }
 
     @Override
-    public void pause() {
+    protected void pausePlayback() {
         if (mSpeed == PlaybackControlGlue.PLAYBACK_SPEED_PAUSED) {
             return;
         }
@@ -254,20 +264,20 @@
     }
 
     @Override
-    public void next() {
+    protected void skipToNext() {
         // Not supported
     }
 
     @Override
-    public void previous() {
+    protected void skipToPrevious() {
         // Not supported
     }
 
     @Override
     public void enableProgressUpdating(boolean enable) {
-        sHandler.removeCallbacks(mUpdateProgressRunnable);
+        mHandler.removeCallbacks(mUpdateProgressRunnable);
         if (enable) {
             mUpdateProgressRunnable.run();
         }
     }
-}
+};
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackControlSupportHelper.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackControlSupportHelper.java
new file mode 100644
index 0000000..e7afb27
--- /dev/null
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackControlSupportHelper.java
@@ -0,0 +1,286 @@
+// CHECKSTYLE:OFF Generated code
+/* This file is auto-generated from PlaybackControlHelper.java.  DO NOT MODIFY. */
+
+/*
+ * Copyright (C) 2015 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 com.example.android.leanback;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.os.Handler;
+import android.support.v17.leanback.app.PlaybackControlSupportGlue;
+import android.support.v17.leanback.widget.Action;
+import android.support.v17.leanback.widget.ArrayObjectAdapter;
+import android.support.v17.leanback.widget.ControlButtonPresenterSelector;
+import android.support.v17.leanback.widget.PlaybackControlsRow;
+import android.support.v17.leanback.widget.PlaybackControlsRowPresenter;
+import android.support.v17.leanback.widget.PresenterSelector;
+import android.support.v17.leanback.widget.SparseArrayObjectAdapter;
+import android.view.KeyEvent;
+import android.view.View;
+import android.widget.Toast;
+
+abstract class PlaybackControlSupportHelper extends PlaybackControlSupportGlue {
+    /**
+     * Change the location of the thumbs up/down controls
+     */
+    private static final boolean THUMBS_PRIMARY = true;
+
+    private static final String FAUX_TITLE = "A short song of silence";
+    private static final String FAUX_SUBTITLE = "2014";
+    private static final int FAUX_DURATION = 33 * 1000;
+
+    // These should match the playback service FF behavior
+    private static int[] sFastForwardSpeeds = { 2, 3, 4, 5 };
+
+    private boolean mIsPlaying;
+    private int mSpeed = PlaybackControlSupportGlue.PLAYBACK_SPEED_PAUSED;
+    private long mStartTime;
+    private long mStartPosition = 0;
+
+    private PlaybackControlsRow.RepeatAction mRepeatAction;
+    private PlaybackControlsRow.ThumbsUpAction mThumbsUpAction;
+    private PlaybackControlsRow.ThumbsDownAction mThumbsDownAction;
+    private PlaybackControlsRow.PictureInPictureAction mPipAction;
+
+    private Handler mHandler = new Handler();
+    private final Runnable mUpdateProgressRunnable = new Runnable() {
+        @Override
+        public void run() {
+            updateProgress();
+            mHandler.postDelayed(this, getUpdatePeriod());
+        }
+    };
+
+    PlaybackControlSupportHelper(Context context, PlaybackOverlaySupportFragment fragment) {
+        super(context, fragment, sFastForwardSpeeds);
+        mThumbsUpAction = new PlaybackControlsRow.ThumbsUpAction(context);
+        mThumbsUpAction.setIndex(PlaybackControlsRow.ThumbsUpAction.OUTLINE);
+        mThumbsDownAction = new PlaybackControlsRow.ThumbsDownAction(context);
+        mThumbsDownAction.setIndex(PlaybackControlsRow.ThumbsDownAction.OUTLINE);
+        mRepeatAction = new PlaybackControlsRow.RepeatAction(context);
+        mPipAction = new PlaybackControlsRow.PictureInPictureAction(context);
+    }
+
+    @Override
+    public PlaybackControlsRowPresenter createControlsRowAndPresenter() {
+        PlaybackControlsRowPresenter presenter = super.createControlsRowAndPresenter();
+
+        ArrayObjectAdapter adapter = new ArrayObjectAdapter(new ControlButtonPresenterSelector());
+        getControlsRow().setSecondaryActionsAdapter(adapter);
+        if (!THUMBS_PRIMARY) {
+            adapter.add(mThumbsDownAction);
+        }
+        if (android.os.Build.VERSION.SDK_INT > 23) {
+            adapter.add(mPipAction);
+        }
+        adapter.add(mRepeatAction);
+        if (!THUMBS_PRIMARY) {
+            adapter.add(mThumbsUpAction);
+        }
+
+        return presenter;
+    }
+
+    @Override
+    protected SparseArrayObjectAdapter createPrimaryActionsAdapter(
+            PresenterSelector presenterSelector) {
+        SparseArrayObjectAdapter adapter = new SparseArrayObjectAdapter(presenterSelector);
+        if (THUMBS_PRIMARY) {
+            adapter.set(PlaybackControlSupportGlue.ACTION_CUSTOM_LEFT_FIRST, mThumbsUpAction);
+            adapter.set(PlaybackControlSupportGlue.ACTION_CUSTOM_RIGHT_FIRST, mThumbsDownAction);
+        }
+        return adapter;
+    }
+
+    @Override
+    public void onActionClicked(Action action) {
+        if (shouldDispatchAction(action)) {
+            dispatchAction(action);
+            return;
+        }
+        super.onActionClicked(action);
+    }
+
+    @Override
+    public boolean onKey(View view, int keyCode, KeyEvent keyEvent) {
+        if (keyEvent.getAction() == KeyEvent.ACTION_DOWN) {
+            Action action = getControlsRow().getActionForKeyCode(keyEvent.getKeyCode());
+            if (shouldDispatchAction(action)) {
+                dispatchAction(action);
+                return true;
+            }
+        }
+        return super.onKey(view, keyCode, keyEvent);
+    }
+
+    private boolean shouldDispatchAction(Action action) {
+        return action == mRepeatAction || action == mThumbsUpAction || action == mThumbsDownAction;
+    }
+
+    private void dispatchAction(Action action) {
+        Toast.makeText(getContext(), action.toString(), Toast.LENGTH_SHORT).show();
+        PlaybackControlsRow.MultiAction multiAction = (PlaybackControlsRow.MultiAction) action;
+        multiAction.nextIndex();
+        notifyActionChanged(multiAction);
+    }
+
+    private void notifyActionChanged(PlaybackControlsRow.MultiAction action) {
+        int index;
+        index = getPrimaryActionsAdapter().indexOf(action);
+        if (index >= 0) {
+            getPrimaryActionsAdapter().notifyArrayItemRangeChanged(index, 1);
+        } else {
+            index = getSecondaryActionsAdapter().indexOf(action);
+            if (index >= 0) {
+                getSecondaryActionsAdapter().notifyArrayItemRangeChanged(index, 1);
+            }
+        }
+    }
+
+    private SparseArrayObjectAdapter getPrimaryActionsAdapter() {
+        return (SparseArrayObjectAdapter) getControlsRow().getPrimaryActionsAdapter();
+    }
+
+    private ArrayObjectAdapter getSecondaryActionsAdapter() {
+        return (ArrayObjectAdapter) getControlsRow().getSecondaryActionsAdapter();
+    }
+
+    @Override
+    public boolean hasValidMedia() {
+        return true;
+    }
+
+    @Override
+    public boolean isMediaPlaying() {
+        return mIsPlaying;
+    }
+
+    @Override
+    public CharSequence getMediaTitle() {
+        return FAUX_TITLE;
+    }
+
+    @Override
+    public CharSequence getMediaSubtitle() {
+        return FAUX_SUBTITLE;
+    }
+
+    @Override
+    public int getMediaDuration() {
+        return FAUX_DURATION;
+    }
+
+    @Override
+    public Drawable getMediaArt() {
+        return null;
+    }
+
+    @Override
+    public long getSupportedActions() {
+        return PlaybackControlSupportGlue.ACTION_PLAY_PAUSE |
+                PlaybackControlSupportGlue.ACTION_FAST_FORWARD |
+                PlaybackControlSupportGlue.ACTION_REWIND;
+    }
+
+    @Override
+    public int getCurrentSpeedId() {
+        return mSpeed;
+    }
+
+    @Override
+    public int getCurrentPosition() {
+        int speed;
+        if (mSpeed == PlaybackControlSupportGlue.PLAYBACK_SPEED_PAUSED) {
+            speed = 0;
+        } else if (mSpeed == PlaybackControlSupportGlue.PLAYBACK_SPEED_NORMAL) {
+            speed = 1;
+        } else if (mSpeed >= PlaybackControlSupportGlue.PLAYBACK_SPEED_FAST_L0) {
+            int index = mSpeed - PlaybackControlSupportGlue.PLAYBACK_SPEED_FAST_L0;
+            speed = getFastForwardSpeeds()[index];
+        } else if (mSpeed <= -PlaybackControlSupportGlue.PLAYBACK_SPEED_FAST_L0) {
+            int index = -mSpeed - PlaybackControlSupportGlue.PLAYBACK_SPEED_FAST_L0;
+            speed = -getRewindSpeeds()[index];
+        } else {
+            return -1;
+        }
+        long position = mStartPosition +
+                (System.currentTimeMillis() - mStartTime) * speed;
+        if (position > getMediaDuration()) {
+            position = getMediaDuration();
+            onPlaybackComplete(true);
+        } else if (position < 0) {
+            position = 0;
+            onPlaybackComplete(false);
+        }
+        return (int) position;
+    }
+
+    void onPlaybackComplete(final boolean ended) {
+        mHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                if (mRepeatAction.getIndex() == PlaybackControlsRow.RepeatAction.NONE) {
+                    pausePlayback();
+                } else {
+                    startPlayback(PlaybackControlSupportGlue.PLAYBACK_SPEED_NORMAL);
+                }
+                mStartPosition = 0;
+                onStateChanged();
+            }
+        });
+    }
+
+    @Override
+    protected void startPlayback(int speed) {
+        if (speed == mSpeed) {
+            return;
+        }
+        mStartPosition = getCurrentPosition();
+        mSpeed = speed;
+        mIsPlaying = true;
+        mStartTime = System.currentTimeMillis();
+    }
+
+    @Override
+    protected void pausePlayback() {
+        if (mSpeed == PlaybackControlSupportGlue.PLAYBACK_SPEED_PAUSED) {
+            return;
+        }
+        mStartPosition = getCurrentPosition();
+        mSpeed = PlaybackControlSupportGlue.PLAYBACK_SPEED_PAUSED;
+        mIsPlaying = false;
+    }
+
+    @Override
+    protected void skipToNext() {
+        // Not supported
+    }
+
+    @Override
+    protected void skipToPrevious() {
+        // Not supported
+    }
+
+    @Override
+    public void enableProgressUpdating(boolean enable) {
+        mHandler.removeCallbacks(mUpdateProgressRunnable);
+        if (enable) {
+            mUpdateProgressRunnable.run();
+        }
+    }
+};
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackFragment.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackFragment.java
new file mode 100644
index 0000000..a29a995
--- /dev/null
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackFragment.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.leanback;
+
+import android.content.Context;
+import android.os.Bundle;
+import android.support.v17.leanback.app.PlaybackFragmentGlueHost;
+import android.support.v17.leanback.widget.Action;
+import android.support.v17.leanback.widget.ArrayObjectAdapter;
+import android.support.v17.leanback.widget.HeaderItem;
+import android.support.v17.leanback.widget.ListRow;
+import android.support.v17.leanback.widget.ListRowPresenter;
+import android.support.v17.leanback.widget.PlaybackControlsRow;
+import android.support.v17.leanback.widget.Presenter;
+import android.support.v17.leanback.widget.PresenterSelector;
+import android.support.v17.leanback.widget.SparseArrayObjectAdapter;
+import android.util.Log;
+
+/**
+ * Example of PlaybackFragment working with a PlaybackControlGlue.
+ */
+public class PlaybackFragment
+        extends android.support.v17.leanback.app.PlaybackFragment
+        implements PlaybackActivity.PictureInPictureListener {
+    private static final String TAG = "leanback.PlaybackControlsFragment";
+
+    /**
+     * Change this to choose a different overlay background.
+     */
+    private static final int BACKGROUND_TYPE = PlaybackFragment.BG_LIGHT;
+
+    /**
+     * Change the number of related content rows.
+     */
+    private static final int RELATED_CONTENT_ROWS = 3;
+
+    /**
+     * Change this to select hidden
+     */
+    private static final boolean SECONDARY_HIDDEN = false;
+
+    private static final int ROW_CONTROLS = 0;
+
+    private PlaybackControlGlue mGlue;
+    private ListRowPresenter mListRowPresenter;
+
+    public SparseArrayObjectAdapter getAdapter() {
+        return (SparseArrayObjectAdapter) super.getAdapter();
+    }
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        Log.i(TAG, "onCreate");
+        super.onCreate(savedInstanceState);
+
+        setBackgroundType(BACKGROUND_TYPE);
+
+        createComponents(getActivity());
+    }
+
+    private void createComponents(Context context) {
+        mGlue = new PlaybackControlGlue(context) {
+            @Override
+            public int getUpdatePeriod() {
+                int totalTime = getControlsRow().getTotalTime();
+                if (getView() == null || getView().getWidth() == 0 || totalTime <= 0) {
+                    return 1000;
+                }
+                return Math.max(16, totalTime / getView().getWidth());
+            }
+
+            @Override
+            public void onActionClicked(Action action) {
+                if (action.getId() == R.id.lb_control_picture_in_picture) {
+                    getActivity().enterPictureInPictureMode();
+                    return;
+                }
+                super.onActionClicked(action);
+            }
+
+            @Override
+            protected void onCreateControlsRowAndPresenter() {
+                super.onCreateControlsRowAndPresenter();
+                getControlsRowPresenter().setSecondaryActionsHidden(SECONDARY_HIDDEN);
+            }
+        };
+
+        mGlue.setHost(new PlaybackFragmentGlueHost(this));
+        mListRowPresenter = new ListRowPresenter();
+
+        setAdapter(new SparseArrayObjectAdapter(new PresenterSelector() {
+            @Override
+            public Presenter getPresenter(Object object) {
+                if (object instanceof PlaybackControlsRow) {
+                    return mGlue.getControlsRowPresenter();
+                } else if (object instanceof ListRow) {
+                    return mListRowPresenter;
+                }
+                throw new IllegalArgumentException("Unhandled object: " + object);
+            }
+        }));
+
+        // Add the controls row
+        getAdapter().set(ROW_CONTROLS, mGlue.getControlsRow());
+
+        // Add related content rows
+        for (int i = 0; i < RELATED_CONTENT_ROWS; ++i) {
+            ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(new StringPresenter());
+            listRowAdapter.add("Some related content");
+            listRowAdapter.add("Other related content");
+            HeaderItem header = new HeaderItem(i, "Row " + i);
+            getAdapter().set(ROW_CONTROLS + 1 + i, new ListRow(header, listRowAdapter));
+        }
+    }
+
+    @Override
+    public void onStart() {
+        super.onStart();
+        ((PlaybackActivity) getActivity()).registerPictureInPictureListener(this);
+    }
+
+    @Override
+    public void onStop() {
+        ((PlaybackActivity) getActivity()).unregisterPictureInPictureListener(this);
+        super.onStop();
+    }
+
+    @Override
+    public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode) {
+        if (isInPictureInPictureMode) {
+            // Hide the controls in picture-in-picture mode.
+            setFadingEnabled(true);
+            fadeOut();
+        } else {
+            setFadingEnabled(mGlue.isMediaPlaying());
+        }
+    }
+}
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackOverlayFragment.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackOverlayFragment.java
index 1701153..1531d14 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackOverlayFragment.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackOverlayFragment.java
@@ -15,28 +15,31 @@
 
 import android.content.Context;
 import android.os.Bundle;
-import android.support.v17.leanback.app.PlaybackFragment;
-import android.support.v17.leanback.app.PlaybackFragmentGlueHost;
 import android.support.v17.leanback.widget.Action;
 import android.support.v17.leanback.widget.ArrayObjectAdapter;
 import android.support.v17.leanback.widget.HeaderItem;
 import android.support.v17.leanback.widget.ListRow;
 import android.support.v17.leanback.widget.ListRowPresenter;
+import android.support.v17.leanback.widget.OnItemViewClickedListener;
+import android.support.v17.leanback.widget.OnItemViewSelectedListener;
 import android.support.v17.leanback.widget.PlaybackControlsRow;
+import android.support.v17.leanback.widget.PlaybackControlsRowPresenter;
 import android.support.v17.leanback.widget.Presenter;
 import android.support.v17.leanback.widget.PresenterSelector;
+import android.support.v17.leanback.widget.Row;
+import android.support.v17.leanback.widget.RowPresenter;
 import android.support.v17.leanback.widget.SparseArrayObjectAdapter;
 import android.util.Log;
 
 public class PlaybackOverlayFragment
-        extends android.support.v17.leanback.app.PlaybackFragment
+        extends android.support.v17.leanback.app.PlaybackOverlayFragment
         implements PlaybackOverlayActivity.PictureInPictureListener {
     private static final String TAG = "leanback.PlaybackControlsFragment";
 
     /**
      * Change this to choose a different overlay background.
      */
-    private static final int BACKGROUND_TYPE = PlaybackFragment.BG_LIGHT;
+    private static final int BACKGROUND_TYPE = PlaybackOverlayFragment.BG_LIGHT;
 
     /**
      * Change the number of related content rows.
@@ -51,8 +54,29 @@
     private static final int ROW_CONTROLS = 0;
 
     private PlaybackControlHelper mGlue;
+    private PlaybackControlsRowPresenter mPlaybackControlsRowPresenter;
     private ListRowPresenter mListRowPresenter;
 
+    private OnItemViewClickedListener mOnItemViewClickedListener = new OnItemViewClickedListener() {
+        @Override
+        public void onItemClicked(Presenter.ViewHolder itemViewHolder, Object item,
+                                  RowPresenter.ViewHolder rowViewHolder, Row row) {
+            Log.i(TAG, "onItemClicked: " + item + " row " + row);
+            if (item instanceof Action) {
+                mGlue.onActionClicked((Action) item);
+            }
+        }
+    };
+
+    private OnItemViewSelectedListener mOnItemViewSelectedListener =
+            new OnItemViewSelectedListener() {
+                @Override
+                public void onItemSelected(Presenter.ViewHolder itemViewHolder, Object item,
+                                           RowPresenter.ViewHolder rowViewHolder, Row row) {
+                    Log.i(TAG, "onItemSelected: " + item + " row " + row);
+                }
+    };
+
     public SparseArrayObjectAdapter getAdapter() {
         return (SparseArrayObjectAdapter) super.getAdapter();
     }
@@ -63,12 +87,13 @@
         super.onCreate(savedInstanceState);
 
         setBackgroundType(BACKGROUND_TYPE);
+        setOnItemViewSelectedListener(mOnItemViewSelectedListener);
 
         createComponents(getActivity());
     }
 
     private void createComponents(Context context) {
-        mGlue = new PlaybackControlHelper(context) {
+        mGlue = new PlaybackControlHelper(context, this) {
             @Override
             public int getUpdatePeriod() {
                 int totalTime = getControlsRow().getTotalTime();
@@ -79,6 +104,17 @@
             }
 
             @Override
+            protected void onRowChanged(PlaybackControlsRow row) {
+                if (getAdapter() == null) {
+                    return;
+                }
+                int index = getAdapter().indexOf(row);
+                if (index >= 0) {
+                    getAdapter().notifyArrayItemRangeChanged(index, 1);
+                }
+            }
+
+            @Override
             public void onActionClicked(Action action) {
                 if (action.getId() == R.id.lb_control_picture_in_picture) {
                     getActivity().enterPictureInPictureMode();
@@ -86,22 +122,19 @@
                 }
                 super.onActionClicked(action);
             }
-
-            @Override
-            protected void onCreateControlsRowAndPresenter() {
-                super.onCreateControlsRowAndPresenter();
-                getControlsRowPresenter().setSecondaryActionsHidden(SECONDARY_HIDDEN);
-            }
         };
 
-        mGlue.setHost(new PlaybackFragmentGlueHost(this));
+        mGlue.setOnItemViewClickedListener(mOnItemViewClickedListener);
+
+        mPlaybackControlsRowPresenter = mGlue.createControlsRowAndPresenter();
+        mPlaybackControlsRowPresenter.setSecondaryActionsHidden(SECONDARY_HIDDEN);
         mListRowPresenter = new ListRowPresenter();
 
         setAdapter(new SparseArrayObjectAdapter(new PresenterSelector() {
             @Override
             public Presenter getPresenter(Object object) {
                 if (object instanceof PlaybackControlsRow) {
-                    return mGlue.getControlsRowPresenter();
+                    return mPlaybackControlsRowPresenter;
                 } else if (object instanceof ListRow) {
                     return mListRowPresenter;
                 }
@@ -120,16 +153,20 @@
             HeaderItem header = new HeaderItem(i, "Row " + i);
             getAdapter().set(ROW_CONTROLS + 1 + i, new ListRow(header, listRowAdapter));
         }
+
     }
 
     @Override
     public void onStart() {
         super.onStart();
+        mGlue.setFadingEnabled(true);
+        mGlue.enableProgressUpdating(true);
         ((PlaybackOverlayActivity) getActivity()).registerPictureInPictureListener(this);
     }
 
     @Override
     public void onStop() {
+        mGlue.enableProgressUpdating(false);
         ((PlaybackOverlayActivity) getActivity()).unregisterPictureInPictureListener(this);
         super.onStop();
     }
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackOverlaySupportFragment.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackOverlaySupportFragment.java
index baa2cb7..7a33493 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackOverlaySupportFragment.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackOverlaySupportFragment.java
@@ -18,28 +18,31 @@
 
 import android.content.Context;
 import android.os.Bundle;
-import android.support.v17.leanback.app.PlaybackSupportFragment;
-import android.support.v17.leanback.app.PlaybackSupportFragmentGlueHost;
 import android.support.v17.leanback.widget.Action;
 import android.support.v17.leanback.widget.ArrayObjectAdapter;
 import android.support.v17.leanback.widget.HeaderItem;
 import android.support.v17.leanback.widget.ListRow;
 import android.support.v17.leanback.widget.ListRowPresenter;
+import android.support.v17.leanback.widget.OnItemViewClickedListener;
+import android.support.v17.leanback.widget.OnItemViewSelectedListener;
 import android.support.v17.leanback.widget.PlaybackControlsRow;
+import android.support.v17.leanback.widget.PlaybackControlsRowPresenter;
 import android.support.v17.leanback.widget.Presenter;
 import android.support.v17.leanback.widget.PresenterSelector;
+import android.support.v17.leanback.widget.Row;
+import android.support.v17.leanback.widget.RowPresenter;
 import android.support.v17.leanback.widget.SparseArrayObjectAdapter;
 import android.util.Log;
 
 public class PlaybackOverlaySupportFragment
-        extends android.support.v17.leanback.app.PlaybackSupportFragment
+        extends android.support.v17.leanback.app.PlaybackOverlaySupportFragment
         implements PlaybackOverlaySupportActivity.PictureInPictureListener {
     private static final String TAG = "leanback.PlaybackControlsFragment";
 
     /**
      * Change this to choose a different overlay background.
      */
-    private static final int BACKGROUND_TYPE = PlaybackSupportFragment.BG_LIGHT;
+    private static final int BACKGROUND_TYPE = PlaybackOverlaySupportFragment.BG_LIGHT;
 
     /**
      * Change the number of related content rows.
@@ -53,9 +56,30 @@
 
     private static final int ROW_CONTROLS = 0;
 
-    private PlaybackControlHelper mGlue;
+    private PlaybackControlSupportHelper mGlue;
+    private PlaybackControlsRowPresenter mPlaybackControlsRowPresenter;
     private ListRowPresenter mListRowPresenter;
 
+    private OnItemViewClickedListener mOnItemViewClickedListener = new OnItemViewClickedListener() {
+        @Override
+        public void onItemClicked(Presenter.ViewHolder itemViewHolder, Object item,
+                                  RowPresenter.ViewHolder rowViewHolder, Row row) {
+            Log.i(TAG, "onItemClicked: " + item + " row " + row);
+            if (item instanceof Action) {
+                mGlue.onActionClicked((Action) item);
+            }
+        }
+    };
+
+    private OnItemViewSelectedListener mOnItemViewSelectedListener =
+            new OnItemViewSelectedListener() {
+                @Override
+                public void onItemSelected(Presenter.ViewHolder itemViewHolder, Object item,
+                                           RowPresenter.ViewHolder rowViewHolder, Row row) {
+                    Log.i(TAG, "onItemSelected: " + item + " row " + row);
+                }
+    };
+
     public SparseArrayObjectAdapter getAdapter() {
         return (SparseArrayObjectAdapter) super.getAdapter();
     }
@@ -66,12 +90,13 @@
         super.onCreate(savedInstanceState);
 
         setBackgroundType(BACKGROUND_TYPE);
+        setOnItemViewSelectedListener(mOnItemViewSelectedListener);
 
         createComponents(getActivity());
     }
 
     private void createComponents(Context context) {
-        mGlue = new PlaybackControlHelper(context) {
+        mGlue = new PlaybackControlSupportHelper(context, this) {
             @Override
             public int getUpdatePeriod() {
                 int totalTime = getControlsRow().getTotalTime();
@@ -82,6 +107,17 @@
             }
 
             @Override
+            protected void onRowChanged(PlaybackControlsRow row) {
+                if (getAdapter() == null) {
+                    return;
+                }
+                int index = getAdapter().indexOf(row);
+                if (index >= 0) {
+                    getAdapter().notifyArrayItemRangeChanged(index, 1);
+                }
+            }
+
+            @Override
             public void onActionClicked(Action action) {
                 if (action.getId() == R.id.lb_control_picture_in_picture) {
                     getActivity().enterPictureInPictureMode();
@@ -89,22 +125,19 @@
                 }
                 super.onActionClicked(action);
             }
-
-            @Override
-            protected void onCreateControlsRowAndPresenter() {
-                super.onCreateControlsRowAndPresenter();
-                getControlsRowPresenter().setSecondaryActionsHidden(SECONDARY_HIDDEN);
-            }
         };
 
-        mGlue.setHost(new PlaybackSupportFragmentGlueHost(this));
+        mGlue.setOnItemViewClickedListener(mOnItemViewClickedListener);
+
+        mPlaybackControlsRowPresenter = mGlue.createControlsRowAndPresenter();
+        mPlaybackControlsRowPresenter.setSecondaryActionsHidden(SECONDARY_HIDDEN);
         mListRowPresenter = new ListRowPresenter();
 
         setAdapter(new SparseArrayObjectAdapter(new PresenterSelector() {
             @Override
             public Presenter getPresenter(Object object) {
                 if (object instanceof PlaybackControlsRow) {
-                    return mGlue.getControlsRowPresenter();
+                    return mPlaybackControlsRowPresenter;
                 } else if (object instanceof ListRow) {
                     return mListRowPresenter;
                 }
@@ -123,16 +156,20 @@
             HeaderItem header = new HeaderItem(i, "Row " + i);
             getAdapter().set(ROW_CONTROLS + 1 + i, new ListRow(header, listRowAdapter));
         }
+
     }
 
     @Override
     public void onStart() {
         super.onStart();
+        mGlue.setFadingEnabled(true);
+        mGlue.enableProgressUpdating(true);
         ((PlaybackOverlaySupportActivity) getActivity()).registerPictureInPictureListener(this);
     }
 
     @Override
     public void onStop() {
+        mGlue.enableProgressUpdating(false);
         ((PlaybackOverlaySupportActivity) getActivity()).unregisterPictureInPictureListener(this);
         super.onStop();
     }
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackSupportActivity.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackSupportActivity.java
new file mode 100644
index 0000000..069b37c
--- /dev/null
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackSupportActivity.java
@@ -0,0 +1,71 @@
+// CHECKSTYLE:OFF Generated code
+/* This file is auto-generated from PlaybackActivity.java.  DO NOT MODIFY. */
+
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.leanback;
+
+import android.support.v4.app.FragmentActivity;
+import android.os.Bundle;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Host PlaybackFragment and provide PIP events.
+ */
+public class PlaybackSupportActivity extends FragmentActivity {
+    private List<PictureInPictureListener> mListeners = new ArrayList<>();
+
+    /** Called when the activity is first created. */
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.playback_activity_support);
+    }
+
+    @Override
+    public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode) {
+        for (PictureInPictureListener listener : mListeners) {
+            listener.onPictureInPictureModeChanged(isInPictureInPictureMode);
+        }
+    }
+
+    /**
+     * Register a PIP listener.
+     */
+    public void registerPictureInPictureListener(PictureInPictureListener listener) {
+        mListeners.add(listener);
+    }
+
+    /**
+     * Unregister a PIP listener.
+     */
+    public void unregisterPictureInPictureListener(PictureInPictureListener listener) {
+        mListeners.remove(listener);
+    }
+
+    /**
+     * Interface of PIP event on Activity.
+     */
+    public interface PictureInPictureListener {
+        /**
+         * Called when Activity's PIP mode is changed.
+         */
+        void onPictureInPictureModeChanged(boolean isInPictureInPictureMode);
+    }
+}
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackSupportFragment.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackSupportFragment.java
new file mode 100644
index 0000000..6d2fa51
--- /dev/null
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackSupportFragment.java
@@ -0,0 +1,155 @@
+// CHECKSTYLE:OFF Generated code
+/* This file is auto-generated from PlaybackFragment.java.  DO NOT MODIFY. */
+
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.leanback;
+
+import android.content.Context;
+import android.os.Bundle;
+import android.support.v17.leanback.app.PlaybackSupportFragmentGlueHost;
+import android.support.v17.leanback.widget.Action;
+import android.support.v17.leanback.widget.ArrayObjectAdapter;
+import android.support.v17.leanback.widget.HeaderItem;
+import android.support.v17.leanback.widget.ListRow;
+import android.support.v17.leanback.widget.ListRowPresenter;
+import android.support.v17.leanback.widget.PlaybackControlsRow;
+import android.support.v17.leanback.widget.Presenter;
+import android.support.v17.leanback.widget.PresenterSelector;
+import android.support.v17.leanback.widget.SparseArrayObjectAdapter;
+import android.util.Log;
+
+/**
+ * Example of PlaybackSupportFragment working with a PlaybackControlGlue.
+ */
+public class PlaybackSupportFragment
+        extends android.support.v17.leanback.app.PlaybackSupportFragment
+        implements PlaybackSupportActivity.PictureInPictureListener {
+    private static final String TAG = "leanback.PlaybackControlsFragment";
+
+    /**
+     * Change this to choose a different overlay background.
+     */
+    private static final int BACKGROUND_TYPE = PlaybackSupportFragment.BG_LIGHT;
+
+    /**
+     * Change the number of related content rows.
+     */
+    private static final int RELATED_CONTENT_ROWS = 3;
+
+    /**
+     * Change this to select hidden
+     */
+    private static final boolean SECONDARY_HIDDEN = false;
+
+    private static final int ROW_CONTROLS = 0;
+
+    private PlaybackControlGlue mGlue;
+    private ListRowPresenter mListRowPresenter;
+
+    public SparseArrayObjectAdapter getAdapter() {
+        return (SparseArrayObjectAdapter) super.getAdapter();
+    }
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        Log.i(TAG, "onCreate");
+        super.onCreate(savedInstanceState);
+
+        setBackgroundType(BACKGROUND_TYPE);
+
+        createComponents(getActivity());
+    }
+
+    private void createComponents(Context context) {
+        mGlue = new PlaybackControlGlue(context) {
+            @Override
+            public int getUpdatePeriod() {
+                int totalTime = getControlsRow().getTotalTime();
+                if (getView() == null || getView().getWidth() == 0 || totalTime <= 0) {
+                    return 1000;
+                }
+                return Math.max(16, totalTime / getView().getWidth());
+            }
+
+            @Override
+            public void onActionClicked(Action action) {
+                if (action.getId() == R.id.lb_control_picture_in_picture) {
+                    getActivity().enterPictureInPictureMode();
+                    return;
+                }
+                super.onActionClicked(action);
+            }
+
+            @Override
+            protected void onCreateControlsRowAndPresenter() {
+                super.onCreateControlsRowAndPresenter();
+                getControlsRowPresenter().setSecondaryActionsHidden(SECONDARY_HIDDEN);
+            }
+        };
+
+        mGlue.setHost(new PlaybackSupportFragmentGlueHost(this));
+        mListRowPresenter = new ListRowPresenter();
+
+        setAdapter(new SparseArrayObjectAdapter(new PresenterSelector() {
+            @Override
+            public Presenter getPresenter(Object object) {
+                if (object instanceof PlaybackControlsRow) {
+                    return mGlue.getControlsRowPresenter();
+                } else if (object instanceof ListRow) {
+                    return mListRowPresenter;
+                }
+                throw new IllegalArgumentException("Unhandled object: " + object);
+            }
+        }));
+
+        // Add the controls row
+        getAdapter().set(ROW_CONTROLS, mGlue.getControlsRow());
+
+        // Add related content rows
+        for (int i = 0; i < RELATED_CONTENT_ROWS; ++i) {
+            ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(new StringPresenter());
+            listRowAdapter.add("Some related content");
+            listRowAdapter.add("Other related content");
+            HeaderItem header = new HeaderItem(i, "Row " + i);
+            getAdapter().set(ROW_CONTROLS + 1 + i, new ListRow(header, listRowAdapter));
+        }
+    }
+
+    @Override
+    public void onStart() {
+        super.onStart();
+        ((PlaybackSupportActivity) getActivity()).registerPictureInPictureListener(this);
+    }
+
+    @Override
+    public void onStop() {
+        ((PlaybackSupportActivity) getActivity()).unregisterPictureInPictureListener(this);
+        super.onStop();
+    }
+
+    @Override
+    public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode) {
+        if (isInPictureInPictureMode) {
+            // Hide the controls in picture-in-picture mode.
+            setFadingEnabled(true);
+            fadeOut();
+        } else {
+            setFadingEnabled(mGlue.isMediaPlaying());
+        }
+    }
+}
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 56bd8da..b16f432 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/PlaybackControlGlue.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/PlaybackControlGlue.java
@@ -20,6 +20,7 @@
 import android.support.v17.leanback.widget.OnItemViewClickedListener;
 import android.support.v17.leanback.widget.PlaybackControlsRow;
 import android.support.v17.leanback.widget.PlaybackControlsRowPresenter;
+import android.support.v17.leanback.widget.PlaybackRowPresenter;
 import android.support.v17.leanback.widget.Presenter;
 import android.support.v17.leanback.widget.PresenterSelector;
 import android.support.v17.leanback.widget.Row;
@@ -276,9 +277,24 @@
     static final class PlaybackGlueHostOld extends PlaybackGlueHost {
         final PlaybackOverlayFragment mFragment;
         PlaybackControlGlue mGlue;
+        OnActionClickedListener mActionClickedListener;
 
         public PlaybackGlueHostOld(PlaybackOverlayFragment fragment) {
             mFragment = fragment;
+            mFragment.setOnItemViewClickedListener(new OnItemViewClickedListener() {
+                @Override
+                public void onItemClicked(Presenter.ViewHolder itemViewHolder, Object item,
+                                          RowPresenter.ViewHolder rowViewHolder, Row row) {
+                    if (item instanceof Action
+                            && rowViewHolder instanceof PlaybackRowPresenter.ViewHolder
+                            && mActionClickedListener != null) {
+                        mActionClickedListener.onActionClicked((Action) item);
+                    } else if (mGlue != null && mGlue.getOnItemViewClickedListener() != null) {
+                        mGlue.getOnItemViewClickedListener().onItemClicked(itemViewHolder,
+                                item, rowViewHolder, row);
+                    }
+                }
+            });
         }
 
         @Override
@@ -302,19 +318,7 @@
 
         @Override
         public void setOnActionClickedListener(final OnActionClickedListener listener) {
-            mFragment.setOnItemViewClickedListener(new OnItemViewClickedListener() {
-                @Override
-                public void onItemClicked(Presenter.ViewHolder itemViewHolder, Object item,
-                                          RowPresenter.ViewHolder rowViewHolder, Row row) {
-                    if (item instanceof Action) {
-                        listener.onActionClicked((Action)item);
-                        if (mGlue.getOnItemViewClickedListener() != null) {
-                            mGlue.getOnItemViewClickedListener().onItemClicked(itemViewHolder,
-                                    item, rowViewHolder, row);
-                        }
-                    }
-                }
-            });
+            mActionClickedListener = listener;
         }
 
         @Override
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 48ca7f3..55ce89e 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/PlaybackControlSupportGlue.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/PlaybackControlSupportGlue.java
@@ -7,6 +7,7 @@
 import android.support.v17.leanback.widget.Action;
 import android.support.v17.leanback.widget.OnActionClickedListener;
 import android.support.v17.leanback.widget.OnItemViewClickedListener;
+import android.support.v17.leanback.widget.PlaybackRowPresenter;
 import android.support.v17.leanback.widget.Presenter;
 import android.support.v17.leanback.widget.Row;
 import android.support.v17.leanback.widget.RowPresenter;
@@ -138,10 +139,25 @@
 
     static final class PlaybackSupportGlueHostOld extends PlaybackGlueHost {
         final PlaybackOverlaySupportFragment mFragment;
-        PlaybackControlGlue mGlue;
+        PlaybackControlSupportGlue mGlue;
+        OnActionClickedListener mActionClickedListener;
 
         public PlaybackSupportGlueHostOld(PlaybackOverlaySupportFragment fragment) {
             mFragment = fragment;
+            mFragment.setOnItemViewClickedListener(new OnItemViewClickedListener() {
+                @Override
+                public void onItemClicked(Presenter.ViewHolder itemViewHolder, Object item,
+                                          RowPresenter.ViewHolder rowViewHolder, Row row) {
+                    if (item instanceof Action
+                            && rowViewHolder instanceof PlaybackRowPresenter.ViewHolder
+                            && mActionClickedListener != null) {
+                        mActionClickedListener.onActionClicked((Action) item);
+                    } else if (mGlue != null && mGlue.getOnItemViewClickedListener() != null) {
+                        mGlue.getOnItemViewClickedListener().onItemClicked(itemViewHolder,
+                                item, rowViewHolder, row);
+                    }
+                }
+            });
         }
 
         @Override
@@ -165,19 +181,7 @@
 
         @Override
         public void setOnActionClickedListener(final OnActionClickedListener listener) {
-            mFragment.setOnItemViewClickedListener(new OnItemViewClickedListener() {
-                @Override
-                public void onItemClicked(Presenter.ViewHolder itemViewHolder, Object item,
-                                          RowPresenter.ViewHolder rowViewHolder, Row row) {
-                    if (item instanceof Action) {
-                        listener.onActionClicked((Action)item);
-                        if (mGlue.mExternalOnItemViewClickedListener != null) {
-                            mGlue.mExternalOnItemViewClickedListener.onItemClicked(itemViewHolder,
-                                    item, rowViewHolder, row);
-                        }
-                    }
-                }
-            });
+            mActionClickedListener = listener;
         }
 
         @Override
diff --git a/v17/leanback/src/android/support/v17/leanback/app/PlaybackFragmentGlueHost.java b/v17/leanback/src/android/support/v17/leanback/app/PlaybackFragmentGlueHost.java
index d0acced..fdaa6ef 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/PlaybackFragmentGlueHost.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/PlaybackFragmentGlueHost.java
@@ -46,15 +46,19 @@
 
     @Override
     public void setOnActionClickedListener(final OnActionClickedListener listener) {
-        mFragment.setOnPlaybackItemViewClickedListener(new OnItemViewClickedListener() {
-            @Override
-            public void onItemClicked(Presenter.ViewHolder itemViewHolder, Object item,
-                                      RowPresenter.ViewHolder rowViewHolder, Row row) {
-                if (item instanceof Action) {
-                    listener.onActionClicked((Action)item);
+        if (listener == null) {
+            mFragment.setOnPlaybackItemViewClickedListener(null);
+        } else {
+            mFragment.setOnPlaybackItemViewClickedListener(new OnItemViewClickedListener() {
+                @Override
+                public void onItemClicked(Presenter.ViewHolder itemViewHolder, Object item,
+                                          RowPresenter.ViewHolder rowViewHolder, Row row) {
+                    if (item instanceof Action) {
+                        listener.onActionClicked((Action) item);
+                    }
                 }
-            }
-        });
+            });
+        }
     }
 
     @Override
diff --git a/v17/leanback/src/android/support/v17/leanback/app/PlaybackSupportFragmentGlueHost.java b/v17/leanback/src/android/support/v17/leanback/app/PlaybackSupportFragmentGlueHost.java
index 145bcbd..da644ae 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/PlaybackSupportFragmentGlueHost.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/PlaybackSupportFragmentGlueHost.java
@@ -49,15 +49,19 @@
 
     @Override
     public void setOnActionClickedListener(final OnActionClickedListener listener) {
-        mFragment.setOnPlaybackItemViewClickedListener(new OnItemViewClickedListener() {
-            @Override
-            public void onItemClicked(Presenter.ViewHolder itemViewHolder, Object item,
-                                      RowPresenter.ViewHolder rowViewHolder, Row row) {
-                if (item instanceof Action) {
-                    listener.onActionClicked((Action)item);
+        if (listener == null) {
+            mFragment.setOnPlaybackItemViewClickedListener(null);
+        } else {
+            mFragment.setOnPlaybackItemViewClickedListener(new OnItemViewClickedListener() {
+                @Override
+                public void onItemClicked(Presenter.ViewHolder itemViewHolder, Object item,
+                                          RowPresenter.ViewHolder rowViewHolder, Row row) {
+                    if (item instanceof Action) {
+                        listener.onActionClicked((Action) item);
+                    }
                 }
-            }
-        });
+            });
+        }
     }
 
     @Override
diff --git a/v17/leanback/src/android/support/v17/leanback/media/PlaybackControlGlue.java b/v17/leanback/src/android/support/v17/leanback/media/PlaybackControlGlue.java
index 6402fc6..bdd67fb 100644
--- a/v17/leanback/src/android/support/v17/leanback/media/PlaybackControlGlue.java
+++ b/v17/leanback/src/android/support/v17/leanback/media/PlaybackControlGlue.java
@@ -335,6 +335,7 @@
         // Add secondary actions
         ArrayObjectAdapter secondaryActions = new ArrayObjectAdapter(
                 new ControlButtonPresenterSelector());
+        onCreateSecondaryActions(secondaryActions);
         getControlsRow().setSecondaryActionsAdapter(secondaryActions);
         updateControlsRow();
     }
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 45b8802..f26c60c 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
@@ -19,20 +19,29 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
 
 import android.content.Context;
 import android.graphics.drawable.Drawable;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.MediumTest;
 import android.support.test.runner.AndroidJUnit4;
+import android.support.v17.leanback.widget.OnItemViewClickedListener;
 import android.support.v17.leanback.widget.PlaybackControlsRow;
+import android.support.v17.leanback.widget.PlaybackRowPresenter;
+import android.support.v17.leanback.widget.Presenter;
+import android.support.v17.leanback.widget.Row;
+import android.support.v17.leanback.widget.RowPresenter;
 import android.support.v17.leanback.widget.SparseArrayObjectAdapter;
 import android.view.KeyEvent;
+import android.view.View;
 
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.Mockito;
 
 @RunWith(AndroidJUnit4.class)
 @MediumTest
@@ -502,4 +511,50 @@
         assertEquals(PlaybackControlGlue.PLAYBACK_SPEED_NORMAL, glue.getCurrentSpeedId());
     }
 
+    @Test
+    public void testOnItemClickedListener() {
+        PlaybackControlsRow row = new PlaybackControlsRow();
+        final PlaybackOverlayFragment[] fragmentResult = new PlaybackOverlayFragment[1];
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                fragmentResult[0] = new PlaybackOverlayFragment();
+            }
+        });
+        PlaybackOverlayFragment fragment = fragmentResult[0];
+        glue.setHost(new PlaybackControlGlue.PlaybackGlueHostOld(fragment));
+        glue.setControlsRow(row);
+        SparseArrayObjectAdapter adapter = (SparseArrayObjectAdapter)
+                row.getPrimaryActionsAdapter();
+        PlaybackControlsRow.MultiAction playPause = (PlaybackControlsRow.MultiAction) adapter
+                .lookup(PlaybackControlGlue.ACTION_PLAY_PAUSE);
+        OnItemViewClickedListener listener = Mockito.mock(OnItemViewClickedListener.class);
+        glue.setOnItemViewClickedListener(listener);
+
+        // create fake row ViewHolder and fade item ViewHolder
+        View rowView = new View(context);
+        View view = new View(context);
+        PlaybackRowPresenter.ViewHolder rowVh = new PlaybackRowPresenter.ViewHolder(rowView);
+        Presenter.ViewHolder vh = new Presenter.ViewHolder(view);
+
+        // Initially media is paused
+        assertEquals(PlaybackControlGlue.PLAYBACK_SPEED_PAUSED, glue.getCurrentSpeedId());
+
+        // simulate a click inside PlaybackOverlayFragment's PlaybackRow.
+        fragment.getOnItemViewClickedListener().onItemClicked(vh, playPause, rowVh, row);
+        verify(listener, times(0)).onItemClicked(vh, playPause, rowVh, row);
+        assertEquals(PlaybackControlGlue.PLAYBACK_SPEED_NORMAL, glue.getCurrentSpeedId());
+
+        // simulate a click on object other than PlaybackRow.
+        Object regularItem = new Object();
+        Row regularRow = new Row();
+        RowPresenter.ViewHolder regularRowViewHolder = new RowPresenter.ViewHolder(rowView);
+        Presenter.ViewHolder regularViewHOlder = new Presenter.ViewHolder(view);
+        fragment.getOnItemViewClickedListener().onItemClicked(regularViewHOlder, regularItem,
+                regularRowViewHolder, regularRow);
+        verify(listener, times(1)).onItemClicked(regularViewHOlder, regularItem,
+                regularRowViewHolder, regularRow);
+        assertEquals(PlaybackControlGlue.PLAYBACK_SPEED_NORMAL, glue.getCurrentSpeedId());
+    }
+
 }
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 d3e3271..211b42c 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
@@ -22,20 +22,29 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
 
 import android.content.Context;
 import android.graphics.drawable.Drawable;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.MediumTest;
 import android.support.test.runner.AndroidJUnit4;
+import android.support.v17.leanback.widget.OnItemViewClickedListener;
 import android.support.v17.leanback.widget.PlaybackControlsRow;
+import android.support.v17.leanback.widget.PlaybackRowPresenter;
+import android.support.v17.leanback.widget.Presenter;
+import android.support.v17.leanback.widget.Row;
+import android.support.v17.leanback.widget.RowPresenter;
 import android.support.v17.leanback.widget.SparseArrayObjectAdapter;
 import android.view.KeyEvent;
+import android.view.View;
 
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.Mockito;
 
 @RunWith(AndroidJUnit4.class)
 @MediumTest
@@ -505,4 +514,50 @@
         assertEquals(PlaybackControlSupportGlue.PLAYBACK_SPEED_NORMAL, glue.getCurrentSpeedId());
     }
 
+    @Test
+    public void testOnItemClickedListener() {
+        PlaybackControlsRow row = new PlaybackControlsRow();
+        final PlaybackOverlayFragment[] fragmentResult = new PlaybackOverlayFragment[1];
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                fragmentResult[0] = new PlaybackOverlayFragment();
+            }
+        });
+        PlaybackOverlayFragment fragment = fragmentResult[0];
+        glue.setHost(new PlaybackControlSupportGlue.PlaybackGlueHostOld(fragment));
+        glue.setControlsRow(row);
+        SparseArrayObjectAdapter adapter = (SparseArrayObjectAdapter)
+                row.getPrimaryActionsAdapter();
+        PlaybackControlsRow.MultiAction playPause = (PlaybackControlsRow.MultiAction) adapter
+                .lookup(PlaybackControlSupportGlue.ACTION_PLAY_PAUSE);
+        OnItemViewClickedListener listener = Mockito.mock(OnItemViewClickedListener.class);
+        glue.setOnItemViewClickedListener(listener);
+
+        // create fake row ViewHolder and fade item ViewHolder
+        View rowView = new View(context);
+        View view = new View(context);
+        PlaybackRowPresenter.ViewHolder rowVh = new PlaybackRowPresenter.ViewHolder(rowView);
+        Presenter.ViewHolder vh = new Presenter.ViewHolder(view);
+
+        // Initially media is paused
+        assertEquals(PlaybackControlSupportGlue.PLAYBACK_SPEED_PAUSED, glue.getCurrentSpeedId());
+
+        // simulate a click inside PlaybackOverlayFragment's PlaybackRow.
+        fragment.getOnItemViewClickedListener().onItemClicked(vh, playPause, rowVh, row);
+        verify(listener, times(0)).onItemClicked(vh, playPause, rowVh, row);
+        assertEquals(PlaybackControlSupportGlue.PLAYBACK_SPEED_NORMAL, glue.getCurrentSpeedId());
+
+        // simulate a click on object other than PlaybackRow.
+        Object regularItem = new Object();
+        Row regularRow = new Row();
+        RowPresenter.ViewHolder regularRowViewHolder = new RowPresenter.ViewHolder(rowView);
+        Presenter.ViewHolder regularViewHOlder = new Presenter.ViewHolder(view);
+        fragment.getOnItemViewClickedListener().onItemClicked(regularViewHOlder, regularItem,
+                regularRowViewHolder, regularRow);
+        verify(listener, times(1)).onItemClicked(regularViewHOlder, regularItem,
+                regularRowViewHolder, regularRow);
+        assertEquals(PlaybackControlSupportGlue.PLAYBACK_SPEED_NORMAL, glue.getCurrentSpeedId());
+    }
+
 }