Merge "Fix setWillNotDraw in ScrimInsetsFrameLayout" into nyc-mr1-dev am: 0a67f0ce0d am: 3adb11fd53
am: 0890fa57c4

Change-Id: I9ce09897341458a1b4150c7f364a4a40ced14fda
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
new file mode 100644
index 0000000..4caef90
--- /dev/null
+++ b/PREUPLOAD.cfg
@@ -0,0 +1,6 @@
+[Hook Scripts]
+checkstyle_hook = ../../development/tools/checkstyle/checkstyle.py --sha ${PREUPLOAD_COMMIT}
+
+[Builtin Hooks]
+commit_msg_changeid_field = true
+commit_msg_test_field = true
diff --git a/api/current.txt b/api/current.txt
index d9d8f01..106f952 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -1228,6 +1228,7 @@
     method public final android.support.v17.leanback.widget.ObjectAdapter getAdapter();
     method public final android.support.v17.leanback.widget.PresenterSelector getPresenterSelector();
     method public int getSelectedPosition();
+    method public final android.support.v17.leanback.widget.VerticalGridView getVerticalGridView();
     method public void onTransitionEnd();
     method public boolean onTransitionPrepare();
     method public void onTransitionStart();
@@ -1242,6 +1243,7 @@
     method public final android.support.v17.leanback.widget.ObjectAdapter getAdapter();
     method public final android.support.v17.leanback.widget.PresenterSelector getPresenterSelector();
     method public int getSelectedPosition();
+    method public final android.support.v17.leanback.widget.VerticalGridView getVerticalGridView();
     method public void onTransitionEnd();
     method public boolean onTransitionPrepare();
     method public void onTransitionStart();
@@ -1304,6 +1306,7 @@
     method public int getBrandColor();
     method public android.support.v17.leanback.app.HeadersFragment getHeadersFragment();
     method public int getHeadersState();
+    method public android.app.Fragment getMainFragment();
     method public final android.support.v17.leanback.app.BrowseFragment.MainFragmentAdapterRegistry getMainFragmentRegistry();
     method public android.support.v17.leanback.widget.OnItemViewClickedListener getOnItemViewClickedListener();
     method public android.support.v17.leanback.widget.OnItemViewSelectedListener getOnItemViewSelectedListener();
@@ -1405,6 +1408,7 @@
     method public int getBrandColor();
     method public int getHeadersState();
     method public android.support.v17.leanback.app.HeadersSupportFragment getHeadersSupportFragment();
+    method public android.support.v4.app.Fragment getMainFragment();
     method public final android.support.v17.leanback.app.BrowseSupportFragment.MainFragmentAdapterRegistry getMainFragmentRegistry();
     method public android.support.v17.leanback.widget.OnItemViewClickedListener getOnItemViewClickedListener();
     method public android.support.v17.leanback.widget.OnItemViewSelectedListener getOnItemViewSelectedListener();
@@ -1496,11 +1500,25 @@
     method public abstract android.support.v17.leanback.app.BrowseSupportFragment.MainFragmentRowsAdapter getMainFragmentRowsAdapter();
   }
 
+  public final class DetailsBackgroundParallaxHelper {
+    method public android.graphics.drawable.Drawable getDrawable();
+    method public void setBitmap(android.graphics.Bitmap);
+    method public void setColor(int);
+  }
+
+  public static class DetailsBackgroundParallaxHelper.ParallaxBuilder {
+    ctor public DetailsBackgroundParallaxHelper.ParallaxBuilder(android.content.Context, android.support.v17.leanback.app.DetailsParallaxManager);
+    method public android.support.v17.leanback.app.DetailsBackgroundParallaxHelper build();
+    method public android.support.v17.leanback.app.DetailsBackgroundParallaxHelper.ParallaxBuilder setBitmapMinVerticalOffset(int);
+    method public android.support.v17.leanback.app.DetailsBackgroundParallaxHelper.ParallaxBuilder setColor(int);
+  }
+
   public class DetailsFragment extends android.support.v17.leanback.app.BrandedFragment {
     ctor public DetailsFragment();
     method protected java.lang.Object createEntranceTransition();
     method public android.support.v17.leanback.widget.ObjectAdapter getAdapter();
     method public android.support.v17.leanback.widget.BaseOnItemViewClickedListener getOnItemViewClickedListener();
+    method public android.support.v17.leanback.app.DetailsParallaxManager getParallaxManager();
     method public android.support.v17.leanback.app.RowsFragment getRowsFragment();
     method protected deprecated android.view.View inflateTitle(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle);
     method protected void onEntranceTransitionEnd();
@@ -1518,11 +1536,19 @@
     method protected void setupPresenter(android.support.v17.leanback.widget.Presenter);
   }
 
+  public class DetailsParallaxManager {
+    ctor public DetailsParallaxManager(android.support.v7.widget.RecyclerView);
+    method public android.support.v17.leanback.widget.ParallaxRecyclerViewSource.ChildPositionProperty getFrameBottom();
+    method public android.support.v17.leanback.widget.ParallaxRecyclerViewSource.ChildPositionProperty getFrameTop();
+    method public android.support.v17.leanback.widget.Parallax getParallax();
+  }
+
   public class DetailsSupportFragment extends android.support.v17.leanback.app.BrandedSupportFragment {
     ctor public DetailsSupportFragment();
     method protected java.lang.Object createEntranceTransition();
     method public android.support.v17.leanback.widget.ObjectAdapter getAdapter();
     method public android.support.v17.leanback.widget.BaseOnItemViewClickedListener getOnItemViewClickedListener();
+    method public android.support.v17.leanback.app.DetailsParallaxManager getParallaxManager();
     method public android.support.v17.leanback.app.RowsSupportFragment getRowsSupportFragment();
     method protected deprecated android.view.View inflateTitle(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle);
     method protected void onEntranceTransitionEnd();
@@ -1577,7 +1603,9 @@
     method public static int add(android.app.FragmentManager, android.support.v17.leanback.app.GuidedStepFragment);
     method public static int add(android.app.FragmentManager, android.support.v17.leanback.app.GuidedStepFragment, int);
     method public static int addAsRoot(android.app.Activity, android.support.v17.leanback.app.GuidedStepFragment, int);
+    method public void collapseAction(boolean);
     method public void collapseSubActions();
+    method public void expandAction(android.support.v17.leanback.widget.GuidedAction, boolean);
     method public void expandSubActions(android.support.v17.leanback.widget.GuidedAction);
     method public android.support.v17.leanback.widget.GuidedAction findActionById(long);
     method public int findActionPositionById(long);
@@ -1595,6 +1623,7 @@
     method public int getSelectedActionPosition();
     method public int getSelectedButtonActionPosition();
     method public int getUiStyle();
+    method public boolean isExpanded();
     method public boolean isFocusOutEndAllowed();
     method public boolean isFocusOutStartAllowed();
     method public boolean isSubActionsExpanded();
@@ -1634,7 +1663,9 @@
     method public static int add(android.support.v4.app.FragmentManager, android.support.v17.leanback.app.GuidedStepSupportFragment);
     method public static int add(android.support.v4.app.FragmentManager, android.support.v17.leanback.app.GuidedStepSupportFragment, int);
     method public static int addAsRoot(android.support.v4.app.FragmentActivity, android.support.v17.leanback.app.GuidedStepSupportFragment, int);
+    method public void collapseAction(boolean);
     method public void collapseSubActions();
+    method public void expandAction(android.support.v17.leanback.widget.GuidedAction, boolean);
     method public void expandSubActions(android.support.v17.leanback.widget.GuidedAction);
     method public android.support.v17.leanback.widget.GuidedAction findActionById(long);
     method public int findActionPositionById(long);
@@ -1652,6 +1683,7 @@
     method public int getSelectedActionPosition();
     method public int getSelectedButtonActionPosition();
     method public int getUiStyle();
+    method public boolean isExpanded();
     method public boolean isFocusOutEndAllowed();
     method public boolean isFocusOutStartAllowed();
     method public boolean isSubActionsExpanded();
@@ -1717,8 +1749,9 @@
   }
 
   public abstract class MediaControllerGlue extends android.support.v17.leanback.app.PlaybackControlGlue {
-    ctor public MediaControllerGlue(android.content.Context, android.support.v17.leanback.app.PlaybackOverlayFragment, int[]);
-    ctor public MediaControllerGlue(android.content.Context, android.support.v17.leanback.app.PlaybackOverlayFragment, int[], int[]);
+    ctor public deprecated MediaControllerGlue(android.content.Context, android.support.v17.leanback.app.PlaybackOverlayFragment, int[]);
+    ctor public deprecated MediaControllerGlue(android.content.Context, android.support.v17.leanback.app.PlaybackOverlayFragment, int[], int[]);
+    ctor public MediaControllerGlue(android.content.Context, android.support.v17.leanback.app.PlaybackGlue.PlaybackGlueHost, int[], int[]);
     method public void attachToMediaController(android.support.v4.media.session.MediaControllerCompat);
     method public void detach();
     method public int getCurrentPosition();
@@ -1773,25 +1806,25 @@
     method public final void setLogoResourceId(int);
   }
 
-  public abstract class PlaybackControlGlue implements android.support.v17.leanback.widget.OnActionClickedListener android.view.View.OnKeyListener {
+  public abstract class PlaybackControlGlue extends android.support.v17.leanback.app.PlaybackGlue implements android.support.v17.leanback.widget.OnActionClickedListener android.view.View.OnKeyListener {
     ctor public PlaybackControlGlue(android.content.Context, int[]);
     ctor public PlaybackControlGlue(android.content.Context, int[], int[]);
-    ctor public PlaybackControlGlue(android.content.Context, android.support.v17.leanback.app.PlaybackOverlayFragment, int[]);
-    ctor public PlaybackControlGlue(android.content.Context, android.support.v17.leanback.app.PlaybackOverlayFragment, int[], int[]);
+    ctor public deprecated PlaybackControlGlue(android.content.Context, android.support.v17.leanback.app.PlaybackOverlayFragment, int[]);
+    ctor public deprecated PlaybackControlGlue(android.content.Context, android.support.v17.leanback.app.PlaybackOverlayFragment, int[], int[]);
+    ctor public PlaybackControlGlue(android.content.Context, android.support.v17.leanback.app.PlaybackGlue.PlaybackGlueHost, int[], int[]);
     method public android.support.v17.leanback.widget.PlaybackControlsRowPresenter createControlsRowAndPresenter();
     method protected android.support.v17.leanback.widget.SparseArrayObjectAdapter createPrimaryActionsAdapter(android.support.v17.leanback.widget.PresenterSelector);
     method public void enableProgressUpdating(boolean);
-    method public android.content.Context getContext();
     method public android.support.v17.leanback.widget.PlaybackControlsRow getControlsRow();
     method public abstract int getCurrentPosition();
     method public abstract int getCurrentSpeedId();
     method public int[] getFastForwardSpeeds();
-    method public android.support.v17.leanback.app.PlaybackOverlayFragment getFragment();
+    method public deprecated android.support.v17.leanback.app.PlaybackOverlayFragment getFragment();
     method public abstract android.graphics.drawable.Drawable getMediaArt();
     method public abstract int getMediaDuration();
     method public abstract java.lang.CharSequence getMediaSubtitle();
     method public abstract java.lang.CharSequence getMediaTitle();
-    method public android.support.v17.leanback.widget.OnItemViewClickedListener getOnItemViewClickedListener();
+    method public deprecated android.support.v17.leanback.widget.OnItemViewClickedListener getOnItemViewClickedListener();
     method public int[] getRewindSpeeds();
     method public abstract long getSupportedActions();
     method public int getUpdatePeriod();
@@ -1828,80 +1861,85 @@
     field public static final int PLAYBACK_SPEED_PAUSED = 0; // 0x0
   }
 
-  public abstract class PlaybackControlSupportGlue implements android.support.v17.leanback.widget.OnActionClickedListener android.view.View.OnKeyListener {
+  public static abstract deprecated interface PlaybackControlGlue.InputEventHandler {
+    method public abstract boolean handleInputEvent(android.view.InputEvent);
+  }
+
+  public abstract deprecated class PlaybackControlSupportGlue extends android.support.v17.leanback.app.PlaybackControlGlue {
     ctor public PlaybackControlSupportGlue(android.content.Context, int[]);
     ctor public PlaybackControlSupportGlue(android.content.Context, int[], int[]);
     ctor public PlaybackControlSupportGlue(android.content.Context, android.support.v17.leanback.app.PlaybackOverlaySupportFragment, int[]);
     ctor public PlaybackControlSupportGlue(android.content.Context, android.support.v17.leanback.app.PlaybackOverlaySupportFragment, int[], int[]);
-    method public android.support.v17.leanback.widget.PlaybackControlsRowPresenter createControlsRowAndPresenter();
-    method protected android.support.v17.leanback.widget.SparseArrayObjectAdapter createPrimaryActionsAdapter(android.support.v17.leanback.widget.PresenterSelector);
-    method public void enableProgressUpdating(boolean);
-    method public android.content.Context getContext();
-    method public android.support.v17.leanback.widget.PlaybackControlsRow getControlsRow();
-    method public abstract int getCurrentPosition();
-    method public abstract int getCurrentSpeedId();
-    method public int[] getFastForwardSpeeds();
-    method public android.support.v17.leanback.app.PlaybackOverlaySupportFragment getFragment();
-    method public abstract android.graphics.drawable.Drawable getMediaArt();
-    method public abstract int getMediaDuration();
-    method public abstract java.lang.CharSequence getMediaSubtitle();
-    method public abstract java.lang.CharSequence getMediaTitle();
-    method public android.support.v17.leanback.widget.OnItemViewClickedListener getOnItemViewClickedListener();
-    method public int[] getRewindSpeeds();
-    method public abstract long getSupportedActions();
-    method public int getUpdatePeriod();
-    method public abstract boolean hasValidMedia();
-    method public boolean isFadingEnabled();
-    method public abstract boolean isMediaPlaying();
-    method public void onActionClicked(android.support.v17.leanback.widget.Action);
-    method public boolean onKey(android.view.View, int, android.view.KeyEvent);
-    method protected void onMetadataChanged();
-    method protected abstract void onRowChanged(android.support.v17.leanback.widget.PlaybackControlsRow);
-    method protected void onStateChanged();
-    method protected abstract void pausePlayback();
-    method public void setControlsRow(android.support.v17.leanback.widget.PlaybackControlsRow);
-    method public void setFadingEnabled(boolean);
-    method public deprecated void setOnItemViewClickedListener(android.support.v17.leanback.widget.OnItemViewClickedListener);
-    method protected abstract void skipToNext();
-    method protected abstract void skipToPrevious();
-    method protected abstract void startPlayback(int);
-    method public void updateProgress();
-    field public static final int ACTION_CUSTOM_LEFT_FIRST = 1; // 0x1
-    field public static final int ACTION_CUSTOM_RIGHT_FIRST = 4096; // 0x1000
-    field public static final int ACTION_FAST_FORWARD = 128; // 0x80
-    field public static final int ACTION_PLAY_PAUSE = 64; // 0x40
-    field public static final int ACTION_REWIND = 32; // 0x20
-    field public static final int ACTION_SKIP_TO_NEXT = 256; // 0x100
-    field public static final int ACTION_SKIP_TO_PREVIOUS = 16; // 0x10
-    field public static final int PLAYBACK_SPEED_FAST_L0 = 10; // 0xa
-    field public static final int PLAYBACK_SPEED_FAST_L1 = 11; // 0xb
-    field public static final int PLAYBACK_SPEED_FAST_L2 = 12; // 0xc
-    field public static final int PLAYBACK_SPEED_FAST_L3 = 13; // 0xd
-    field public static final int PLAYBACK_SPEED_FAST_L4 = 14; // 0xe
-    field public static final int PLAYBACK_SPEED_INVALID = -1; // 0xffffffff
-    field public static final int PLAYBACK_SPEED_NORMAL = 1; // 0x1
-    field public static final int PLAYBACK_SPEED_PAUSED = 0; // 0x0
   }
 
-  public class PlaybackOverlayFragment extends android.support.v17.leanback.app.DetailsFragment {
-    ctor public PlaybackOverlayFragment();
+  public class PlaybackFragment extends android.app.Fragment {
+    ctor public PlaybackFragment();
     method public void fadeOut();
+    method public android.support.v17.leanback.widget.ObjectAdapter getAdapter();
     method public int getBackgroundType();
-    method public android.support.v17.leanback.app.PlaybackOverlayFragment.OnFadeCompleteListener getFadeCompleteListener();
-    method public final android.support.v17.leanback.app.PlaybackOverlayFragment.InputEventHandler getInputEventHandler();
+    method public final android.view.View.OnKeyListener getEventHandler();
+    method public android.support.v17.leanback.app.PlaybackFragment.OnFadeCompleteListener getFadeCompleteListener();
     method public boolean isFadingEnabled();
+    method public void setAdapter(android.support.v17.leanback.widget.ObjectAdapter);
     method public void setBackgroundType(int);
-    method public void setFadeCompleteListener(android.support.v17.leanback.app.PlaybackOverlayFragment.OnFadeCompleteListener);
+    method public void setFadeCompleteListener(android.support.v17.leanback.app.PlaybackFragment.OnFadeCompleteListener);
     method public void setFadingEnabled(boolean);
-    method public final void setInputEventHandler(android.support.v17.leanback.app.PlaybackOverlayFragment.InputEventHandler);
+    method public void setOnItemViewClickedListener(android.support.v17.leanback.widget.BaseOnItemViewClickedListener);
+    method public final void setOnKeyInterceptListener(android.view.View.OnKeyListener);
+    method public void setOnPlaybackItemViewClickedListener(android.support.v17.leanback.widget.BaseOnItemViewClickedListener);
+    method public void setSelectedPosition(int);
+    method public void setSelectedPosition(int, boolean);
     method public void tickle();
     field public static final int BG_DARK = 1; // 0x1
     field public static final int BG_LIGHT = 2; // 0x2
     field public static final int BG_NONE = 0; // 0x0
   }
 
-  public static abstract interface PlaybackOverlayFragment.InputEventHandler {
-    method public abstract boolean handleInputEvent(android.view.InputEvent);
+  public static class PlaybackFragment.OnFadeCompleteListener {
+    ctor public PlaybackFragment.OnFadeCompleteListener();
+    method public void onFadeInComplete();
+    method public void onFadeOutComplete();
+  }
+
+  public final class PlaybackFragmentGlueHost extends android.support.v17.leanback.app.PlaybackGlue.PlaybackGlueHost {
+    ctor public PlaybackFragmentGlueHost(android.support.v17.leanback.app.PlaybackFragment);
+  }
+
+  public abstract class PlaybackGlue {
+    ctor public PlaybackGlue(android.content.Context);
+    method public android.content.Context getContext();
+    method public android.support.v17.leanback.app.PlaybackGlue.PlaybackGlueHost getHost();
+    method public void setHost(android.support.v17.leanback.app.PlaybackGlue.PlaybackGlueHost);
+    field protected android.support.v17.leanback.app.PlaybackGlue.PlaybackGlueHost mPlaybackGlueHost;
+  }
+
+  public static class PlaybackGlue.PlaybackGlueHost {
+    ctor public PlaybackGlue.PlaybackGlueHost();
+    method public void setFadingEnabled(boolean);
+    method public void setOnActionClickedListener(android.support.v17.leanback.widget.OnActionClickedListener);
+    method public void setOnKeyInterceptListener(android.view.View.OnKeyListener);
+  }
+
+  public deprecated class PlaybackOverlayFragment extends android.support.v17.leanback.app.DetailsFragment {
+    ctor public PlaybackOverlayFragment();
+    method public void fadeOut();
+    method public int getBackgroundType();
+    method public final android.support.v17.leanback.app.PlaybackControlGlue.InputEventHandler getEventHandler();
+    method public android.support.v17.leanback.app.PlaybackOverlayFragment.OnFadeCompleteListener getFadeCompleteListener();
+    method public final deprecated android.support.v17.leanback.app.PlaybackOverlayFragment.InputEventHandler getInputEventHandler();
+    method public boolean isFadingEnabled();
+    method public void setBackgroundType(int);
+    method public final void setEventHandler(android.support.v17.leanback.app.PlaybackControlGlue.InputEventHandler);
+    method public void setFadeCompleteListener(android.support.v17.leanback.app.PlaybackOverlayFragment.OnFadeCompleteListener);
+    method public void setFadingEnabled(boolean);
+    method public final deprecated void setInputEventHandler(android.support.v17.leanback.app.PlaybackOverlayFragment.InputEventHandler);
+    method public void tickle();
+    field public static final int BG_DARK = 1; // 0x1
+    field public static final int BG_LIGHT = 2; // 0x2
+    field public static final int BG_NONE = 0; // 0x0
+  }
+
+  public static abstract deprecated interface PlaybackOverlayFragment.InputEventHandler implements android.support.v17.leanback.app.PlaybackControlGlue.InputEventHandler {
   }
 
   public static class PlaybackOverlayFragment.OnFadeCompleteListener {
@@ -1910,25 +1948,26 @@
     method public void onFadeOutComplete();
   }
 
-  public class PlaybackOverlaySupportFragment extends android.support.v17.leanback.app.DetailsSupportFragment {
+  public deprecated class PlaybackOverlaySupportFragment extends android.support.v17.leanback.app.DetailsSupportFragment {
     ctor public PlaybackOverlaySupportFragment();
     method public void fadeOut();
     method public int getBackgroundType();
+    method public final android.support.v17.leanback.app.PlaybackControlGlue.InputEventHandler getEventHandler();
     method public android.support.v17.leanback.app.PlaybackOverlaySupportFragment.OnFadeCompleteListener getFadeCompleteListener();
-    method public final android.support.v17.leanback.app.PlaybackOverlaySupportFragment.InputEventHandler getInputEventHandler();
+    method public final deprecated android.support.v17.leanback.app.PlaybackOverlaySupportFragment.InputEventHandler getInputEventHandler();
     method public boolean isFadingEnabled();
     method public void setBackgroundType(int);
+    method public final void setEventHandler(android.support.v17.leanback.app.PlaybackControlGlue.InputEventHandler);
     method public void setFadeCompleteListener(android.support.v17.leanback.app.PlaybackOverlaySupportFragment.OnFadeCompleteListener);
     method public void setFadingEnabled(boolean);
-    method public final void setInputEventHandler(android.support.v17.leanback.app.PlaybackOverlaySupportFragment.InputEventHandler);
+    method public final deprecated void setInputEventHandler(android.support.v17.leanback.app.PlaybackOverlaySupportFragment.InputEventHandler);
     method public void tickle();
     field public static final int BG_DARK = 1; // 0x1
     field public static final int BG_LIGHT = 2; // 0x2
     field public static final int BG_NONE = 0; // 0x0
   }
 
-  public static abstract interface PlaybackOverlaySupportFragment.InputEventHandler {
-    method public abstract boolean handleInputEvent(android.view.InputEvent);
+  public static abstract deprecated interface PlaybackOverlaySupportFragment.InputEventHandler implements android.support.v17.leanback.app.PlaybackControlGlue.InputEventHandler {
   }
 
   public static class PlaybackOverlaySupportFragment.OnFadeCompleteListener {
@@ -1937,6 +1976,39 @@
     method public void onFadeOutComplete();
   }
 
+  public class PlaybackSupportFragment extends android.support.v4.app.Fragment {
+    ctor public PlaybackSupportFragment();
+    method public void fadeOut();
+    method public android.support.v17.leanback.widget.ObjectAdapter getAdapter();
+    method public int getBackgroundType();
+    method public final android.view.View.OnKeyListener getEventHandler();
+    method public android.support.v17.leanback.app.PlaybackSupportFragment.OnFadeCompleteListener getFadeCompleteListener();
+    method public boolean isFadingEnabled();
+    method public void setAdapter(android.support.v17.leanback.widget.ObjectAdapter);
+    method public void setBackgroundType(int);
+    method public void setFadeCompleteListener(android.support.v17.leanback.app.PlaybackSupportFragment.OnFadeCompleteListener);
+    method public void setFadingEnabled(boolean);
+    method public void setOnItemViewClickedListener(android.support.v17.leanback.widget.BaseOnItemViewClickedListener);
+    method public final void setOnKeyInterceptListener(android.view.View.OnKeyListener);
+    method public void setOnPlaybackItemViewClickedListener(android.support.v17.leanback.widget.BaseOnItemViewClickedListener);
+    method public void setSelectedPosition(int);
+    method public void setSelectedPosition(int, boolean);
+    method public void tickle();
+    field public static final int BG_DARK = 1; // 0x1
+    field public static final int BG_LIGHT = 2; // 0x2
+    field public static final int BG_NONE = 0; // 0x0
+  }
+
+  public static class PlaybackSupportFragment.OnFadeCompleteListener {
+    ctor public PlaybackSupportFragment.OnFadeCompleteListener();
+    method public void onFadeInComplete();
+    method public void onFadeOutComplete();
+  }
+
+  public final class PlaybackSupportFragmentGlueHost extends android.support.v17.leanback.app.PlaybackGlue.PlaybackGlueHost {
+    ctor public PlaybackSupportFragmentGlueHost(android.support.v17.leanback.app.PlaybackSupportFragment);
+  }
+
   public final class ProgressBarManager {
     ctor public ProgressBarManager();
     method public void disableProgressBar();
@@ -2012,6 +2084,8 @@
     method public void setBadgeDrawable(android.graphics.drawable.Drawable);
     method public void setOnItemViewClickedListener(android.support.v17.leanback.widget.OnItemViewClickedListener);
     method public void setOnItemViewSelectedListener(android.support.v17.leanback.widget.OnItemViewSelectedListener);
+    method public void setSearchAffordanceColors(android.support.v17.leanback.widget.SearchOrbView.Colors);
+    method public void setSearchAffordanceColorsInListening(android.support.v17.leanback.widget.SearchOrbView.Colors);
     method public void setSearchQuery(java.lang.String, boolean);
     method public void setSearchQuery(android.content.Intent, boolean);
     method public void setSearchResultProvider(android.support.v17.leanback.app.SearchFragment.SearchResultProvider);
@@ -2039,6 +2113,8 @@
     method public void setBadgeDrawable(android.graphics.drawable.Drawable);
     method public void setOnItemViewClickedListener(android.support.v17.leanback.widget.OnItemViewClickedListener);
     method public void setOnItemViewSelectedListener(android.support.v17.leanback.widget.OnItemViewSelectedListener);
+    method public void setSearchAffordanceColors(android.support.v17.leanback.widget.SearchOrbView.Colors);
+    method public void setSearchAffordanceColorsInListening(android.support.v17.leanback.widget.SearchOrbView.Colors);
     method public void setSearchQuery(java.lang.String, boolean);
     method public void setSearchQuery(android.content.Intent, boolean);
     method public void setSearchResultProvider(android.support.v17.leanback.app.SearchSupportFragment.SearchResultProvider);
@@ -2096,6 +2172,25 @@
 
 package android.support.v17.leanback.graphics {
 
+  public class BoundsRule {
+    ctor public BoundsRule();
+    method public static android.support.v17.leanback.graphics.BoundsRule.ValueRule absoluteValue(int);
+    method public void calculateBounds(android.graphics.Rect, android.graphics.Rect);
+    method public static android.support.v17.leanback.graphics.BoundsRule.ValueRule inheritFromParent(float);
+    method public static android.support.v17.leanback.graphics.BoundsRule.ValueRule inheritFromParentWithOffset(float, int);
+    field public android.support.v17.leanback.graphics.BoundsRule.ValueRule mBottom;
+    field public android.support.v17.leanback.graphics.BoundsRule.ValueRule mLeft;
+    field public android.support.v17.leanback.graphics.BoundsRule.ValueRule mRight;
+    field public android.support.v17.leanback.graphics.BoundsRule.ValueRule mTop;
+  }
+
+  public static final class BoundsRule.ValueRule {
+    method public int getAbsoluteValue();
+    method public float getFraction();
+    method public void setAbsoluteValue(int);
+    method public void setFraction(float);
+  }
+
   public final class ColorFilterCache {
     method public static android.support.v17.leanback.graphics.ColorFilterCache getColorFilterCache(int);
     method public android.graphics.ColorFilter getFilterForLevel(float);
@@ -2122,6 +2217,52 @@
     method public void setActiveLevel(float);
   }
 
+  public class CompositeDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Drawable.Callback {
+    ctor public CompositeDrawable();
+    method public void addChildDrawable(android.graphics.drawable.Drawable);
+    method public void draw(android.graphics.Canvas);
+    method public android.support.v17.leanback.graphics.CompositeDrawable.ChildDrawable getChildAt(int);
+    method public int getChildCount();
+    method public android.graphics.drawable.Drawable getDrawable(int);
+    method public int getOpacity();
+    method public void invalidateDrawable(android.graphics.drawable.Drawable);
+    method public void removeChild(int);
+    method public void removeDrawable(android.graphics.drawable.Drawable);
+    method public void scheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable, long);
+    method public void setAlpha(int);
+    method public void setColorFilter(android.graphics.ColorFilter);
+    method public void unscheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable);
+  }
+
+  public static final class CompositeDrawable.ChildDrawable {
+    ctor public CompositeDrawable.ChildDrawable(android.graphics.drawable.Drawable, android.support.v17.leanback.graphics.CompositeDrawable);
+    method public android.support.v17.leanback.graphics.BoundsRule getBoundsRule();
+    method public android.graphics.drawable.Drawable getDrawable();
+    method public void recomputeBounds();
+    field public static final android.util.Property<android.support.v17.leanback.graphics.CompositeDrawable.ChildDrawable, java.lang.Integer> BOTTOM_ABSOLUTE;
+    field public static final android.util.Property<android.support.v17.leanback.graphics.CompositeDrawable.ChildDrawable, java.lang.Float> BOTTOM_FRACTION;
+    field public static final android.util.Property<android.support.v17.leanback.graphics.CompositeDrawable.ChildDrawable, java.lang.Integer> LEFT_ABSOLUTE;
+    field public static final android.util.Property<android.support.v17.leanback.graphics.CompositeDrawable.ChildDrawable, java.lang.Float> LEFT_FRACTION;
+    field public static final android.util.Property<android.support.v17.leanback.graphics.CompositeDrawable.ChildDrawable, java.lang.Integer> RIGHT_ABSOLUTE;
+    field public static final android.util.Property<android.support.v17.leanback.graphics.CompositeDrawable.ChildDrawable, java.lang.Float> RIGHT_FRACTION;
+    field public static final android.util.Property<android.support.v17.leanback.graphics.CompositeDrawable.ChildDrawable, java.lang.Integer> TOP_ABSOLUTE;
+    field public static final android.util.Property<android.support.v17.leanback.graphics.CompositeDrawable.ChildDrawable, java.lang.Float> TOP_FRACTION;
+  }
+
+  public class FitWidthBitmapDrawable extends android.graphics.drawable.Drawable {
+    ctor public FitWidthBitmapDrawable();
+    method public void draw(android.graphics.Canvas);
+    method public android.graphics.Bitmap getBitmap();
+    method public int getOpacity();
+    method public android.graphics.Rect getSource();
+    method public int getVerticalOffset();
+    method public void setAlpha(int);
+    method public void setBitmap(android.graphics.Bitmap);
+    method public void setColorFilter(android.graphics.ColorFilter);
+    method public void setSource(android.graphics.Rect);
+    method public void setVerticalOffset(int);
+  }
+
 }
 
 package android.support.v17.leanback.system {
@@ -2249,11 +2390,11 @@
     ctor public BaseCardView(android.content.Context, android.util.AttributeSet);
     ctor public BaseCardView(android.content.Context, android.util.AttributeSet, int);
     method public int getCardType();
-    method public int getExtraVisibility();
+    method public deprecated int getExtraVisibility();
     method public int getInfoVisibility();
     method public boolean isSelectedAnimationDelayed();
     method public void setCardType(int);
-    method public void setExtraVisibility(int);
+    method public deprecated void setExtraVisibility(int);
     method public void setInfoVisibility(int);
     method public void setSelectedAnimationDelayed(boolean);
     field public static final int CARD_REGION_VISIBLE_ACTIVATED = 1; // 0x1
@@ -2623,12 +2764,17 @@
 
   public class GuidedActionsStylist implements android.support.v17.leanback.widget.FragmentAnimationProvider {
     ctor public GuidedActionsStylist();
+    method public void collapseAction(boolean);
+    method public void expandAction(android.support.v17.leanback.widget.GuidedAction, boolean);
     method public android.support.v17.leanback.widget.VerticalGridView getActionsGridView();
     method public android.support.v17.leanback.widget.GuidedAction getExpandedAction();
     method public int getItemViewType(android.support.v17.leanback.widget.GuidedAction);
     method public android.support.v17.leanback.widget.VerticalGridView getSubActionsGridView();
+    method public final boolean isBackKeyToCollapseActivatorView();
+    method public final boolean isBackKeyToCollapseSubActions();
     method public boolean isButtonActions();
     method public boolean isExpandTransitionSupported();
+    method public boolean isExpanded();
     method public boolean isInExpandTransition();
     method public boolean isSubActionsExpanded();
     method public void onAnimateItemChecked(android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder, boolean);
@@ -2643,7 +2789,8 @@
     method public android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder onCreateViewHolder(android.view.ViewGroup);
     method public android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder onCreateViewHolder(android.view.ViewGroup, int);
     method public void onDestroyView();
-    method protected void onEditingModeChange(android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder, android.support.v17.leanback.widget.GuidedAction, boolean);
+    method protected deprecated void onEditingModeChange(android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder, android.support.v17.leanback.widget.GuidedAction, boolean);
+    method protected void onEditingModeChange(android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder, boolean, boolean);
     method public void onImeAppearing(java.util.List<android.animation.Animator>);
     method public void onImeDisappearing(java.util.List<android.animation.Animator>);
     method public int onProvideItemLayoutId();
@@ -2652,10 +2799,11 @@
     method public boolean onUpdateActivatorView(android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder, android.support.v17.leanback.widget.GuidedAction);
     method public void onUpdateExpandedViewHolder(android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder);
     method public void setAsButtonActions();
-    method public void setEditingMode(android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder, android.support.v17.leanback.widget.GuidedAction, boolean);
-    method public void setExpandedViewHolder(android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder);
+    method public final void setBackKeyToCollapseActivatorView(boolean);
+    method public final void setBackKeyToCollapseSubActions(boolean);
+    method public deprecated void setExpandedViewHolder(android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder);
     method protected void setupImeOptions(android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder, android.support.v17.leanback.widget.GuidedAction);
-    method public void startExpandedTransition(android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder);
+    method public deprecated void startExpandedTransition(android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder);
     field public static final int VIEW_TYPE_DATE_PICKER = 1; // 0x1
     field public static final int VIEW_TYPE_DEFAULT = 0; // 0x0
   }
@@ -2709,9 +2857,11 @@
     ctor public HeaderItem(long, java.lang.String);
     ctor public HeaderItem(java.lang.String);
     method public java.lang.CharSequence getContentDescription();
+    method public java.lang.CharSequence getDescription();
     method public final long getId();
     method public final java.lang.String getName();
     method public void setContentDescription(java.lang.CharSequence);
+    method public void setDescription(java.lang.CharSequence);
   }
 
   public class HorizontalGridView extends android.support.v7.widget.RecyclerView {
@@ -2996,6 +3146,7 @@
   public abstract class OnChildViewHolderSelectedListener {
     ctor public OnChildViewHolderSelectedListener();
     method public void onChildViewHolderSelected(android.support.v7.widget.RecyclerView, android.support.v7.widget.RecyclerView.ViewHolder, int, int);
+    method public void onChildViewHolderSelectedAndPositioned(android.support.v7.widget.RecyclerView, android.support.v7.widget.RecyclerView.ViewHolder, int, int);
   }
 
   public abstract interface OnItemViewClickedListener implements android.support.v17.leanback.widget.BaseOnItemViewClickedListener {
@@ -3009,25 +3160,169 @@
     method public final boolean isRenderedAsRowView();
   }
 
+  public final class Parallax {
+    ctor public Parallax();
+    method public void addEffect(android.support.v17.leanback.widget.ParallaxEffect);
+    method public android.support.v17.leanback.widget.ParallaxEffect addEffect(android.support.v17.leanback.widget.ParallaxSource.IntPropertyKeyValue...);
+    method public android.support.v17.leanback.widget.ParallaxEffect addEffect(android.support.v17.leanback.widget.ParallaxSource.FloatPropertyKeyValue...);
+    method public java.util.List<android.support.v17.leanback.widget.ParallaxEffect> getEffects();
+    method public android.support.v17.leanback.widget.ParallaxSource getSource();
+    method public void removeAllEffects();
+    method public void removeEffect(android.support.v17.leanback.widget.ParallaxEffect);
+    method public void setSource(android.support.v17.leanback.widget.ParallaxSource);
+  }
+
+  public abstract class ParallaxEffect<ParallaxEffectT extends android.support.v17.leanback.widget.ParallaxEffect, PropertyKeyValueT extends android.support.v17.leanback.widget.ParallaxSource.PropertyKeyValue> {
+    ctor public ParallaxEffect();
+    method public final void addTarget(android.support.v17.leanback.widget.ParallaxTarget);
+    method protected abstract float calculateFraction(android.support.v17.leanback.widget.ParallaxSource);
+    method public final java.util.List<PropertyKeyValueT> getPropertyRanges();
+    method public final java.util.List<android.support.v17.leanback.widget.ParallaxTarget> getTargets();
+    method public final void performMapping(android.support.v17.leanback.widget.ParallaxSource);
+    method public final void removeTarget(android.support.v17.leanback.widget.ParallaxTarget);
+    method public final void setPropertyRanges(PropertyKeyValueT...);
+    method public final android.support.v17.leanback.widget.ParallaxEffect target(android.support.v17.leanback.widget.ParallaxTarget);
+    method public final android.support.v17.leanback.widget.ParallaxEffect target(java.lang.Object, android.animation.PropertyValuesHolder);
+  }
+
+  public static final class ParallaxEffect.FloatEffect extends android.support.v17.leanback.widget.ParallaxEffect {
+    ctor public ParallaxEffect.FloatEffect();
+    method protected float calculateFraction(android.support.v17.leanback.widget.ParallaxSource);
+  }
+
+  public static final class ParallaxEffect.IntEffect extends android.support.v17.leanback.widget.ParallaxEffect {
+    ctor public ParallaxEffect.IntEffect();
+    method protected float calculateFraction(android.support.v17.leanback.widget.ParallaxSource);
+  }
+
+  public class ParallaxRecyclerViewSource extends android.support.v17.leanback.widget.ParallaxSource.IntSource {
+    ctor public ParallaxRecyclerViewSource(android.support.v7.widget.RecyclerView);
+    method public android.support.v17.leanback.widget.ParallaxRecyclerViewSource.ChildPositionProperty createProperty(java.lang.String, int);
+    method public int getMaxParentVisibleSize();
+    method public void setListener(android.support.v17.leanback.widget.ParallaxSource.Listener);
+  }
+
+  public static final class ParallaxRecyclerViewSource.ChildPositionProperty extends android.support.v17.leanback.widget.ParallaxSource.IntProperty {
+    method public android.support.v17.leanback.widget.ParallaxRecyclerViewSource.ChildPositionProperty adapterPosition(int);
+    method public android.support.v17.leanback.widget.ParallaxRecyclerViewSource.ChildPositionProperty fraction(float);
+    method public int getAdapterPosition();
+    method public float getFraction();
+    method public int getOffset();
+    method public int getViewId();
+    method public android.support.v17.leanback.widget.ParallaxRecyclerViewSource.ChildPositionProperty offset(int);
+    method public android.support.v17.leanback.widget.ParallaxRecyclerViewSource.ChildPositionProperty viewId(int);
+  }
+
+  public abstract class ParallaxSource<PropertyT extends android.util.Property> {
+    ctor public ParallaxSource();
+    method public abstract PropertyT addProperty(java.lang.String);
+    method public abstract PropertyT createProperty(java.lang.String, int);
+    method public final java.util.List<PropertyT> getProperties();
+    method public abstract void setListener(android.support.v17.leanback.widget.ParallaxSource.Listener);
+    method public abstract void verifyProperties() throws java.lang.IllegalStateException;
+  }
+
+  public static class ParallaxSource.FloatProperty extends android.util.Property {
+    ctor public ParallaxSource.FloatProperty(java.lang.String, int);
+    method public final android.support.v17.leanback.widget.ParallaxSource.FloatPropertyKeyValue at(float, float);
+    method public final android.support.v17.leanback.widget.ParallaxSource.FloatPropertyKeyValue atAbsolute(float);
+    method public final android.support.v17.leanback.widget.ParallaxSource.FloatPropertyKeyValue atFraction(float);
+    method public final java.lang.Float get(android.support.v17.leanback.widget.ParallaxSource.FloatSource);
+    method public final int getIndex();
+    method public final void set(android.support.v17.leanback.widget.ParallaxSource.FloatSource, java.lang.Float);
+    field public static final float UNKNOWN_AFTER = 3.4028235E38f;
+    field public static final float UNKNOWN_BEFORE = -3.4028235E38f;
+  }
+
+  public static class ParallaxSource.FloatPropertyKeyValue extends android.support.v17.leanback.widget.ParallaxSource.PropertyKeyValue {
+    ctor public ParallaxSource.FloatPropertyKeyValue(android.support.v17.leanback.widget.ParallaxSource.FloatProperty, float);
+    ctor public ParallaxSource.FloatPropertyKeyValue(android.support.v17.leanback.widget.ParallaxSource.FloatProperty, float, float);
+    method public final float getKeyValue(android.support.v17.leanback.widget.ParallaxSource.FloatSource);
+  }
+
+  public static abstract class ParallaxSource.FloatSource<FloatPropertyT extends android.support.v17.leanback.widget.ParallaxSource.FloatProperty> extends android.support.v17.leanback.widget.ParallaxSource {
+    ctor public ParallaxSource.FloatSource();
+    method public final FloatPropertyT addProperty(java.lang.String);
+    method public abstract float getMaxParentVisibleSize();
+    method public final float getPropertyValue(int);
+    method public final void setPropertyValue(int, float);
+    method public final void verifyProperties() throws java.lang.IllegalStateException;
+  }
+
+  public static class ParallaxSource.IntProperty extends android.util.Property {
+    ctor public ParallaxSource.IntProperty(java.lang.String, int);
+    method public final android.support.v17.leanback.widget.ParallaxSource.IntPropertyKeyValue at(int, float);
+    method public final android.support.v17.leanback.widget.ParallaxSource.IntPropertyKeyValue atAbsolute(int);
+    method public final android.support.v17.leanback.widget.ParallaxSource.IntPropertyKeyValue atFraction(float);
+    method public final java.lang.Integer get(android.support.v17.leanback.widget.ParallaxSource.IntSource);
+    method public final int getIndex();
+    method public final void set(android.support.v17.leanback.widget.ParallaxSource.IntSource, java.lang.Integer);
+    field public static final int UNKNOWN_AFTER = 2147483647; // 0x7fffffff
+    field public static final int UNKNOWN_BEFORE = -2147483648; // 0x80000000
+  }
+
+  public static class ParallaxSource.IntPropertyKeyValue extends android.support.v17.leanback.widget.ParallaxSource.PropertyKeyValue {
+    ctor public ParallaxSource.IntPropertyKeyValue(android.support.v17.leanback.widget.ParallaxSource.IntProperty, int);
+    ctor public ParallaxSource.IntPropertyKeyValue(android.support.v17.leanback.widget.ParallaxSource.IntProperty, int, float);
+    method public final int getKeyValue(android.support.v17.leanback.widget.ParallaxSource.IntSource);
+  }
+
+  public static abstract class ParallaxSource.IntSource<IntPropertyT extends android.support.v17.leanback.widget.ParallaxSource.IntProperty> extends android.support.v17.leanback.widget.ParallaxSource {
+    ctor public ParallaxSource.IntSource();
+    method public final IntPropertyT addProperty(java.lang.String);
+    method public abstract int getMaxParentVisibleSize();
+    method public final int getPropertyValue(int);
+    method public final void setPropertyValue(int, int);
+    method public final void verifyProperties() throws java.lang.IllegalStateException;
+  }
+
+  public static abstract class ParallaxSource.Listener {
+    ctor public ParallaxSource.Listener();
+    method public void onPropertiesChanged(android.support.v17.leanback.widget.ParallaxSource);
+  }
+
+  public static class ParallaxSource.PropertyKeyValue<PropertyT extends android.util.Property> {
+    ctor public ParallaxSource.PropertyKeyValue(PropertyT);
+    method public PropertyT getProperty();
+  }
+
+  public abstract class ParallaxTarget {
+    ctor public ParallaxTarget();
+    method public abstract float getFraction();
+    method public abstract void update(float);
+  }
+
+  public static final class ParallaxTarget.PropertyValuesHolderTarget extends android.support.v17.leanback.widget.ParallaxTarget {
+    ctor public ParallaxTarget.PropertyValuesHolderTarget(java.lang.Object, android.animation.PropertyValuesHolder);
+    method public float getFraction();
+    method public void update(float);
+  }
+
   public class PlaybackControlsRow extends android.support.v17.leanback.widget.Row {
     ctor public PlaybackControlsRow(java.lang.Object);
     ctor public PlaybackControlsRow();
     method public android.support.v17.leanback.widget.Action getActionForKeyCode(int);
     method public android.support.v17.leanback.widget.Action getActionForKeyCode(android.support.v17.leanback.widget.ObjectAdapter, int);
     method public int getBufferedProgress();
+    method public long getBufferedProgressLong();
     method public int getCurrentTime();
+    method public long getCurrentTimeLong();
     method public final android.graphics.drawable.Drawable getImageDrawable();
     method public final java.lang.Object getItem();
     method public final android.support.v17.leanback.widget.ObjectAdapter getPrimaryActionsAdapter();
     method public final android.support.v17.leanback.widget.ObjectAdapter getSecondaryActionsAdapter();
     method public int getTotalTime();
+    method public long getTotalTimeLong();
     method public void setBufferedProgress(int);
+    method public void setBufferedProgressLong(long);
     method public void setCurrentTime(int);
+    method public void setCurrentTimeLong(long);
     method public final void setImageBitmap(android.content.Context, android.graphics.Bitmap);
     method public final void setImageDrawable(android.graphics.drawable.Drawable);
     method public final void setPrimaryActionsAdapter(android.support.v17.leanback.widget.ObjectAdapter);
     method public final void setSecondaryActionsAdapter(android.support.v17.leanback.widget.ObjectAdapter);
     method public void setTotalTime(int);
+    method public void setTotalTimeLong(long);
   }
 
   public static class PlaybackControlsRow.ClosedCaptioningAction extends android.support.v17.leanback.widget.PlaybackControlsRow.MultiAction {
@@ -3120,7 +3415,7 @@
     ctor public PlaybackControlsRow.ThumbsUpAction(android.content.Context);
   }
 
-  public class PlaybackControlsRowPresenter extends android.support.v17.leanback.widget.RowPresenter {
+  public class PlaybackControlsRowPresenter extends android.support.v17.leanback.widget.PlaybackRowPresenter {
     ctor public PlaybackControlsRowPresenter(android.support.v17.leanback.widget.Presenter);
     ctor public PlaybackControlsRowPresenter();
     method public boolean areSecondaryActionsHidden();
@@ -3136,10 +3431,19 @@
     method public void showPrimaryActions(android.support.v17.leanback.widget.PlaybackControlsRowPresenter.ViewHolder);
   }
 
-  public class PlaybackControlsRowPresenter.ViewHolder extends android.support.v17.leanback.widget.RowPresenter.ViewHolder {
+  public class PlaybackControlsRowPresenter.ViewHolder extends android.support.v17.leanback.widget.PlaybackRowPresenter.ViewHolder {
     field public final android.support.v17.leanback.widget.Presenter.ViewHolder mDescriptionViewHolder;
   }
 
+  public abstract class PlaybackRowPresenter extends android.support.v17.leanback.widget.RowPresenter {
+    ctor public PlaybackRowPresenter();
+    method public void onReappear(android.support.v17.leanback.widget.RowPresenter.ViewHolder);
+  }
+
+  public static class PlaybackRowPresenter.ViewHolder extends android.support.v17.leanback.widget.RowPresenter.ViewHolder {
+    ctor public PlaybackRowPresenter.ViewHolder(android.view.View);
+  }
+
   public abstract class Presenter implements android.support.v17.leanback.widget.FacetProvider {
     ctor public Presenter();
     method protected static void cancelAnimationsRecursive(android.view.View);
@@ -3287,6 +3591,8 @@
     method public boolean isRecognizing();
     method public void setBadgeDrawable(android.graphics.drawable.Drawable);
     method public void setPermissionListener(android.support.v17.leanback.widget.SearchBar.SearchBarPermissionListener);
+    method public void setSearchAffordanceColors(android.support.v17.leanback.widget.SearchOrbView.Colors);
+    method public void setSearchAffordanceColorsInListening(android.support.v17.leanback.widget.SearchOrbView.Colors);
     method public void setSearchBarListener(android.support.v17.leanback.widget.SearchBar.SearchBarListener);
     method public void setSearchQuery(java.lang.String);
     method public void setSpeechRecognitionCallback(android.support.v17.leanback.widget.SpeechRecognitionCallback);
@@ -3438,6 +3744,8 @@
     ctor public SpeechOrbView(android.content.Context);
     ctor public SpeechOrbView(android.content.Context, android.util.AttributeSet);
     ctor public SpeechOrbView(android.content.Context, android.util.AttributeSet, int);
+    method public void setListeningOrbColors(android.support.v17.leanback.widget.SearchOrbView.Colors);
+    method public void setNotListeningOrbColors(android.support.v17.leanback.widget.SearchOrbView.Colors);
     method public void setSoundLevel(int);
     method public void showListening();
     method public void showNotListening();
@@ -3649,6 +3957,7 @@
 
   public abstract class LeanbackPreferenceFragment extends android.support.v17.preference.BaseLeanbackPreferenceFragment {
     ctor public LeanbackPreferenceFragment();
+    method public void setTitle(java.lang.CharSequence);
   }
 
   public abstract class LeanbackSettingsFragment extends android.app.Fragment implements android.support.v14.preference.PreferenceFragment.OnPreferenceDisplayDialogCallback android.support.v14.preference.PreferenceFragment.OnPreferenceStartFragmentCallback android.support.v14.preference.PreferenceFragment.OnPreferenceStartScreenCallback {
@@ -5306,9 +5615,11 @@
     method public java.util.List<android.support.v4.media.session.MediaSessionCompat.QueueItem> getQueue();
     method public java.lang.CharSequence getQueueTitle();
     method public int getRatingType();
+    method public int getRepeatMode();
     method public android.app.PendingIntent getSessionActivity();
     method public android.support.v4.media.session.MediaSessionCompat.Token getSessionToken();
     method public android.support.v4.media.session.MediaControllerCompat.TransportControls getTransportControls();
+    method public boolean isShuffleModeEnabled();
     method public void registerCallback(android.support.v4.media.session.MediaControllerCompat.Callback);
     method public void registerCallback(android.support.v4.media.session.MediaControllerCompat.Callback, android.os.Handler);
     method public void sendCommand(java.lang.String, android.os.Bundle, android.os.ResultReceiver);
@@ -5325,8 +5636,10 @@
     method public void onPlaybackStateChanged(android.support.v4.media.session.PlaybackStateCompat);
     method public void onQueueChanged(java.util.List<android.support.v4.media.session.MediaSessionCompat.QueueItem>);
     method public void onQueueTitleChanged(java.lang.CharSequence);
+    method public void onRepeatModeChanged(int);
     method public void onSessionDestroyed();
     method public void onSessionEvent(java.lang.String, android.os.Bundle);
+    method public void onShuffleModeChanged(boolean);
   }
 
   public static final class MediaControllerCompat.PlaybackInfo {
@@ -5355,6 +5668,8 @@
     method public abstract void sendCustomAction(android.support.v4.media.session.PlaybackStateCompat.CustomAction, android.os.Bundle);
     method public abstract void sendCustomAction(java.lang.String, android.os.Bundle);
     method public abstract void setRating(android.support.v4.media.RatingCompat);
+    method public abstract void setRepeatMode(int);
+    method public abstract void setShuffleModeEnabled(boolean);
     method public abstract void skipToNext();
     method public abstract void skipToPrevious();
     method public abstract void skipToQueueItem(long);
@@ -5388,7 +5703,9 @@
     method public void setQueue(java.util.List<android.support.v4.media.session.MediaSessionCompat.QueueItem>);
     method public void setQueueTitle(java.lang.CharSequence);
     method public void setRatingType(int);
+    method public void setRepeatMode(int);
     method public void setSessionActivity(android.app.PendingIntent);
+    method public void setShuffleModeEnabled(boolean);
     field public static final int FLAG_HANDLES_MEDIA_BUTTONS = 1; // 0x1
     field public static final int FLAG_HANDLES_TRANSPORT_CONTROLS = 2; // 0x2
   }
@@ -5411,6 +5728,8 @@
     method public void onRewind();
     method public void onSeekTo(long);
     method public void onSetRating(android.support.v4.media.RatingCompat);
+    method public void onSetRepeatMode(int);
+    method public void onSetShuffleModeEnabled(boolean);
     method public void onSkipToNext();
     method public void onSkipToPrevious();
     method public void onSkipToQueueItem(long);
@@ -5486,12 +5805,17 @@
     field public static final long ACTION_REWIND = 8L; // 0x8L
     field public static final long ACTION_SEEK_TO = 256L; // 0x100L
     field public static final long ACTION_SET_RATING = 128L; // 0x80L
+    field public static final long ACTION_SET_REPEAT_MODE = 262144L; // 0x40000L
+    field public static final long ACTION_SET_SHUFFLE_MODE_ENABLED = 524288L; // 0x80000L
     field public static final long ACTION_SKIP_TO_NEXT = 32L; // 0x20L
     field public static final long ACTION_SKIP_TO_PREVIOUS = 16L; // 0x10L
     field public static final long ACTION_SKIP_TO_QUEUE_ITEM = 4096L; // 0x1000L
     field public static final long ACTION_STOP = 1L; // 0x1L
     field public static final android.os.Parcelable.Creator<android.support.v4.media.session.PlaybackStateCompat> CREATOR;
     field public static final long PLAYBACK_POSITION_UNKNOWN = -1L; // 0xffffffffffffffffL
+    field public static final int REPEAT_MODE_ALL = 2; // 0x2
+    field public static final int REPEAT_MODE_NONE = 0; // 0x0
+    field public static final int REPEAT_MODE_ONE = 1; // 0x1
     field public static final int STATE_BUFFERING = 6; // 0x6
     field public static final int STATE_CONNECTING = 8; // 0x8
     field public static final int STATE_ERROR = 7; // 0x7
@@ -5575,6 +5899,7 @@
   public class BuildCompat {
     method public static boolean isAtLeastN();
     method public static boolean isAtLeastNMR1();
+    method public static boolean isAtLeastO();
   }
 
   public final class CancellationSignal {
@@ -5765,6 +6090,31 @@
     method public java.util.Collection<V> values();
   }
 
+  public final class ArraySet<E> implements java.util.Collection java.util.Set {
+    ctor public ArraySet();
+    ctor public ArraySet(int);
+    ctor public ArraySet(android.support.v4.util.ArraySet<E>);
+    method public boolean add(E);
+    method public void addAll(android.support.v4.util.ArraySet<? extends E>);
+    method public boolean addAll(java.util.Collection<? extends E>);
+    method public void clear();
+    method public boolean contains(java.lang.Object);
+    method public boolean containsAll(java.util.Collection<?>);
+    method public void ensureCapacity(int);
+    method public int indexOf(java.lang.Object);
+    method public boolean isEmpty();
+    method public java.util.Iterator<E> iterator();
+    method public boolean remove(java.lang.Object);
+    method public boolean removeAll(android.support.v4.util.ArraySet<? extends E>);
+    method public boolean removeAll(java.util.Collection<?>);
+    method public E removeAt(int);
+    method public boolean retainAll(java.util.Collection<?>);
+    method public int size();
+    method public java.lang.Object[] toArray();
+    method public <T> T[] toArray(T[]);
+    method public E valueAt(int);
+  }
+
   public class AtomicFile {
     ctor public AtomicFile(java.io.File);
     method public void delete();
@@ -7887,7 +8237,7 @@
     method public boolean showDialog();
   }
 
-  public class MediaRouteChooserDialog extends android.app.Dialog {
+  public class MediaRouteChooserDialog extends android.support.v7.app.AppCompatDialog {
     ctor public MediaRouteChooserDialog(android.content.Context);
     ctor public MediaRouteChooserDialog(android.content.Context, int);
     method public android.support.v7.media.MediaRouteSelector getRouteSelector();
@@ -8778,6 +9128,7 @@
     method public android.support.v7.preference.PreferenceManager.OnDisplayPreferenceDialogListener getOnDisplayPreferenceDialogListener();
     method public android.support.v7.preference.PreferenceManager.OnNavigateToScreenListener getOnNavigateToScreenListener();
     method public android.support.v7.preference.PreferenceManager.OnPreferenceTreeClickListener getOnPreferenceTreeClickListener();
+    method public android.support.v7.preference.PreferenceManager.PreferenceComparisonCallback getPreferenceComparisonCallback();
     method public android.support.v7.preference.PreferenceScreen getPreferenceScreen();
     method public android.content.SharedPreferences getSharedPreferences();
     method public int getSharedPreferencesMode();
@@ -8789,6 +9140,7 @@
     method public void setOnDisplayPreferenceDialogListener(android.support.v7.preference.PreferenceManager.OnDisplayPreferenceDialogListener);
     method public void setOnNavigateToScreenListener(android.support.v7.preference.PreferenceManager.OnNavigateToScreenListener);
     method public void setOnPreferenceTreeClickListener(android.support.v7.preference.PreferenceManager.OnPreferenceTreeClickListener);
+    method public void setPreferenceComparisonCallback(android.support.v7.preference.PreferenceManager.PreferenceComparisonCallback);
     method public boolean setPreferences(android.support.v7.preference.PreferenceScreen);
     method public void setSharedPreferencesMode(int);
     method public void setSharedPreferencesName(java.lang.String);
@@ -8810,6 +9162,18 @@
     method public abstract boolean onPreferenceTreeClick(android.support.v7.preference.Preference);
   }
 
+  public static abstract class PreferenceManager.PreferenceComparisonCallback {
+    ctor public PreferenceManager.PreferenceComparisonCallback();
+    method public abstract boolean arePreferenceContentsTheSame(android.support.v7.preference.Preference, android.support.v7.preference.Preference);
+    method public abstract boolean arePreferenceItemsTheSame(android.support.v7.preference.Preference, android.support.v7.preference.Preference);
+  }
+
+  public static class PreferenceManager.SimplePreferenceComparisonCallback extends android.support.v7.preference.PreferenceManager.PreferenceComparisonCallback {
+    ctor public PreferenceManager.SimplePreferenceComparisonCallback();
+    method public boolean arePreferenceContentsTheSame(android.support.v7.preference.Preference, android.support.v7.preference.Preference);
+    method public boolean arePreferenceItemsTheSame(android.support.v7.preference.Preference, android.support.v7.preference.Preference);
+  }
+
   public final class PreferenceScreen extends android.support.v7.preference.PreferenceGroup {
     method public void setShouldUseGeneratedIds(boolean);
     method public boolean shouldUseGeneratedIds();
@@ -9564,6 +9928,7 @@
     method public void setScrollingTouchSlop(int);
     method public void setViewCacheExtension(android.support.v7.widget.RecyclerView.ViewCacheExtension);
     method public void smoothScrollBy(int, int);
+    method public void smoothScrollBy(int, int, android.view.animation.Interpolator);
     method public void smoothScrollToPosition(int);
     method public void stopScroll();
     method public void swapAdapter(android.support.v7.widget.RecyclerView.Adapter, boolean);
@@ -9880,6 +10245,7 @@
     ctor public RecyclerView.RecycledViewPool();
     method public void clear();
     method public android.support.v7.widget.RecyclerView.ViewHolder getRecycledView(int);
+    method public int getRecycledViewCount(int);
     method public void putRecycledView(android.support.v7.widget.RecyclerView.ViewHolder);
     method public void setMaxRecycledViews(int, int);
   }
diff --git a/build.gradle b/build.gradle
index 0145e20..1442e38 100644
--- a/build.gradle
+++ b/build.gradle
@@ -14,6 +14,7 @@
         maven { url "../../prebuilts/maven_repo/android" }
     }
     dependencies {
+        // Keep gradle plugin version in sync with ub_supportlib-master manifest.
         classpath 'com.android.tools.build:gradle:2.2.0'
     }
 }
diff --git a/buildSrc/studioCompat.gradle b/buildSrc/studioCompat.gradle
index 1712bda..f845af1 100644
--- a/buildSrc/studioCompat.gradle
+++ b/buildSrc/studioCompat.gradle
@@ -44,7 +44,7 @@
                 new ApiModule("api21",21),
                 new ApiModule("api22",22),
                 new ApiModule("api23",23),
-                new ApiModule("api24", ApiModule.CURRENT)
+                new ApiModule("api24",24)
             ],
             dependencies : [":support-annotations"],
             folder : "compat",
@@ -58,7 +58,8 @@
                         new ApiModule("api21",21),
                         new ApiModule("api22",22),
                         new ApiModule("api23",23),
-                        new ApiModule("api24", ApiModule.CURRENT)
+                        new ApiModule("api24",24),
+                        new ApiModule("api25",ApiModule.CURRENT)
                 ],
                 dependencies : [":support-compat"],
                 folder : "media-compat",
@@ -73,7 +74,7 @@
                         new ApiModule("api20",20),
                         new ApiModule("api21",21),
                         new ApiModule("api23",23),
-                        new ApiModule("api24", ApiModule.CURRENT)
+                        new ApiModule("api24",24)
                 ],
                 dependencies : [":support-compat"],
                 folder : "core-utils",
@@ -118,7 +119,7 @@
                 new ApiModule("jellybean", 16),
                 new ApiModule("jellybean-mr1", 17),
                 new ApiModule("jellybean-mr2", 18),
-                new ApiModule("api24", ApiModule.CURRENT)
+                new ApiModule("api24",24)
             ],
             folder : "v7/mediarouter",
             moduleName : "support-mediarouter-v7"
diff --git a/compat/Android.mk b/compat/Android.mk
index 8fea612..3e1a2a6 100644
--- a/compat/Android.mk
+++ b/compat/Android.mk
@@ -171,7 +171,7 @@
 # A helper sub-library that makes direct use of V24 APIs.
 include $(CLEAR_VARS)
 LOCAL_MODULE := android-support-compat-api24
-LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
+LOCAL_SDK_VERSION := 24
 LOCAL_SRC_FILES := $(call all-java-files-under, api24)
 LOCAL_STATIC_JAVA_LIBRARIES := android-support-compat-api23
 LOCAL_JAVA_LANGUAGE_VERSION := 1.7
diff --git a/compat/gingerbread/android/support/v4/os/BuildCompat.java b/compat/gingerbread/android/support/v4/os/BuildCompat.java
index 3c73e4d..d406caf 100644
--- a/compat/gingerbread/android/support/v4/os/BuildCompat.java
+++ b/compat/gingerbread/android/support/v4/os/BuildCompat.java
@@ -45,4 +45,14 @@
     public static boolean isAtLeastNMR1() {
         return VERSION.SDK_INT >= 25;
     }
+
+    /**
+     * Check if the device is running on the Android O release or newer.
+     *
+     * @return {@code true} if O APIs are available for use
+     */
+    public static boolean isAtLeastO() {
+        return !"REL".equals(VERSION.CODENAME)
+                && "O".compareTo(VERSION.CODENAME) <= 0;
+    }
 }
diff --git a/compat/java/android/support/v4/util/ArraySet.java b/compat/java/android/support/v4/util/ArraySet.java
new file mode 100644
index 0000000..d03dfd1
--- /dev/null
+++ b/compat/java/android/support/v4/util/ArraySet.java
@@ -0,0 +1,784 @@
+/*
+ * 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 android.support.v4.util;
+
+import android.util.Log;
+
+import java.lang.reflect.Array;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * ArraySet is a generic set data structure that is designed to be more memory efficient than a
+ * traditional {@link java.util.HashSet}.  The design is very similar to
+ * {@link ArrayMap}, with all of the caveats described there.  This implementation is
+ * separate from ArrayMap, however, so the Object array contains only one item for each
+ * entry in the set (instead of a pair for a mapping).
+ *
+ * <p>Note that this implementation is not intended to be appropriate for data structures
+ * that may contain large numbers of items.  It is generally slower than a traditional
+ * HashSet, since lookups require a binary search and adds and removes require inserting
+ * and deleting entries in the array.  For containers holding up to hundreds of items,
+ * the performance difference is not significant, less than 50%.</p>
+ *
+ * <p>Because this container is intended to better balance memory use, unlike most other
+ * standard Java containers it will shrink its array as items are removed from it.  Currently
+ * you have no control over this shrinking -- if you set a capacity and then remove an
+ * item, it may reduce the capacity to better match the current size.  In the future an
+ * explicit call to set the capacity should turn off this aggressive shrinking behavior.</p>
+ */
+public final class ArraySet<E> implements Collection<E>, Set<E> {
+    private static final boolean DEBUG = false;
+    private static final String TAG = "ArraySet";
+    private static final int[] INT = new int[0];
+    private static final Object[] OBJECT = new Object[0];
+
+    /**
+     * The minimum amount by which the capacity of a ArraySet will increase.
+     * This is tuned to be relatively space-efficient.
+     */
+    private static final int BASE_SIZE = 4;
+
+    /**
+     * Maximum number of entries to have in array caches.
+     */
+    private static final int CACHE_SIZE = 10;
+
+    /**
+     * Caches of small array objects to avoid spamming garbage.  The cache
+     * Object[] variable is a pointer to a linked list of array objects.
+     * The first entry in the array is a pointer to the next array in the
+     * list; the second entry is a pointer to the int[] hash code array for it.
+     */
+    static Object[] sBaseCache;
+    static int sBaseCacheSize;
+    static Object[] sTwiceBaseCache;
+    static int sTwiceBaseCacheSize;
+
+    final boolean mIdentityHashCode;
+    int[] mHashes;
+    Object[] mArray;
+    int mSize;
+    MapCollections<E, E> mCollections;
+
+    private int indexOf(Object key, int hash) {
+        final int N = mSize;
+
+        // Important fast case: if nothing is in here, nothing to look for.
+        if (N == 0) {
+            return ~0;
+        }
+
+        int index = ContainerHelpers.binarySearch(mHashes, N, hash);
+
+        // If the hash code wasn't found, then we have no entry for this key.
+        if (index < 0) {
+            return index;
+        }
+
+        // If the key at the returned index matches, that's what we want.
+        if (key.equals(mArray[index])) {
+            return index;
+        }
+
+        // Search for a matching key after the index.
+        int end;
+        for (end = index + 1; end < N && mHashes[end] == hash; end++) {
+            if (key.equals(mArray[end])) return end;
+        }
+
+        // Search for a matching key before the index.
+        for (int i = index - 1; i >= 0 && mHashes[i] == hash; i--) {
+            if (key.equals(mArray[i])) return i;
+        }
+
+        // Key not found -- return negative value indicating where a
+        // new entry for this key should go.  We use the end of the
+        // hash chain to reduce the number of array entries that will
+        // need to be copied when inserting.
+        return ~end;
+    }
+
+    private int indexOfNull() {
+        final int N = mSize;
+
+        // Important fast case: if nothing is in here, nothing to look for.
+        if (N == 0) {
+            return ~0;
+        }
+
+        int index = ContainerHelpers.binarySearch(mHashes, N, 0);
+
+        // If the hash code wasn't found, then we have no entry for this key.
+        if (index < 0) {
+            return index;
+        }
+
+        // If the key at the returned index matches, that's what we want.
+        if (null == mArray[index]) {
+            return index;
+        }
+
+        // Search for a matching key after the index.
+        int end;
+        for (end = index + 1; end < N && mHashes[end] == 0; end++) {
+            if (null == mArray[end]) return end;
+        }
+
+        // Search for a matching key before the index.
+        for (int i = index - 1; i >= 0 && mHashes[i] == 0; i--) {
+            if (null == mArray[i]) return i;
+        }
+
+        // Key not found -- return negative value indicating where a
+        // new entry for this key should go.  We use the end of the
+        // hash chain to reduce the number of array entries that will
+        // need to be copied when inserting.
+        return ~end;
+    }
+
+    private void allocArrays(final int size) {
+        if (size == (BASE_SIZE * 2)) {
+            synchronized (ArraySet.class) {
+                if (sTwiceBaseCache != null) {
+                    final Object[] array = sTwiceBaseCache;
+                    mArray = array;
+                    sTwiceBaseCache = (Object[]) array[0];
+                    mHashes = (int[]) array[1];
+                    array[0] = array[1] = null;
+                    sTwiceBaseCacheSize--;
+                    if (DEBUG) {
+                        Log.d(TAG, "Retrieving 2x cache " + mHashes + " now have "
+                                + sTwiceBaseCacheSize + " entries");
+                    }
+                    return;
+                }
+            }
+        } else if (size == BASE_SIZE) {
+            synchronized (ArraySet.class) {
+                if (sBaseCache != null) {
+                    final Object[] array = sBaseCache;
+                    mArray = array;
+                    sBaseCache = (Object[]) array[0];
+                    mHashes = (int[]) array[1];
+                    array[0] = array[1] = null;
+                    sBaseCacheSize--;
+                    if (DEBUG) {
+                        Log.d(TAG, "Retrieving 1x cache " + mHashes + " now have " + sBaseCacheSize
+                                + " entries");
+                    }
+                    return;
+                }
+            }
+        }
+
+        mHashes = new int[size];
+        mArray = new Object[size];
+    }
+
+    private static void freeArrays(final int[] hashes, final Object[] array, final int size) {
+        if (hashes.length == (BASE_SIZE * 2)) {
+            synchronized (ArraySet.class) {
+                if (sTwiceBaseCacheSize < CACHE_SIZE) {
+                    array[0] = sTwiceBaseCache;
+                    array[1] = hashes;
+                    for (int i = size - 1; i >= 2; i--) {
+                        array[i] = null;
+                    }
+                    sTwiceBaseCache = array;
+                    sTwiceBaseCacheSize++;
+                    if (DEBUG) {
+                        Log.d(TAG, "Storing 2x cache " + array + " now have " + sTwiceBaseCacheSize
+                                + " entries");
+                    }
+                }
+            }
+        } else if (hashes.length == BASE_SIZE) {
+            synchronized (ArraySet.class) {
+                if (sBaseCacheSize < CACHE_SIZE) {
+                    array[0] = sBaseCache;
+                    array[1] = hashes;
+                    for (int i = size - 1; i >= 2; i--) {
+                        array[i] = null;
+                    }
+                    sBaseCache = array;
+                    sBaseCacheSize++;
+                    if (DEBUG) {
+                        Log.d(TAG, "Storing 1x cache " + array + " now have "
+                                + sBaseCacheSize + " entries");
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Create a new empty ArraySet.  The default capacity of an array map is 0, and
+     * will grow once items are added to it.
+     */
+    public ArraySet() {
+        this(0, false);
+    }
+
+    /**
+     * Create a new ArraySet with a given initial capacity.
+     */
+    public ArraySet(int capacity) {
+        this(capacity, false);
+    }
+
+    /** {@hide} */
+    public ArraySet(int capacity, boolean identityHashCode) {
+        mIdentityHashCode = identityHashCode;
+        if (capacity == 0) {
+            mHashes = INT;
+            mArray = OBJECT;
+        } else {
+            allocArrays(capacity);
+        }
+        mSize = 0;
+    }
+
+    /**
+     * Create a new ArraySet with the mappings from the given ArraySet.
+     */
+    public ArraySet(ArraySet<E> set) {
+        this();
+        if (set != null) {
+            addAll(set);
+        }
+    }
+
+    /** {@hide} */
+    public ArraySet(Collection<E> set) {
+        this();
+        if (set != null) {
+            addAll(set);
+        }
+    }
+
+    /**
+     * Make the array map empty.  All storage is released.
+     */
+    @Override
+    public void clear() {
+        if (mSize != 0) {
+            freeArrays(mHashes, mArray, mSize);
+            mHashes = INT;
+            mArray = OBJECT;
+            mSize = 0;
+        }
+    }
+
+    /**
+     * Ensure the array map can hold at least <var>minimumCapacity</var>
+     * items.
+     */
+    public void ensureCapacity(int minimumCapacity) {
+        if (mHashes.length < minimumCapacity) {
+            final int[] ohashes = mHashes;
+            final Object[] oarray = mArray;
+            allocArrays(minimumCapacity);
+            if (mSize > 0) {
+                System.arraycopy(ohashes, 0, mHashes, 0, mSize);
+                System.arraycopy(oarray, 0, mArray, 0, mSize);
+            }
+            freeArrays(ohashes, oarray, mSize);
+        }
+    }
+
+    /**
+     * Check whether a value exists in the set.
+     *
+     * @param key The value to search for.
+     * @return Returns true if the value exists, else false.
+     */
+    @Override
+    public boolean contains(Object key) {
+        return indexOf(key) >= 0;
+    }
+
+    /**
+     * Returns the index of a value in the set.
+     *
+     * @param key The value to search for.
+     * @return Returns the index of the value if it exists, else a negative integer.
+     */
+    public int indexOf(Object key) {
+        return key == null ? indexOfNull()
+                : indexOf(key, mIdentityHashCode ? System.identityHashCode(key) : key.hashCode());
+    }
+
+    /**
+     * Return the value at the given index in the array.
+     * @param index The desired index, must be between 0 and {@link #size()}-1.
+     * @return Returns the value stored at the given index.
+     */
+    public E valueAt(int index) {
+        return (E) mArray[index];
+    }
+
+    /**
+     * Return true if the array map contains no items.
+     */
+    @Override
+    public boolean isEmpty() {
+        return mSize <= 0;
+    }
+
+    /**
+     * Adds the specified object to this set. The set is not modified if it
+     * already contains the object.
+     *
+     * @param value the object to add.
+     * @return {@code true} if this set is modified, {@code false} otherwise.
+     * @throws ClassCastException
+     *             when the class of the object is inappropriate for this set.
+     */
+    @Override
+    public boolean add(E value) {
+        final int hash;
+        int index;
+        if (value == null) {
+            hash = 0;
+            index = indexOfNull();
+        } else {
+            hash = mIdentityHashCode ? System.identityHashCode(value) : value.hashCode();
+            index = indexOf(value, hash);
+        }
+        if (index >= 0) {
+            return false;
+        }
+
+        index = ~index;
+        if (mSize >= mHashes.length) {
+            final int n = mSize >= (BASE_SIZE * 2) ? (mSize + (mSize >> 1))
+                    : (mSize >= BASE_SIZE ? (BASE_SIZE * 2) : BASE_SIZE);
+
+            if (DEBUG) Log.d(TAG, "add: grow from " + mHashes.length + " to " + n);
+
+            final int[] ohashes = mHashes;
+            final Object[] oarray = mArray;
+            allocArrays(n);
+
+            if (mHashes.length > 0) {
+                if (DEBUG) Log.d(TAG, "add: copy 0-" + mSize + " to 0");
+                System.arraycopy(ohashes, 0, mHashes, 0, ohashes.length);
+                System.arraycopy(oarray, 0, mArray, 0, oarray.length);
+            }
+
+            freeArrays(ohashes, oarray, mSize);
+        }
+
+        if (index < mSize) {
+            if (DEBUG) {
+                Log.d(TAG, "add: move " + index + "-" + (mSize - index) + " to " + (index + 1));
+            }
+            System.arraycopy(mHashes, index, mHashes, index + 1, mSize - index);
+            System.arraycopy(mArray, index, mArray, index + 1, mSize - index);
+        }
+
+        mHashes[index] = hash;
+        mArray[index] = value;
+        mSize++;
+        return true;
+    }
+
+    /**
+     * Special fast path for appending items to the end of the array without validation.
+     * The array must already be large enough to contain the item.
+     * @hide
+     */
+    public void append(E value) {
+        final int index = mSize;
+        final int hash = value == null ? 0
+                : (mIdentityHashCode ? System.identityHashCode(value) : value.hashCode());
+        if (index >= mHashes.length) {
+            throw new IllegalStateException("Array is full");
+        }
+        if (index > 0 && mHashes[index - 1] > hash) {
+            // Cannot optimize since it would break the sorted order - fallback to add()
+            if (DEBUG) {
+                RuntimeException e = new RuntimeException("here");
+                e.fillInStackTrace();
+                Log.w(TAG, "New hash " + hash
+                        + " is before end of array hash " + mHashes[index - 1]
+                        + " at index " + index, e);
+            }
+            add(value);
+            return;
+        }
+        mSize = index + 1;
+        mHashes[index] = hash;
+        mArray[index] = value;
+    }
+
+    /**
+     * Perform a {@link #add(Object)} of all values in <var>array</var>
+     * @param array The array whose contents are to be retrieved.
+     */
+    public void addAll(ArraySet<? extends E> array) {
+        final int N = array.mSize;
+        ensureCapacity(mSize + N);
+        if (mSize == 0) {
+            if (N > 0) {
+                System.arraycopy(array.mHashes, 0, mHashes, 0, N);
+                System.arraycopy(array.mArray, 0, mArray, 0, N);
+                mSize = N;
+            }
+        } else {
+            for (int i = 0; i < N; i++) {
+                add(array.valueAt(i));
+            }
+        }
+    }
+
+    /**
+     * Removes the specified object from this set.
+     *
+     * @param object the object to remove.
+     * @return {@code true} if this set was modified, {@code false} otherwise.
+     */
+    @Override
+    public boolean remove(Object object) {
+        final int index = indexOf(object);
+        if (index >= 0) {
+            removeAt(index);
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Remove the key/value mapping at the given index.
+     * @param index The desired index, must be between 0 and {@link #size()}-1.
+     * @return Returns the value that was stored at this index.
+     */
+    public E removeAt(int index) {
+        final Object old = mArray[index];
+        if (mSize <= 1) {
+            // Now empty.
+            if (DEBUG) Log.d(TAG, "remove: shrink from " + mHashes.length + " to 0");
+            freeArrays(mHashes, mArray, mSize);
+            mHashes = INT;
+            mArray = OBJECT;
+            mSize = 0;
+        } else {
+            if (mHashes.length > (BASE_SIZE * 2) && mSize < mHashes.length / 3) {
+                // Shrunk enough to reduce size of arrays.  We don't allow it to
+                // shrink smaller than (BASE_SIZE*2) to avoid flapping between
+                // that and BASE_SIZE.
+                final int n = mSize > (BASE_SIZE * 2) ? (mSize + (mSize >> 1)) : (BASE_SIZE * 2);
+
+                if (DEBUG) Log.d(TAG, "remove: shrink from " + mHashes.length + " to " + n);
+
+                final int[] ohashes = mHashes;
+                final Object[] oarray = mArray;
+                allocArrays(n);
+
+                mSize--;
+                if (index > 0) {
+                    if (DEBUG) Log.d(TAG, "remove: copy from 0-" + index + " to 0");
+                    System.arraycopy(ohashes, 0, mHashes, 0, index);
+                    System.arraycopy(oarray, 0, mArray, 0, index);
+                }
+                if (index < mSize) {
+                    if (DEBUG) {
+                        Log.d(TAG, "remove: copy from " + (index + 1) + "-" + mSize
+                                + " to " + index);
+                    }
+                    System.arraycopy(ohashes, index + 1, mHashes, index, mSize - index);
+                    System.arraycopy(oarray, index + 1, mArray, index, mSize - index);
+                }
+            } else {
+                mSize--;
+                if (index < mSize) {
+                    if (DEBUG) {
+                        Log.d(TAG, "remove: move " + (index + 1) + "-" + mSize + " to " + index);
+                    }
+                    System.arraycopy(mHashes, index + 1, mHashes, index, mSize - index);
+                    System.arraycopy(mArray, index + 1, mArray, index, mSize - index);
+                }
+                mArray[mSize] = null;
+            }
+        }
+        return (E) old;
+    }
+
+    /**
+     * Perform a {@link #remove(Object)} of all values in <var>array</var>
+     * @param array The array whose contents are to be removed.
+     */
+    public boolean removeAll(ArraySet<? extends E> array) {
+        // TODO: If array is sufficiently large, a marking approach might be beneficial. In a first
+        //       pass, use the property that the sets are sorted by hash to make this linear passes
+        //       (except for hash collisions, which means worst case still n*m), then do one
+        //       collection pass into a new array. This avoids binary searches and excessive memcpy.
+        final int N = array.mSize;
+
+        // Note: ArraySet does not make thread-safety guarantees. So instead of OR-ing together all
+        //       the single results, compare size before and after.
+        final int originalSize = mSize;
+        for (int i = 0; i < N; i++) {
+            remove(array.valueAt(i));
+        }
+        return originalSize != mSize;
+    }
+
+    /**
+     * Return the number of items in this array map.
+     */
+    @Override
+    public int size() {
+        return mSize;
+    }
+
+    @Override
+    public Object[] toArray() {
+        Object[] result = new Object[mSize];
+        System.arraycopy(mArray, 0, result, 0, mSize);
+        return result;
+    }
+
+    @Override
+    public <T> T[] toArray(T[] array) {
+        if (array.length < mSize) {
+            @SuppressWarnings("unchecked") T[] newArray =
+                    (T[]) Array.newInstance(array.getClass().getComponentType(), mSize);
+            array = newArray;
+        }
+        System.arraycopy(mArray, 0, array, 0, mSize);
+        if (array.length > mSize) {
+            array[mSize] = null;
+        }
+        return array;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This implementation returns false if the object is not a set, or
+     * if the sets have different sizes.  Otherwise, for each value in this
+     * set, it checks to make sure the value also exists in the other set.
+     * If any value doesn't exist, the method returns false; otherwise, it
+     * returns true.
+     */
+    @Override
+    public boolean equals(Object object) {
+        if (this == object) {
+            return true;
+        }
+        if (object instanceof Set) {
+            Set<?> set = (Set<?>) object;
+            if (size() != set.size()) {
+                return false;
+            }
+
+            try {
+                for (int i = 0; i < mSize; i++) {
+                    E mine = valueAt(i);
+                    if (!set.contains(mine)) {
+                        return false;
+                    }
+                }
+            } catch (NullPointerException ignored) {
+                return false;
+            } catch (ClassCastException ignored) {
+                return false;
+            }
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int hashCode() {
+        final int[] hashes = mHashes;
+        int result = 0;
+        for (int i = 0, s = mSize; i < s; i++) {
+            result += hashes[i];
+        }
+        return result;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This implementation composes a string by iterating over its values. If
+     * this set contains itself as a value, the string "(this Set)"
+     * will appear in its place.
+     */
+    @Override
+    public String toString() {
+        if (isEmpty()) {
+            return "{}";
+        }
+
+        StringBuilder buffer = new StringBuilder(mSize * 14);
+        buffer.append('{');
+        for (int i = 0; i < mSize; i++) {
+            if (i > 0) {
+                buffer.append(", ");
+            }
+            Object value = valueAt(i);
+            if (value != this) {
+                buffer.append(value);
+            } else {
+                buffer.append("(this Set)");
+            }
+        }
+        buffer.append('}');
+        return buffer.toString();
+    }
+
+    // ------------------------------------------------------------------------
+    // Interop with traditional Java containers.  Not as efficient as using
+    // specialized collection APIs.
+    // ------------------------------------------------------------------------
+
+    private MapCollections<E, E> getCollection() {
+        if (mCollections == null) {
+            mCollections = new MapCollections<E, E>() {
+                @Override
+                protected int colGetSize() {
+                    return mSize;
+                }
+
+                @Override
+                protected Object colGetEntry(int index, int offset) {
+                    return mArray[index];
+                }
+
+                @Override
+                protected int colIndexOfKey(Object key) {
+                    return indexOf(key);
+                }
+
+                @Override
+                protected int colIndexOfValue(Object value) {
+                    return indexOf(value);
+                }
+
+                @Override
+                protected Map<E, E> colGetMap() {
+                    throw new UnsupportedOperationException("not a map");
+                }
+
+                @Override
+                protected void colPut(E key, E value) {
+                    add(key);
+                }
+
+                @Override
+                protected E colSetValue(int index, E value) {
+                    throw new UnsupportedOperationException("not a map");
+                }
+
+                @Override
+                protected void colRemoveAt(int index) {
+                    removeAt(index);
+                }
+
+                @Override
+                protected void colClear() {
+                    clear();
+                }
+            };
+        }
+        return mCollections;
+    }
+
+    /**
+     * Return an {@link java.util.Iterator} over all values in the set.
+     *
+     * <p><b>Note:</b> this is a fairly inefficient way to access the array contents, it
+     * requires generating a number of temporary objects and allocates additional state
+     * information associated with the container that will remain for the life of the container.</p>
+     */
+    @Override
+    public Iterator<E> iterator() {
+        return getCollection().getKeySet().iterator();
+    }
+
+    /**
+     * Determine if the array set contains all of the values in the given collection.
+     * @param collection The collection whose contents are to be checked against.
+     * @return Returns true if this array set contains a value for every entry
+     * in <var>collection</var>, else returns false.
+     */
+    @Override
+    public boolean containsAll(Collection<?> collection) {
+        Iterator<?> it = collection.iterator();
+        while (it.hasNext()) {
+            if (!contains(it.next())) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Perform an {@link #add(Object)} of all values in <var>collection</var>
+     * @param collection The collection whose contents are to be retrieved.
+     */
+    @Override
+    public boolean addAll(Collection<? extends E> collection) {
+        ensureCapacity(mSize + collection.size());
+        boolean added = false;
+        for (E value : collection) {
+            added |= add(value);
+        }
+        return added;
+    }
+
+    /**
+     * Remove all values in the array set that exist in the given collection.
+     * @param collection The collection whose contents are to be used to remove values.
+     * @return Returns true if any values were removed from the array set, else false.
+     */
+    @Override
+    public boolean removeAll(Collection<?> collection) {
+        boolean removed = false;
+        for (Object value : collection) {
+            removed |= remove(value);
+        }
+        return removed;
+    }
+
+    /**
+     * Remove all values in the array set that do <b>not</b> exist in the given collection.
+     * @param collection The collection whose contents are to be used to determine which
+     * values to keep.
+     * @return Returns true if any values were removed from the array set, else false.
+     */
+    @Override
+    public boolean retainAll(Collection<?> collection) {
+        boolean removed = false;
+        for (int i = mSize - 1; i >= 0; i--) {
+            if (!collection.contains(mArray[i])) {
+                removeAt(i);
+                removed = true;
+            }
+        }
+        return removed;
+    }
+}
diff --git a/compat/java/android/support/v4/view/ViewCompat.java b/compat/java/android/support/v4/view/ViewCompat.java
index 9637e65..af621f5 100644
--- a/compat/java/android/support/v4/view/ViewCompat.java
+++ b/compat/java/android/support/v4/view/ViewCompat.java
@@ -1810,7 +1810,8 @@
     static class Api24ViewCompatImpl extends MarshmallowViewCompatImpl {
         @Override
         public void setPointerIcon(View view, PointerIconCompat pointerIconCompat) {
-            ViewCompatApi24.setPointerIcon(view, pointerIconCompat.getPointerIcon());
+            ViewCompatApi24.setPointerIcon(view,
+                    pointerIconCompat != null ? pointerIconCompat.getPointerIcon() : null);
         }
     }
 
diff --git a/compat/tests/java/android/support/v4/text/util/LinkifyCompatTest.java b/compat/tests/java/android/support/v4/text/util/LinkifyCompatTest.java
index 45779c7..96e6315 100644
--- a/compat/tests/java/android/support/v4/text/util/LinkifyCompatTest.java
+++ b/compat/tests/java/android/support/v4/text/util/LinkifyCompatTest.java
@@ -24,7 +24,7 @@
 
 import android.support.test.runner.AndroidJUnit4;
 import android.support.v4.util.PatternsCompat;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.test.suitebuilder.annotation.MediumTest;
 import android.text.Spannable;
 import android.text.SpannableString;
 import android.text.style.URLSpan;
@@ -39,8 +39,11 @@
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
+/**
+ * Test {@link LinkifyCompat}.
+ */
+@MediumTest
 @RunWith(AndroidJUnit4.class)
-@SmallTest
 public class LinkifyCompatTest {
     private static final Pattern LINKIFY_TEST_PATTERN = Pattern.compile(
             "(test:)?[a-zA-Z0-9]+(\\.pattern)?");
@@ -77,7 +80,7 @@
     };
 
     @Test
-    public void testAddLinks1() {
+    public void testAddLinksToSpannable() {
         // Verify URLs including the ones that have new gTLDs, and the
         // ones that look like gTLDs (and so are accepted by linkify)
         // and the ones that should not be linkified due to non-compliant
@@ -115,7 +118,7 @@
     }
 
     @Test
-    public void testAddLinks2() {
+    public void testAddLinksToSpannableWithScheme() {
         String text = "google.pattern, test:AZ0101.pattern";
 
         SpannableString spannable = new SpannableString(text);
@@ -126,7 +129,7 @@
         assertEquals("test:AZ0101.pattern", spans[1].getURL());
 
         try {
-            LinkifyCompat.addLinks((Spannable)null, LINKIFY_TEST_PATTERN, "Test:");
+            LinkifyCompat.addLinks((Spannable) null, LINKIFY_TEST_PATTERN, "Test:");
             fail("Should throw NullPointerException!");
         } catch (NullPointerException e) {
         }
@@ -198,7 +201,7 @@
     }
 
     @Test
-    public void testAddLinks4() {
+    public void testAddLinksPhoneNumbers() {
         String numbersInvalid = "123456789 not a phone number";
         String numbersUKLocal = "tel:(0812)1234560 (0812)1234561";
         String numbersUSLocal = "tel:(812)1234562 (812)123.4563 "
@@ -294,181 +297,180 @@
     // WEB_URLS Related Tests
 
     @Test
-    public void testAddLinks_doesNotAddLinksForUrlWithoutProtocolAndWithoutKnownTld()
-            throws Exception {
+    public void testAddLinks_doesNotAddLinksForUrlWithoutProtocolAndWithoutKnownTld() {
         Spannable spannable = new SpannableString("hey man.its me");
         boolean linksAdded = LinkifyCompat.addLinks(spannable, Linkify.ALL);
         assertFalse("Should not add link with unknown TLD", linksAdded);
     }
 
     @Test
-    public void testAddLinks_shouldNotAddEmailAddressAsUrl() throws Exception {
+    public void testAddLinks_shouldNotAddEmailAddressAsUrl() {
         String url = "name@gmail.com";
-        assertAddLinksWithWebUrlFails("Should not recognize email address as URL", url);
+        verifyAddLinksWithWebUrlFails("Should not recognize email address as URL", url);
     }
 
-    public void testAddLinks_acceptsUrlsWithCommasInRequestParameterValues() throws Exception {
+    @Test
+    public void testAddLinks_acceptsUrlsWithCommasInRequestParameterValues() {
         String url = "https://android.com/path?ll=37.4221,-122.0836&z=17&pll=37.4221,-122.0836";
-        assertAddLinksWithWebUrlSucceeds("Should accept commas", url);
+        verifyAddLinksWithWebUrlSucceeds("Should accept commas", url);
     }
 
     @Test
-    public void testAddLinks_addsLinksForUrlWithProtocolWithoutTld() throws Exception {
+    public void testAddLinks_addsLinksForUrlWithProtocolWithoutTld() {
         String url = "http://android/#notld///a/n/d/r/o/i/d&p1=1&p2=2";
-        assertAddLinksWithWebUrlSucceeds("Should accept URL starting with protocol but does not" +
-                " have TLD", url);
+        verifyAddLinksWithWebUrlSucceeds("Should accept URL starting with protocol but does not"
+                + " have TLD", url);
     }
 
     @Test
-    public void testAddLinks_matchesProtocolCaseInsensitive() throws Exception {
+    public void testAddLinks_matchesProtocolCaseInsensitive() {
         String url = "hTtP://android.com";
-        assertAddLinksWithWebUrlSucceeds("Protocol matching should be case insensitive", url);
+        verifyAddLinksWithWebUrlSucceeds("Protocol matching should be case insensitive", url);
     }
 
     @Test
-    public void testAddLinks_matchesValidUrlWithSchemeAndHostname() throws Exception {
+    public void testAddLinks_matchesValidUrlWithSchemeAndHostname() {
         String url = "http://www.android.com";
-        assertAddLinksWithWebUrlSucceeds("Should match valid URL with scheme and hostname", url);
+        verifyAddLinksWithWebUrlSucceeds("Should match valid URL with scheme and hostname", url);
     }
 
     @Test
-    public void testAddLinks_matchesValidUrlWithSchemeHostnameAndNewTld() throws Exception {
+    public void testAddLinks_matchesValidUrlWithSchemeHostnameAndNewTld() {
         String url = "http://www.android.me";
-        assertAddLinksWithWebUrlSucceeds("Should match valid URL with scheme hostname and new TLD",
+        verifyAddLinksWithWebUrlSucceeds("Should match valid URL with scheme hostname and new TLD",
                 url);
     }
 
     @Test
-    public void testAddLinks_matchesValidUrlWithHostnameAndNewTld() throws Exception {
+    public void testAddLinks_matchesValidUrlWithHostnameAndNewTld() {
         String url = "android.camera";
-        assertAddLinksWithWebUrlSucceeds("Should match valid URL with hostname and new TLD", url);
+        verifyAddLinksWithWebUrlSucceeds("Should match valid URL with hostname and new TLD", url);
     }
 
     @Test
-    public void testAddLinks_matchesPunycodeUrl() throws Exception {
+    public void testAddLinks_matchesPunycodeUrl() {
         String url = "http://xn--fsqu00a.xn--unup4y";
-        assertAddLinksWithWebUrlSucceeds("Should match Punycode URL", url);
+        verifyAddLinksWithWebUrlSucceeds("Should match Punycode URL", url);
     }
 
     @Test
-    public void testAddLinks_matchesPunycodeUrlWithoutProtocol() throws Exception {
+    public void testAddLinks_matchesPunycodeUrlWithoutProtocol() {
         String url = "xn--fsqu00a.xn--unup4y";
-        assertAddLinksWithWebUrlSucceeds("Should match Punycode URL without protocol", url);
+        verifyAddLinksWithWebUrlSucceeds("Should match Punycode URL without protocol", url);
     }
 
     @Test
-    public void testAddLinks_doesNotMatchPunycodeTldThatStartsWithDash() throws Exception {
+    public void testAddLinks_doesNotMatchPunycodeTldThatStartsWithDash() {
         String url = "xn--fsqu00a.-xn--unup4y";
-        assertAddLinksWithWebUrlFails("Should not match Punycode TLD that starts with dash", url);
+        verifyAddLinksWithWebUrlFails("Should not match Punycode TLD that starts with dash", url);
     }
 
     @Test
-    public void testAddLinks_partiallyMatchesPunycodeTldThatEndsWithDash() throws Exception {
+    public void testAddLinks_partiallyMatchesPunycodeTldThatEndsWithDash() {
         String url = "http://xn--fsqu00a.xn--unup4y-";
-        assertAddLinksWithWebUrlPartiallyMatches("Should partially match Punycode TLD that ends " +
-                "with dash", "http://xn--fsqu00a.xn--unup4y", url);
+        verifyAddLinksWithWebUrlPartiallyMatches("Should partially match Punycode TLD that ends "
+                + "with dash", "http://xn--fsqu00a.xn--unup4y", url);
     }
 
     @Test
-    public void testAddLinks_matchesUrlWithUnicodeDomainName() throws Exception {
+    public void testAddLinks_matchesUrlWithUnicodeDomainName() {
         String url = "http://\uD604\uAE08\uC601\uC218\uC99D.kr";
-        assertAddLinksWithWebUrlSucceeds("Should match URL with Unicode domain name", url);
+        verifyAddLinksWithWebUrlSucceeds("Should match URL with Unicode domain name", url);
     }
 
     @Test
-    public void testAddLinks_matchesUrlWithUnicodeDomainNameWithoutProtocol() throws Exception {
+    public void testAddLinks_matchesUrlWithUnicodeDomainNameWithoutProtocol() {
         String url = "\uD604\uAE08\uC601\uC218\uC99D.kr";
-        assertAddLinksWithWebUrlSucceeds("Should match URL without protocol and with Unicode " +
-                "domain name", url);
+        verifyAddLinksWithWebUrlSucceeds("Should match URL without protocol and with Unicode "
+                + "domain name", url);
     }
 
     @Test
-    public void testAddLinks_matchesUrlWithUnicodeDomainNameAndTld() throws Exception {
+    public void testAddLinks_matchesUrlWithUnicodeDomainNameAndTld() {
         String url = "\uB3C4\uBA54\uC778.\uD55C\uAD6D";
-        assertAddLinksWithWebUrlSucceeds("Should match URL with Unicode domain name and TLD", url);
+        verifyAddLinksWithWebUrlSucceeds("Should match URL with Unicode domain name and TLD", url);
     }
 
     @Test
-    public void testAddLinks_matchesUrlWithUnicodePath() throws Exception {
+    public void testAddLinks_matchesUrlWithUnicodePath() {
         String url = "http://android.com/\u2019/a";
-        assertAddLinksWithWebUrlSucceeds("Should match URL with Unicode path", url);
+        verifyAddLinksWithWebUrlSucceeds("Should match URL with Unicode path", url);
     }
 
     @Test
-    public void testAddLinks_matchesValidUrlWithPort() throws Exception {
+    public void testAddLinks_matchesValidUrlWithPort() {
         String url = "http://www.example.com:8080";
-        assertAddLinksWithWebUrlSucceeds("Should match URL with port", url);
+        verifyAddLinksWithWebUrlSucceeds("Should match URL with port", url);
     }
 
     @Test
-    public void testAddLinks_matchesUrlWithPortAndQuery() throws Exception {
+    public void testAddLinks_matchesUrlWithPortAndQuery() {
         String url = "http://www.example.com:8080/?foo=bar";
-        assertAddLinksWithWebUrlSucceeds("Should match URL with port and query", url);
+        verifyAddLinksWithWebUrlSucceeds("Should match URL with port and query", url);
     }
 
     @Test
-    public void testAddLinks_matchesUrlWithTilde() throws Exception {
+    public void testAddLinks_matchesUrlWithTilde() {
         String url = "http://www.example.com:8080/~user/?foo=bar";
-        assertAddLinksWithWebUrlSucceeds("Should match URL with tilde", url);
+        verifyAddLinksWithWebUrlSucceeds("Should match URL with tilde", url);
     }
 
     @Test
-    public void testAddLinks_matchesUrlStartingWithHttpAndDoesNotHaveTld() throws Exception {
+    public void testAddLinks_matchesUrlStartingWithHttpAndDoesNotHaveTld() {
         String url = "http://android/#notld///a/n/d/r/o/i/d&p1=1&p2=2";
-        assertAddLinksWithWebUrlSucceeds("Should match URL without a TLD and starting with http",
+        verifyAddLinksWithWebUrlSucceeds("Should match URL without a TLD and starting with http",
                 url);
     }
 
     @Test
-    public void testAddLinks_doesNotMatchUrlsWithoutProtocolAndWithUnknownTld() throws Exception {
+    public void testAddLinks_doesNotMatchUrlsWithoutProtocolAndWithUnknownTld() {
         String url = "thank.you";
-        assertAddLinksWithWebUrlFails("Should not match URL that does not start with a protocol " +
-                "and does not contain a known TLD", url);
+        verifyAddLinksWithWebUrlFails("Should not match URL that does not start with a protocol "
+                + "and does not contain a known TLD", url);
     }
 
     @Test
-    public void testAddLinks_matchesValidUrlWithEmoji() throws Exception {
+    public void testAddLinks_matchesValidUrlWithEmoji() {
         String url = "Thank\u263A.com";
-        assertAddLinksWithWebUrlSucceeds("Should match URL with emoji", url);
+        verifyAddLinksWithWebUrlSucceeds("Should match URL with emoji", url);
     }
 
     @Test
-    public void testAddLinks_doesNotMatchUrlsWithEmojiWithoutProtocolAndWithoutKnownTld()
-            throws Exception {
+    public void testAddLinks_doesNotMatchUrlsWithEmojiWithoutProtocolAndWithoutKnownTld() {
         String url = "Thank\u263A.you";
-        assertAddLinksWithWebUrlFails("Should not match URLs containing emoji and with unknown " +
-                "TLD", url);
+        verifyAddLinksWithWebUrlFails("Should not match URLs containing emoji and with unknown "
+                + "TLD", url);
     }
 
     @Test
-    public void testAddLinks_matchesDomainNameWithSurrogatePairs() throws Exception {
+    public void testAddLinks_matchesDomainNameWithSurrogatePairs() {
         String url = "android\uD83C\uDF38.com";
-        assertAddLinksWithWebUrlSucceeds("Should match domain name with Unicode surrogate pairs",
+        verifyAddLinksWithWebUrlSucceeds("Should match domain name with Unicode surrogate pairs",
                 url);
     }
 
     @Test
-    public void testAddLinks_matchesTldWithSurrogatePairs() throws Exception {
+    public void testAddLinks_matchesTldWithSurrogatePairs() {
         String url = "http://android.\uD83C\uDF38com";
-        assertAddLinksWithWebUrlSucceeds("Should match TLD with Unicode surrogate pairs", url);
+        verifyAddLinksWithWebUrlSucceeds("Should match TLD with Unicode surrogate pairs", url);
     }
 
     @Test
-    public void testAddLinks_doesNotMatchUrlWithExcludedSurrogate() throws Exception {
+    public void testAddLinks_doesNotMatchUrlWithExcludedSurrogate() {
         String url = "android\uD83F\uDFFE.com";
-        assertAddLinksWithWebUrlFails("Should not match URL with excluded Unicode surrogate" +
-                " pair",  url);
+        verifyAddLinksWithWebUrlFails("Should not match URL with excluded Unicode surrogate"
+                + " pair",  url);
     }
 
     @Test
-    public void testAddLinks_matchesPathWithSurrogatePairs() throws Exception {
+    public void testAddLinks_matchesPathWithSurrogatePairs() {
         String url = "http://android.com/path-with-\uD83C\uDF38?v=\uD83C\uDF38f";
-        assertAddLinksWithWebUrlSucceeds("Should match path and query with Unicode surrogate pairs",
+        verifyAddLinksWithWebUrlSucceeds("Should match path and query with Unicode surrogate pairs",
                 url);
     }
 
     @Test
-    public void testAddLinks__doesNotMatchUnicodeSpaces() throws Exception {
+    public void testAddLinks__doesNotMatchUnicodeSpaces() {
         String part1 = "http://and";
         String part2 = "roid.com";
         String[] emptySpaces = new String[]{
@@ -492,269 +494,260 @@
 
         for (String emptySpace : emptySpaces) {
             String url = part1 + emptySpace + part2;
-            assertAddLinksWithWebUrlPartiallyMatches("Should not include empty space with code: " +
-                    emptySpace.codePointAt(0), part1, url);
+            verifyAddLinksWithWebUrlPartiallyMatches("Should not include empty space with code: "
+                    + emptySpace.codePointAt(0), part1, url);
         }
     }
 
     @Test
-    public void testAddLinks_matchesDomainNameWithDash() throws Exception {
+    public void testAddLinks_matchesDomainNameWithDash() {
         String url = "http://a-nd.r-oid.com";
-        assertAddLinksWithWebUrlSucceeds("Should match domain name with '-'", url);
+        verifyAddLinksWithWebUrlSucceeds("Should match domain name with '-'", url);
 
         url = "a-nd.r-oid.com";
-        assertAddLinksWithWebUrlSucceeds("Should match domain name with '-'", url);
+        verifyAddLinksWithWebUrlSucceeds("Should match domain name with '-'", url);
     }
 
     @Test
-    public void testAddLinks_matchesDomainNameWithUnderscore() throws Exception {
+    public void testAddLinks_matchesDomainNameWithUnderscore() {
         String url = "http://a_nd.r_oid.com";
-        assertAddLinksWithWebUrlSucceeds("Should match domain name with '_'", url);
+        verifyAddLinksWithWebUrlSucceeds("Should match domain name with '_'", url);
 
         url = "a_nd.r_oid.com";
-        assertAddLinksWithWebUrlSucceeds("Should match domain name with '_'", url);
+        verifyAddLinksWithWebUrlSucceeds("Should match domain name with '_'", url);
     }
 
     @Test
-    public void testAddLinks_matchesPathAndQueryWithDollarSign() throws Exception {
+    public void testAddLinks_matchesPathAndQueryWithDollarSign() {
         String url = "http://android.com/path$?v=$val";
-        assertAddLinksWithWebUrlSucceeds("Should match path and query with '$'", url);
+        verifyAddLinksWithWebUrlSucceeds("Should match path and query with '$'", url);
 
         url = "android.com/path$?v=$val";
-        assertAddLinksWithWebUrlSucceeds("Should match path and query with '$'", url);
+        verifyAddLinksWithWebUrlSucceeds("Should match path and query with '$'", url);
     }
 
     @Test
-    public void testAddLinks_matchesEmptyPathWithQueryParams() throws Exception {
+    public void testAddLinks_matchesEmptyPathWithQueryParams() {
         String url = "http://android.com?q=v";
-        assertAddLinksWithWebUrlSucceeds("Should match empty path with query params", url);
+        verifyAddLinksWithWebUrlSucceeds("Should match empty path with query params", url);
 
         url = "android.com?q=v";
-        assertAddLinksWithWebUrlSucceeds("Should match empty path with query params", url);
+        verifyAddLinksWithWebUrlSucceeds("Should match empty path with query params", url);
 
         url = "http://android.com/?q=v";
-        assertAddLinksWithWebUrlSucceeds("Should match empty path with query params", url);
+        verifyAddLinksWithWebUrlSucceeds("Should match empty path with query params", url);
 
         url = "android.com/?q=v";
-        assertAddLinksWithWebUrlSucceeds("Should match empty path with query params", url);
+        verifyAddLinksWithWebUrlSucceeds("Should match empty path with query params", url);
     }
 
     // EMAIL_ADDRESSES Related Tests
 
     @Test
-    public void testAddLinks_email_matchesShortValidEmail() throws Exception {
+    public void testAddLinks_email_matchesShortValidEmail() {
         String email = "a@a.co";
-        assertAddLinksWithEmailSucceeds("Should match email: " + email, email);
+        verifyAddLinksWithEmailSucceeds("Should match email: " + email, email);
     }
 
     @Test
-    public void testAddLinks_email_matchesRegularEmail() throws Exception {
+    public void testAddLinks_email_matchesRegularEmail() {
         String email = "email@android.com";
-        assertAddLinksWithEmailSucceeds("Should match email: " + email, email);
+        verifyAddLinksWithEmailSucceeds("Should match email: " + email, email);
     }
 
     @Test
-    public void testAddLinks_email_matchesEmailWithMultipleSubdomains() throws Exception {
+    public void testAddLinks_email_matchesEmailWithMultipleSubdomains() {
         String email = "email@e.somelongdomainnameforandroid.abc.uk";
-        assertAddLinksWithEmailSucceeds("Should match email: " + email, email);
+        verifyAddLinksWithEmailSucceeds("Should match email: " + email, email);
     }
 
     @Test
-    public void testAddLinks_email_matchesLocalPartWithDot() throws Exception {
+    public void testAddLinks_email_matchesLocalPartWithDot() {
         String email = "e.mail@android.com";
-        assertAddLinksWithEmailSucceeds("Should match email: " + email, email);
+        verifyAddLinksWithEmailSucceeds("Should match email: " + email, email);
     }
 
     @Test
-    public void testAddLinks_email_matchesLocalPartWithPlus() throws Exception {
+    public void testAddLinks_email_matchesLocalPartWithPlus() {
         String email = "e+mail@android.com";
-        assertAddLinksWithEmailSucceeds("Should match email: " + email, email);
+        verifyAddLinksWithEmailSucceeds("Should match email: " + email, email);
     }
 
     @Test
-    public void testAddLinks_email_matchesLocalPartWithUnderscore() throws Exception {
+    public void testAddLinks_email_matchesLocalPartWithUnderscore() {
         String email = "e_mail@android.com";
-        assertAddLinksWithEmailSucceeds("Should match email: " + email, email);
+        verifyAddLinksWithEmailSucceeds("Should match email: " + email, email);
     }
 
     @Test
-    public void testAddLinks_email_matchesLocalPartWithDash() throws Exception {
+    public void testAddLinks_email_matchesLocalPartWithDash() {
         String email = "e-mail@android.com";
-        assertAddLinksWithEmailSucceeds("Should match email: " + email, email);
+        verifyAddLinksWithEmailSucceeds("Should match email: " + email, email);
     }
 
     @Test
-    public void testAddLinks_email_matchesLocalPartWithApostrophe() throws Exception {
+    public void testAddLinks_email_matchesLocalPartWithApostrophe() {
         String email = "e'mail@android.com";
-        assertAddLinksWithEmailSucceeds("Should match email: " + email, email);
+        verifyAddLinksWithEmailSucceeds("Should match email: " + email, email);
     }
 
     @Test
-    public void testAddLinks_email_matchesLocalPartWithDigits() throws Exception {
+    public void testAddLinks_email_matchesLocalPartWithDigits() {
         String email = "123@android.com";
-        assertAddLinksWithEmailSucceeds("Should match email: " + email, email);
+        verifyAddLinksWithEmailSucceeds("Should match email: " + email, email);
     }
 
     @Test
-    public void testAddLinks_email_matchesUnicodeLocalPart() throws Exception {
+    public void testAddLinks_email_matchesUnicodeLocalPart() {
         String email = "\uD604\uAE08\uC601\uC218\uC99D@android.kr";
-        assertAddLinksWithEmailSucceeds("Should match email: " + email, email);
+        verifyAddLinksWithEmailSucceeds("Should match email: " + email, email);
     }
 
     @Test
-    public void testAddLinks_email_matchesLocalPartWithEmoji() throws Exception {
+    public void testAddLinks_email_matchesLocalPartWithEmoji() {
         String email = "smiley\u263A@android.com";
-        assertAddLinksWithEmailSucceeds("Should match email: " + email, email);
+        verifyAddLinksWithEmailSucceeds("Should match email: " + email, email);
     }
 
     @Test
-    public void testAddLinks_email_matchesLocalPartWithSurrogatePairs()
-            throws Exception {
+    public void testAddLinks_email_matchesLocalPartWithSurrogatePairs() {
         String email = "a\uD83C\uDF38a@android.com";
-        assertAddLinksWithEmailSucceeds("Should match email: " + email, email);
+        verifyAddLinksWithEmailSucceeds("Should match email: " + email, email);
     }
 
     @Test
-    public void testAddLinks_email_matchesDomainWithDash() throws Exception {
+    public void testAddLinks_email_matchesDomainWithDash() {
         String email = "email@an-droid.com";
-        assertAddLinksWithEmailSucceeds("Should match email: " + email, email);
+        verifyAddLinksWithEmailSucceeds("Should match email: " + email, email);
     }
 
     @Test
-    public void testAddLinks_email_matchesUnicodeDomain() throws Exception {
+    public void testAddLinks_email_matchesUnicodeDomain() {
         String email = "email@\uD604\uAE08\uC601\uC218\uC99D.kr";
-        assertAddLinksWithEmailSucceeds("Should match email: " + email, email);
+        verifyAddLinksWithEmailSucceeds("Should match email: " + email, email);
     }
 
     @Test
-    public void testAddLinks_email_matchesUnicodeLocalPartAndDomain()
-            throws Exception {
+    public void testAddLinks_email_matchesUnicodeLocalPartAndDomain() {
         String email = "\uD604\uAE08\uC601\uC218\uC99D@\uD604\uAE08\uC601\uC218\uC99D.kr";
-        assertAddLinksWithEmailSucceeds("Should match email: " + email, email);
+        verifyAddLinksWithEmailSucceeds("Should match email: " + email, email);
     }
 
     @Test
-    public void testAddLinks_email_matchesDomainWithEmoji() throws Exception {
+    public void testAddLinks_email_matchesDomainWithEmoji() {
         String email = "smiley@\u263Aandroid.com";
-        assertAddLinksWithEmailSucceeds("Should match email: " + email, email);
+        verifyAddLinksWithEmailSucceeds("Should match email: " + email, email);
     }
 
     @Test
-    public void testAddLinks_email_matchesDomainWithSurrogatePairs()
-            throws Exception {
+    public void testAddLinks_email_matchesDomainWithSurrogatePairs() {
         String email = "email@\uD83C\uDF38android.com";
-        assertAddLinksWithEmailSucceeds("Should match email: " + email, email);
+        verifyAddLinksWithEmailSucceeds("Should match email: " + email, email);
     }
 
     @Test
-    public void testAddLinks_email_matchesLocalPartAndDomainWithSurrogatePairs()
-            throws Exception {
+    public void testAddLinks_email_matchesLocalPartAndDomainWithSurrogatePairs() {
         String email = "a\uD83C\uDF38a@\uD83C\uDF38android.com";
-        assertAddLinksWithEmailSucceeds("Should match email: " + email, email);
+        verifyAddLinksWithEmailSucceeds("Should match email: " + email, email);
     }
 
     @Test
-    public void testAddLinks_partiallyMatchesEmailEndingWithDot() throws Exception {
+    public void testAddLinks_partiallyMatchesEmailEndingWithDot() {
         String email = "email@android.co.uk.";
-        assertAddLinksWithEmailPartiallyMatches("Should partially match email ending with dot",
+        verifyAddLinksWithEmailPartiallyMatches("Should partially match email ending with dot",
                 "mailto:email@android.co.uk", email);
     }
 
     @Test
-    public void testAddLinks_email_partiallyMatchesLocalPartStartingWithDot()
-            throws Exception {
+    public void testAddLinks_email_partiallyMatchesLocalPartStartingWithDot() {
         String email = ".email@android.com";
-        assertAddLinksWithEmailPartiallyMatches("Should partially match email starting " +
-                "with dot", "mailto:email@android.com", email);
+        verifyAddLinksWithEmailPartiallyMatches("Should partially match email starting "
+                + "with dot", "mailto:email@android.com", email);
     }
 
     @Test
-    public void testAddLinks_email_doesNotMatchStringWithoutAtSign() throws Exception {
+    public void testAddLinks_email_doesNotMatchStringWithoutAtSign() {
         String email = "android.com";
-        assertAddLinksWithEmailFails("Should not match email: " + email, email);
+        verifyAddLinksWithEmailFails("Should not match email: " + email, email);
     }
 
     @Test
-    public void testAddLinks_email_doesNotMatchPlainString() throws Exception {
+    public void testAddLinks_email_doesNotMatchPlainString() {
         String email = "email";
-        assertAddLinksWithEmailFails("Should not match email: " + email, email);
+        verifyAddLinksWithEmailFails("Should not match email: " + email, email);
     }
 
     @Test
-    public void testAddLinks_email_doesNotMatchEmailWithoutTld() throws Exception {
+    public void testAddLinks_email_doesNotMatchEmailWithoutTld() {
         String email = "email@android";
-        assertAddLinksWithEmailFails("Should not match email: " + email, email);
+        verifyAddLinksWithEmailFails("Should not match email: " + email, email);
     }
 
     @Test
-    public void testAddLinks_email_doesNotMatchLocalPartEndingWithDot()
-            throws Exception {
+    public void testAddLinks_email_doesNotMatchLocalPartEndingWithDot() {
         String email = "email.@android.com";
-        assertAddLinksWithEmailFails("Should not match email: " + email, email);
+        verifyAddLinksWithEmailFails("Should not match email: " + email, email);
     }
 
     @Test
-    public void testAddLinks_email_doesNotMatchDomainStartingWithDash()
-            throws Exception {
+    public void testAddLinks_email_doesNotMatchDomainStartingWithDash() {
         String email = "email@-android.com";
-        assertAddLinksWithEmailFails("Should not match email: " + email, email);
+        verifyAddLinksWithEmailFails("Should not match email: " + email, email);
     }
 
     @Test
-    public void testAddLinks_email_doesNotMatchDomainWithConsecutiveDots()
-            throws Exception {
+    public void testAddLinks_email_doesNotMatchDomainWithConsecutiveDots() {
         String email = "email@android..com";
-        assertAddLinksWithEmailFails("Should not match email: " + email, email);
+        verifyAddLinksWithEmailFails("Should not match email: " + email, email);
     }
 
     @Test
-    public void testAddLinks_email_doesNotMatchEmailWithIp() throws Exception {
+    public void testAddLinks_email_doesNotMatchEmailWithIp() {
         String email = "email@127.0.0.1";
-        assertAddLinksWithEmailFails("Should not match email: " + email, email);
+        verifyAddLinksWithEmailFails("Should not match email: " + email, email);
     }
 
     @Test
-    public void testAddLinks_email_doesNotMatchEmailWithInvalidTld()
-            throws Exception {
+    public void testAddLinks_email_doesNotMatchEmailWithInvalidTld() {
         String email = "email@android.c";
-        assertAddLinksWithEmailFails("Should not match email: " + email, email);
+        verifyAddLinksWithEmailFails("Should not match email: " + email, email);
     }
 
     @Test
-    public void testAddLinks_email_matchesLocalPartUpTo64Chars() throws Exception {
+    public void testAddLinks_email_matchesLocalPartUpTo64Chars() {
         String localPart = "";
         for (int i = 0; i < 64; i++) {
             localPart += "a";
         }
         String email = localPart + "@android.com";
-        assertAddLinksWithEmailSucceeds("Should match email local part of length: " +
-                localPart.length(), email);
+        verifyAddLinksWithEmailSucceeds("Should match email local part of length: "
+                + localPart.length(), email);
 
         email = localPart + "a@android.com";
-        assertAddLinksWithEmailFails("Should not match email local part of length:" +
-                localPart.length(), email);
+        verifyAddLinksWithEmailFails("Should not match email local part of length:"
+                + localPart.length(), email);
     }
 
     @Test
-    public void testAddLinks_email_matchesSubdomainUpTo63Chars() throws Exception {
+    public void testAddLinks_email_matchesSubdomainUpTo63Chars() {
         String subdomain = "";
         for (int i = 0; i < 63; i++) {
             subdomain += "a";
         }
         String email = "email@" + subdomain + ".com";
 
-        assertAddLinksWithEmailSucceeds("Should match email subdomain of length: " +
-                subdomain.length(), email);
+        verifyAddLinksWithEmailSucceeds("Should match email subdomain of length: "
+                + subdomain.length(), email);
 
         subdomain += "a";
         email = "email@" + subdomain + ".com";
 
-        assertAddLinksWithEmailFails("Should not match email subdomain of length:" +
-                subdomain.length(), email);
+        verifyAddLinksWithEmailFails("Should not match email subdomain of length:"
+                + subdomain.length(), email);
     }
 
     @Test
-    public void testAddLinks_email_matchesDomainUpTo255Chars() throws Exception {
+    public void testAddLinks_email_matchesDomainUpTo255Chars() {
         String domain = "";
         while (domain.length() <= 250) {
             domain += "d.";
@@ -762,42 +755,42 @@
         domain += "com";
         assertEquals(255, domain.length());
         String email = "a@" + domain;
-        assertAddLinksWithEmailSucceeds("Should match email domain of length: " +
-                domain.length(), email);
+        verifyAddLinksWithEmailSucceeds("Should match email domain of length: "
+                + domain.length(), email);
 
         email = email + "m";
-        assertAddLinksWithEmailFails("Should not match email domain of length:" +
-                domain.length(), email);
+        verifyAddLinksWithEmailFails("Should not match email domain of length:"
+                + domain.length(), email);
     }
 
     // Utility functions
-    private static void assertAddLinksWithWebUrlSucceeds(String msg, String url) {
-        assertAddLinksSucceeds(msg, url, Linkify.WEB_URLS);
+    private static void verifyAddLinksWithWebUrlSucceeds(String msg, String url) {
+        verifyAddLinksSucceeds(msg, url, Linkify.WEB_URLS);
     }
 
-    private static void assertAddLinksWithWebUrlFails(String msg, String url) {
-        assertAddLinksFails(msg, url, Linkify.WEB_URLS);
+    private static void verifyAddLinksWithWebUrlFails(String msg, String url) {
+        verifyAddLinksFails(msg, url, Linkify.WEB_URLS);
     }
 
-    private static void assertAddLinksWithWebUrlPartiallyMatches(String msg, String expected,
+    private static void verifyAddLinksWithWebUrlPartiallyMatches(String msg, String expected,
             String url) {
-        assertAddLinksPartiallyMatches(msg, expected, url, Linkify.WEB_URLS);
+        verifyAddLinksPartiallyMatches(msg, expected, url, Linkify.WEB_URLS);
     }
 
-    private static void assertAddLinksWithEmailSucceeds(String msg, String url) {
-        assertAddLinksSucceeds(msg, url, Linkify.EMAIL_ADDRESSES);
+    private static void verifyAddLinksWithEmailSucceeds(String msg, String url) {
+        verifyAddLinksSucceeds(msg, url, Linkify.EMAIL_ADDRESSES);
     }
 
-    private static void assertAddLinksWithEmailFails(String msg, String url) {
-        assertAddLinksFails(msg, url, Linkify.EMAIL_ADDRESSES);
+    private static void verifyAddLinksWithEmailFails(String msg, String url) {
+        verifyAddLinksFails(msg, url, Linkify.EMAIL_ADDRESSES);
     }
 
-    private static void assertAddLinksWithEmailPartiallyMatches(String msg, String expected,
+    private static void verifyAddLinksWithEmailPartiallyMatches(String msg, String expected,
             String url) {
-        assertAddLinksPartiallyMatches(msg, expected, url, Linkify.EMAIL_ADDRESSES);
+        verifyAddLinksPartiallyMatches(msg, expected, url, Linkify.EMAIL_ADDRESSES);
     }
 
-    private static void assertAddLinksSucceeds(String msg, String string, int type) {
+    private static void verifyAddLinksSucceeds(String msg, String string, int type) {
         String str = "start " + string + " end";
         Spannable spannable = new SpannableString(str);
 
@@ -811,13 +804,13 @@
                 str.length() - " end".length(), spannable.getSpanEnd(spans[0]));
     }
 
-    private static void assertAddLinksFails(String msg, String string, int type) {
+    private static void verifyAddLinksFails(String msg, String string, int type) {
         Spannable spannable = new SpannableString("start " + string + " end");
         boolean linksAdded = LinkifyCompat.addLinks(spannable, type);
         assertFalse(msg, linksAdded);
     }
 
-    private static void assertAddLinksPartiallyMatches(String msg, String expected,
+    private static void verifyAddLinksPartiallyMatches(String msg, String expected,
             String string, int type) {
         Spannable spannable = new SpannableString("start " + string + " end");
         boolean linksAdded = LinkifyCompat.addLinks(spannable, type);
@@ -825,4 +818,4 @@
         assertTrue(msg, linksAdded);
         assertEquals(msg, expected, spans[0].getURL().toString());
     }
-}
\ No newline at end of file
+}
diff --git a/compat/tests/java/android/support/v4/view/GravityCompatTest.java b/compat/tests/java/android/support/v4/view/GravityCompatTest.java
index 36e557a..ae2f53c 100644
--- a/compat/tests/java/android/support/v4/view/GravityCompatTest.java
+++ b/compat/tests/java/android/support/v4/view/GravityCompatTest.java
@@ -15,18 +15,18 @@
  */
 package android.support.v4.view;
 
+import static org.junit.Assert.assertEquals;
+
 import android.graphics.Rect;
 import android.os.Build;
 import android.support.test.runner.AndroidJUnit4;
 import android.support.v4.testutils.TestUtils;
-import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.view.Gravity;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import static org.junit.Assert.assertEquals;
-
 @RunWith(AndroidJUnit4.class)
 @SmallTest
 public class GravityCompatTest {
diff --git a/compat/tests/java/android/support/v4/view/MarginLayoutParamsCompatTest.java b/compat/tests/java/android/support/v4/view/MarginLayoutParamsCompatTest.java
index 48d6dab..60ec90d 100644
--- a/compat/tests/java/android/support/v4/view/MarginLayoutParamsCompatTest.java
+++ b/compat/tests/java/android/support/v4/view/MarginLayoutParamsCompatTest.java
@@ -15,16 +15,16 @@
  */
 package android.support.v4.view;
 
+import static org.junit.Assert.assertEquals;
+
 import android.os.Build;
 import android.support.test.runner.AndroidJUnit4;
-import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.view.ViewGroup;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import static org.junit.Assert.assertEquals;
-
 @RunWith(AndroidJUnit4.class)
 @SmallTest
 public class MarginLayoutParamsCompatTest {
diff --git a/core-utils/Android.mk b/core-utils/Android.mk
index 3b64d2b..add72db 100644
--- a/core-utils/Android.mk
+++ b/core-utils/Android.mk
@@ -96,7 +96,7 @@
 # A helper sub-library that makes direct use of V24 APIs.
 include $(CLEAR_VARS)
 LOCAL_MODULE := android-support-core-utils-api24
-LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
+LOCAL_SDK_VERSION := 24
 LOCAL_SRC_FILES := $(call all-java-files-under, api24)
 LOCAL_STATIC_JAVA_LIBRARIES := android-support-core-utils-api23
 LOCAL_JAVA_LANGUAGE_VERSION := 1.7
diff --git a/core-utils/java/android/support/v4/content/res/TypedArrayUtils.java b/core-utils/java/android/support/v4/content/res/TypedArrayUtils.java
index 5d2a2ad..894c708 100644
--- a/core-utils/java/android/support/v4/content/res/TypedArrayUtils.java
+++ b/core-utils/java/android/support/v4/content/res/TypedArrayUtils.java
@@ -68,6 +68,15 @@
         return val;
     }
 
+    public static CharSequence getText(TypedArray a, @StyleableRes int index,
+            @StyleableRes int fallbackIndex) {
+        CharSequence val = a.getText(index);
+        if (val == null) {
+            val = a.getText(fallbackIndex);
+        }
+        return val;
+    }
+
     public static CharSequence[] getTextArray(TypedArray a, @StyleableRes int index,
             @StyleableRes int fallbackIndex) {
         CharSequence[] val = a.getTextArray(index);
diff --git a/core-utils/java/android/support/v4/print/PrintHelper.java b/core-utils/java/android/support/v4/print/PrintHelper.java
index 88d5387..87899e2 100644
--- a/core-utils/java/android/support/v4/print/PrintHelper.java
+++ b/core-utils/java/android/support/v4/print/PrintHelper.java
@@ -195,9 +195,9 @@
         @Override
         public void printBitmap(String jobName, Bitmap bitmap,
                 final OnPrintFinishCallback callback) {
-            RealHelper.OnPrintFinishCallback delegateCallback = null;
+            PrintHelperKitkat.OnPrintFinishCallback delegateCallback = null;
             if (callback != null) {
-                delegateCallback = new RealHelper.OnPrintFinishCallback() {
+                delegateCallback = new PrintHelperKitkat.OnPrintFinishCallback() {
                     @Override
                     public void onFinish() {
                         callback.onFinish();
@@ -210,9 +210,9 @@
         @Override
         public void printBitmap(String jobName, Uri imageFile,
                 final OnPrintFinishCallback callback) throws FileNotFoundException {
-            RealHelper.OnPrintFinishCallback delegateCallback = null;
+            PrintHelperKitkat.OnPrintFinishCallback delegateCallback = null;
             if (callback != null) {
-                delegateCallback = new RealHelper.OnPrintFinishCallback() {
+                delegateCallback = new PrintHelperKitkat.OnPrintFinishCallback() {
                     @Override
                     public void onFinish() {
                         callback.onFinish();
diff --git a/core-utils/tests/java/android/support/v4/content/FileProviderTest.java b/core-utils/tests/java/android/support/v4/content/FileProviderTest.java
index ec472b7..97fecf8 100644
--- a/core-utils/tests/java/android/support/v4/content/FileProviderTest.java
+++ b/core-utils/tests/java/android/support/v4/content/FileProviderTest.java
@@ -19,16 +19,25 @@
 import static android.provider.OpenableColumns.DISPLAY_NAME;
 import static android.provider.OpenableColumns.SIZE;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
 import android.content.ContentResolver;
+import android.content.Context;
 import android.database.Cursor;
 import android.net.Uri;
 import android.os.Environment;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
 import android.support.v4.content.FileProvider.SimplePathStrategy;
-import android.test.AndroidTestCase;
 import android.test.MoreAsserts;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
 import java.io.ByteArrayOutputStream;
-import java.io.Closeable;
 import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
@@ -39,7 +48,9 @@
 /**
  * Tests for {@link FileProvider}
  */
-public class FileProviderTest extends AndroidTestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class FileProviderTest {
     private static final String TEST_AUTHORITY = "moocow";
 
     private static final String TEST_FILE = "file.test";
@@ -47,14 +58,15 @@
     private static final byte[] TEST_DATA_ALT = new byte[] { (byte) 0x33, 0x66 };
 
     private ContentResolver mResolver;
+    private Context mContext;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-
-        mResolver = getContext().getContentResolver();
+    @Before
+    public void setup() throws Exception {
+        mContext = InstrumentationRegistry.getTargetContext();
+        mResolver = mContext.getContentResolver();
     }
 
+    @Test
     public void testStrategyUriSimple() throws Exception {
         final SimplePathStrategy strat = new SimplePathStrategy("authority");
         strat.addRoot("tag", mContext.getFilesDir());
@@ -75,6 +87,7 @@
         }
     }
 
+    @Test
     public void testStrategyUriJumpOutside() throws Exception {
         final SimplePathStrategy strat = new SimplePathStrategy("authority");
         strat.addRoot("tag", mContext.getFilesDir());
@@ -87,6 +100,7 @@
         }
     }
 
+    @Test
     public void testStrategyUriShortestRoot() throws Exception {
         SimplePathStrategy strat = new SimplePathStrategy("authority");
         strat.addRoot("tag1", mContext.getFilesDir());
@@ -105,6 +119,7 @@
                 strat.getUriForFile(file).toString());
     }
 
+    @Test
     public void testStrategyFileSimple() throws Exception {
         final SimplePathStrategy strat = new SimplePathStrategy("authority");
         strat.addRoot("tag", mContext.getFilesDir());
@@ -119,6 +134,7 @@
                 Uri.parse("content://authority/tag/subdir/file.test")).getPath());
     }
 
+    @Test
     public void testStrategyFileJumpOutside() throws Exception {
         final SimplePathStrategy strat = new SimplePathStrategy("authority");
         strat.addRoot("tag", mContext.getFilesDir());
@@ -130,6 +146,7 @@
         }
     }
 
+    @Test
     public void testStrategyEscaping() throws Exception {
         final SimplePathStrategy strat = new SimplePathStrategy("authority");
         strat.addRoot("t/g", mContext.getFilesDir());
@@ -144,6 +161,7 @@
                 strat.getFileForUri(Uri.parse(expected)).getPath());
     }
 
+    @Test
     public void testStrategyExtraParams() throws Exception {
         final SimplePathStrategy strat = new SimplePathStrategy("authority");
         strat.addRoot("tag", mContext.getFilesDir());
@@ -154,6 +172,7 @@
                 Uri.parse("content://authority/tag/file.txt?extra=foo")).getPath());
     }
 
+    @Test
     public void testStrategyExtraSeparators() throws Exception {
         final SimplePathStrategy strat = new SimplePathStrategy("authority");
         strat.addRoot("tag", mContext.getFilesDir());
@@ -170,6 +189,7 @@
                 strat.getFileForUri(Uri.parse(expected)).getPath());
     }
 
+    @Test
     public void testQueryProjectionNull() throws Exception {
         final File file = new File(mContext.getFilesDir(), TEST_FILE);
         final Uri uri = stageFileAndGetUri(file, TEST_DATA);
@@ -186,6 +206,7 @@
         }
     }
 
+    @Test
     public void testQueryProjectionOrder() throws Exception {
         final File file = new File(mContext.getFilesDir(), TEST_FILE);
         final Uri uri = stageFileAndGetUri(file, TEST_DATA);
@@ -214,6 +235,7 @@
         }
     }
 
+    @Test
     public void testQueryExtraColumn() throws Exception {
         final File file = new File(mContext.getFilesDir(), TEST_FILE);
         final Uri uri = stageFileAndGetUri(file, TEST_DATA);
@@ -231,6 +253,7 @@
         }
     }
 
+    @Test
     public void testReadFile() throws Exception {
         final File file = new File(mContext.getFilesDir(), TEST_FILE);
         final Uri uri = stageFileAndGetUri(file, TEST_DATA);
@@ -238,6 +261,7 @@
         assertContentsEquals(TEST_DATA, uri);
     }
 
+    @Test
     public void testWriteFile() throws Exception {
         final File file = new File(mContext.getFilesDir(), TEST_FILE);
         final Uri uri = stageFileAndGetUri(file, TEST_DATA);
@@ -254,6 +278,7 @@
         assertContentsEquals(TEST_DATA_ALT, uri);
     }
 
+    @Test
     public void testWriteMissingFile() throws Exception {
         final File file = new File(mContext.getFilesDir(), TEST_FILE);
         final Uri uri = stageFileAndGetUri(file, null);
@@ -274,6 +299,7 @@
         assertContentsEquals(TEST_DATA_ALT, uri);
     }
 
+    @Test
     public void testDelete() throws Exception {
         final File file = new File(mContext.getFilesDir(), TEST_FILE);
         final Uri uri = stageFileAndGetUri(file, TEST_DATA);
@@ -290,6 +316,7 @@
         }
     }
 
+    @Test
     public void testMetaDataTargets() {
         Uri actual;
 
diff --git a/design/Android.mk b/design/Android.mk
index 38ca592..3217915 100644
--- a/design/Android.mk
+++ b/design/Android.mk
@@ -43,7 +43,10 @@
 LOCAL_SRC_FILES := $(call all-java-files-under, base)
 LOCAL_JAVA_LIBRARIES := \
     android-support-design-res \
-    android-support-v4 \
+    android-support-compat \
+    android-support-core-utils \
+    android-support-core-ui \
+    android-support-fragment \
     android-support-v7-appcompat \
     android-support-v7-recyclerview
 LOCAL_JAVA_LANGUAGE_VERSION := 1.7
@@ -57,7 +60,10 @@
 LOCAL_STATIC_JAVA_LIBRARIES := android-support-design-base
 LOCAL_JAVA_LIBRARIES := \
     android-support-design-res \
-    android-support-v4 \
+    android-support-compat \
+    android-support-core-utils \
+    android-support-core-ui \
+    android-support-fragment \
     android-support-v7-appcompat \
     android-support-v7-recyclerview
 LOCAL_JAVA_LANGUAGE_VERSION := 1.7
@@ -71,7 +77,10 @@
 LOCAL_STATIC_JAVA_LIBRARIES := android-support-design-gingerbread
 LOCAL_JAVA_LIBRARIES := \
     android-support-design-res \
-    android-support-v4 \
+    android-support-compat \
+    android-support-core-utils \
+    android-support-core-ui \
+    android-support-fragment \
     android-support-v7-appcompat \
     android-support-v7-recyclerview
 LOCAL_JAVA_LANGUAGE_VERSION := 1.7
@@ -85,7 +94,10 @@
 LOCAL_STATIC_JAVA_LIBRARIES := android-support-design-honeycomb
 LOCAL_JAVA_LIBRARIES := \
     android-support-design-res \
-    android-support-v4 \
+    android-support-compat \
+    android-support-core-utils \
+    android-support-core-ui \
+    android-support-fragment \
     android-support-v7-appcompat \
     android-support-v7-recyclerview
 LOCAL_JAVA_LANGUAGE_VERSION := 1.7
@@ -99,7 +111,10 @@
 LOCAL_STATIC_JAVA_LIBRARIES := android-support-design-honeycomb-mr1
 LOCAL_JAVA_LIBRARIES := \
     android-support-design-res \
-    android-support-v4 \
+    android-support-compat \
+    android-support-core-utils \
+    android-support-core-ui \
+    android-support-fragment \
     android-support-v7-appcompat \
     android-support-v7-recyclerview \
     android-support-transition
@@ -114,7 +129,10 @@
 LOCAL_STATIC_JAVA_LIBRARIES := android-support-design-ics
 LOCAL_JAVA_LIBRARIES := \
     android-support-design-res \
-    android-support-v4 \
+    android-support-compat \
+    android-support-core-utils \
+    android-support-core-ui \
+    android-support-fragment \
     android-support-v7-appcompat \
     android-support-v7-recyclerview \
     android-support-transition
@@ -128,7 +146,10 @@
 #       android-support-design \
 #       android-support-v7-appcompat \
 #       android-support-v7-recyclerview \
-#       android-support-v4
+#       android-support-compat \
+#       android-support-core-utils \
+#       android-support-core-ui \
+#       android-support-fragment
 #
 # in their makefiles to include the resources and their dependencies in their package.
 include $(CLEAR_VARS)
@@ -138,7 +159,12 @@
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 LOCAL_STATIC_JAVA_LIBRARIES := android-support-design-lollipop
 LOCAL_STATIC_ANDROID_LIBRARIES := android-support-design-res
-LOCAL_SHARED_ANDROID_LIBRARIES := $(resource_libs) android-support-v4
+LOCAL_SHARED_ANDROID_LIBRARIES := \
+    $(resource_libs) \
+    android-support-compat \
+    android-support-core-utils \
+    android-support-core-ui \
+    android-support-fragment
 LOCAL_JAR_EXCLUDE_FILES := none
 LOCAL_JAVA_LANGUAGE_VERSION := 1.7
 LOCAL_AAPT_FLAGS := --add-javadoc-annotation doconly
diff --git a/design/build.gradle b/design/build.gradle
index 8ae45d7..4423186 100644
--- a/design/build.gradle
+++ b/design/build.gradle
@@ -3,7 +3,10 @@
 archivesBaseName = 'design'
 
 dependencies {
-    compile project(':support-v4')
+    compile project(':support-compat')
+    compile project(':support-core-utils')
+    compile project(':support-core-ui')
+    compile project(':support-fragment')
     compile project(':support-appcompat-v7')
     compile project(':support-recyclerview-v7')
     compile project(':support-transition')
diff --git a/design/src/android/support/design/internal/BottomNavigationItemView.java b/design/src/android/support/design/internal/BottomNavigationItemView.java
index ea22399..05a9b89 100644
--- a/design/src/android/support/design/internal/BottomNavigationItemView.java
+++ b/design/src/android/support/design/internal/BottomNavigationItemView.java
@@ -25,6 +25,7 @@
 import android.support.design.R;
 import android.support.v4.content.ContextCompat;
 import android.support.v4.graphics.drawable.DrawableCompat;
+import android.support.v4.view.PointerIconCompat;
 import android.support.v4.view.ViewCompat;
 import android.support.v7.view.menu.MenuItemImpl;
 import android.support.v7.view.menu.MenuView;
@@ -87,7 +88,6 @@
         mIcon = (ImageView) findViewById(R.id.icon);
         mSmallLabel = (TextView) findViewById(R.id.smallLabel);
         mLargeLabel = (TextView) findViewById(R.id.largeLabel);
-
     }
 
     @Override
@@ -193,6 +193,14 @@
         mSmallLabel.setEnabled(enabled);
         mLargeLabel.setEnabled(enabled);
         mIcon.setEnabled(enabled);
+
+        if (enabled) {
+            ViewCompat.setPointerIcon(this,
+                    PointerIconCompat.getSystemIcon(getContext(), PointerIconCompat.TYPE_HAND));
+        } else {
+            ViewCompat.setPointerIcon(this, null);
+        }
+
     }
 
     @Override
diff --git a/design/src/android/support/design/widget/TabLayout.java b/design/src/android/support/design/widget/TabLayout.java
index bc52ab7..904c904 100755
--- a/design/src/android/support/design/widget/TabLayout.java
+++ b/design/src/android/support/design/widget/TabLayout.java
@@ -44,6 +44,7 @@
 import android.support.v4.util.Pools;
 import android.support.v4.view.GravityCompat;
 import android.support.v4.view.PagerAdapter;
+import android.support.v4.view.PointerIconCompat;
 import android.support.v4.view.ViewCompat;
 import android.support.v4.view.ViewPager;
 import android.support.v4.widget.TextViewCompat;
@@ -1507,6 +1508,8 @@
             setGravity(Gravity.CENTER);
             setOrientation(VERTICAL);
             setClickable(true);
+            ViewCompat.setPointerIcon(this,
+                    PointerIconCompat.getSystemIcon(getContext(), PointerIconCompat.TYPE_HAND));
         }
 
         @Override
diff --git a/fragment/tests/java/android/support/v4/app/FragmentReplaceTest.java b/fragment/tests/java/android/support/v4/app/FragmentReplaceTest.java
index 89566eb..55f8b6f 100644
--- a/fragment/tests/java/android/support/v4/app/FragmentReplaceTest.java
+++ b/fragment/tests/java/android/support/v4/app/FragmentReplaceTest.java
@@ -15,76 +15,108 @@
  */
 package android.support.v4.app;
 
+import android.app.Activity;
 import android.app.Fragment;
+import android.app.Instrumentation;
 import android.support.fragment.test.R;
+import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.SdkSuppress;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
 import android.support.v4.app.test.FragmentTestActivity;
 import android.support.v4.app.test.FragmentTestActivity.TestFragment;
-import android.test.ActivityInstrumentationTestCase2;
 import android.test.UiThreadTest;
+import android.test.suitebuilder.annotation.MediumTest;
 import android.view.KeyEvent;
 
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
 /**
  * Test to prevent regressions in SupportFragmentManager fragment replace method. See b/24693644
  */
-public class FragmentReplaceTest extends
-        ActivityInstrumentationTestCase2<FragmentTestActivity> {
-    private FragmentTestActivity mActivity;
+@RunWith(AndroidJUnit4.class)
+@MediumTest
+public class FragmentReplaceTest {
+    @Rule
+    public ActivityTestRule<FragmentTestActivity> mActivityRule =
+            new ActivityTestRule<FragmentTestActivity>(FragmentTestActivity.class);
 
+    private Instrumentation mInstrumentation;
 
-    public FragmentReplaceTest() {
-        super(FragmentTestActivity.class);
+    @Before
+    public void setUp() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
     }
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mActivity = getActivity();
-    }
-
-    @UiThreadTest
+    @Test
     public void testReplaceFragment() throws Throwable {
-        mActivity.getSupportFragmentManager().beginTransaction()
+        final FragmentActivity activity = mActivityRule.getActivity();
+        final FragmentManager fm = activity.getSupportFragmentManager();
+
+        fm.beginTransaction()
                 .add(R.id.content, TestFragment.create(R.layout.fragment_a))
                 .addToBackStack(null)
                 .commit();
-        mActivity.getSupportFragmentManager().executePendingTransactions();
-        assertNotNull(mActivity.findViewById(R.id.textA));
-        assertNull(mActivity.findViewById(R.id.textB));
-        assertNull(mActivity.findViewById(R.id.textC));
+        executePendingTransactions(fm);
+        assertNotNull(activity.findViewById(R.id.textA));
+        assertNull(activity.findViewById(R.id.textB));
+        assertNull(activity.findViewById(R.id.textC));
 
 
-        mActivity.getSupportFragmentManager().beginTransaction()
+        fm.beginTransaction()
                 .add(R.id.content, TestFragment.create(R.layout.fragment_b))
                 .addToBackStack(null)
                 .commit();
-        mActivity.getSupportFragmentManager().executePendingTransactions();
-        assertNotNull(mActivity.findViewById(R.id.textA));
-        assertNotNull(mActivity.findViewById(R.id.textB));
-        assertNull(mActivity.findViewById(R.id.textC));
+        executePendingTransactions(fm);
+        assertNotNull(activity.findViewById(R.id.textA));
+        assertNotNull(activity.findViewById(R.id.textB));
+        assertNull(activity.findViewById(R.id.textC));
 
-        mActivity.getSupportFragmentManager().beginTransaction()
+        activity.getSupportFragmentManager().beginTransaction()
                 .replace(R.id.content, TestFragment.create(R.layout.fragment_c))
                 .addToBackStack(null)
                 .commit();
-        mActivity.getSupportFragmentManager().executePendingTransactions();
-        assertNull(mActivity.findViewById(R.id.textA));
-        assertNull(mActivity.findViewById(R.id.textB));
-        assertNotNull(mActivity.findViewById(R.id.textC));
+        executePendingTransactions(fm);
+        assertNull(activity.findViewById(R.id.textA));
+        assertNull(activity.findViewById(R.id.textB));
+        assertNotNull(activity.findViewById(R.id.textC));
+    }
+
+    private void executePendingTransactions(final FragmentManager fm) {
+        mInstrumentation.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                fm.executePendingTransactions();
+            }
+        });
     }
 
     @SdkSuppress(minSdkVersion = 11)
-    @UiThreadTest
+    @Test
     public void testBackPressWithFrameworkFragment() throws Throwable {
-        mActivity.getFragmentManager().beginTransaction()
+        final Activity activity = mActivityRule.getActivity();
+
+        activity.getFragmentManager().beginTransaction()
                 .add(R.id.content, new Fragment())
                 .addToBackStack(null)
                 .commit();
-        mActivity.getFragmentManager().executePendingTransactions();
-        assertEquals(1, mActivity.getFragmentManager().getBackStackEntryCount());
+        mInstrumentation.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                activity.getFragmentManager().executePendingTransactions();
+            }
+        });
+        assertEquals(1, activity.getFragmentManager().getBackStackEntryCount());
 
-        getInstrumentation().sendKeyDownUpSync(KeyEvent.KEYCODE_BACK);
+        mInstrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_BACK);
 
-        assertEquals(0, mActivity.getFragmentManager().getBackStackEntryCount());
+        assertEquals(0, activity.getFragmentManager().getBackStackEntryCount());
     }
 }
diff --git a/media-compat/Android.mk b/media-compat/Android.mk
index e8f9c8b..d1c2569 100644
--- a/media-compat/Android.mk
+++ b/media-compat/Android.mk
@@ -85,7 +85,7 @@
 # A helper sub-library that makes direct use of V24 APIs.
 include $(CLEAR_VARS)
 LOCAL_MODULE := android-support-media-compat-api24
-LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
+LOCAL_SDK_VERSION := 24
 LOCAL_SRC_FILES := $(call all-java-files-under, api24)
 LOCAL_STATIC_JAVA_LIBRARIES := android-support-media-compat-api23
 LOCAL_JAVA_LANGUAGE_VERSION := 1.7
@@ -93,6 +93,17 @@
 
 # -----------------------------------------------------------------------
 
+# A helper sub-library that makes direct use of V25 APIs.
+include $(CLEAR_VARS)
+LOCAL_MODULE := android-support-media-compat-api25
+LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
+LOCAL_SRC_FILES := $(call all-java-files-under, api25)
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-media-compat-api24
+LOCAL_JAVA_LANGUAGE_VERSION := 1.7
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+# -----------------------------------------------------------------------
+
 # Here is the final static library that apps can link against.
 include $(CLEAR_VARS)
 LOCAL_USE_AAPT2 := true
@@ -102,7 +113,7 @@
 LOCAL_SRC_FILES := $(call all-java-files-under, java) \
     $(call all-Iaidl-files-under, java)
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
-LOCAL_STATIC_JAVA_LIBRARIES += android-support-media-compat-api24
+LOCAL_STATIC_JAVA_LIBRARIES += android-support-media-compat-api25
 LOCAL_SHARED_ANDROID_LIBRARIES := \
     android-support-compat \
     android-support-annotations
diff --git a/media-compat/api25/android/support/v4/media/session/MediaControllerCompatApi25.java b/media-compat/api25/android/support/v4/media/session/MediaControllerCompatApi25.java
new file mode 100644
index 0000000..307dfe2
--- /dev/null
+++ b/media-compat/api25/android/support/v4/media/session/MediaControllerCompatApi25.java
@@ -0,0 +1,65 @@
+/*
+ * 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 android.support.v4.media.session;
+
+import android.media.session.MediaController;
+
+class MediaControllerCompatApi25 {
+    public static Object createCallback(Callback callback) {
+        return new CallbackProxy<Callback>(callback);
+    }
+
+    public static int getRepeatMode(Object controllerObj) {
+        return ((MediaController) controllerObj).getRepeatMode();
+    }
+
+    public static boolean isShuffleModeEnabled(Object controllerObj) {
+        return ((MediaController) controllerObj).isShuffleModeEnabled();
+    }
+
+    public static class TransportControls extends MediaControllerCompatApi23.TransportControls {
+        public static void setRepeatMode(Object controlsObj, int repeatMode) {
+            ((MediaController.TransportControls) controlsObj).setRepeatMode(repeatMode);
+        }
+
+        public static void setShuffleModeEnabled(Object controlsObj, boolean enabled) {
+            ((MediaController.TransportControls) controlsObj).setShuffleModeEnabled(enabled);
+        }
+    }
+
+    public interface Callback extends MediaControllerCompatApi21.Callback {
+        void onRepeatModeChanged(int repeatMode);
+        void onShuffleModeChanged(boolean enabled);
+    }
+
+    static class CallbackProxy<T extends Callback> extends MediaControllerCompatApi21
+            .CallbackProxy<T> {
+        CallbackProxy(T callback) {
+            super(callback);
+        }
+
+        @Override
+        public void onRepeatModeChanged(int repeatMode) {
+            mCallback.onRepeatModeChanged(repeatMode);
+        }
+
+        @Override
+        public void onShuffleModeChanged(boolean enabled) {
+            mCallback.onShuffleModeChanged(enabled);
+        }
+    }
+}
diff --git a/media-compat/api25/android/support/v4/media/session/MediaSessionCompatApi25.java b/media-compat/api25/android/support/v4/media/session/MediaSessionCompatApi25.java
new file mode 100644
index 0000000..cba1020
--- /dev/null
+++ b/media-compat/api25/android/support/v4/media/session/MediaSessionCompatApi25.java
@@ -0,0 +1,56 @@
+/*
+ * 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 android.support.v4.media.session;
+
+import android.media.session.MediaSession;
+
+class MediaSessionCompatApi25 {
+
+    public static Object createCallback(Callback callback) {
+        return new CallbackProxy<Callback>(callback);
+    }
+
+    public static void setRepeatMode(Object sessionObj, int repeatMode) {
+        ((MediaSession) sessionObj).setRepeatMode(repeatMode);
+    }
+
+    public static void setShuffleModeEnabled(Object sessionObj, boolean enabled) {
+        ((MediaSession) sessionObj).setShuffleModeEnabled(enabled);
+    }
+
+    public interface Callback extends MediaSessionCompatApi24.Callback {
+        void onSetRepeatMode(int repeatMode);
+        void onSetShuffleModeEnabled(boolean enabled);
+    }
+
+    static class CallbackProxy<T extends Callback>
+            extends MediaSessionCompatApi24.CallbackProxy<T> {
+        CallbackProxy(T callback) {
+            super(callback);
+        }
+
+        @Override
+        public void onSetRepeatMode(int repeatMode) {
+            mCallback.onSetRepeatMode(repeatMode);
+        }
+
+        @Override
+        public void onSetShuffleModeEnabled(boolean enabled) {
+            mCallback.onSetShuffleModeEnabled(enabled);
+        }
+    }
+}
diff --git a/media-compat/java/android/support/v4/media/session/IMediaControllerCallback.aidl b/media-compat/java/android/support/v4/media/session/IMediaControllerCallback.aidl
index d905350..d1d143d 100644
--- a/media-compat/java/android/support/v4/media/session/IMediaControllerCallback.aidl
+++ b/media-compat/java/android/support/v4/media/session/IMediaControllerCallback.aidl
@@ -37,4 +37,6 @@
     void onQueueTitleChanged(CharSequence title);
     void onExtrasChanged(in Bundle extras);
     void onVolumeInfoChanged(in ParcelableVolumeInfo info);
+    void onRepeatModeChanged(int repeatMode);
+    void onShuffleModeChanged(boolean enabled);
 }
diff --git a/media-compat/java/android/support/v4/media/session/IMediaSession.aidl b/media-compat/java/android/support/v4/media/session/IMediaSession.aidl
index 718b870..4f2e38a 100644
--- a/media-compat/java/android/support/v4/media/session/IMediaSession.aidl
+++ b/media-compat/java/android/support/v4/media/session/IMediaSession.aidl
@@ -33,42 +33,47 @@
  * @hide
  */
 interface IMediaSession {
-    void sendCommand(String command, in Bundle args, in MediaSessionCompat.ResultReceiverWrapper cb);
-    boolean sendMediaButton(in KeyEvent mediaButton);
-    void registerCallbackListener(in IMediaControllerCallback cb);
-    void unregisterCallbackListener(in IMediaControllerCallback cb);
-    boolean isTransportControlEnabled();
-    String getPackageName();
-    String getTag();
-    PendingIntent getLaunchPendingIntent();
-    long getFlags();
-    ParcelableVolumeInfo getVolumeAttributes();
-    void adjustVolume(int direction, int flags, String packageName);
-    void setVolumeTo(int value, int flags, String packageName);
+    // Next ID: 40
+    void sendCommand(String command, in Bundle args, in MediaSessionCompat.ResultReceiverWrapper cb) = 0;
+    boolean sendMediaButton(in KeyEvent mediaButton) = 1;
+    void registerCallbackListener(in IMediaControllerCallback cb) = 2;
+    void unregisterCallbackListener(in IMediaControllerCallback cb) = 3;
+    boolean isTransportControlEnabled() = 4;
+    String getPackageName() = 5;
+    String getTag() = 6;
+    PendingIntent getLaunchPendingIntent() = 7;
+    long getFlags() = 8;
+    ParcelableVolumeInfo getVolumeAttributes() = 9;
+    void adjustVolume(int direction, int flags, String packageName) = 10;
+    void setVolumeTo(int value, int flags, String packageName) = 11;
+    MediaMetadataCompat getMetadata() = 26;
+    PlaybackStateCompat getPlaybackState() = 27;
+    List<MediaSessionCompat.QueueItem> getQueue() = 28;
+    CharSequence getQueueTitle() = 29;
+    Bundle getExtras() = 30;
+    int getRatingType() = 31;
+    int getRepeatMode() = 36;
+    boolean isShuffleModeEnabled() = 37;
 
     // These commands are for the TransportControls
-    void play();
-    void playFromMediaId(String uri, in Bundle extras);
-    void playFromSearch(String string, in Bundle extras);
-    void playFromUri(in Uri uri, in Bundle extras);
-    void skipToQueueItem(long id);
-    void pause();
-    void stop();
-    void next();
-    void previous();
-    void fastForward();
-    void rewind();
-    void seekTo(long pos);
-    void rate(in RatingCompat rating);
-    void sendCustomAction(String action, in Bundle args);
-    MediaMetadataCompat getMetadata();
-    PlaybackStateCompat getPlaybackState();
-    List<MediaSessionCompat.QueueItem> getQueue();
-    CharSequence getQueueTitle();
-    Bundle getExtras();
-    int getRatingType();
-    void prepare();
-    void prepareFromMediaId(String uri, in Bundle extras);
-    void prepareFromSearch(String string, in Bundle extras);
-    void prepareFromUri(in Uri uri, in Bundle extras);
+    void prepare() = 32;
+    void prepareFromMediaId(String uri, in Bundle extras) = 33;
+    void prepareFromSearch(String string, in Bundle extras) = 34;
+    void prepareFromUri(in Uri uri, in Bundle extras) = 35;
+    void play() = 12;
+    void playFromMediaId(String uri, in Bundle extras) = 13;
+    void playFromSearch(String string, in Bundle extras) = 14;
+    void playFromUri(in Uri uri, in Bundle extras) = 15;
+    void skipToQueueItem(long id) = 16;
+    void pause() = 17;
+    void stop() = 18;
+    void next() = 19;
+    void previous() = 20;
+    void fastForward() = 21;
+    void rewind() = 22;
+    void seekTo(long pos) = 23;
+    void rate(in RatingCompat rating) = 24;
+    void setRepeatMode(int repeatMode) = 38;
+    void setShuffleModeEnabled(boolean shuffleMode) = 39;
+    void sendCustomAction(String action, in Bundle args) = 25;
 }
diff --git a/media-compat/java/android/support/v4/media/session/MediaControllerCompat.java b/media-compat/java/android/support/v4/media/session/MediaControllerCompat.java
index 266a4d1..8f73abf 100644
--- a/media-compat/java/android/support/v4/media/session/MediaControllerCompat.java
+++ b/media-compat/java/android/support/v4/media/session/MediaControllerCompat.java
@@ -27,6 +27,7 @@
 import android.os.Message;
 import android.os.RemoteException;
 import android.os.ResultReceiver;
+import android.support.v4.app.BundleCompat;
 import android.support.v4.media.MediaMetadataCompat;
 import android.support.v4.media.RatingCompat;
 import android.support.v4.media.VolumeProviderCompat;
@@ -36,6 +37,8 @@
 import android.util.Log;
 import android.view.KeyEvent;
 
+import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
 
 /**
@@ -54,6 +57,9 @@
 public final class MediaControllerCompat {
     static final String TAG = "MediaControllerCompat";
 
+    static final String COMMAND_GET_EXTRA_BINDER =
+            "android.support.v4.media.session.command.GET_EXTRA_BINDER";
+
     private final MediaControllerImpl mImpl;
     private final MediaSessionCompat.Token mToken;
 
@@ -68,7 +74,9 @@
         }
         mToken = session.getSessionToken();
 
-        if (android.os.Build.VERSION.SDK_INT >= 24) {
+        if (android.os.Build.VERSION.SDK_INT >= 25) {
+            mImpl = new MediaControllerImplApi25(context, session);
+        } else if (android.os.Build.VERSION.SDK_INT >= 24) {
             mImpl = new MediaControllerImplApi24(context, session);
         } else if (android.os.Build.VERSION.SDK_INT >= 23) {
             mImpl = new MediaControllerImplApi23(context, session);
@@ -93,7 +101,9 @@
         }
         mToken = sessionToken;
 
-        if (android.os.Build.VERSION.SDK_INT >= 24) {
+        if (android.os.Build.VERSION.SDK_INT >= 25) {
+            mImpl = new MediaControllerImplApi25(context, sessionToken);
+        } else if (android.os.Build.VERSION.SDK_INT >= 24) {
             mImpl = new MediaControllerImplApi24(context, sessionToken);
         } else if (android.os.Build.VERSION.SDK_INT >= 23) {
             mImpl = new MediaControllerImplApi23(context, sessionToken);
@@ -188,6 +198,25 @@
     }
 
     /**
+     * Get the repeat mode for this session.
+     *
+     * @return The latest repeat mode set to the session, or
+     *         {@link PlaybackStateCompat#REPEAT_MODE_NONE} if not set.
+     */
+    public int getRepeatMode() {
+        return mImpl.getRepeatMode();
+    }
+
+    /**
+     * Return whether the shuffle mode is enabled for this session.
+     *
+     * @return {@code true} if the shuffle mode is enabled, {@code false} if disabled or not set.
+     */
+    public boolean isShuffleModeEnabled() {
+        return mImpl.isShuffleModeEnabled();
+    }
+
+    /**
      * Get the flags for this session. Flags are defined in
      * {@link MediaSessionCompat}.
      *
@@ -344,11 +373,14 @@
     public static abstract class Callback implements IBinder.DeathRecipient {
         private final Object mCallbackObj;
         MessageHandler mHandler;
+        boolean mHasExtraCallback;
 
         boolean mRegistered = false;
 
         public Callback() {
-            if (android.os.Build.VERSION.SDK_INT >= 21) {
+            if (android.os.Build.VERSION.SDK_INT >= 25) {
+                mCallbackObj = MediaControllerCompatApi25.createCallback(new StubApi25());
+            } else if (android.os.Build.VERSION.SDK_INT >= 21) {
                 mCallbackObj = MediaControllerCompatApi21.createCallback(new StubApi21());
             } else {
                 mCallbackObj = new StubCompat();
@@ -428,6 +460,25 @@
         public void onAudioInfoChanged(PlaybackInfo info) {
         }
 
+        /**
+         * Override to handle changes to the repeat mode.
+         *
+         * @param repeatMode The repeat mode. It should be one of followings:
+         *            {@link PlaybackStateCompat#REPEAT_MODE_NONE},
+         *            {@link PlaybackStateCompat#REPEAT_MODE_ONE},
+         *            {@link PlaybackStateCompat#REPEAT_MODE_ALL}
+         */
+        public void onRepeatModeChanged(@PlaybackStateCompat.RepeatMode int repeatMode) {
+        }
+
+        /**
+         * Override to handle changes to the shuffle mode.
+         *
+         * @param enabled {@code true} if the shuffle mode is enabled, {@code false} otherwise.
+         */
+        public void onShuffleModeChanged(boolean enabled) {
+        }
+
         @Override
         public void binderDied() {
             onSessionDestroyed();
@@ -451,13 +502,21 @@
 
             @Override
             public void onSessionEvent(String event, Bundle extras) {
-                Callback.this.onSessionEvent(event, extras);
+                if (mHasExtraCallback && android.os.Build.VERSION.SDK_INT < 23) {
+                    // Ignore. ExtraCallback will handle this.
+                } else {
+                    Callback.this.onSessionEvent(event, extras);
+                }
             }
 
             @Override
             public void onPlaybackStateChanged(Object stateObj) {
-                Callback.this.onPlaybackStateChanged(
-                        PlaybackStateCompat.fromPlaybackState(stateObj));
+                if (mHasExtraCallback && android.os.Build.VERSION.SDK_INT < 22) {
+                    // Ignore. ExtraCallback will handle this.
+                } else {
+                    Callback.this.onPlaybackStateChanged(
+                            PlaybackStateCompat.fromPlaybackState(stateObj));
+                }
             }
 
             @Override
@@ -488,6 +547,18 @@
             }
         }
 
+        private class StubApi25 extends StubApi21 implements MediaControllerCompatApi25.Callback {
+            @Override
+            public void onRepeatModeChanged(@PlaybackStateCompat.RepeatMode int repeatMode) {
+                Callback.this.onRepeatModeChanged(repeatMode);
+            }
+
+            @Override
+            public void onShuffleModeChanged(boolean enabled) {
+                Callback.this.onShuffleModeChanged(enabled);
+            }
+        }
+
         private class StubCompat extends IMediaControllerCallback.Stub {
 
             StubCompat() {
@@ -524,6 +595,16 @@
             }
 
             @Override
+            public void onRepeatModeChanged(int repeatMode) throws RemoteException {
+                mHandler.post(MessageHandler.MSG_UPDATE_REPEAT_MODE, repeatMode, null);
+            }
+
+            @Override
+            public void onShuffleModeChanged(boolean enabled) throws RemoteException {
+                mHandler.post(MessageHandler.MSG_UPDATE_SHUFFLE_MODE, enabled, null);
+            }
+
+            @Override
             public void onExtrasChanged(Bundle extras) throws RemoteException {
                 mHandler.post(MessageHandler.MSG_UPDATE_EXTRAS, extras, null);
             }
@@ -548,6 +629,8 @@
             private static final int MSG_UPDATE_QUEUE_TITLE = 6;
             private static final int MSG_UPDATE_EXTRAS = 7;
             private static final int MSG_DESTROYED = 8;
+            private static final int MSG_UPDATE_REPEAT_MODE = 9;
+            private static final int MSG_UPDATE_SHUFFLE_MODE = 10;
 
             public MessageHandler(Looper looper) {
                 super(looper);
@@ -574,6 +657,12 @@
                     case MSG_UPDATE_QUEUE_TITLE:
                         onQueueTitleChanged((CharSequence) msg.obj);
                         break;
+                    case MSG_UPDATE_REPEAT_MODE:
+                        onRepeatModeChanged((int) msg.obj);
+                        break;
+                    case MSG_UPDATE_SHUFFLE_MODE:
+                        onShuffleModeChanged((boolean) msg.obj);
+                        break;
                     case MSG_UPDATE_EXTRAS:
                         onExtrasChanged((Bundle) msg.obj);
                         break;
@@ -749,6 +838,23 @@
         public abstract void setRating(RatingCompat rating);
 
         /**
+         * Set the repeat mode for this session.
+         *
+         * @param repeatMode The repeat mode. Must be one of the followings:
+         *            {@link PlaybackStateCompat#REPEAT_MODE_NONE},
+         *            {@link PlaybackStateCompat#REPEAT_MODE_ONE},
+         *            {@link PlaybackStateCompat#REPEAT_MODE_ALL}
+         */
+        public abstract void setRepeatMode(@PlaybackStateCompat.RepeatMode int repeatMode);
+
+        /**
+         * Set the shuffle mode for this session.
+         *
+         * @param enabled {@code true} to enable the shuffle mode, {@code false} to disable.
+         */
+        public abstract void setShuffleModeEnabled(boolean enabled);
+
+        /**
          * Send a custom action for the {@link MediaSessionCompat} to perform.
          *
          * @param customAction The action to perform.
@@ -873,6 +979,8 @@
         CharSequence getQueueTitle();
         Bundle getExtras();
         int getRatingType();
+        int getRepeatMode();
+        boolean isShuffleModeEnabled();
         long getFlags();
         PlaybackInfo getPlaybackInfo();
         PendingIntent getSessionActivity();
@@ -1009,6 +1117,26 @@
         }
 
         @Override
+        public int getRepeatMode() {
+            try {
+                return mBinder.getRepeatMode();
+            } catch (RemoteException e) {
+                Log.e(TAG, "Dead object in getRepeatMode. " + e);
+            }
+            return 0;
+        }
+
+        @Override
+        public boolean isShuffleModeEnabled() {
+            try {
+                return mBinder.isShuffleModeEnabled();
+            } catch (RemoteException e) {
+                Log.e(TAG, "Dead object in isShuffleModeEnabled. " + e);
+            }
+            return false;
+        }
+
+        @Override
         public long getFlags() {
             try {
                 return mBinder.getFlags();
@@ -1246,6 +1374,24 @@
         }
 
         @Override
+        public void setRepeatMode(@PlaybackStateCompat.RepeatMode int repeatMode) {
+            try {
+                mBinder.setRepeatMode(repeatMode);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Dead object in setRepeatMode. " + e);
+            }
+        }
+
+        @Override
+        public void setShuffleModeEnabled(boolean enabled) {
+            try {
+                mBinder.setShuffleModeEnabled(enabled);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Dead object in setShuffleModeEnabled. " + e);
+            }
+        }
+
+        @Override
         public void sendCustomAction(CustomAction customAction, Bundle args) {
             sendCustomAction(customAction.getAction(), args);
         }
@@ -1263,9 +1409,18 @@
     static class MediaControllerImplApi21 implements MediaControllerImpl {
         protected final Object mControllerObj;
 
+        // Extra binder is used for applying the framework change of new APIs and bug fixes
+        // after API 21.
+        private IMediaSession mExtraBinder;
+        private HashMap<Callback, ExtraCallback> mCallbackMap = new HashMap<>();
+        private List<Callback> mPendingCallbacks;
+
         public MediaControllerImplApi21(Context context, MediaSessionCompat session) {
             mControllerObj = MediaControllerCompatApi21.fromToken(context,
                     session.getSessionToken().getToken());
+            if (android.os.Build.VERSION.SDK_INT < 23) {
+                requestExtraBinder();
+            }
         }
 
         public MediaControllerImplApi21(Context context, MediaSessionCompat.Token sessionToken)
@@ -1273,16 +1428,52 @@
             mControllerObj = MediaControllerCompatApi21.fromToken(context,
                     sessionToken.getToken());
             if (mControllerObj == null) throw new RemoteException();
+            if (android.os.Build.VERSION.SDK_INT < 23) {
+                requestExtraBinder();
+            }
         }
 
         @Override
-        public void registerCallback(Callback callback, Handler handler) {
-            MediaControllerCompatApi21.registerCallback(mControllerObj, callback.mCallbackObj, handler);
+        public final void registerCallback(Callback callback, Handler handler) {
+            MediaControllerCompatApi21.registerCallback(
+                    mControllerObj, callback.mCallbackObj, handler);
+            if (mExtraBinder != null) {
+                callback.setHandler(handler);
+                ExtraCallback extraCallback = new ExtraCallback(callback);
+                mCallbackMap.put(callback, extraCallback);
+                callback.mHasExtraCallback = true;
+                try {
+                    mExtraBinder.registerCallbackListener(extraCallback);
+                } catch (RemoteException e) {
+                    Log.e(TAG, "Dead object in registerCallback. " + e);
+                }
+            } else if (android.os.Build.VERSION.SDK_INT < 23) {
+                if (mPendingCallbacks == null) {
+                    mPendingCallbacks = new ArrayList<>();
+                }
+                callback.setHandler(handler);
+                mPendingCallbacks.add(callback);
+            }
         }
 
         @Override
-        public void unregisterCallback(Callback callback) {
+        public final void unregisterCallback(Callback callback) {
             MediaControllerCompatApi21.unregisterCallback(mControllerObj, callback.mCallbackObj);
+            if (mExtraBinder != null) {
+                try {
+                    ExtraCallback extraCallback = mCallbackMap.remove(callback);
+                    if (extraCallback != null) {
+                        mExtraBinder.unregisterCallbackListener(extraCallback);
+                    }
+                } catch (RemoteException e) {
+                    Log.e(TAG, "Dead object in unregisterCallback. " + e);
+                }
+            } else if (android.os.Build.VERSION.SDK_INT < 23) {
+                if (mPendingCallbacks == null) {
+                    mPendingCallbacks = new ArrayList<>();
+                }
+                mPendingCallbacks.remove(callback);
+            }
         }
 
         @Override
@@ -1298,6 +1489,13 @@
 
         @Override
         public PlaybackStateCompat getPlaybackState() {
+            if (android.os.Build.VERSION.SDK_INT < 22 && mExtraBinder != null) {
+                try {
+                    return mExtraBinder.getPlaybackState();
+                } catch (RemoteException e) {
+                    Log.e(TAG, "Dead object in getPlaybackState. " + e);
+                }
+            }
             Object stateObj = MediaControllerCompatApi21.getPlaybackState(mControllerObj);
             return stateObj != null ? PlaybackStateCompat.fromPlaybackState(stateObj) : null;
         }
@@ -1327,10 +1525,29 @@
 
         @Override
         public int getRatingType() {
+            if (android.os.Build.VERSION.SDK_INT < 22 && mExtraBinder != null) {
+                try {
+                    return mExtraBinder.getRatingType();
+                } catch (RemoteException e) {
+                    Log.e(TAG, "Dead object in getRatingType. " + e);
+                }
+            }
             return MediaControllerCompatApi21.getRatingType(mControllerObj);
         }
 
         @Override
+        public int getRepeatMode() {
+            // TODO: implement this
+            return 0;
+        }
+
+        @Override
+        public boolean isShuffleModeEnabled() {
+            // TODO: implement this
+            return false;
+        }
+
+        @Override
         public long getFlags() {
             return MediaControllerCompatApi21.getFlags(mControllerObj);
         }
@@ -1375,6 +1592,111 @@
         public Object getMediaController() {
             return mControllerObj;
         }
+
+        private void requestExtraBinder() {
+            ResultReceiver cb = new ResultReceiver(new Handler()) {
+                @Override
+                protected void onReceiveResult(int resultCode, Bundle resultData) {
+                    if (resultData != null) {
+                        mExtraBinder = IMediaSession.Stub.asInterface(
+                                BundleCompat.getBinder(
+                                        resultData, MediaSessionCompat.EXTRA_BINDER));
+                        if (mPendingCallbacks != null) {
+                            for (Callback callback : mPendingCallbacks) {
+                                ExtraCallback extraCallback = new ExtraCallback(callback);
+                                mCallbackMap.put(callback, extraCallback);
+                                callback.mHasExtraCallback = true;
+                                try {
+                                    mExtraBinder.registerCallbackListener(extraCallback);
+                                } catch (RemoteException e) {
+                                    Log.e(TAG, "Dead object in registerCallback. " + e);
+                                    break;
+                                }
+                            }
+                            mPendingCallbacks = null;
+                        }
+                    }
+                }
+            };
+            sendCommand(COMMAND_GET_EXTRA_BINDER, null, cb);
+        }
+
+        private class ExtraCallback extends IMediaControllerCallback.Stub {
+            private Callback mCallback;
+
+            ExtraCallback(Callback callback) {
+                mCallback = callback;
+            }
+
+            @Override
+            public void onEvent(final String event, final Bundle extras) throws RemoteException {
+                mCallback.mHandler.post(new Runnable() {
+                    @Override
+                    public void run() {
+                        mCallback.onSessionEvent(event, extras);
+                    }
+                });
+            }
+
+            @Override
+            public void onSessionDestroyed() throws RemoteException {
+                // Will not be called.
+                throw new AssertionError();
+            }
+
+            @Override
+            public void onPlaybackStateChanged(final PlaybackStateCompat state)
+                    throws RemoteException {
+                mCallback.mHandler.post(new Runnable() {
+                    @Override
+                    public void run() {
+                        mCallback.onPlaybackStateChanged(state);
+                    }
+                });
+            }
+
+            @Override
+            public void onMetadataChanged(MediaMetadataCompat metadata) throws RemoteException {
+                // Will not be called.
+                throw new AssertionError();
+            }
+
+            @Override
+            public void onQueueChanged(List<QueueItem> queue) throws RemoteException {
+                // Will not be called.
+                throw new AssertionError();
+            }
+
+            @Override
+            public void onQueueTitleChanged(CharSequence title) throws RemoteException {
+                // Will not be called.
+                throw new AssertionError();
+            }
+
+            @Override
+            public void onRepeatModeChanged(int repeatMode) throws RemoteException {
+                // Will not be called.
+                throw new AssertionError();
+            }
+
+            @Override
+            public void onShuffleModeChanged(boolean enabled) throws RemoteException {
+                // Will not be called.
+                throw new AssertionError();
+            }
+
+            @Override
+            public void onExtrasChanged(Bundle extras) throws RemoteException {
+                // Will not be called.
+                throw new AssertionError();
+            }
+
+            @Override
+            public void onVolumeInfoChanged(ParcelableVolumeInfo info) throws RemoteException {
+                // Will not be called.
+                throw new AssertionError();
+            }
+        }
     }
 
     static class TransportControlsApi21 extends TransportControls {
@@ -1460,6 +1782,16 @@
         }
 
         @Override
+        public void setRepeatMode(@PlaybackStateCompat.RepeatMode int repeatMode) {
+            // TODO: implement this
+        }
+
+        @Override
+        public void setShuffleModeEnabled(boolean enabled) {
+            // TODO: implement this
+        }
+
+        @Override
         public void playFromMediaId(String mediaId, Bundle extras) {
             MediaControllerCompatApi21.TransportControls.playFromMediaId(mControlsObj, mediaId,
                     extras);
@@ -1579,4 +1911,50 @@
         }
     }
 
+    static class MediaControllerImplApi25 extends MediaControllerImplApi24 {
+
+        MediaControllerImplApi25(Context context, MediaSessionCompat session) {
+            super(context, session);
+        }
+
+        MediaControllerImplApi25(Context context, MediaSessionCompat.Token sessionToken)
+                throws RemoteException {
+            super(context, sessionToken);
+        }
+
+        @Override
+        public TransportControls getTransportControls() {
+            Object controlsObj = MediaControllerCompatApi21.getTransportControls(mControllerObj);
+            return controlsObj != null ? new TransportControlsApi25(controlsObj) : null;
+        }
+
+        @Override
+        public int getRepeatMode() {
+            return MediaControllerCompatApi25.getRepeatMode(mControllerObj);
+        }
+
+        @Override
+        public boolean isShuffleModeEnabled() {
+            return MediaControllerCompatApi25.isShuffleModeEnabled(mControllerObj);
+        }
+    }
+
+    static class TransportControlsApi25 extends TransportControlsApi24 {
+
+        TransportControlsApi25(Object controlsObj) {
+            super(controlsObj);
+        }
+
+        @Override
+        public void setRepeatMode(@PlaybackStateCompat.RepeatMode int repeatMode) {
+            MediaControllerCompatApi25.TransportControls.setRepeatMode(mControlsObj, repeatMode);
+        }
+
+        @Override
+        public void setShuffleModeEnabled(boolean enabled) {
+            MediaControllerCompatApi25.TransportControls.setShuffleModeEnabled(mControlsObj,
+                    enabled);
+        }
+    }
+
 }
diff --git a/media-compat/java/android/support/v4/media/session/MediaSessionCompat.java b/media-compat/java/android/support/v4/media/session/MediaSessionCompat.java
index e73666c..3c0760a 100644
--- a/media-compat/java/android/support/v4/media/session/MediaSessionCompat.java
+++ b/media-compat/java/android/support/v4/media/session/MediaSessionCompat.java
@@ -17,13 +17,14 @@
 
 package android.support.v4.media.session;
 
+import static android.support.annotation.RestrictTo.Scope.GROUP_ID;
+
 import android.app.Activity;
 import android.app.PendingIntent;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
-import android.graphics.Bitmap;
 import android.media.AudioManager;
 import android.net.Uri;
 import android.os.Build;
@@ -40,6 +41,7 @@
 import android.os.SystemClock;
 import android.support.annotation.IntDef;
 import android.support.annotation.RestrictTo;
+import android.support.v4.app.BundleCompat;
 import android.support.v4.media.MediaDescriptionCompat;
 import android.support.v4.media.MediaMetadataCompat;
 import android.support.v4.media.RatingCompat;
@@ -51,11 +53,10 @@
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.List;
 
-import static android.support.annotation.RestrictTo.Scope.GROUP_ID;
-
 /**
  * Allows interaction with media controllers, volume keys, media buttons, and
  * transport controls.
@@ -163,6 +164,8 @@
     static final String ACTION_ARGUMENT_EXTRAS =
             "android.support.v4.media.session.action.ARGUMENT_EXTRAS";
 
+    static final String EXTRA_BINDER = "android.support.v4.media.session.EXTRA_BINDER";
+
     // Maximum size of the bitmap in dp.
     private static final int MAX_BITMAP_SIZE_IN_DP = 320;
 
@@ -480,6 +483,33 @@
     }
 
     /**
+     * Set the repeat mode for this session.
+     * <p>
+     * Note that if this method is not called before, {@link MediaControllerCompat#getRepeatMode}
+     * will return {@link PlaybackStateCompat#REPEAT_MODE_NONE}.
+     *
+     * @param repeatMode The repeat mode. Must be one of the followings:
+     *            {@link PlaybackStateCompat#REPEAT_MODE_NONE},
+     *            {@link PlaybackStateCompat#REPEAT_MODE_ONE},
+     *            {@link PlaybackStateCompat#REPEAT_MODE_ALL}
+     */
+    public void setRepeatMode(@PlaybackStateCompat.RepeatMode int repeatMode) {
+        mImpl.setRepeatMode(repeatMode);
+    }
+
+    /**
+     * Set the shuffle mode for this session.
+     * <p>
+     * Note that if this method is not called before,
+     * {@link MediaControllerCompat#isShuffleModeEnabled} will return {@code false}.
+     *
+     * @param enabled {@code true} to enable the shuffle mode, {@code false} to disable.
+     */
+    public void setShuffleModeEnabled(boolean enabled) {
+        mImpl.setShuffleModeEnabled(enabled);
+    }
+
+    /**
      * Set some extras that can be associated with the
      * {@link MediaSessionCompat}. No assumptions should be made as to how a
      * {@link MediaControllerCompat} will handle these extras. Keys should be
@@ -597,9 +627,12 @@
      */
     public abstract static class Callback {
         final Object mCallbackObj;
+        WeakReference<MediaSessionImpl> mSessionImpl;
 
         public Callback() {
-            if (android.os.Build.VERSION.SDK_INT >= 24) {
+            if (android.os.Build.VERSION.SDK_INT >= 25) {
+                mCallbackObj = MediaSessionCompatApi25.createCallback(new StubApi25());
+            } else if (android.os.Build.VERSION.SDK_INT >= 24) {
                 mCallbackObj = MediaSessionCompatApi24.createCallback(new StubApi24());
             } else if (android.os.Build.VERSION.SDK_INT >= 23) {
                 mCallbackObj = MediaSessionCompatApi23.createCallback(new StubApi23());
@@ -765,6 +798,33 @@
         }
 
         /**
+         * Override to handle the setting of the repeat mode.
+         * <p>
+         * You should call {@link #setRepeatMode} before end of this method in order to notify
+         * the change to the {@link MediaControllerCompat}, or
+         * {@link MediaControllerCompat#getRepeatMode} could return an invalid value.
+         *
+         * @param repeatMode The repeat mode which is one of followings:
+         *            {@link PlaybackStateCompat#REPEAT_MODE_NONE},
+         *            {@link PlaybackStateCompat#REPEAT_MODE_ONE},
+         *            {@link PlaybackStateCompat#REPEAT_MODE_ALL}
+         */
+        public void onSetRepeatMode(@PlaybackStateCompat.RepeatMode int repeatMode) {
+        }
+
+        /**
+         * Override to handle the setting of the shuffle mode.
+         * <p>
+         * You should call {@link #setShuffleModeEnabled} before the end of this method in order to
+         * notify the change to the {@link MediaControllerCompat}, or
+         * {@link MediaControllerCompat#isShuffleModeEnabled} could return an invalid value.
+         *
+         * @param enabled true when the shuffle mode is enabled, false otherwise.
+         */
+        public void onSetShuffleModeEnabled(boolean enabled) {
+        }
+
+        /**
          * Called when a {@link MediaControllerCompat} wants a
          * {@link PlaybackStateCompat.CustomAction} to be performed.
          *
@@ -783,7 +843,16 @@
 
             @Override
             public void onCommand(String command, Bundle extras, ResultReceiver cb) {
-                Callback.this.onCommand(command, extras, cb);
+                if (command.equals(MediaControllerCompat.COMMAND_GET_EXTRA_BINDER)) {
+                    MediaSessionImplApi21 impl = (MediaSessionImplApi21) mSessionImpl.get();
+                    if (impl != null) {
+                        Bundle result = new Bundle();
+                        BundleCompat.putBinder(result, EXTRA_BINDER, impl.getExtraSessionBinder());
+                        cb.send(0, result);
+                    }
+                } else {
+                    Callback.this.onCommand(command, extras, cb);
+                }
             }
 
             @Override
@@ -913,6 +982,18 @@
                 Callback.this.onPrepareFromUri(uri, extras);
             }
         }
+
+        private class StubApi25 extends StubApi24 implements MediaSessionCompatApi25.Callback {
+            @Override
+            public void onSetRepeatMode(int repeatMode) {
+                Callback.this.onSetRepeatMode(repeatMode);
+            }
+
+            @Override
+            public void onSetShuffleModeEnabled(boolean enabled) {
+                Callback.this.onSetShuffleModeEnabled(enabled);
+            }
+        }
     }
 
     /**
@@ -1250,6 +1331,8 @@
         void setQueueTitle(CharSequence title);
 
         void setRatingType(@RatingCompat.Style int type);
+        void setRepeatMode(@PlaybackStateCompat.RepeatMode int repeatMode);
+        void setShuffleModeEnabled(boolean enabled);
         void setExtras(Bundle extras);
 
         Object getMediaSession();
@@ -1289,6 +1372,8 @@
         List<QueueItem> mQueue;
         CharSequence mQueueTitle;
         @RatingCompat.Style int mRatingType;
+        @PlaybackStateCompat.RepeatMode int mRepeatMode;
+        boolean mShuffleModeEnabled;
         Bundle mExtras;
 
         int mVolumeType;
@@ -1591,6 +1676,22 @@
         }
 
         @Override
+        public void setRepeatMode(@PlaybackStateCompat.RepeatMode int repeatMode) {
+            if (mRepeatMode != repeatMode) {
+                mRepeatMode = repeatMode;
+                sendRepeatMode(repeatMode);
+            }
+        }
+
+        @Override
+        public void setShuffleModeEnabled(boolean enabled) {
+            if (mShuffleModeEnabled != enabled) {
+                mShuffleModeEnabled = enabled;
+                sendShuffleModeEnabled(enabled);
+            }
+        }
+
+        @Override
         public void setExtras(Bundle extras) {
             mExtras = extras;
             sendExtras(extras);
@@ -1809,6 +1910,30 @@
             mControllerCallbacks.finishBroadcast();
         }
 
+        private void sendRepeatMode(int repeatMode) {
+            int size = mControllerCallbacks.beginBroadcast();
+            for (int i = size - 1; i >= 0; i--) {
+                IMediaControllerCallback cb = mControllerCallbacks.getBroadcastItem(i);
+                try {
+                    cb.onRepeatModeChanged(repeatMode);
+                } catch (RemoteException e) {
+                }
+            }
+            mControllerCallbacks.finishBroadcast();
+        }
+
+        private void sendShuffleModeEnabled(boolean enabled) {
+            int size = mControllerCallbacks.beginBroadcast();
+            for (int i = size - 1; i >= 0; i--) {
+                IMediaControllerCallback cb = mControllerCallbacks.getBroadcastItem(i);
+                try {
+                    cb.onShuffleModeChanged(enabled);
+                } catch (RemoteException e) {
+                }
+            }
+            mControllerCallbacks.finishBroadcast();
+        }
+
         private void sendExtras(Bundle extras) {
             int size = mControllerCallbacks.beginBroadcast();
             for (int i = size - 1; i >= 0; i--) {
@@ -2005,6 +2130,16 @@
             }
 
             @Override
+            public void setRepeatMode(int repeatMode) throws RemoteException {
+                postToHandler(MessageHandler.MSG_SET_REPEAT_MODE, repeatMode);
+            }
+
+            @Override
+            public void setShuffleModeEnabled(boolean enabled) throws RemoteException {
+                postToHandler(MessageHandler.MSG_SET_SHUFFLE_MODE_ENABLED, enabled);
+            }
+
+            @Override
             public void sendCustomAction(String action, Bundle args)
                     throws RemoteException {
                 postToHandler(MessageHandler.MSG_CUSTOM_ACTION, action, args);
@@ -2046,6 +2181,17 @@
             }
 
             @Override
+            @PlaybackStateCompat.RepeatMode
+            public int getRepeatMode() {
+                return mRepeatMode;
+            }
+
+            @Override
+            public boolean isShuffleModeEnabled() {
+                return mShuffleModeEnabled;
+            }
+
+            @Override
             public boolean isTransportControlEnabled() {
                 return (mFlags & FLAG_HANDLES_TRANSPORT_CONTROLS) != 0;
             }
@@ -2087,6 +2233,8 @@
             private static final int MSG_CUSTOM_ACTION = 20;
             private static final int MSG_MEDIA_BUTTON = 21;
             private static final int MSG_SET_VOLUME = 22;
+            private static final int MSG_SET_REPEAT_MODE = 23;
+            private static final int MSG_SET_SHUFFLE_MODE_ENABLED = 24;
 
             // KeyEvent constants only available on API 11+
             private static final int KEYCODE_MEDIA_PAUSE = 127;
@@ -2194,6 +2342,12 @@
                     case MSG_SET_VOLUME:
                         setVolumeTo((int) msg.obj, 0);
                         break;
+                    case MSG_SET_REPEAT_MODE:
+                        cb.onSetRepeatMode((int) msg.obj);
+                        break;
+                    case MSG_SET_SHUFFLE_MODE_ENABLED:
+                        cb.onSetShuffleModeEnabled((boolean) msg.obj);
+                        break;
                 }
             }
 
@@ -2263,7 +2417,13 @@
         private final Object mSessionObj;
         private final Token mToken;
 
-        private PendingIntent mMediaButtonIntent;
+        private boolean mDestroyed = false;
+        private ExtraSession mExtraSessionBinder;
+        private final RemoteCallbackList<IMediaControllerCallback> mExtraControllerCallbacks =
+                new RemoteCallbackList<>();
+
+        private PlaybackStateCompat mPlaybackState;
+        @RatingCompat.Style int mRatingType;
 
         public MediaSessionImplApi21(Context context, String tag) {
             mSessionObj = MediaSessionCompatApi21.createSession(context, tag);
@@ -2279,6 +2439,9 @@
         public void setCallback(Callback callback, Handler handler) {
             MediaSessionCompatApi21.setCallback(mSessionObj,
                     callback == null ? null : callback.mCallbackObj, handler);
+            if (android.os.Build.VERSION.SDK_INT < 23) {
+                callback.mSessionImpl = new WeakReference<MediaSessionImpl>(this);
+            }
         }
 
         @Override
@@ -2309,11 +2472,23 @@
 
         @Override
         public void sendSessionEvent(String event, Bundle extras) {
+            if (android.os.Build.VERSION.SDK_INT < 23) {
+                int size = mExtraControllerCallbacks.beginBroadcast();
+                for (int i = size - 1; i >= 0; i--) {
+                    IMediaControllerCallback cb = mExtraControllerCallbacks.getBroadcastItem(i);
+                    try {
+                        cb.onEvent(event, extras);
+                    } catch (RemoteException e) {
+                    }
+                }
+                mExtraControllerCallbacks.finishBroadcast();
+            }
             MediaSessionCompatApi21.sendSessionEvent(mSessionObj, event, extras);
         }
 
         @Override
         public void release() {
+            mDestroyed = true;
             MediaSessionCompatApi21.release(mSessionObj);
         }
 
@@ -2324,6 +2499,18 @@
 
         @Override
         public void setPlaybackState(PlaybackStateCompat state) {
+            if (android.os.Build.VERSION.SDK_INT < 22) {
+                mPlaybackState = state;
+                int size = mExtraControllerCallbacks.beginBroadcast();
+                for (int i = size - 1; i >= 0; i--) {
+                    IMediaControllerCallback cb = mExtraControllerCallbacks.getBroadcastItem(i);
+                    try {
+                        cb.onPlaybackStateChanged(state);
+                    } catch (RemoteException e) {
+                    }
+                }
+                mExtraControllerCallbacks.finishBroadcast();
+            }
             MediaSessionCompatApi21.setPlaybackState(mSessionObj,
                     state == null ? null : state.getPlaybackState());
         }
@@ -2341,7 +2528,6 @@
 
         @Override
         public void setMediaButtonReceiver(PendingIntent mbr) {
-            mMediaButtonIntent = mbr;
             MediaSessionCompatApi21.setMediaButtonReceiver(mSessionObj, mbr);
         }
 
@@ -2365,13 +2551,31 @@
         @Override
         public void setRatingType(@RatingCompat.Style int type) {
             if (android.os.Build.VERSION.SDK_INT < 22) {
-                // TODO figure out 21 implementation
+                mRatingType = type;
             } else {
                 MediaSessionCompatApi22.setRatingType(mSessionObj, type);
             }
         }
 
         @Override
+        public void setRepeatMode(@PlaybackStateCompat.RepeatMode int repeatMode) {
+            if (android.os.Build.VERSION.SDK_INT < 25) {
+                // TODO: implement this
+            } else {
+                MediaSessionCompatApi25.setRepeatMode(mSessionObj, repeatMode);
+            }
+        }
+
+        @Override
+        public void setShuffleModeEnabled(boolean enabled) {
+            if (android.os.Build.VERSION.SDK_INT < 25) {
+                // TODO: implement this
+            } else {
+                MediaSessionCompatApi25.setShuffleModeEnabled(mSessionObj, enabled);
+            }
+        }
+
+        @Override
         public void setExtras(Bundle extras) {
             MediaSessionCompatApi21.setExtras(mSessionObj, extras);
         }
@@ -2394,5 +2598,255 @@
                 return MediaSessionCompatApi24.getCallingPackage(mSessionObj);
             }
         }
+
+        ExtraSession getExtraSessionBinder() {
+            if (mExtraSessionBinder == null) {
+                mExtraSessionBinder = new ExtraSession();
+            }
+            return mExtraSessionBinder;
+        }
+
+        class ExtraSession extends IMediaSession.Stub {
+            @Override
+            public void sendCommand(String command, Bundle args, ResultReceiverWrapper cb) {
+                // Will not be called.
+                throw new AssertionError();
+            }
+
+            @Override
+            public boolean sendMediaButton(KeyEvent mediaButton) {
+                // Will not be called.
+                throw new AssertionError();
+            }
+
+            @Override
+            public void registerCallbackListener(IMediaControllerCallback cb) {
+                if (!mDestroyed) {
+                    mExtraControllerCallbacks.register(cb);
+                }
+            }
+
+            @Override
+            public void unregisterCallbackListener(IMediaControllerCallback cb) {
+                mExtraControllerCallbacks.unregister(cb);
+            }
+
+            @Override
+            public String getPackageName() {
+                // Will not be called.
+                throw new AssertionError();
+            }
+
+            @Override
+            public String getTag() {
+                // Will not be called.
+                throw new AssertionError();
+            }
+
+            @Override
+            public PendingIntent getLaunchPendingIntent() {
+                // Will not be called.
+                throw new AssertionError();
+            }
+
+            @Override
+            @SessionFlags
+            public long getFlags() {
+                // Will not be called.
+                throw new AssertionError();
+            }
+
+            @Override
+            public ParcelableVolumeInfo getVolumeAttributes() {
+                // Will not be called.
+                throw new AssertionError();
+            }
+
+            @Override
+            public void adjustVolume(int direction, int flags, String packageName) {
+                // Will not be called.
+                throw new AssertionError();
+            }
+
+            @Override
+            public void setVolumeTo(int value, int flags, String packageName) {
+                // Will not be called.
+                throw new AssertionError();
+            }
+
+            @Override
+            public void prepare() throws RemoteException {
+                // Will not be called.
+                throw new AssertionError();
+            }
+
+            @Override
+            public void prepareFromMediaId(String mediaId, Bundle extras) throws RemoteException {
+                // Will not be called.
+                throw new AssertionError();
+            }
+
+            @Override
+            public void prepareFromSearch(String query, Bundle extras) throws RemoteException {
+                // Will not be called.
+                throw new AssertionError();
+            }
+
+            @Override
+            public void prepareFromUri(Uri uri, Bundle extras) throws RemoteException {
+                // Will not be called.
+                throw new AssertionError();
+            }
+
+            @Override
+            public void play() throws RemoteException {
+                // Will not be called.
+                throw new AssertionError();
+            }
+
+            @Override
+            public void playFromMediaId(String mediaId, Bundle extras) throws RemoteException {
+                // Will not be called.
+                throw new AssertionError();
+            }
+
+            @Override
+            public void playFromSearch(String query, Bundle extras) throws RemoteException {
+                // Will not be called.
+                throw new AssertionError();
+            }
+
+            @Override
+            public void playFromUri(Uri uri, Bundle extras) throws RemoteException {
+                // Will not be called.
+                throw new AssertionError();
+            }
+
+            @Override
+            public void skipToQueueItem(long id) {
+                // Will not be called.
+                throw new AssertionError();
+            }
+
+            @Override
+            public void pause() throws RemoteException {
+                // Will not be called.
+                throw new AssertionError();
+            }
+
+            @Override
+            public void stop() throws RemoteException {
+                // Will not be called.
+                throw new AssertionError();
+            }
+
+            @Override
+            public void next() throws RemoteException {
+                // Will not be called.
+                throw new AssertionError();
+            }
+
+            @Override
+            public void previous() throws RemoteException {
+                // Will not be called.
+                throw new AssertionError();
+            }
+
+            @Override
+            public void fastForward() throws RemoteException {
+                // Will not be called.
+                throw new AssertionError();
+            }
+
+            @Override
+            public void rewind() throws RemoteException {
+                // Will not be called.
+                throw new AssertionError();
+            }
+
+            @Override
+            public void seekTo(long pos) throws RemoteException {
+                // Will not be called.
+                throw new AssertionError();
+            }
+
+            @Override
+            public void rate(RatingCompat rating) throws RemoteException {
+                // Will not be called.
+                throw new AssertionError();
+            }
+
+            @Override
+            public void setRepeatMode(int repeatMode) throws RemoteException {
+                // Will not be called.
+                throw new AssertionError();
+            }
+
+            @Override
+            public void setShuffleModeEnabled(boolean enabled) throws RemoteException {
+                // Will not be called.
+                throw new AssertionError();
+            }
+
+            @Override
+            public void sendCustomAction(String action, Bundle args) throws RemoteException {
+                // Will not be called.
+                throw new AssertionError();
+            }
+
+            @Override
+            public MediaMetadataCompat getMetadata() {
+                // Will not be called.
+                throw new AssertionError();
+            }
+
+            @Override
+            public PlaybackStateCompat getPlaybackState() {
+                return mPlaybackState;
+            }
+
+            @Override
+            public List<QueueItem> getQueue() {
+                // Will not be called.
+                return null;
+            }
+
+            @Override
+            public CharSequence getQueueTitle() {
+                // Will not be called.
+                throw new AssertionError();
+            }
+
+            @Override
+            public Bundle getExtras() {
+                // Will not be called.
+                throw new AssertionError();
+            }
+
+            @Override
+            @RatingCompat.Style
+            public int getRatingType() {
+                return mRatingType;
+            }
+
+            @Override
+            @PlaybackStateCompat.RepeatMode
+            public int getRepeatMode() {
+                // Will not be called.
+                throw new AssertionError();
+            }
+
+            @Override
+            public boolean isShuffleModeEnabled() {
+                // Will not be called.
+                throw new AssertionError();
+            }
+
+            @Override
+            public boolean isTransportControlEnabled() {
+                // Will not be called.
+                throw new AssertionError();
+            }
+        }
     }
 }
diff --git a/media-compat/java/android/support/v4/media/session/PlaybackStateCompat.java b/media-compat/java/android/support/v4/media/session/PlaybackStateCompat.java
index f23d0fa..569e2c9 100644
--- a/media-compat/java/android/support/v4/media/session/PlaybackStateCompat.java
+++ b/media-compat/java/android/support/v4/media/session/PlaybackStateCompat.java
@@ -16,6 +16,8 @@
 package android.support.v4.media.session;
 
 
+import static android.support.annotation.RestrictTo.Scope.GROUP_ID;
+
 import android.os.Build;
 import android.os.Bundle;
 import android.os.Parcel;
@@ -32,8 +34,6 @@
 import java.util.ArrayList;
 import java.util.List;
 
-import static android.support.annotation.RestrictTo.Scope.GROUP_ID;
-
 /**
  * Playback state for a {@link MediaSessionCompat}. This includes a state like
  * {@link PlaybackStateCompat#STATE_PLAYING}, the current playback position,
@@ -49,7 +49,8 @@
             ACTION_SKIP_TO_PREVIOUS, ACTION_SKIP_TO_NEXT, ACTION_FAST_FORWARD, ACTION_SET_RATING,
             ACTION_SEEK_TO, ACTION_PLAY_PAUSE, ACTION_PLAY_FROM_MEDIA_ID, ACTION_PLAY_FROM_SEARCH,
             ACTION_SKIP_TO_QUEUE_ITEM, ACTION_PLAY_FROM_URI, ACTION_PREPARE,
-            ACTION_PREPARE_FROM_MEDIA_ID, ACTION_PREPARE_FROM_SEARCH, ACTION_PREPARE_FROM_URI})
+            ACTION_PREPARE_FROM_MEDIA_ID, ACTION_PREPARE_FROM_SEARCH, ACTION_PREPARE_FROM_URI,
+            ACTION_SET_REPEAT_MODE, ACTION_SET_SHUFFLE_MODE_ENABLED})
     @Retention(RetentionPolicy.SOURCE)
     public @interface Actions {}
 
@@ -189,6 +190,20 @@
     public static final long ACTION_PREPARE_FROM_URI = 1 << 17;
 
     /**
+     * Indicates this session supports the set repeat mode command.
+     *
+     * @see Builder#setActions(long)
+     */
+    public static final long ACTION_SET_REPEAT_MODE = 1 << 18;
+
+    /**
+     * Indicates this session supports the set shuffle mode enabled command.
+     *
+     * @see Builder#setActions(long)
+     */
+    public static final long ACTION_SET_SHUFFLE_MODE_ENABLED = 1 << 19;
+
+    /**
      * @hide
      */
     @RestrictTo(GROUP_ID)
@@ -300,6 +315,31 @@
      */
     public final static long PLAYBACK_POSITION_UNKNOWN = -1;
 
+    /**
+     * @hide
+     */
+    @IntDef({REPEAT_MODE_NONE, REPEAT_MODE_ONE, REPEAT_MODE_ALL})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface RepeatMode {}
+
+    /**
+     * Use this value with {@link MediaControllerCompat.TransportControls#setRepeatMode}
+     * to indicate that the playback will be stopped at the end of the playing media list.
+     */
+    public static final int REPEAT_MODE_NONE = 0;
+
+    /**
+     * Use this value with {@link MediaControllerCompat.TransportControls#setRepeatMode}
+     * to indicate that the playback of the current playing media item will be repeated.
+     */
+    public static final int REPEAT_MODE_ONE = 1;
+
+    /**
+     * Use this value with {@link MediaControllerCompat.TransportControls#setRepeatMode}
+     * to indicate that the playback of the playing media list will be repeated.
+     */
+    public static final int REPEAT_MODE_ALL = 2;
+
     // KeyEvent constants only available on API 11+
     private static final int KEYCODE_MEDIA_PAUSE = 127;
     private static final int KEYCODE_MEDIA_PLAY = 126;
@@ -490,6 +530,8 @@
      * <li> {@link PlaybackStateCompat#ACTION_PREPARE_FROM_MEDIA_ID}</li>
      * <li> {@link PlaybackStateCompat#ACTION_PREPARE_FROM_SEARCH}</li>
      * <li> {@link PlaybackStateCompat#ACTION_PREPARE_FROM_URI}</li>
+     * <li> {@link PlaybackStateCompat#ACTION_SET_REPEAT_MODE}</li>
+     * <li> {@link PlaybackStateCompat#ACTION_SET_SHUFFLE_MODE_ENABLED}</li>
      * </ul>
      */
     @Actions
@@ -1000,6 +1042,8 @@
          * <li> {@link PlaybackStateCompat#ACTION_PREPARE_FROM_MEDIA_ID}</li>
          * <li> {@link PlaybackStateCompat#ACTION_PREPARE_FROM_SEARCH}</li>
          * <li> {@link PlaybackStateCompat#ACTION_PREPARE_FROM_URI}</li>
+         * <li> {@link PlaybackStateCompat#ACTION_SET_REPEAT_MODE}</li>
+         * <li> {@link PlaybackStateCompat#ACTION_SET_SHUFFLE_MODE_ENABLED}</li>
          * </ul>
          *
          * @return this
diff --git a/samples/Support13Demos/Android.mk b/samples/Support13Demos/Android.mk
index 52646b3..a227e10 100644
--- a/samples/Support13Demos/Android.mk
+++ b/samples/Support13Demos/Android.mk
@@ -1,12 +1,14 @@
 LOCAL_PATH:= $(call my-dir)
 include $(CLEAR_VARS)
 
+LOCAL_USE_AAPT2 := true
+
 LOCAL_MODULE_TAGS := samples tests
 
 # Only compile source java files in this apk.
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
-LOCAL_STATIC_JAVA_LIBRARIES += android-support-v13
+LOCAL_STATIC_ANDROID_LIBRARIES += android-support-v13
 
 LOCAL_PACKAGE_NAME := Support13Demos
 
diff --git a/samples/Support4Demos/Android.mk b/samples/Support4Demos/Android.mk
index eefbdab..0ba19b0 100644
--- a/samples/Support4Demos/Android.mk
+++ b/samples/Support4Demos/Android.mk
@@ -1,12 +1,13 @@
 LOCAL_PATH:= $(call my-dir)
 include $(CLEAR_VARS)
 
+LOCAL_USE_AAPT2 := true
 LOCAL_MODULE_TAGS := samples tests
 
 # Only compile source java files in this apk.
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
-LOCAL_STATIC_JAVA_LIBRARIES += android-support-v4
+LOCAL_STATIC_ANDROID_LIBRARIES += android-support-v4
 
 LOCAL_PACKAGE_NAME := Support4Demos
 
diff --git a/samples/Support7Demos/res/values/styles.xml b/samples/Support7Demos/res/values/styles.xml
index 250b4bf..a1ec841 100644
--- a/samples/Support7Demos/res/values/styles.xml
+++ b/samples/Support7Demos/res/values/styles.xml
@@ -32,34 +32,16 @@
     <style name="Theme.SampleMediaRouter" parent="Theme.AppCompat">
         <item name="colorPrimary">#fff44336</item>
         <item name="colorPrimaryDark">#d32f2f</item>
-        <item name="alertDialogTheme">@style/Theme.SampleMediaRouter.Dialog.Alert</item>
     </style>
 
     <style name="Theme.SampleMediaRouter.Light" parent="Theme.AppCompat.Light">
         <item name="colorPrimary">#ffff9800</item>
         <item name="colorPrimaryDark">#f57c00</item>
-        <item name="alertDialogTheme">@style/Theme.SampleMediaRouter.Light.Dialog.Alert</item>
     </style>
 
     <style name="Theme.SampleMediaRouter.Light.DarkActionBar" parent="Theme.AppCompat.Light.DarkActionBar">
         <item name="colorPrimary">#ff2196f3</item>
         <item name="colorPrimaryDark">#1976d2</item>
-        <item name="alertDialogTheme">@style/Theme.SampleMediaRouter.Light.DarkActionBar.Dialog.Alert</item>
-    </style>
-
-    <style name="Theme.SampleMediaRouter.Dialog.Alert" parent="Theme.AppCompat.Dialog.Alert">
-        <item name="colorPrimary">#fff44336</item>
-        <item name="colorPrimaryDark">#d32f2f</item>
-    </style>
-
-    <style name="Theme.SampleMediaRouter.Light.Dialog.Alert" parent="Theme.AppCompat.Light.Dialog.Alert">
-        <item name="colorPrimary">#ffff9800</item>
-        <item name="colorPrimaryDark">#f57c00</item>
-    </style>
-
-    <style name="Theme.SampleMediaRouter.Light.DarkActionBar.Dialog.Alert" parent="Theme.AppCompat.Light.Dialog.Alert">
-        <item name="colorPrimary">#ff2196f3</item>
-        <item name="colorPrimaryDark">#1976d2</item>
     </style>
 
     <style name="SortedListItem" parent="@android:style/TextAppearance.Medium">
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/util/SortedListActivity.java b/samples/Support7Demos/src/com/example/android/supportv7/util/SortedListActivity.java
index 8f3871d..b2e7094 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/util/SortedListActivity.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/util/SortedListActivity.java
@@ -15,9 +15,8 @@
  */
 package com.example.android.supportv7.util;
 
-import com.example.android.supportv7.R;
 import android.os.Bundle;
-import android.support.v7.app.ActionBarActivity;
+import android.support.v7.app.AppCompatActivity;
 import android.support.v7.util.SortedList;
 import android.support.v7.widget.LinearLayoutManager;
 import android.support.v7.widget.RecyclerView;
@@ -32,10 +31,12 @@
 import android.widget.EditText;
 import android.widget.TextView;
 
+import com.example.android.supportv7.R;
+
 /**
  * A sample activity that uses {@link SortedList} in combination with RecyclerView.
  */
-public class SortedListActivity extends ActionBarActivity {
+public class SortedListActivity extends AppCompatActivity {
     private RecyclerView mRecyclerView;
     private LinearLayoutManager mLinearLayoutManager;
     private SortedListAdapter mAdapter;
diff --git a/samples/SupportAppNavigation/Android.mk b/samples/SupportAppNavigation/Android.mk
index 8e6ec46..ea9322f 100644
--- a/samples/SupportAppNavigation/Android.mk
+++ b/samples/SupportAppNavigation/Android.mk
@@ -1,13 +1,15 @@
 LOCAL_PATH:= $(call my-dir)
 include $(CLEAR_VARS)
 
+LOCAL_USE_AAPT2 := true
+
 LOCAL_MODULE_TAGS := samples tests
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
 LOCAL_PACKAGE_NAME := SupportAppNavigation
 
-LOCAL_STATIC_JAVA_LIBRARIES += android-support-v4
+LOCAL_STATIC_ANDROID_LIBRARIES += android-support-v4
 
 LOCAL_SDK_VERSION := current
 
diff --git a/samples/SupportDesignDemos/Android.mk b/samples/SupportDesignDemos/Android.mk
index 8ae120e..4c74ad2 100644
--- a/samples/SupportDesignDemos/Android.mk
+++ b/samples/SupportDesignDemos/Android.mk
@@ -18,30 +18,19 @@
 # We need to add some special AAPT flags to generate R classes
 # for resources that are included from the libraries.
 include $(CLEAR_VARS)
+LOCAL_USE_AAPT2 := true
 LOCAL_PACKAGE_NAME := SupportDesignDemos
 LOCAL_MODULE_TAGS := samples
 LOCAL_SDK_VERSION := current
 LOCAL_MIN_SDK_VERSION := 7
 LOCAL_DEX_PREOPT := false
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_STATIC_JAVA_LIBRARIES := \
+LOCAL_STATIC_ANDROID_LIBRARIES := \
         android-support-v4 \
         android-support-v7-appcompat \
         android-support-v7-recyclerview \
         android-support-transition \
         android-support-design
-LOCAL_RESOURCE_DIR = \
-        $(LOCAL_PATH)/res \
-        frameworks/support/v7/appcompat/res \
-        frameworks/support/v7/recyclerview/res \
-        frameworks/support/transition/res \
-        frameworks/support/design/res
-LOCAL_AAPT_FLAGS := \
-        --auto-add-overlay \
-        --extra-packages android.support.v7.appcompat \
-        --extra-packages android.support.v7.recyclerview \
-        --extra-packages android.support.transition \
-        --extra-packages android.support.design \
-        --no-version-vectors
+LOCAL_AAPT_FLAGS := --no-version-vectors
 LOCAL_PROGUARD_FLAG_FILES := proguard.flags
 include $(BUILD_PACKAGE)
diff --git a/samples/SupportDesignDemos/res/layout/include_bottom_sheet.xml b/samples/SupportDesignDemos/res/layout/include_bottom_sheet.xml
index ab00ece..c4dfcab 100644
--- a/samples/SupportDesignDemos/res/layout/include_bottom_sheet.xml
+++ b/samples/SupportDesignDemos/res/layout/include_bottom_sheet.xml
@@ -15,8 +15,7 @@
      limitations under the License.
 -->
 <merge xmlns:tools="http://schemas.android.com/tools"
-       xmlns:android="http://schemas.android.com/apk/res/android"
-       tools:showIn="@layout/design_bottom_sheet">
+       xmlns:android="http://schemas.android.com/apk/res/android">
 
     <TextView
             android:layout_width="match_parent"
diff --git a/samples/SupportLeanbackDemos/Android.mk b/samples/SupportLeanbackDemos/Android.mk
index 53bb778..ee031e5 100644
--- a/samples/SupportLeanbackDemos/Android.mk
+++ b/samples/SupportLeanbackDemos/Android.mk
@@ -18,22 +18,15 @@
 # We need to add some special AAPT flags to generate R classes
 # for resources that are included from the libraries.
 include $(CLEAR_VARS)
+LOCAL_USE_AAPT2 := true
 LOCAL_PACKAGE_NAME := SupportLeanbackDemos
 LOCAL_MODULE_TAGS := samples tests
 LOCAL_SDK_VERSION := current
 LOCAL_MIN_SDK_VERSION := 17
 LOCAL_DEX_PREOPT := false
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_STATIC_JAVA_LIBRARIES := \
+LOCAL_STATIC_ANDROID_LIBRARIES := \
         android-support-v4 \
         android-support-v7-recyclerview \
         android-support-v17-leanback
-LOCAL_RESOURCE_DIR = \
-        $(LOCAL_PATH)/res \
-        frameworks/support/v17/leanback/res \
-        frameworks/support/v7/recyclerview/res
-LOCAL_AAPT_FLAGS := \
-        --auto-add-overlay \
-        --extra-packages android.support.v17.leanback \
-        --extra-packages android.support.v7.recyclerview
 include $(BUILD_PACKAGE)
diff --git a/samples/SupportLeanbackDemos/generatev4.py b/samples/SupportLeanbackDemos/generatev4.py
index 7c9f0fe..e567b10 100755
--- a/samples/SupportLeanbackDemos/generatev4.py
+++ b/samples/SupportLeanbackDemos/generatev4.py
@@ -117,6 +117,7 @@
     line = line.replace('DetailsActivity', 'DetailsSupportActivity')
     line = line.replace('PlaybackOverlayActivity', 'PlaybackOverlaySupportActivity')
     line = line.replace('SearchActivity', 'SearchSupportActivity')
+    line = line.replace('getRowsFragment', 'getRowsSupportFragment')
     outfile.write(line)
 file.close()
 outfile.close()
@@ -300,19 +301,9 @@
 write_java_head(outfile, "PlaybackOverlayFragment")
 for line in file:
     line = line.replace('PlaybackOverlayFragment', 'PlaybackOverlaySupportFragment')
-    line = line.replace('PlaybackControlHelper', 'PlaybackControlSupportHelper')
     line = line.replace('PlaybackOverlayActivity', 'PlaybackOverlaySupportActivity')
-    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')
+    line = line.replace('PlaybackFragmentGlueHost', 'PlaybackSupportFragmentGlueHost')
+    line = line.replace('PlaybackFragment', 'PlaybackSupportFragment')
     outfile.write(line)
 file.close()
 outfile.close()
diff --git a/samples/SupportLeanbackDemos/res/drawable/spiderman.jpg b/samples/SupportLeanbackDemos/res/drawable/spiderman.jpg
new file mode 100644
index 0000000..b68384c
--- /dev/null
+++ b/samples/SupportLeanbackDemos/res/drawable/spiderman.jpg
Binary files differ
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/BackgroundHelper.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/BackgroundHelper.java
index 99943df..95b36d5 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/BackgroundHelper.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/BackgroundHelper.java
@@ -69,7 +69,7 @@
             mTask.execute(mRequest);
             mRunnable = null;
         }
-    };
+    }
 
     class LoadBitmapTask extends AsyncTask<Request, Object, Request> {
         @Override
@@ -136,6 +136,14 @@
         mHandler.postDelayed(mRunnable, SET_BACKGROUND_DELAY_MS);
     }
 
+    public void setDrawable(Activity activity, Drawable drawable) {
+        BackgroundManager backgroundManager = BackgroundManager.getInstance(activity);
+        if (!backgroundManager.isAttached()) {
+            backgroundManager.attach(activity.getWindow());
+        }
+        backgroundManager.setDrawable(drawable);
+    }
+
     static public void attach(Activity activity) {
         if (!ENABLED) {
             return;
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/BrowseAnimationFragment.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/BrowseAnimationFragment.java
index 6892c2c..9a95e33 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/BrowseAnimationFragment.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/BrowseAnimationFragment.java
@@ -15,6 +15,7 @@
 
 import android.content.Intent;
 import android.os.Bundle;
+import android.os.Handler;
 import android.support.v17.leanback.widget.ArrayObjectAdapter;
 import android.support.v17.leanback.widget.HeaderItem;
 import android.support.v17.leanback.widget.ListRow;
@@ -23,9 +24,9 @@
 import android.support.v17.leanback.widget.Presenter;
 import android.support.v17.leanback.widget.Row;
 import android.support.v17.leanback.widget.RowPresenter;
+import android.support.v4.content.res.ResourcesCompat;
 import android.util.Log;
 import android.view.View;
-import android.os.Handler;
 
 import java.util.Random;
 
@@ -57,8 +58,8 @@
         Log.i(TAG, "onCreate");
         super.onCreate(savedInstanceState);
 
-        setBadgeDrawable(
-                getActivity().getResources().getDrawable(R.drawable.ic_title));
+        setBadgeDrawable(ResourcesCompat.getDrawable(getActivity().getResources(),
+                R.drawable.ic_title, getActivity().getTheme()));
         setTitle("Leanback Sample App");
         setHeadersState(HEADERS_ENABLED);
 
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/BrowseErrorActivity.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/BrowseErrorActivity.java
index 43f726e..9b978f9 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/BrowseErrorActivity.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/BrowseErrorActivity.java
@@ -26,9 +26,6 @@
 
 public class BrowseErrorActivity extends Activity
 {
-    private ErrorFragment mErrorFragment;
-    private SpinnerFragment mSpinnerFragment;
-
     /** Called when the activity is first created. */
     @Override
     public void onCreate(Bundle savedInstanceState)
@@ -52,12 +49,6 @@
     }
 
     private void testError() {
-        mErrorFragment = new ErrorFragment();
-        getFragmentManager().beginTransaction().add(R.id.main_frame, mErrorFragment).commit();
-
-        mSpinnerFragment = new SpinnerFragment();
-        getFragmentManager().beginTransaction().add(R.id.main_frame, mSpinnerFragment).commit();
-
         Handler handler = new Handler();
         handler.postDelayed(new Runnable() {
             @Override
@@ -65,8 +56,8 @@
                 if (getFragmentManager().isDestroyed()) {
                     return;
                 }
-                getFragmentManager().beginTransaction().remove(mSpinnerFragment).commit();
-                mErrorFragment.setErrorContent(getResources());
+                getFragmentManager().beginTransaction().add(R.id.main_frame,
+                        new ErrorFragment()).commit();
             }
         }, 3000);
     }
@@ -77,7 +68,8 @@
                     Bundle savedInstanceState) {
             ProgressBar progressBar = new ProgressBar(container.getContext());
             if (container instanceof FrameLayout) {
-                FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(100, 100, Gravity.CENTER);
+                FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(100, 100,
+                        Gravity.CENTER);
                 progressBar.setLayoutParams(layoutParams);
             }
             return progressBar;
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/BrowseErrorSupportActivity.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/BrowseErrorSupportActivity.java
index f1e7b1e..f2c8a3a 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/BrowseErrorSupportActivity.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/BrowseErrorSupportActivity.java
@@ -28,9 +28,6 @@
 
 public class BrowseErrorSupportActivity extends FragmentActivity
 {
-    private ErrorSupportFragment mErrorSupportFragment;
-    private SpinnerSupportFragment mSpinnerSupportFragment;
-
     /** Called when the activity is first created. */
     @Override
     public void onCreate(Bundle savedInstanceState)
@@ -54,12 +51,6 @@
     }
 
     private void testError() {
-        mErrorSupportFragment = new ErrorSupportFragment();
-        getSupportFragmentManager().beginTransaction().add(R.id.main_frame, mErrorSupportFragment).commit();
-
-        mSpinnerSupportFragment = new SpinnerSupportFragment();
-        getSupportFragmentManager().beginTransaction().add(R.id.main_frame, mSpinnerSupportFragment).commit();
-
         Handler handler = new Handler();
         handler.postDelayed(new Runnable() {
             @Override
@@ -67,8 +58,8 @@
                 if (getSupportFragmentManager().isDestroyed()) {
                     return;
                 }
-                getSupportFragmentManager().beginTransaction().remove(mSpinnerSupportFragment).commit();
-                mErrorSupportFragment.setErrorContent(getResources());
+                getSupportFragmentManager().beginTransaction().add(R.id.main_frame,
+                        new ErrorSupportFragment()).commit();
             }
         }, 3000);
     }
@@ -79,7 +70,8 @@
                     Bundle savedInstanceState) {
             ProgressBar progressBar = new ProgressBar(container.getContext());
             if (container instanceof FrameLayout) {
-                FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(100, 100, Gravity.CENTER);
+                FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(100, 100,
+                        Gravity.CENTER);
                 progressBar.setLayoutParams(layoutParams);
             }
             return progressBar;
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/BrowseFragment.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/BrowseFragment.java
index c601ca8..378b7b5 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/BrowseFragment.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/BrowseFragment.java
@@ -33,6 +33,7 @@
 import android.support.v17.leanback.widget.RowPresenter;
 import android.support.v17.leanback.widget.SectionRow;
 import android.support.v4.app.ActivityOptionsCompat;
+import android.support.v4.content.res.ResourcesCompat;
 import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -64,7 +65,8 @@
         Log.i(TAG, "onCreate");
         super.onCreate(savedInstanceState);
 
-        setBadgeDrawable(getActivity().getResources().getDrawable(R.drawable.ic_title));
+        setBadgeDrawable(ResourcesCompat.getDrawable(getActivity().getResources(),
+                R.drawable.ic_title, getActivity().getTheme()));
         setTitle("Leanback Sample App");
         setHeadersState(HEADERS_ENABLED);
         setOnSearchClickedListener(new View.OnClickListener() {
@@ -115,7 +117,7 @@
 
     private void setupRows() {
         ListRowPresenter listRowPresenter = new ListRowPresenter();
-        listRowPresenter.setNumRows(2);
+        listRowPresenter.setNumRows(1);
         mRowsAdapter = new ArrayObjectAdapter(listRowPresenter);
         setAdapter(mRowsAdapter);
     }
@@ -128,7 +130,9 @@
 
         mRowsAdapter.add(new SectionRow(new HeaderItem("section 0")));
         for (; i < NUM_ROWS; ++i) {
-            mRowsAdapter.add(new ListRow(new HeaderItem(i, "Row " + i), createListRowAdapter(i)));
+            HeaderItem headerItem = new HeaderItem(i, "Row " + i);
+            headerItem.setDescription("Description for Row "+i);
+            mRowsAdapter.add(new ListRow(headerItem, createListRowAdapter(i)));
         }
 
         mRowsAdapter.add(new DividerRow());
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/BrowseSupportFragment.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/BrowseSupportFragment.java
index 7719b0e..eb29e54 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/BrowseSupportFragment.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/BrowseSupportFragment.java
@@ -35,6 +35,7 @@
 import android.support.v17.leanback.widget.RowPresenter;
 import android.support.v17.leanback.widget.SectionRow;
 import android.support.v4.app.ActivityOptionsCompat;
+import android.support.v4.content.res.ResourcesCompat;
 import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -66,7 +67,8 @@
         Log.i(TAG, "onCreate");
         super.onCreate(savedInstanceState);
 
-        setBadgeDrawable(getActivity().getResources().getDrawable(R.drawable.ic_title));
+        setBadgeDrawable(ResourcesCompat.getDrawable(getActivity().getResources(),
+                R.drawable.ic_title, getActivity().getTheme()));
         setTitle("Leanback Sample App");
         setHeadersState(HEADERS_ENABLED);
         setOnSearchClickedListener(new View.OnClickListener() {
@@ -117,7 +119,7 @@
 
     private void setupRows() {
         ListRowPresenter listRowPresenter = new ListRowPresenter();
-        listRowPresenter.setNumRows(2);
+        listRowPresenter.setNumRows(1);
         mRowsAdapter = new ArrayObjectAdapter(listRowPresenter);
         setAdapter(mRowsAdapter);
     }
@@ -130,7 +132,9 @@
 
         mRowsAdapter.add(new SectionRow(new HeaderItem("section 0")));
         for (; i < NUM_ROWS; ++i) {
-            mRowsAdapter.add(new ListRow(new HeaderItem(i, "Row " + i), createListRowAdapter(i)));
+            HeaderItem headerItem = new HeaderItem(i, "Row " + i);
+            headerItem.setDescription("Description for Row "+i);
+            mRowsAdapter.add(new ListRow(headerItem, createListRowAdapter(i)));
         }
 
         mRowsAdapter.add(new DividerRow());
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/CardPresenter.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/CardPresenter.java
index 924975d..066832b 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/CardPresenter.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/CardPresenter.java
@@ -15,16 +15,15 @@
 
 import android.content.Context;
 import android.graphics.drawable.Drawable;
-import com.example.android.leanback.R;
 import android.support.v17.leanback.widget.ImageCardView;
 import android.support.v17.leanback.widget.Presenter;
+import android.support.v4.content.res.ResourcesCompat;
 import android.text.TextUtils;
 import android.util.Log;
-import android.view.ViewGroup;
 import android.view.ContextThemeWrapper;
 import android.view.View.MeasureSpec;
+import android.view.ViewGroup;
 import android.view.ViewGroup.LayoutParams;
-import android.widget.TextView;
 
 import java.util.Random;
 
@@ -104,8 +103,9 @@
     public void onBindViewHolder(ViewHolder viewHolder, Object item) {
         Log.d(TAG, "onBindViewHolder for " + item.toString());
         PhotoItem photoItem = (PhotoItem) item;
-        Drawable drawable =  viewHolder.view.getContext().getResources()
-                .getDrawable(photoItem.getImageResourceId());
+        final Context context = viewHolder.view.getContext();
+        Drawable drawable =  ResourcesCompat.getDrawable(context.getResources(),
+                photoItem.getImageResourceId(), context.getTheme());
         ((ImageCardView) viewHolder.view).setMainImage(drawable);
         ((ImageCardView) viewHolder.view).setTitleText(photoItem.getTitle());
         if (!TextUtils.isEmpty(photoItem.getContent())) {
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/DetailsFragment.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/DetailsFragment.java
index 9238562..467290e 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/DetailsFragment.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/DetailsFragment.java
@@ -13,11 +13,10 @@
  */
 package com.example.android.leanback;
 
+import android.content.Context;
 import android.content.Intent;
-import android.content.res.Resources;
 import android.os.Bundle;
 import android.os.Handler;
-import android.support.v4.app.ActivityOptionsCompat;
 import android.support.v17.leanback.widget.Action;
 import android.support.v17.leanback.widget.ArrayObjectAdapter;
 import android.support.v17.leanback.widget.ClassPresenterSelector;
@@ -34,6 +33,8 @@
 import android.support.v17.leanback.widget.Row;
 import android.support.v17.leanback.widget.RowPresenter;
 import android.support.v17.leanback.widget.SparseArrayObjectAdapter;
+import android.support.v4.app.ActivityOptionsCompat;
+import android.support.v4.content.res.ResourcesCompat;
 import android.util.Log;
 import android.view.View;
 import android.widget.Toast;
@@ -67,7 +68,9 @@
         Log.i(TAG, "onCreate");
         super.onCreate(savedInstanceState);
 
-        setBadgeDrawable(getActivity().getResources().getDrawable(R.drawable.ic_title));
+        Context context = getActivity();
+        setBadgeDrawable(ResourcesCompat.getDrawable(context.getResources(),
+                R.drawable.ic_title, context.getTheme()));
         setTitle("Leanback Sample App");
         setOnSearchClickedListener(new View.OnClickListener() {
             @Override
@@ -78,17 +81,19 @@
         });
 
         mActionPlay = new Action(ACTION_PLAY, "Play");
-        mActionRent = new Action(ACTION_RENT, "Rent", "$3.99",
-                getResources().getDrawable(R.drawable.ic_action_a));
+        mActionRent = new Action(ACTION_RENT, "Rent", "$3.99", ResourcesCompat.getDrawable(
+                context.getResources(), R.drawable.ic_action_a, context.getTheme()));
         mActionBuy = new Action(ACTION_BUY, "Buy $9.99");
 
         ClassPresenterSelector ps = new ClassPresenterSelector();
+        @SuppressWarnings("deprecation")
         DetailsOverviewRowPresenter dorPresenter =
                 new DetailsOverviewRowPresenter(new DetailsDescriptionPresenter());
         dorPresenter.setOnActionClickedListener(new OnActionClickedListener() {
             @Override
             public void onActionClicked(Action action) {
-                Toast.makeText(getActivity(), action.toString(), Toast.LENGTH_SHORT).show();
+                final Context context = getActivity();
+                Toast.makeText(context, action.toString(), Toast.LENGTH_SHORT).show();
                 DetailsOverviewRow dor = (DetailsOverviewRow) mRowsAdapter.get(0);
                 if (action.getId() == ACTION_BUY) {
                     // on the UI thread, we can modify actions adapter directly
@@ -98,7 +103,8 @@
                     actions.clear(ACTION_RENT);
                     actions.clear(ACTION_BUY);
                     dor.setItem(mPhotoItem.getTitle() + "(Owned)");
-                    dor.setImageDrawable(getResources().getDrawable(R.drawable.details_img_16x9));
+                    dor.setImageDrawable(ResourcesCompat.getDrawable(context.getResources(),
+                            R.drawable.details_img_16x9, context.getTheme()));
                 } else if (action.getId() == ACTION_RENT) {
                     // on the UI thread, we can modify actions adapter directly
                     SparseArrayObjectAdapter actions = (SparseArrayObjectAdapter)
@@ -107,7 +113,7 @@
                     actions.clear(ACTION_RENT);
                     dor.setItem(mPhotoItem.getTitle() + "(Rented)");
                 } else if (action.getId() == ACTION_PLAY) {
-                    Intent intent = new Intent(getActivity(), PlaybackOverlayActivity.class);
+                    Intent intent = new Intent(context, PlaybackOverlayActivity.class);
                     getActivity().startActivity(intent);
                 }
             }
@@ -173,9 +179,10 @@
         mRowsAdapter.clear();
         new Handler().postDelayed(new Runnable() {
             public void run() {
-                Resources res = getActivity().getResources();
+                final Context context = getActivity();
                 DetailsOverviewRow dor = new DetailsOverviewRow(mPhotoItem.getTitle());
-                dor.setImageDrawable(res.getDrawable(mPhotoItem.getImageResourceId()));
+                dor.setImageDrawable(ResourcesCompat.getDrawable(context.getResources(),
+                        mPhotoItem.getImageResourceId(), context.getTheme()));
                 SparseArrayObjectAdapter adapter = new SparseArrayObjectAdapter();
                 adapter.set(ACTION_RENT, mActionRent);
                 adapter.set(ACTION_BUY, mActionBuy);
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/DetailsPresenterSelectionActivity.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/DetailsPresenterSelectionActivity.java
index 9fe7fd3..01bd583 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/DetailsPresenterSelectionActivity.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/DetailsPresenterSelectionActivity.java
@@ -17,18 +17,15 @@
 package com.example.android.leanback;
 
 import android.app.Activity;
-import android.app.FragmentManager;
 import android.content.Context;
-import android.content.Intent;
 import android.graphics.drawable.Drawable;
 import android.os.Bundle;
 import android.support.v17.leanback.app.GuidedStepFragment;
-import android.support.v17.leanback.widget.GuidedAction;
 import android.support.v17.leanback.widget.GuidanceStylist;
 import android.support.v17.leanback.widget.GuidanceStylist.Guidance;
+import android.support.v17.leanback.widget.GuidedAction;
 
 import java.util.List;
-import java.util.ArrayList;
 
 /**
  * Activity that showcases different aspects of GuidedStepFragments.
@@ -54,7 +51,7 @@
     }
 
     private static void addAction(List<GuidedAction> actions, long id, String title, String desc) {
-        actions.add(new GuidedAction.Builder()
+        actions.add(new GuidedAction.Builder(null)
                 .id(id)
                 .title(title)
                 .description(desc)
@@ -63,7 +60,7 @@
 
     private static void addCheckedAction(List<GuidedAction> actions, Context context,
             long id, String title, String desc, boolean checked) {
-        actions.add(new GuidedAction.Builder()
+        actions.add(new GuidedAction.Builder(null)
                 .title(title)
                 .description(desc)
                 .id(id)
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/DetailsSupportFragment.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/DetailsSupportFragment.java
index 143a37d..6c18dfe 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/DetailsSupportFragment.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/DetailsSupportFragment.java
@@ -15,11 +15,10 @@
  */
 package com.example.android.leanback;
 
+import android.content.Context;
 import android.content.Intent;
-import android.content.res.Resources;
 import android.os.Bundle;
 import android.os.Handler;
-import android.support.v4.app.ActivityOptionsCompat;
 import android.support.v17.leanback.widget.Action;
 import android.support.v17.leanback.widget.ArrayObjectAdapter;
 import android.support.v17.leanback.widget.ClassPresenterSelector;
@@ -36,6 +35,8 @@
 import android.support.v17.leanback.widget.Row;
 import android.support.v17.leanback.widget.RowPresenter;
 import android.support.v17.leanback.widget.SparseArrayObjectAdapter;
+import android.support.v4.app.ActivityOptionsCompat;
+import android.support.v4.content.res.ResourcesCompat;
 import android.util.Log;
 import android.view.View;
 import android.widget.Toast;
@@ -69,7 +70,9 @@
         Log.i(TAG, "onCreate");
         super.onCreate(savedInstanceState);
 
-        setBadgeDrawable(getActivity().getResources().getDrawable(R.drawable.ic_title));
+        Context context = getActivity();
+        setBadgeDrawable(ResourcesCompat.getDrawable(context.getResources(),
+                R.drawable.ic_title, context.getTheme()));
         setTitle("Leanback Sample App");
         setOnSearchClickedListener(new View.OnClickListener() {
             @Override
@@ -80,17 +83,19 @@
         });
 
         mActionPlay = new Action(ACTION_PLAY, "Play");
-        mActionRent = new Action(ACTION_RENT, "Rent", "$3.99",
-                getResources().getDrawable(R.drawable.ic_action_a));
+        mActionRent = new Action(ACTION_RENT, "Rent", "$3.99", ResourcesCompat.getDrawable(
+                context.getResources(), R.drawable.ic_action_a, context.getTheme()));
         mActionBuy = new Action(ACTION_BUY, "Buy $9.99");
 
         ClassPresenterSelector ps = new ClassPresenterSelector();
+        @SuppressWarnings("deprecation")
         DetailsOverviewRowPresenter dorPresenter =
                 new DetailsOverviewRowPresenter(new DetailsDescriptionPresenter());
         dorPresenter.setOnActionClickedListener(new OnActionClickedListener() {
             @Override
             public void onActionClicked(Action action) {
-                Toast.makeText(getActivity(), action.toString(), Toast.LENGTH_SHORT).show();
+                final Context context = getActivity();
+                Toast.makeText(context, action.toString(), Toast.LENGTH_SHORT).show();
                 DetailsOverviewRow dor = (DetailsOverviewRow) mRowsAdapter.get(0);
                 if (action.getId() == ACTION_BUY) {
                     // on the UI thread, we can modify actions adapter directly
@@ -100,7 +105,8 @@
                     actions.clear(ACTION_RENT);
                     actions.clear(ACTION_BUY);
                     dor.setItem(mPhotoItem.getTitle() + "(Owned)");
-                    dor.setImageDrawable(getResources().getDrawable(R.drawable.details_img_16x9));
+                    dor.setImageDrawable(ResourcesCompat.getDrawable(context.getResources(),
+                            R.drawable.details_img_16x9, context.getTheme()));
                 } else if (action.getId() == ACTION_RENT) {
                     // on the UI thread, we can modify actions adapter directly
                     SparseArrayObjectAdapter actions = (SparseArrayObjectAdapter)
@@ -109,7 +115,7 @@
                     actions.clear(ACTION_RENT);
                     dor.setItem(mPhotoItem.getTitle() + "(Rented)");
                 } else if (action.getId() == ACTION_PLAY) {
-                    Intent intent = new Intent(getActivity(), PlaybackOverlaySupportActivity.class);
+                    Intent intent = new Intent(context, PlaybackOverlaySupportActivity.class);
                     getActivity().startActivity(intent);
                 }
             }
@@ -175,9 +181,10 @@
         mRowsAdapter.clear();
         new Handler().postDelayed(new Runnable() {
             public void run() {
-                Resources res = getActivity().getResources();
+                final Context context = getActivity();
                 DetailsOverviewRow dor = new DetailsOverviewRow(mPhotoItem.getTitle());
-                dor.setImageDrawable(res.getDrawable(mPhotoItem.getImageResourceId()));
+                dor.setImageDrawable(ResourcesCompat.getDrawable(context.getResources(),
+                        mPhotoItem.getImageResourceId(), context.getTheme()));
                 SparseArrayObjectAdapter adapter = new SparseArrayObjectAdapter();
                 adapter.set(ACTION_RENT, mActionRent);
                 adapter.set(ACTION_BUY, mActionBuy);
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/ErrorFragment.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/ErrorFragment.java
index 7a88c91..c05fbe0 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/ErrorFragment.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/ErrorFragment.java
@@ -13,15 +13,9 @@
  */
 package com.example.android.leanback;
 
-import android.content.Intent;
-import android.content.res.Resources;
+import android.content.Context;
 import android.os.Bundle;
-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.Row;
-import android.support.v17.leanback.widget.SearchOrbView;
+import android.support.v4.content.res.ResourcesCompat;
 import android.util.Log;
 import android.view.View;
 
@@ -35,10 +29,9 @@
         super.onCreate(savedInstanceState);
 
         setTitle("Leanback Sample App");
-    }
-
-    void setErrorContent(Resources resources) {
-        setImageDrawable(resources.getDrawable(R.drawable.lb_ic_sad_cloud));
+        final Context context = getActivity();
+        setImageDrawable(ResourcesCompat.getDrawable(context.getResources(),
+                R.drawable.lb_ic_sad_cloud, context.getTheme()));
         setMessage("An error occurred.");
         setDefaultBackground(TRANSLUCENT);
 
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/ErrorSupportFragment.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/ErrorSupportFragment.java
index ea3e17c..9124efa 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/ErrorSupportFragment.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/ErrorSupportFragment.java
@@ -15,15 +15,9 @@
  */
 package com.example.android.leanback;
 
-import android.content.Intent;
-import android.content.res.Resources;
+import android.content.Context;
 import android.os.Bundle;
-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.Row;
-import android.support.v17.leanback.widget.SearchOrbView;
+import android.support.v4.content.res.ResourcesCompat;
 import android.util.Log;
 import android.view.View;
 
@@ -37,10 +31,9 @@
         super.onCreate(savedInstanceState);
 
         setTitle("Leanback Sample App");
-    }
-
-    void setErrorContent(Resources resources) {
-        setImageDrawable(resources.getDrawable(R.drawable.lb_ic_sad_cloud));
+        final Context context = getActivity();
+        setImageDrawable(ResourcesCompat.getDrawable(context.getResources(),
+                R.drawable.lb_ic_sad_cloud, context.getTheme()));
         setMessage("An error occurred.");
         setDefaultBackground(TRANSLUCENT);
 
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/GuidedStepActivity.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/GuidedStepActivity.java
index 15af18f..94f7d6c 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/GuidedStepActivity.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/GuidedStepActivity.java
@@ -17,9 +17,9 @@
 package com.example.android.leanback;
 
 import android.app.Activity;
+import android.app.Fragment;
 import android.app.FragmentManager;
 import android.content.Context;
-import android.content.Intent;
 import android.content.res.Configuration;
 import android.graphics.drawable.Drawable;
 import android.os.Bundle;
@@ -28,13 +28,14 @@
 import android.support.v17.leanback.widget.GuidanceStylist.Guidance;
 import android.support.v17.leanback.widget.GuidedAction;
 import android.support.v17.leanback.widget.GuidedActionsStylist;
-import android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder;
 import android.support.v17.leanback.widget.GuidedDatePickerAction;
+import android.support.v4.content.res.ResourcesCompat;
 import android.text.InputType;
 import android.text.TextUtils;
 import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
 import android.view.ViewGroup;
-import android.view.ViewTreeObserver.OnGlobalLayoutListener;
 import android.view.inputmethod.EditorInfo;
 
 import java.util.ArrayList;
@@ -94,49 +95,59 @@
         super.onRestoreInstanceState(savedInstanceState);
     }
 
-    private static void addAction(List<GuidedAction> actions, long id, String title, String desc) {
-        actions.add(new GuidedAction.Builder()
+    private static GuidedAction addAction(List<GuidedAction> actions, long id, String title,
+            String desc) {
+        GuidedAction action;
+        actions.add(action = new GuidedAction.Builder(null)
                 .id(id)
                 .title(title)
                 .description(desc)
                 .build());
+        return action;
     }
 
-    private static void addAction(List<GuidedAction> actions, long id, String title, String desc,
-            List<GuidedAction> subActions) {
-        actions.add(new GuidedAction.Builder()
+    private static GuidedAction addAction(List<GuidedAction> actions, long id, String title,
+            String desc, List<GuidedAction> subActions) {
+        GuidedAction action;
+        actions.add(action = new GuidedAction.Builder(null)
                 .id(id)
                 .title(title)
                 .description(desc)
                 .subActions(subActions)
                 .build());
+        return action;
     }
 
-    private static void addEditableAction(Context context, List<GuidedAction> actions,
+    private static GuidedAction addEditableAction(Context context, List<GuidedAction> actions,
             long id, String title, String desc) {
-        actions.add(new GuidedAction.Builder(context)
+        GuidedAction action;
+        actions.add(action = new GuidedAction.Builder(context)
                 .id(id)
                 .title(title)
                 .description(desc)
                 .editable(true)
                 .icon(R.drawable.lb_ic_search_mic)
                 .build());
+        return action;
     }
 
-    private static void addEditableAction(List<GuidedAction> actions, long id, String title,
+    private static GuidedAction addEditableAction(List<GuidedAction> actions, long id, String title,
             String editTitle, String desc) {
-        actions.add(new GuidedAction.Builder()
+        GuidedAction action;
+        actions.add(action = new GuidedAction.Builder(null)
                 .id(id)
                 .title(title)
                 .editTitle(editTitle)
                 .description(desc)
                 .editable(true)
                 .build());
+        return action;
     }
 
-    private static void addEditableAction(List<GuidedAction> actions, long id, String title,
+    private static GuidedAction addEditableAction(List<GuidedAction> actions, long id, String title,
             String editTitle, int editInputType, String desc, String editDesc) {
-        actions.add(new GuidedAction.Builder()
+        GuidedAction action;
+        actions.add(action = new GuidedAction.Builder(null)
                 .id(id)
                 .title(title)
                 .editTitle(editTitle)
@@ -145,19 +156,24 @@
                 .editDescription(editDesc)
                 .editable(true)
                 .build());
+        return action;
     }
 
-    private static void addDatePickerAction(List<GuidedAction> actions, long id, String title) {
-        actions.add(new GuidedDatePickerAction.Builder(null)
+    private static GuidedDatePickerAction addDatePickerAction(List<GuidedAction> actions, long id,
+            String title) {
+        GuidedDatePickerAction action;
+        actions.add(action = new GuidedDatePickerAction.Builder(null)
                 .id(id)
                 .title(title)
                 .datePickerFormat("MY")
                 .build());
+        return action;
     }
 
-    private static void addEditableDescriptionAction(List<GuidedAction> actions, long id,
+    private static GuidedAction addEditableDescriptionAction(List<GuidedAction> actions, long id,
             String title, String desc, String editDescription, int descriptionEditInputType) {
-        actions.add(new GuidedAction.Builder()
+        GuidedAction action;
+        actions.add(action = new GuidedAction.Builder(null)
                 .id(id)
                 .title(title)
                 .description(desc)
@@ -165,16 +181,19 @@
                 .descriptionEditInputType(descriptionEditInputType)
                 .descriptionEditable(true)
                 .build());
+        return action;
     }
 
-    private static void addCheckedAction(List<GuidedAction> actions, long id, Context context,
+    private static GuidedAction addCheckedAction(List<GuidedAction> actions, long id,
             String title, String desc, int checkSetId) {
-        actions.add(new GuidedAction.Builder()
+        GuidedAction action;
+        actions.add(action = new GuidedAction.Builder(null)
                 .id(id)
                 .title(title)
                 .description(desc)
                 .checkSetId(checkSetId)
                 .build());
+        return action;
     }
 
     public static class FirstStepFragment extends GuidedStepFragment {
@@ -189,7 +208,9 @@
             String title = getString(R.string.guidedstep_first_title);
             String breadcrumb = getString(R.string.guidedstep_first_breadcrumb);
             String description = getString(R.string.guidedstep_first_description);
-            Drawable icon = getActivity().getResources().getDrawable(R.drawable.ic_main_icon);
+            final Context context = getActivity();
+            Drawable icon = ResourcesCompat.getDrawable(context.getResources(),
+                    R.drawable.ic_main_icon, context.getTheme());
             return new Guidance(title, description, breadcrumb, icon);
         }
 
@@ -217,6 +238,11 @@
         }
     }
 
+    public interface NewPaymentFragmentTarget {
+        void onNewPaymentFragmentStarted();
+        void onNewPaymentAdded(int selection);
+    }
+
     static ArrayList<String> sCards = new ArrayList<String>();
     static int sSelectedCard = -1;
     static {
@@ -226,12 +252,26 @@
 
     public static class NewPaymentStepFragment extends GuidedStepFragment {
 
+        NewPaymentFragmentTarget mNewPaymentTarget;
+
+        @Override
+        public void onCreate(Bundle savedInstance) {
+            super.onCreate(savedInstance);
+            Fragment targetFragment = getTargetFragment();
+            if (targetFragment instanceof NewPaymentFragmentTarget) {
+                mNewPaymentTarget = ((NewPaymentFragmentTarget) targetFragment);
+                mNewPaymentTarget.onNewPaymentFragmentStarted();
+            }
+        }
+
         @Override
         public Guidance onCreateGuidance(Bundle savedInstanceState) {
             String title = getString(R.string.guidedstep_newpayment_title);
             String breadcrumb = getString(R.string.guidedstep_newpayment_breadcrumb);
             String description = getString(R.string.guidedstep_newpayment_description);
-            Drawable icon = getActivity().getResources().getDrawable(R.drawable.ic_main_icon);
+            final Context context = getActivity();
+            Drawable icon = ResourcesCompat.getDrawable(context.getResources(),
+                    R.drawable.ic_main_icon, context.getTheme());
             return new Guidance(title, description, breadcrumb, icon);
         }
 
@@ -262,8 +302,11 @@
                 } else {
                     card = "Master "+cardNumber;
                 }
-                sSelectedCard = sCards.size();
+                int selection = sCards.size();
                 sCards.add(card);
+                if (mNewPaymentTarget != null) {
+                    mNewPaymentTarget.onNewPaymentAdded(selection);
+                }
                 popBackStackToGuidedStepFragment(NewPaymentStepFragment.class,
                         FragmentManager.POP_BACK_STACK_INCLUSIVE);
             }
@@ -311,7 +354,27 @@
         }
     }
 
-    public static class SecondStepFragment extends GuidedStepFragment {
+    public static class SecondStepFragment extends GuidedStepFragment
+            implements NewPaymentFragmentTarget {
+
+
+        boolean mExpandPaymentListInOnCreateView;
+
+        @Override
+        public void onNewPaymentAdded(int selection) {
+            // if a new payment is added, we dont need expand the sub actions list.
+            mExpandPaymentListInOnCreateView = false;
+            sSelectedCard = selection;
+            updatePaymentAction(findActionById(PAYMENT));
+            findButtonActionById(GuidedAction.ACTION_ID_CONTINUE).setEnabled(sSelectedCard != -1);
+        }
+
+        @Override
+        public void onNewPaymentFragmentStarted() {
+            // if a new payment fragment is opened, when come back we should expand the payment
+            // sub actions list unless user created a new payment in onNewPaymentAdded
+            mExpandPaymentListInOnCreateView = true;
+        }
 
         public GuidedActionsStylist onCreateActionsStylist() {
             return new GuidedActionsStylist() {
@@ -332,7 +395,9 @@
             String title = getString(R.string.guidedstep_second_title);
             String breadcrumb = getString(R.string.guidedstep_second_breadcrumb);
             String description = getString(R.string.guidedstep_second_description);
-            Drawable icon = getActivity().getResources().getDrawable(R.drawable.ic_main_icon);
+            final Context context = getActivity();
+            Drawable icon = ResourcesCompat.getDrawable(context.getResources(),
+                    R.drawable.ic_main_icon, context.getTheme());
             return new Guidance(title, description, breadcrumb, icon);
         }
 
@@ -341,7 +406,7 @@
             addEditableAction(getContext(), actions, FIRST_NAME, "Pat", "Your first name");
             addEditableAction(getContext(), actions, LAST_NAME, "Smith", "Your last name");
             List<GuidedAction> subActions = new ArrayList<GuidedAction>();
-            addAction(actions, PAYMENT, "Select Payment", "", subActions);
+            updatePaymentAction(addAction(actions, PAYMENT, "Select Payment", "", subActions));
             addEditableDescriptionAction(actions, PASSWORD, "Password", "", "",
                     InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
         }
@@ -351,6 +416,7 @@
             actions.add(new GuidedAction.Builder(getActivity())
                     .clickAction(GuidedAction.ACTION_ID_CONTINUE)
                     .description("Continue")
+                    .enabled(isPasswordValid() && isPaymentValid())
                     .build());
         }
 
@@ -362,6 +428,20 @@
             }
         }
 
+        void updatePaymentAction(GuidedAction paymentAction) {
+            List<GuidedAction> subActions = paymentAction.getSubActions();
+            subActions.clear();
+            for (int i = 0; i < sCards.size(); i++) {
+                addCheckedAction(subActions, -1, sCards.get(i), "",
+                        GuidedAction.DEFAULT_CHECK_SET_ID);
+                if (i == sSelectedCard) {
+                    subActions.get(i).setChecked(true);
+                }
+            }
+            addAction(subActions, NEW_PAYMENT, "Add New Card", "");
+            paymentAction.setDescription(sSelectedCard == -1 ? "" : sCards.get(sSelectedCard));
+        }
+
         @Override
         public long onGuidedActionEditedAndProceed(GuidedAction action) {
             if (action.getId() == PASSWORD) {
@@ -398,30 +478,21 @@
                 return true;
             } else {
                 FragmentManager fm = getFragmentManager();
-                GuidedStepFragment.add(fm, new NewPaymentStepFragment(), R.id.lb_guidedstep_host);
+                NewPaymentStepFragment newPaymentFragment = new NewPaymentStepFragment();
+                newPaymentFragment.setTargetFragment(this, 0);
+                GuidedStepFragment.add(fm, newPaymentFragment, R.id.lb_guidedstep_host);
                 return false;
             }
         }
 
         @Override
-        public void onResume() {
-            super.onResume();
-            // when resumed, update sub actions list and selected index from data model.
-            GuidedAction payments = findActionById(PAYMENT);
-            payments.getSubActions().clear();
-            for (int i = 0; i < sCards.size(); i++) {
-                addCheckedAction(payments.getSubActions(), -1, getActivity(), sCards.get(i), "",
-                        GuidedAction.DEFAULT_CHECK_SET_ID);
-                if (i == sSelectedCard) {
-                    payments.getSubActions().get(i).setChecked(true);
-                }
+        public View onCreateView(LayoutInflater inflater, ViewGroup container,
+                Bundle savedInstanceState) {
+            View view = super.onCreateView(inflater, container, savedInstanceState);
+            if (mExpandPaymentListInOnCreateView) {
+                expandAction(findActionById(PAYMENT), false);
             }
-            addAction(payments.getSubActions(), NEW_PAYMENT, "Add New Card", "");
-            if (sSelectedCard != -1) {
-                payments.setDescription(sCards.get(sSelectedCard));
-            }
-            notifyActionChanged(findActionPositionById(PAYMENT));
-            updateContinue(isPasswordValid() && isPaymentValid());
+            return view;
         }
 
         boolean isPaymentValid() {
@@ -452,7 +523,9 @@
             String title = getString(R.string.guidedstep_third_title);
             String breadcrumb = getString(R.string.guidedstep_third_breadcrumb);
             String description = getString(R.string.guidedstep_third_description);
-            Drawable icon = getActivity().getResources().getDrawable(R.drawable.ic_main_icon);
+            final Context context = getActivity();
+            Drawable icon = ResourcesCompat.getDrawable(context.getResources(),
+                    R.drawable.ic_main_icon, context.getTheme());
             return new Guidance(title, description, breadcrumb, icon);
         }
 
@@ -470,7 +543,7 @@
         public void onCreateActions(List<GuidedAction> actions, Bundle savedInstanceState) {
             String desc = "The description can be quite long as well.  " +
                     "Just be sure to set multilineDescription to true in the GuidedAction.";
-            actions.add(new GuidedAction.Builder()
+            actions.add(new GuidedAction.Builder(getActivity())
                     .title("Note that Guided Actions can have titles that are quite long.")
                     .description(desc)
                     .multilineDescription(true)
@@ -479,14 +552,14 @@
                     .focusable(false)
                     .build());
             for (int i = 0; i < OPTION_NAMES.length; i++) {
-                addCheckedAction(actions, RADIO_ID_BASE + i, getActivity(), OPTION_NAMES[i],
+                addCheckedAction(actions, RADIO_ID_BASE + i, OPTION_NAMES[i],
                         OPTION_DESCRIPTIONS[i], GuidedAction.DEFAULT_CHECK_SET_ID);
                 if (i == DEFAULT_OPTION) {
                     actions.get(actions.size() -1).setChecked(true);
                 }
             }
             for (int i = 0; i < OPTION_NAMES.length; i++) {
-                addCheckedAction(actions, CHECKBOX_ID_BASE + i, getActivity(), OPTION_NAMES[i],
+                addCheckedAction(actions, CHECKBOX_ID_BASE + i, OPTION_NAMES[i],
                         OPTION_DESCRIPTIONS[i], GuidedAction.CHECKBOX_CHECK_SET_ID);
             }
         }
@@ -531,7 +604,9 @@
             String title = getString(R.string.guidedstep_fourth_title);
             String breadcrumb = getString(R.string.guidedstep_fourth_breadcrumb);
             String description = "You chose: " + OPTION_NAMES[(int) getOption()];
-            Drawable icon = getActivity().getResources().getDrawable(R.drawable.ic_main_icon);
+            final Context context = getActivity();
+            Drawable icon = ResourcesCompat.getDrawable(context.getResources(),
+                    R.drawable.ic_main_icon, context.getTheme());
             return new Guidance(title, description, breadcrumb, icon);
         }
 
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/GuidedStepHalfScreenActivity.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/GuidedStepHalfScreenActivity.java
index 4e8b33f..9ee12c3 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/GuidedStepHalfScreenActivity.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/GuidedStepHalfScreenActivity.java
@@ -22,9 +22,9 @@
 import android.graphics.drawable.Drawable;
 import android.os.Bundle;
 import android.support.v17.leanback.app.GuidedStepFragment;
-import android.support.v17.leanback.widget.GuidanceStylist;
 import android.support.v17.leanback.widget.GuidanceStylist.Guidance;
 import android.support.v17.leanback.widget.GuidedAction;
+import android.support.v4.content.res.ResourcesCompat;
 import android.util.Log;
 
 import java.util.List;
@@ -52,7 +52,9 @@
             String title = getString(R.string.guidedstep_first_title);
             String breadcrumb = getString(R.string.guidedstep_first_breadcrumb);
             String description = getString(R.string.guidedstep_first_description);
-            Drawable icon = getActivity().getResources().getDrawable(R.drawable.ic_main_icon);
+            final Context context = getActivity();
+            Drawable icon = ResourcesCompat.getDrawable(context.getResources(),
+                    R.drawable.ic_main_icon, context.getTheme());
             return new Guidance(title, description, breadcrumb, icon);
         }
 
@@ -107,7 +109,9 @@
             String title = getString(R.string.guidedstep_second_title);
             String breadcrumb = getString(R.string.guidedstep_second_breadcrumb);
             String description = getString(R.string.guidedstep_second_description);
-            Drawable icon = getActivity().getResources().getDrawable(R.drawable.ic_main_icon);
+            final Context context = getActivity();
+            Drawable icon = ResourcesCompat.getDrawable(context.getResources(),
+                    R.drawable.ic_main_icon, context.getTheme());
             return new Guidance(title, description, breadcrumb, icon);
         }
 
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/GuidedStepSupportActivity.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/GuidedStepSupportActivity.java
index 6aaaa69..6cd54df 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/GuidedStepSupportActivity.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/GuidedStepSupportActivity.java
@@ -19,9 +19,9 @@
 package com.example.android.leanback;
 
 import android.support.v4.app.FragmentActivity;
+import android.support.v4.app.Fragment;
 import android.support.v4.app.FragmentManager;
 import android.content.Context;
-import android.content.Intent;
 import android.content.res.Configuration;
 import android.graphics.drawable.Drawable;
 import android.os.Bundle;
@@ -30,13 +30,14 @@
 import android.support.v17.leanback.widget.GuidanceStylist.Guidance;
 import android.support.v17.leanback.widget.GuidedAction;
 import android.support.v17.leanback.widget.GuidedActionsStylist;
-import android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder;
 import android.support.v17.leanback.widget.GuidedDatePickerAction;
+import android.support.v4.content.res.ResourcesCompat;
 import android.text.InputType;
 import android.text.TextUtils;
 import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
 import android.view.ViewGroup;
-import android.view.ViewTreeObserver.OnGlobalLayoutListener;
 import android.view.inputmethod.EditorInfo;
 
 import java.util.ArrayList;
@@ -96,49 +97,59 @@
         super.onRestoreInstanceState(savedInstanceState);
     }
 
-    private static void addAction(List<GuidedAction> actions, long id, String title, String desc) {
-        actions.add(new GuidedAction.Builder()
+    private static GuidedAction addAction(List<GuidedAction> actions, long id, String title,
+            String desc) {
+        GuidedAction action;
+        actions.add(action = new GuidedAction.Builder(null)
                 .id(id)
                 .title(title)
                 .description(desc)
                 .build());
+        return action;
     }
 
-    private static void addAction(List<GuidedAction> actions, long id, String title, String desc,
-            List<GuidedAction> subActions) {
-        actions.add(new GuidedAction.Builder()
+    private static GuidedAction addAction(List<GuidedAction> actions, long id, String title,
+            String desc, List<GuidedAction> subActions) {
+        GuidedAction action;
+        actions.add(action = new GuidedAction.Builder(null)
                 .id(id)
                 .title(title)
                 .description(desc)
                 .subActions(subActions)
                 .build());
+        return action;
     }
 
-    private static void addEditableAction(Context context, List<GuidedAction> actions,
+    private static GuidedAction addEditableAction(Context context, List<GuidedAction> actions,
             long id, String title, String desc) {
-        actions.add(new GuidedAction.Builder(context)
+        GuidedAction action;
+        actions.add(action = new GuidedAction.Builder(context)
                 .id(id)
                 .title(title)
                 .description(desc)
                 .editable(true)
                 .icon(R.drawable.lb_ic_search_mic)
                 .build());
+        return action;
     }
 
-    private static void addEditableAction(List<GuidedAction> actions, long id, String title,
+    private static GuidedAction addEditableAction(List<GuidedAction> actions, long id, String title,
             String editTitle, String desc) {
-        actions.add(new GuidedAction.Builder()
+        GuidedAction action;
+        actions.add(action = new GuidedAction.Builder(null)
                 .id(id)
                 .title(title)
                 .editTitle(editTitle)
                 .description(desc)
                 .editable(true)
                 .build());
+        return action;
     }
 
-    private static void addEditableAction(List<GuidedAction> actions, long id, String title,
+    private static GuidedAction addEditableAction(List<GuidedAction> actions, long id, String title,
             String editTitle, int editInputType, String desc, String editDesc) {
-        actions.add(new GuidedAction.Builder()
+        GuidedAction action;
+        actions.add(action = new GuidedAction.Builder(null)
                 .id(id)
                 .title(title)
                 .editTitle(editTitle)
@@ -147,19 +158,24 @@
                 .editDescription(editDesc)
                 .editable(true)
                 .build());
+        return action;
     }
 
-    private static void addDatePickerAction(List<GuidedAction> actions, long id, String title) {
-        actions.add(new GuidedDatePickerAction.Builder(null)
+    private static GuidedDatePickerAction addDatePickerAction(List<GuidedAction> actions, long id,
+            String title) {
+        GuidedDatePickerAction action;
+        actions.add(action = new GuidedDatePickerAction.Builder(null)
                 .id(id)
                 .title(title)
                 .datePickerFormat("MY")
                 .build());
+        return action;
     }
 
-    private static void addEditableDescriptionAction(List<GuidedAction> actions, long id,
+    private static GuidedAction addEditableDescriptionAction(List<GuidedAction> actions, long id,
             String title, String desc, String editDescription, int descriptionEditInputType) {
-        actions.add(new GuidedAction.Builder()
+        GuidedAction action;
+        actions.add(action = new GuidedAction.Builder(null)
                 .id(id)
                 .title(title)
                 .description(desc)
@@ -167,16 +183,19 @@
                 .descriptionEditInputType(descriptionEditInputType)
                 .descriptionEditable(true)
                 .build());
+        return action;
     }
 
-    private static void addCheckedAction(List<GuidedAction> actions, long id, Context context,
+    private static GuidedAction addCheckedAction(List<GuidedAction> actions, long id,
             String title, String desc, int checkSetId) {
-        actions.add(new GuidedAction.Builder()
+        GuidedAction action;
+        actions.add(action = new GuidedAction.Builder(null)
                 .id(id)
                 .title(title)
                 .description(desc)
                 .checkSetId(checkSetId)
                 .build());
+        return action;
     }
 
     public static class FirstStepFragment extends GuidedStepSupportFragment {
@@ -191,7 +210,9 @@
             String title = getString(R.string.guidedstep_first_title);
             String breadcrumb = getString(R.string.guidedstep_first_breadcrumb);
             String description = getString(R.string.guidedstep_first_description);
-            Drawable icon = getActivity().getResources().getDrawable(R.drawable.ic_main_icon);
+            final Context context = getActivity();
+            Drawable icon = ResourcesCompat.getDrawable(context.getResources(),
+                    R.drawable.ic_main_icon, context.getTheme());
             return new Guidance(title, description, breadcrumb, icon);
         }
 
@@ -219,6 +240,11 @@
         }
     }
 
+    public interface NewPaymentFragmentTarget {
+        void onNewPaymentFragmentStarted();
+        void onNewPaymentAdded(int selection);
+    }
+
     static ArrayList<String> sCards = new ArrayList<String>();
     static int sSelectedCard = -1;
     static {
@@ -228,12 +254,26 @@
 
     public static class NewPaymentStepFragment extends GuidedStepSupportFragment {
 
+        NewPaymentFragmentTarget mNewPaymentTarget;
+
+        @Override
+        public void onCreate(Bundle savedInstance) {
+            super.onCreate(savedInstance);
+            Fragment targetFragment = getTargetFragment();
+            if (targetFragment instanceof NewPaymentFragmentTarget) {
+                mNewPaymentTarget = ((NewPaymentFragmentTarget) targetFragment);
+                mNewPaymentTarget.onNewPaymentFragmentStarted();
+            }
+        }
+
         @Override
         public Guidance onCreateGuidance(Bundle savedInstanceState) {
             String title = getString(R.string.guidedstep_newpayment_title);
             String breadcrumb = getString(R.string.guidedstep_newpayment_breadcrumb);
             String description = getString(R.string.guidedstep_newpayment_description);
-            Drawable icon = getActivity().getResources().getDrawable(R.drawable.ic_main_icon);
+            final Context context = getActivity();
+            Drawable icon = ResourcesCompat.getDrawable(context.getResources(),
+                    R.drawable.ic_main_icon, context.getTheme());
             return new Guidance(title, description, breadcrumb, icon);
         }
 
@@ -264,8 +304,11 @@
                 } else {
                     card = "Master "+cardNumber;
                 }
-                sSelectedCard = sCards.size();
+                int selection = sCards.size();
                 sCards.add(card);
+                if (mNewPaymentTarget != null) {
+                    mNewPaymentTarget.onNewPaymentAdded(selection);
+                }
                 popBackStackToGuidedStepSupportFragment(NewPaymentStepFragment.class,
                         FragmentManager.POP_BACK_STACK_INCLUSIVE);
             }
@@ -313,7 +356,27 @@
         }
     }
 
-    public static class SecondStepFragment extends GuidedStepSupportFragment {
+    public static class SecondStepFragment extends GuidedStepSupportFragment
+            implements NewPaymentFragmentTarget {
+
+
+        boolean mExpandPaymentListInOnCreateView;
+
+        @Override
+        public void onNewPaymentAdded(int selection) {
+            // if a new payment is added, we dont need expand the sub actions list.
+            mExpandPaymentListInOnCreateView = false;
+            sSelectedCard = selection;
+            updatePaymentAction(findActionById(PAYMENT));
+            findButtonActionById(GuidedAction.ACTION_ID_CONTINUE).setEnabled(sSelectedCard != -1);
+        }
+
+        @Override
+        public void onNewPaymentFragmentStarted() {
+            // if a new payment fragment is opened, when come back we should expand the payment
+            // sub actions list unless user created a new payment in onNewPaymentAdded
+            mExpandPaymentListInOnCreateView = true;
+        }
 
         public GuidedActionsStylist onCreateActionsStylist() {
             return new GuidedActionsStylist() {
@@ -334,7 +397,9 @@
             String title = getString(R.string.guidedstep_second_title);
             String breadcrumb = getString(R.string.guidedstep_second_breadcrumb);
             String description = getString(R.string.guidedstep_second_description);
-            Drawable icon = getActivity().getResources().getDrawable(R.drawable.ic_main_icon);
+            final Context context = getActivity();
+            Drawable icon = ResourcesCompat.getDrawable(context.getResources(),
+                    R.drawable.ic_main_icon, context.getTheme());
             return new Guidance(title, description, breadcrumb, icon);
         }
 
@@ -343,7 +408,7 @@
             addEditableAction(getContext(), actions, FIRST_NAME, "Pat", "Your first name");
             addEditableAction(getContext(), actions, LAST_NAME, "Smith", "Your last name");
             List<GuidedAction> subActions = new ArrayList<GuidedAction>();
-            addAction(actions, PAYMENT, "Select Payment", "", subActions);
+            updatePaymentAction(addAction(actions, PAYMENT, "Select Payment", "", subActions));
             addEditableDescriptionAction(actions, PASSWORD, "Password", "", "",
                     InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
         }
@@ -353,6 +418,7 @@
             actions.add(new GuidedAction.Builder(getActivity())
                     .clickAction(GuidedAction.ACTION_ID_CONTINUE)
                     .description("Continue")
+                    .enabled(isPasswordValid() && isPaymentValid())
                     .build());
         }
 
@@ -364,6 +430,20 @@
             }
         }
 
+        void updatePaymentAction(GuidedAction paymentAction) {
+            List<GuidedAction> subActions = paymentAction.getSubActions();
+            subActions.clear();
+            for (int i = 0; i < sCards.size(); i++) {
+                addCheckedAction(subActions, -1, sCards.get(i), "",
+                        GuidedAction.DEFAULT_CHECK_SET_ID);
+                if (i == sSelectedCard) {
+                    subActions.get(i).setChecked(true);
+                }
+            }
+            addAction(subActions, NEW_PAYMENT, "Add New Card", "");
+            paymentAction.setDescription(sSelectedCard == -1 ? "" : sCards.get(sSelectedCard));
+        }
+
         @Override
         public long onGuidedActionEditedAndProceed(GuidedAction action) {
             if (action.getId() == PASSWORD) {
@@ -400,30 +480,21 @@
                 return true;
             } else {
                 FragmentManager fm = getFragmentManager();
-                GuidedStepSupportFragment.add(fm, new NewPaymentStepFragment(), R.id.lb_guidedstep_host);
+                NewPaymentStepFragment newPaymentFragment = new NewPaymentStepFragment();
+                newPaymentFragment.setTargetFragment(this, 0);
+                GuidedStepSupportFragment.add(fm, newPaymentFragment, R.id.lb_guidedstep_host);
                 return false;
             }
         }
 
         @Override
-        public void onResume() {
-            super.onResume();
-            // when resumed, update sub actions list and selected index from data model.
-            GuidedAction payments = findActionById(PAYMENT);
-            payments.getSubActions().clear();
-            for (int i = 0; i < sCards.size(); i++) {
-                addCheckedAction(payments.getSubActions(), -1, getActivity(), sCards.get(i), "",
-                        GuidedAction.DEFAULT_CHECK_SET_ID);
-                if (i == sSelectedCard) {
-                    payments.getSubActions().get(i).setChecked(true);
-                }
+        public View onCreateView(LayoutInflater inflater, ViewGroup container,
+                Bundle savedInstanceState) {
+            View view = super.onCreateView(inflater, container, savedInstanceState);
+            if (mExpandPaymentListInOnCreateView) {
+                expandAction(findActionById(PAYMENT), false);
             }
-            addAction(payments.getSubActions(), NEW_PAYMENT, "Add New Card", "");
-            if (sSelectedCard != -1) {
-                payments.setDescription(sCards.get(sSelectedCard));
-            }
-            notifyActionChanged(findActionPositionById(PAYMENT));
-            updateContinue(isPasswordValid() && isPaymentValid());
+            return view;
         }
 
         boolean isPaymentValid() {
@@ -454,7 +525,9 @@
             String title = getString(R.string.guidedstep_third_title);
             String breadcrumb = getString(R.string.guidedstep_third_breadcrumb);
             String description = getString(R.string.guidedstep_third_description);
-            Drawable icon = getActivity().getResources().getDrawable(R.drawable.ic_main_icon);
+            final Context context = getActivity();
+            Drawable icon = ResourcesCompat.getDrawable(context.getResources(),
+                    R.drawable.ic_main_icon, context.getTheme());
             return new Guidance(title, description, breadcrumb, icon);
         }
 
@@ -472,7 +545,7 @@
         public void onCreateActions(List<GuidedAction> actions, Bundle savedInstanceState) {
             String desc = "The description can be quite long as well.  " +
                     "Just be sure to set multilineDescription to true in the GuidedAction.";
-            actions.add(new GuidedAction.Builder()
+            actions.add(new GuidedAction.Builder(getActivity())
                     .title("Note that Guided Actions can have titles that are quite long.")
                     .description(desc)
                     .multilineDescription(true)
@@ -481,14 +554,14 @@
                     .focusable(false)
                     .build());
             for (int i = 0; i < OPTION_NAMES.length; i++) {
-                addCheckedAction(actions, RADIO_ID_BASE + i, getActivity(), OPTION_NAMES[i],
+                addCheckedAction(actions, RADIO_ID_BASE + i, OPTION_NAMES[i],
                         OPTION_DESCRIPTIONS[i], GuidedAction.DEFAULT_CHECK_SET_ID);
                 if (i == DEFAULT_OPTION) {
                     actions.get(actions.size() -1).setChecked(true);
                 }
             }
             for (int i = 0; i < OPTION_NAMES.length; i++) {
-                addCheckedAction(actions, CHECKBOX_ID_BASE + i, getActivity(), OPTION_NAMES[i],
+                addCheckedAction(actions, CHECKBOX_ID_BASE + i, OPTION_NAMES[i],
                         OPTION_DESCRIPTIONS[i], GuidedAction.CHECKBOX_CHECK_SET_ID);
             }
         }
@@ -533,7 +606,9 @@
             String title = getString(R.string.guidedstep_fourth_title);
             String breadcrumb = getString(R.string.guidedstep_fourth_breadcrumb);
             String description = "You chose: " + OPTION_NAMES[(int) getOption()];
-            Drawable icon = getActivity().getResources().getDrawable(R.drawable.ic_main_icon);
+            final Context context = getActivity();
+            Drawable icon = ResourcesCompat.getDrawable(context.getResources(),
+                    R.drawable.ic_main_icon, context.getTheme());
             return new Guidance(title, description, breadcrumb, icon);
         }
 
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/GuidedStepSupportHalfScreenActivity.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/GuidedStepSupportHalfScreenActivity.java
index 388a559..9c78714 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/GuidedStepSupportHalfScreenActivity.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/GuidedStepSupportHalfScreenActivity.java
@@ -24,9 +24,9 @@
 import android.graphics.drawable.Drawable;
 import android.os.Bundle;
 import android.support.v17.leanback.app.GuidedStepSupportFragment;
-import android.support.v17.leanback.widget.GuidanceStylist;
 import android.support.v17.leanback.widget.GuidanceStylist.Guidance;
 import android.support.v17.leanback.widget.GuidedAction;
+import android.support.v4.content.res.ResourcesCompat;
 import android.util.Log;
 
 import java.util.List;
@@ -54,7 +54,9 @@
             String title = getString(R.string.guidedstep_first_title);
             String breadcrumb = getString(R.string.guidedstep_first_breadcrumb);
             String description = getString(R.string.guidedstep_first_description);
-            Drawable icon = getActivity().getResources().getDrawable(R.drawable.ic_main_icon);
+            final Context context = getActivity();
+            Drawable icon = ResourcesCompat.getDrawable(context.getResources(),
+                    R.drawable.ic_main_icon, context.getTheme());
             return new Guidance(title, description, breadcrumb, icon);
         }
 
@@ -109,7 +111,9 @@
             String title = getString(R.string.guidedstep_second_title);
             String breadcrumb = getString(R.string.guidedstep_second_breadcrumb);
             String description = getString(R.string.guidedstep_second_description);
-            Drawable icon = getActivity().getResources().getDrawable(R.drawable.ic_main_icon);
+            final Context context = getActivity();
+            Drawable icon = ResourcesCompat.getDrawable(context.getResources(),
+                    R.drawable.ic_main_icon, context.getTheme());
             return new Guidance(title, description, breadcrumb, icon);
         }
 
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/HorizontalGridTestActivity.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/HorizontalGridTestActivity.java
index 59155af..14c1db5 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/HorizontalGridTestActivity.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/HorizontalGridTestActivity.java
@@ -16,30 +16,20 @@
 
 package com.example.android.leanback;
 
-import android.support.v7.widget.RecyclerView;
-import android.support.v17.leanback.widget.HorizontalGridView;
-import android.support.v17.leanback.widget.OnChildSelectedListener;
 import android.app.Activity;
-import android.content.Context;
 import android.content.Intent;
-import android.graphics.BitmapFactory;
 import android.graphics.Color;
-import android.graphics.drawable.ColorDrawable;
-import android.graphics.drawable.Drawable;
-import android.net.Uri;
 import android.os.Bundle;
+import android.support.v17.leanback.widget.HorizontalGridView;
+import android.support.v17.leanback.widget.OnChildViewHolderSelectedListener;
+import android.support.v7.widget.RecyclerView;
 import android.util.Log;
-import android.util.SparseArray;
-import android.view.MotionEvent;
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.view.View.OnFocusChangeListener;
 import android.view.ViewGroup;
-import android.widget.ImageView;
 import android.widget.TextView;
 
-import java.io.File;
-
 public class HorizontalGridTestActivity extends Activity {
     private static final String TAG = "HorizontalGridTestActivity";
     private static final boolean DEBUG = true;
@@ -48,7 +38,6 @@
     private static final boolean STAGGERED = true;
 
     private HorizontalGridView mHorizontalGridView;
-    private int mScrollState = RecyclerView.SCROLL_STATE_IDLE;
 
     private RecyclerView.OnScrollListener mScrollListener = new RecyclerView.OnScrollListener() {
         @Override
@@ -58,7 +47,6 @@
                 Log.v(TAG, "onScrollStateChanged "
                         + (newState < stateNames.length ? stateNames[newState] : newState));
             }
-            mScrollState = newState;
         }
     };
 
@@ -68,12 +56,16 @@
 
         mHorizontalGridView.setWindowAlignment(HorizontalGridView.WINDOW_ALIGN_BOTH_EDGE);
         mHorizontalGridView.setWindowAlignmentOffsetPercent(35);
-        mHorizontalGridView.setOnChildSelectedListener(new OnChildSelectedListener() {
-            @Override
-            public void onChildSelected(ViewGroup parent, View view, int position, long id) {
-                if (DEBUG) Log.d(TAG, "onChildSelected position=" + position +  " id="+id);
-            }
-        });
+        mHorizontalGridView.setOnChildViewHolderSelectedListener(
+                new OnChildViewHolderSelectedListener() {
+                    @Override
+                    public void onChildViewHolderSelected(RecyclerView parent,
+                                                          RecyclerView.ViewHolder child,
+                                                          int position, int subposition) {
+                        if (DEBUG) Log.d(TAG, "onChildSelected position=" + position);
+                    }
+
+                });
         return view;
     }
 
@@ -90,7 +82,7 @@
         mHorizontalGridView.setAdapter(new MyAdapter());
         setContentView(view);
 
-        mHorizontalGridView.setOnScrollListener(mScrollListener);
+        mHorizontalGridView.addOnScrollListener(mScrollListener);
     }
 
     @Override
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/MainActivity.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/MainActivity.java
index 298ef70..863efdb 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/MainActivity.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/MainActivity.java
@@ -17,6 +17,7 @@
 package com.example.android.leanback;
 
 import android.app.Activity;
+import android.content.Context;
 import android.content.Intent;
 import android.graphics.drawable.Drawable;
 import android.os.Bundle;
@@ -24,11 +25,8 @@
 import android.support.v17.leanback.widget.GuidanceStylist.Guidance;
 import android.support.v17.leanback.widget.GuidedAction;
 import android.support.v4.app.ActivityOptionsCompat;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
+import android.support.v4.content.res.ResourcesCompat;
 
-import java.util.ArrayList;
 import java.util.List;
 
 /**
@@ -36,14 +34,11 @@
  */
 public class MainActivity extends Activity {
 
-    private GuidedStepFragment mGuidedStepFragment;
-
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
-        mGuidedStepFragment = new StepFragment();
-        GuidedStepFragment.addAsRoot(this, mGuidedStepFragment, android.R.id.content);
+        GuidedStepFragment.addAsRoot(this, new StepFragment(), android.R.id.content);
     }
 
     public static class StepFragment extends GuidedStepFragment {
@@ -53,7 +48,9 @@
             String title = getString(R.string.main_title);
             String breadcrumb = getString(R.string.main_breadcrumb);
             String description = "";
-            Drawable icon = getActivity().getResources().getDrawable(R.drawable.ic_main_icon);
+            final Context context = getActivity();
+            Drawable icon = ResourcesCompat.getDrawable(context.getResources(),
+                    R.drawable.ic_main_icon, context.getTheme());
             return new Guidance(title, description, breadcrumb, icon);
         }
 
@@ -113,7 +110,7 @@
         }
 
         private void addAction(List<GuidedAction> actions, Class cls, int titleRes, int descRes) {
-            actions.add(new GuidedAction.Builder()
+            actions.add(new GuidedAction.Builder(getActivity())
                     .intent(new Intent(getActivity(), cls))
                     .title(getString(titleRes))
                     .description(getString(descRes))
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/NewDetailsFragment.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/NewDetailsFragment.java
index 4d04502..9b9935b 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/NewDetailsFragment.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/NewDetailsFragment.java
@@ -13,12 +13,13 @@
  */
 package com.example.android.leanback;
 
-import android.app.Activity;
+import android.content.Context;
 import android.content.Intent;
-import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
 import android.os.Bundle;
 import android.os.Handler;
-import android.support.v4.app.ActivityOptionsCompat;
+import android.support.v17.leanback.app.DetailsBackgroundParallaxHelper;
 import android.support.v17.leanback.widget.Action;
 import android.support.v17.leanback.widget.ArrayObjectAdapter;
 import android.support.v17.leanback.widget.ClassPresenterSelector;
@@ -36,6 +37,8 @@
 import android.support.v17.leanback.widget.Row;
 import android.support.v17.leanback.widget.RowPresenter;
 import android.support.v17.leanback.widget.SparseArrayObjectAdapter;
+import android.support.v4.app.ActivityOptionsCompat;
+import android.support.v4.content.res.ResourcesCompat;
 import android.util.Log;
 import android.view.View;
 import android.widget.Toast;
@@ -48,7 +51,6 @@
     private ArrayObjectAdapter mRowsAdapter;
     private PhotoItem mPhotoItem;
     final CardPresenter cardPresenter = new CardPresenter();
-    private BackgroundHelper mBackgroundHelper = new BackgroundHelper();
 
     private static final int ACTION_PLAY = 1;
     private static final int ACTION_RENT = 2;
@@ -66,9 +68,13 @@
     private Action mActionBuy;
 
     private FullWidthDetailsOverviewSharedElementHelper mHelper;
+    private DetailsBackgroundParallaxHelper mParallaxHelper;
+    private BackgroundHelper mBackgroundHelper = new BackgroundHelper();
+    private int mBitmapMinVerticalOffset = -100;
 
     private void initializeTest() {
-        TEST_SHARED_ELEMENT_TRANSITION = null != getActivity().getWindow().getSharedElementEnterTransition();
+        TEST_SHARED_ELEMENT_TRANSITION = null != getActivity().getWindow()
+                .getSharedElementEnterTransition();
         TEST_OVERVIEW_ROW_ON_SECOND = !TEST_SHARED_ELEMENT_TRANSITION;
         TEST_ENTRANCE_TRANSITION = true;
     }
@@ -79,7 +85,9 @@
         super.onCreate(savedInstanceState);
         initializeTest();
 
-        setBadgeDrawable(getActivity().getResources().getDrawable(R.drawable.ic_title));
+        final Context context = getActivity();
+        setBadgeDrawable(ResourcesCompat.getDrawable(context.getResources(), R.drawable.ic_title,
+                context.getTheme()));
         setTitle("Leanback Sample App");
         setOnSearchClickedListener(new View.OnClickListener() {
             @Override
@@ -90,8 +98,8 @@
         });
 
         mActionPlay = new Action(ACTION_PLAY, "Play");
-        mActionRent = new Action(ACTION_RENT, "Rent", "$3.99",
-                getResources().getDrawable(R.drawable.ic_action_a));
+        mActionRent = new Action(ACTION_RENT, "Rent", "$3.99", ResourcesCompat.getDrawable(
+                context.getResources(), R.drawable.ic_action_a, context.getTheme()));
         mActionBuy = new Action(ACTION_BUY, "Buy $9.99");
 
         ClassPresenterSelector ps = new ClassPresenterSelector();
@@ -100,7 +108,8 @@
         dorPresenter.setOnActionClickedListener(new OnActionClickedListener() {
             @Override
             public void onActionClicked(Action action) {
-                Toast.makeText(getActivity(), action.toString(), Toast.LENGTH_SHORT).show();
+                final Context context = getActivity();
+                Toast.makeText(context, action.toString(), Toast.LENGTH_SHORT).show();
                 int indexOfOverviewRow = TEST_OVERVIEW_ROW_ON_SECOND ? 1 : 0;
                 DetailsOverviewRow dor = (DetailsOverviewRow) mRowsAdapter.get(indexOfOverviewRow);
                 if (action.getId() == ACTION_BUY) {
@@ -111,7 +120,8 @@
                     actions.clear(ACTION_RENT);
                     actions.clear(ACTION_BUY);
                     dor.setItem(mPhotoItem.getTitle() + "(Owned)");
-                    dor.setImageDrawable(getResources().getDrawable(R.drawable.details_img_16x9));
+                    dor.setImageDrawable(ResourcesCompat.getDrawable(context.getResources(),
+                            R.drawable.details_img_16x9, context.getTheme()));
                 } else if (action.getId() == ACTION_RENT) {
                     // on the UI thread, we can modify actions adapter directly
                     SparseArrayObjectAdapter actions = (SparseArrayObjectAdapter)
@@ -120,7 +130,7 @@
                     actions.clear(ACTION_RENT);
                     dor.setItem(mPhotoItem.getTitle() + "(Rented)");
                 } else if (action.getId() == ACTION_PLAY) {
-                    Intent intent = new Intent(getActivity(), PlaybackOverlayActivity.class);
+                    Intent intent = new Intent(context, PlaybackOverlayActivity.class);
                     getActivity().startActivity(intent);
                 }
             }
@@ -204,9 +214,10 @@
                     mRowsAdapter.add(0, new ListRow(header, listRowAdapter));
                 }
 
-                Resources res = getActivity().getResources();
+                final Context context = getActivity();
                 DetailsOverviewRow dor = new DetailsOverviewRow(mPhotoItem.getTitle());
-                dor.setImageDrawable(res.getDrawable(mPhotoItem.getImageResourceId()));
+                dor.setImageDrawable(ResourcesCompat.getDrawable(context.getResources(),
+                        mPhotoItem.getImageResourceId(), context.getTheme()));
                 SparseArrayObjectAdapter adapter = new SparseArrayObjectAdapter();
                 adapter.set(ACTION_RENT, mActionRent);
                 adapter.set(ACTION_BUY, mActionBuy);
@@ -244,10 +255,23 @@
     @Override
     public void onStart() {
         super.onStart();
-        if (mPhotoItem != null) {
-            mBackgroundHelper.setBackground(
-                    getActivity(), mPhotoItem.getImageResourceId());
-        }
+        mParallaxHelper = new DetailsBackgroundParallaxHelper.ParallaxBuilder(
+                getActivity(),
+                getParallaxManager())
+                .setBitmapMinVerticalOffset(mBitmapMinVerticalOffset)
+                .build();
+        mBackgroundHelper.setDrawable(getActivity(), mParallaxHelper.getDrawable());
     }
 
+    @Override
+    public void onResume() {
+        super.onResume();
+        Bitmap bitmap = BitmapFactory.decodeResource(getActivity().getResources(),
+                R.drawable.spiderman);
+        mParallaxHelper.setBitmap(bitmap);
+    }
+
+    public void setMinimumVerticalOffset(int minimumVerticalOffset) {
+        this.mBitmapMinVerticalOffset = minimumVerticalOffset;
+    }
 }
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/NewDetailsSupportFragment.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/NewDetailsSupportFragment.java
index 8a43d8b..675c75c 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/NewDetailsSupportFragment.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/NewDetailsSupportFragment.java
@@ -15,12 +15,13 @@
  */
 package com.example.android.leanback;
 
-import android.support.v4.app.FragmentActivity;
+import android.content.Context;
 import android.content.Intent;
-import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
 import android.os.Bundle;
 import android.os.Handler;
-import android.support.v4.app.ActivityOptionsCompat;
+import android.support.v17.leanback.app.DetailsBackgroundParallaxHelper;
 import android.support.v17.leanback.widget.Action;
 import android.support.v17.leanback.widget.ArrayObjectAdapter;
 import android.support.v17.leanback.widget.ClassPresenterSelector;
@@ -38,6 +39,8 @@
 import android.support.v17.leanback.widget.Row;
 import android.support.v17.leanback.widget.RowPresenter;
 import android.support.v17.leanback.widget.SparseArrayObjectAdapter;
+import android.support.v4.app.ActivityOptionsCompat;
+import android.support.v4.content.res.ResourcesCompat;
 import android.util.Log;
 import android.view.View;
 import android.widget.Toast;
@@ -50,7 +53,6 @@
     private ArrayObjectAdapter mRowsAdapter;
     private PhotoItem mPhotoItem;
     final CardPresenter cardPresenter = new CardPresenter();
-    private BackgroundHelper mBackgroundHelper = new BackgroundHelper();
 
     private static final int ACTION_PLAY = 1;
     private static final int ACTION_RENT = 2;
@@ -68,9 +70,13 @@
     private Action mActionBuy;
 
     private FullWidthDetailsOverviewSharedElementHelper mHelper;
+    private DetailsBackgroundParallaxHelper mParallaxHelper;
+    private BackgroundHelper mBackgroundHelper = new BackgroundHelper();
+    private int mBitmapMinVerticalOffset = -100;
 
     private void initializeTest() {
-        TEST_SHARED_ELEMENT_TRANSITION = null != getActivity().getWindow().getSharedElementEnterTransition();
+        TEST_SHARED_ELEMENT_TRANSITION = null != getActivity().getWindow()
+                .getSharedElementEnterTransition();
         TEST_OVERVIEW_ROW_ON_SECOND = !TEST_SHARED_ELEMENT_TRANSITION;
         TEST_ENTRANCE_TRANSITION = true;
     }
@@ -81,7 +87,9 @@
         super.onCreate(savedInstanceState);
         initializeTest();
 
-        setBadgeDrawable(getActivity().getResources().getDrawable(R.drawable.ic_title));
+        final Context context = getActivity();
+        setBadgeDrawable(ResourcesCompat.getDrawable(context.getResources(), R.drawable.ic_title,
+                context.getTheme()));
         setTitle("Leanback Sample App");
         setOnSearchClickedListener(new View.OnClickListener() {
             @Override
@@ -92,8 +100,8 @@
         });
 
         mActionPlay = new Action(ACTION_PLAY, "Play");
-        mActionRent = new Action(ACTION_RENT, "Rent", "$3.99",
-                getResources().getDrawable(R.drawable.ic_action_a));
+        mActionRent = new Action(ACTION_RENT, "Rent", "$3.99", ResourcesCompat.getDrawable(
+                context.getResources(), R.drawable.ic_action_a, context.getTheme()));
         mActionBuy = new Action(ACTION_BUY, "Buy $9.99");
 
         ClassPresenterSelector ps = new ClassPresenterSelector();
@@ -102,7 +110,8 @@
         dorPresenter.setOnActionClickedListener(new OnActionClickedListener() {
             @Override
             public void onActionClicked(Action action) {
-                Toast.makeText(getActivity(), action.toString(), Toast.LENGTH_SHORT).show();
+                final Context context = getActivity();
+                Toast.makeText(context, action.toString(), Toast.LENGTH_SHORT).show();
                 int indexOfOverviewRow = TEST_OVERVIEW_ROW_ON_SECOND ? 1 : 0;
                 DetailsOverviewRow dor = (DetailsOverviewRow) mRowsAdapter.get(indexOfOverviewRow);
                 if (action.getId() == ACTION_BUY) {
@@ -113,7 +122,8 @@
                     actions.clear(ACTION_RENT);
                     actions.clear(ACTION_BUY);
                     dor.setItem(mPhotoItem.getTitle() + "(Owned)");
-                    dor.setImageDrawable(getResources().getDrawable(R.drawable.details_img_16x9));
+                    dor.setImageDrawable(ResourcesCompat.getDrawable(context.getResources(),
+                            R.drawable.details_img_16x9, context.getTheme()));
                 } else if (action.getId() == ACTION_RENT) {
                     // on the UI thread, we can modify actions adapter directly
                     SparseArrayObjectAdapter actions = (SparseArrayObjectAdapter)
@@ -122,7 +132,7 @@
                     actions.clear(ACTION_RENT);
                     dor.setItem(mPhotoItem.getTitle() + "(Rented)");
                 } else if (action.getId() == ACTION_PLAY) {
-                    Intent intent = new Intent(getActivity(), PlaybackOverlaySupportActivity.class);
+                    Intent intent = new Intent(context, PlaybackOverlaySupportActivity.class);
                     getActivity().startActivity(intent);
                 }
             }
@@ -206,9 +216,10 @@
                     mRowsAdapter.add(0, new ListRow(header, listRowAdapter));
                 }
 
-                Resources res = getActivity().getResources();
+                final Context context = getActivity();
                 DetailsOverviewRow dor = new DetailsOverviewRow(mPhotoItem.getTitle());
-                dor.setImageDrawable(res.getDrawable(mPhotoItem.getImageResourceId()));
+                dor.setImageDrawable(ResourcesCompat.getDrawable(context.getResources(),
+                        mPhotoItem.getImageResourceId(), context.getTheme()));
                 SparseArrayObjectAdapter adapter = new SparseArrayObjectAdapter();
                 adapter.set(ACTION_RENT, mActionRent);
                 adapter.set(ACTION_BUY, mActionBuy);
@@ -246,10 +257,23 @@
     @Override
     public void onStart() {
         super.onStart();
-        if (mPhotoItem != null) {
-            mBackgroundHelper.setBackground(
-                    getActivity(), mPhotoItem.getImageResourceId());
-        }
+        mParallaxHelper = new DetailsBackgroundParallaxHelper.ParallaxBuilder(
+                getActivity(),
+                getParallaxManager())
+                .setBitmapMinVerticalOffset(mBitmapMinVerticalOffset)
+                .build();
+        mBackgroundHelper.setDrawable(getActivity(), mParallaxHelper.getDrawable());
     }
 
+    @Override
+    public void onResume() {
+        super.onResume();
+        Bitmap bitmap = BitmapFactory.decodeResource(getActivity().getResources(),
+                R.drawable.spiderman);
+        mParallaxHelper.setBitmap(bitmap);
+    }
+
+    public void setMinimumVerticalOffset(int minimumVerticalOffset) {
+        this.mBitmapMinVerticalOffset = minimumVerticalOffset;
+    }
 }
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/OnboardingDemoFragment.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/OnboardingDemoFragment.java
index 5868c26..0aa2e70 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/OnboardingDemoFragment.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/OnboardingDemoFragment.java
@@ -51,6 +51,7 @@
 
     private Animator mContentAnimator;
 
+    @SuppressWarnings("deprecation")
     @Override
     public void onAttach(android.app.Activity activity) {
         super.onAttach(activity);
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/OnboardingDemoSupportFragment.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/OnboardingDemoSupportFragment.java
index 32f38f3..24172c8 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/OnboardingDemoSupportFragment.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/OnboardingDemoSupportFragment.java
@@ -53,6 +53,7 @@
 
     private Animator mContentAnimator;
 
+    @SuppressWarnings("deprecation")
     @Override
     public void onAttach(android.app.Activity activity) {
         super.onAttach(activity);
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackControlHelper.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackControlHelper.java
index e282f83..a6f911d 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackControlHelper.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackControlHelper.java
@@ -63,8 +63,8 @@
         }
     };
 
-    public PlaybackControlHelper(Context context, PlaybackOverlayFragment fragment) {
-        super(context, fragment, sFastForwardSpeeds);
+    public PlaybackControlHelper(Context context, PlaybackGlueHost host) {
+        super(context, host, sFastForwardSpeeds, sFastForwardSpeeds);
         mThumbsUpAction = new PlaybackControlsRow.ThumbsUpAction(context);
         mThumbsUpAction.setIndex(PlaybackControlsRow.ThumbsUpAction.OUTLINE);
         mThumbsDownAction = new PlaybackControlsRow.ThumbsDownAction(context);
@@ -280,4 +280,4 @@
             mUpdateProgressRunnable.run();
         }
     }
-};
+}
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackControlSupportHelper.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackControlSupportHelper.java
deleted file mode 100644
index a538a44..0000000
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackControlSupportHelper.java
+++ /dev/null
@@ -1,285 +0,0 @@
-/* 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());
-        }
-    };
-
-    public 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/PlaybackOverlayFragment.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackOverlayFragment.java
index c918774..d9fcbc9 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackOverlayFragment.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackOverlayFragment.java
@@ -14,43 +14,34 @@
 package com.example.android.leanback;
 
 import android.content.Context;
-import android.graphics.drawable.Drawable;
 import android.os.Bundle;
-import android.os.Handler;
-import android.support.v17.leanback.app.PlaybackControlGlue;
+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.PlaybackControlsRow;
-import android.support.v17.leanback.widget.PlaybackControlsRow.RepeatAction;
-import android.support.v17.leanback.widget.PlaybackControlsRow.ThumbsUpAction;
-import android.support.v17.leanback.widget.PlaybackControlsRow.ThumbsDownAction;
-import android.support.v17.leanback.widget.PlaybackControlsRowPresenter;
 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.ListRow;
-import android.support.v17.leanback.widget.Presenter;
 import android.support.v17.leanback.widget.RowPresenter;
-import android.support.v17.leanback.widget.ListRowPresenter;
-import android.support.v17.leanback.widget.OnItemViewSelectedListener;
-import android.support.v17.leanback.widget.OnItemViewClickedListener;
-import android.support.v17.leanback.widget.ControlButtonPresenterSelector;
 import android.support.v17.leanback.widget.SparseArrayObjectAdapter;
 import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.Toast;
 
 public class PlaybackOverlayFragment
-        extends android.support.v17.leanback.app.PlaybackOverlayFragment
+        extends android.support.v17.leanback.app.PlaybackFragment
         implements PlaybackOverlayActivity.PictureInPictureListener {
     private static final String TAG = "leanback.PlaybackControlsFragment";
 
     /**
      * Change this to choose a different overlay background.
      */
-    private static final int BACKGROUND_TYPE = PlaybackOverlayFragment.BG_LIGHT;
+    private static final int BACKGROUND_TYPE = PlaybackFragment.BG_LIGHT;
 
     /**
      * Change the number of related content rows.
@@ -68,25 +59,6 @@
     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();
     }
@@ -97,13 +69,12 @@
         super.onCreate(savedInstanceState);
 
         setBackgroundType(BACKGROUND_TYPE);
-        setOnItemViewSelectedListener(mOnItemViewSelectedListener);
 
         createComponents(getActivity());
     }
 
     private void createComponents(Context context) {
-        mGlue = new PlaybackControlHelper(context, this) {
+        mGlue = new PlaybackControlHelper(context, new PlaybackFragmentGlueHost(this)) {
             @Override
             public int getUpdatePeriod() {
                 int totalTime = getControlsRow().getTotalTime();
@@ -134,7 +105,7 @@
             }
         };
 
-        mGlue.setOnItemViewClickedListener(mOnItemViewClickedListener);
+        //mGlue.setOnItemViewClickedListener(mOnItemViewClickedListener);
 
         mPlaybackControlsRowPresenter = mGlue.createControlsRowAndPresenter();
         mPlaybackControlsRowPresenter.setSecondaryActionsHidden(SECONDARY_HIDDEN);
@@ -163,7 +134,6 @@
             HeaderItem header = new HeaderItem(i, "Row " + i);
             getAdapter().set(ROW_CONTROLS + 1 + i, new ListRow(header, listRowAdapter));
         }
-
     }
 
     @Override
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackOverlaySupportFragment.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackOverlaySupportFragment.java
index e8ea8f5..c8824d9 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackOverlaySupportFragment.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackOverlaySupportFragment.java
@@ -16,43 +16,34 @@
 package com.example.android.leanback;
 
 import android.content.Context;
-import android.graphics.drawable.Drawable;
 import android.os.Bundle;
-import android.os.Handler;
-import android.support.v17.leanback.app.PlaybackControlGlue;
+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.PlaybackControlsRow;
-import android.support.v17.leanback.widget.PlaybackControlsRow.RepeatAction;
-import android.support.v17.leanback.widget.PlaybackControlsRow.ThumbsUpAction;
-import android.support.v17.leanback.widget.PlaybackControlsRow.ThumbsDownAction;
-import android.support.v17.leanback.widget.PlaybackControlsRowPresenter;
 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.ListRow;
-import android.support.v17.leanback.widget.Presenter;
 import android.support.v17.leanback.widget.RowPresenter;
-import android.support.v17.leanback.widget.ListRowPresenter;
-import android.support.v17.leanback.widget.OnItemViewSelectedListener;
-import android.support.v17.leanback.widget.OnItemViewClickedListener;
-import android.support.v17.leanback.widget.ControlButtonPresenterSelector;
 import android.support.v17.leanback.widget.SparseArrayObjectAdapter;
 import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.Toast;
 
 public class PlaybackOverlaySupportFragment
-        extends android.support.v17.leanback.app.PlaybackOverlaySupportFragment
+        extends android.support.v17.leanback.app.PlaybackSupportFragment
         implements PlaybackOverlaySupportActivity.PictureInPictureListener {
     private static final String TAG = "leanback.PlaybackControlsFragment";
 
     /**
      * Change this to choose a different overlay background.
      */
-    private static final int BACKGROUND_TYPE = PlaybackOverlaySupportFragment.BG_LIGHT;
+    private static final int BACKGROUND_TYPE = PlaybackSupportFragment.BG_LIGHT;
 
     /**
      * Change the number of related content rows.
@@ -66,29 +57,10 @@
 
     private static final int ROW_CONTROLS = 0;
 
-    private PlaybackControlSupportHelper mGlue;
+    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();
     }
@@ -99,13 +71,12 @@
         super.onCreate(savedInstanceState);
 
         setBackgroundType(BACKGROUND_TYPE);
-        setOnItemViewSelectedListener(mOnItemViewSelectedListener);
 
         createComponents(getActivity());
     }
 
     private void createComponents(Context context) {
-        mGlue = new PlaybackControlSupportHelper(context, this) {
+        mGlue = new PlaybackControlHelper(context, new PlaybackSupportFragmentGlueHost(this)) {
             @Override
             public int getUpdatePeriod() {
                 int totalTime = getControlsRow().getTotalTime();
@@ -136,7 +107,7 @@
             }
         };
 
-        mGlue.setOnItemViewClickedListener(mOnItemViewClickedListener);
+        //mGlue.setOnItemViewClickedListener(mOnItemViewClickedListener);
 
         mPlaybackControlsRowPresenter = mGlue.createControlsRowAndPresenter();
         mPlaybackControlsRowPresenter.setSecondaryActionsHidden(SECONDARY_HIDDEN);
@@ -165,7 +136,6 @@
             HeaderItem header = new HeaderItem(i, "Row " + i);
             getAdapter().set(ROW_CONTROLS + 1 + i, new ListRow(header, listRowAdapter));
         }
-
     }
 
     @Override
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/RowsActivity.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/RowsActivity.java
index c44557d..0565865 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/RowsActivity.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/RowsActivity.java
@@ -24,7 +24,6 @@
 public class RowsActivity extends Activity
 {
     private RowsFragment mRowsFragment;
-    private TitleHelper mTitleHelper;
 
     /** Called when the activity is first created. */
     @Override
@@ -50,8 +49,8 @@
         });
 
         BrowseFrameLayout frameLayout = (BrowseFrameLayout) findViewById(R.id.rows_frame);
-        mTitleHelper = new TitleHelper(frameLayout, titleView);
-        frameLayout.setOnFocusSearchListener(mTitleHelper.getOnFocusSearchListener());
-        mRowsFragment.setTitleHelper(mTitleHelper);
+        TitleHelper titleHelper = new TitleHelper(frameLayout, titleView);
+        frameLayout.setOnFocusSearchListener(titleHelper.getOnFocusSearchListener());
+        mRowsFragment.setTitleHelper(titleHelper);
     }
 }
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/RowsFragment.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/RowsFragment.java
index ea524f0..3fa6560 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/RowsFragment.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/RowsFragment.java
@@ -37,7 +37,6 @@
     // Row heights default to wrap content
     private static final boolean USE_FIXED_ROW_HEIGHT = false;
 
-    private ArrayObjectAdapter mRowsAdapter;
     private TitleHelper mTitleHelper;
 
     public void setTitleHelper(TitleHelper titleHelper) {
@@ -76,7 +75,7 @@
             lrp.setExpandedRowHeight(cardPresenter.getExpandedRowHeight(getActivity()));
         }
 
-        mRowsAdapter = new ArrayObjectAdapter(lrp);
+        ArrayObjectAdapter rowsAdapter = new ArrayObjectAdapter(lrp);
 
         for (int i = 0; i < NUM_ROWS; ++i) {
             ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(cardPresenter);
@@ -89,10 +88,10 @@
             listRowAdapter.add(new PhotoItem("Android TV", R.drawable.gallery_photo_7));
             listRowAdapter.add(new PhotoItem("Leanback", R.drawable.gallery_photo_8));
             HeaderItem header = new HeaderItem(i, "Row " + i);
-            mRowsAdapter.add(new ListRow(header, listRowAdapter));
+            rowsAdapter.add(new ListRow(header, listRowAdapter));
         }
 
-        setAdapter(mRowsAdapter);
+        setAdapter(rowsAdapter);
     }
 
     private final class ItemViewClickedListener implements OnItemViewClickedListener {
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/RowsSupportActivity.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/RowsSupportActivity.java
index 2035806..810d60e 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/RowsSupportActivity.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/RowsSupportActivity.java
@@ -15,18 +15,17 @@
  */
 package com.example.android.leanback;
 
+import android.support.v4.app.FragmentActivity;
 import android.content.Intent;
 import android.os.Bundle;
 import android.support.v17.leanback.widget.BrowseFrameLayout;
 import android.support.v17.leanback.widget.TitleHelper;
 import android.support.v17.leanback.widget.TitleView;
-import android.support.v4.app.FragmentActivity;
 import android.view.View;
 
 public class RowsSupportActivity extends FragmentActivity
 {
     private RowsSupportFragment mRowsSupportFragment;
-    private TitleHelper mTitleHelper;
 
     /** Called when the activity is first created. */
     @Override
@@ -52,8 +51,8 @@
         });
 
         BrowseFrameLayout frameLayout = (BrowseFrameLayout) findViewById(R.id.rows_frame);
-        mTitleHelper = new TitleHelper(frameLayout, titleView);
-        frameLayout.setOnFocusSearchListener(mTitleHelper.getOnFocusSearchListener());
-        mRowsSupportFragment.setTitleHelper(mTitleHelper);
+        TitleHelper titleHelper = new TitleHelper(frameLayout, titleView);
+        frameLayout.setOnFocusSearchListener(titleHelper.getOnFocusSearchListener());
+        mRowsSupportFragment.setTitleHelper(titleHelper);
     }
 }
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/RowsSupportFragment.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/RowsSupportFragment.java
index 6d66f77..4f8a5ab 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/RowsSupportFragment.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/RowsSupportFragment.java
@@ -39,7 +39,6 @@
     // Row heights default to wrap content
     private static final boolean USE_FIXED_ROW_HEIGHT = false;
 
-    private ArrayObjectAdapter mRowsAdapter;
     private TitleHelper mTitleHelper;
 
     public void setTitleHelper(TitleHelper titleHelper) {
@@ -78,7 +77,7 @@
             lrp.setExpandedRowHeight(cardPresenter.getExpandedRowHeight(getActivity()));
         }
 
-        mRowsAdapter = new ArrayObjectAdapter(lrp);
+        ArrayObjectAdapter rowsAdapter = new ArrayObjectAdapter(lrp);
 
         for (int i = 0; i < NUM_ROWS; ++i) {
             ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(cardPresenter);
@@ -91,10 +90,10 @@
             listRowAdapter.add(new PhotoItem("Android TV", R.drawable.gallery_photo_7));
             listRowAdapter.add(new PhotoItem("Leanback", R.drawable.gallery_photo_8));
             HeaderItem header = new HeaderItem(i, "Row " + i);
-            mRowsAdapter.add(new ListRow(header, listRowAdapter));
+            rowsAdapter.add(new ListRow(header, listRowAdapter));
         }
 
-        setAdapter(mRowsAdapter);
+        setAdapter(rowsAdapter);
     }
 
     private final class ItemViewClickedListener implements OnItemViewClickedListener {
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/SearchActivity.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/SearchActivity.java
index 374382b..5f69037 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/SearchActivity.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/SearchActivity.java
@@ -26,7 +26,7 @@
     private static boolean DEBUG = true;
 
     /** If using internal speech recognizer, you must have RECORD_AUDIO permission */
-    private static boolean USE_INTERNAL_SPEECH_RECOGNIZER = true;
+    private static final boolean USE_INTERNAL_SPEECH_RECOGNIZER = true;
     private static final int REQUEST_SPEECH = 1;
 
     private SearchFragment mFragment;
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/SearchFragment.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/SearchFragment.java
index b55b82f..7152bae 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/SearchFragment.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/SearchFragment.java
@@ -1,9 +1,9 @@
 package com.example.android.leanback;
 
+import android.content.Context;
 import android.content.Intent;
 import android.os.Bundle;
 import android.os.Handler;
-import android.support.v4.app.ActivityOptionsCompat;
 import android.support.v17.leanback.widget.ArrayObjectAdapter;
 import android.support.v17.leanback.widget.HeaderItem;
 import android.support.v17.leanback.widget.ImageCardView;
@@ -14,6 +14,8 @@
 import android.support.v17.leanback.widget.Presenter;
 import android.support.v17.leanback.widget.Row;
 import android.support.v17.leanback.widget.RowPresenter;
+import android.support.v4.app.ActivityOptionsCompat;
+import android.support.v4.content.res.ResourcesCompat;
 import android.text.TextUtils;
 import android.util.Log;
 
@@ -33,7 +35,9 @@
 
         mRowsAdapter = new ArrayObjectAdapter(new ListRowPresenter());
 
-        setBadgeDrawable(getActivity().getResources().getDrawable(R.drawable.ic_title));
+        final Context context = getActivity();
+        setBadgeDrawable(ResourcesCompat.getDrawable(context.getResources(),
+                R.drawable.ic_title, context.getTheme()));
         setTitle("Leanback Sample App");
         setSearchResultProvider(this);
         setOnItemViewClickedListener(new ItemViewClickedListener());
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/SearchSupportActivity.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/SearchSupportActivity.java
index 25e5cbf..536edc4 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/SearchSupportActivity.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/SearchSupportActivity.java
@@ -28,7 +28,7 @@
     private static boolean DEBUG = true;
 
     /** If using internal speech recognizer, you must have RECORD_AUDIO permission */
-    private static boolean USE_INTERNAL_SPEECH_RECOGNIZER = true;
+    private static final boolean USE_INTERNAL_SPEECH_RECOGNIZER = true;
     private static final int REQUEST_SPEECH = 1;
 
     private SearchSupportFragment mFragment;
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/SearchSupportFragment.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/SearchSupportFragment.java
index 35c5eb2..20c5ef6 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/SearchSupportFragment.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/SearchSupportFragment.java
@@ -2,10 +2,10 @@
 
 package com.example.android.leanback;
 
+import android.content.Context;
 import android.content.Intent;
 import android.os.Bundle;
 import android.os.Handler;
-import android.support.v4.app.ActivityOptionsCompat;
 import android.support.v17.leanback.widget.ArrayObjectAdapter;
 import android.support.v17.leanback.widget.HeaderItem;
 import android.support.v17.leanback.widget.ImageCardView;
@@ -16,6 +16,8 @@
 import android.support.v17.leanback.widget.Presenter;
 import android.support.v17.leanback.widget.Row;
 import android.support.v17.leanback.widget.RowPresenter;
+import android.support.v4.app.ActivityOptionsCompat;
+import android.support.v4.content.res.ResourcesCompat;
 import android.text.TextUtils;
 import android.util.Log;
 
@@ -35,7 +37,9 @@
 
         mRowsAdapter = new ArrayObjectAdapter(new ListRowPresenter());
 
-        setBadgeDrawable(getActivity().getResources().getDrawable(R.drawable.ic_title));
+        final Context context = getActivity();
+        setBadgeDrawable(ResourcesCompat.getDrawable(context.getResources(),
+                R.drawable.ic_title, context.getTheme()));
         setTitle("Leanback Sample App");
         setSearchResultProvider(this);
         setOnItemViewClickedListener(new ItemViewClickedListener());
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/StringPresenter.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/StringPresenter.java
index 5c80e0b..0302f68 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/StringPresenter.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/StringPresenter.java
@@ -13,7 +13,9 @@
  */
 package com.example.android.leanback;
 
+import android.content.Context;
 import android.support.v17.leanback.widget.Presenter;
+import android.support.v4.content.res.ResourcesCompat;
 import android.util.Log;
 import android.view.ViewGroup;
 import android.widget.TextView;
@@ -23,11 +25,12 @@
 
     public ViewHolder onCreateViewHolder(ViewGroup parent) {
         Log.d(TAG, "onCreateViewHolder");
-        TextView tv = new TextView(parent.getContext());
+        final Context context = parent.getContext();
+        TextView tv = new TextView(context);
         tv.setFocusable(true);
         tv.setFocusableInTouchMode(true);
-        tv.setBackground(
-                parent.getContext().getResources().getDrawable(R.drawable.text_bg));
+        tv.setBackground(ResourcesCompat.getDrawable(context.getResources(), R.drawable.text_bg,
+                context.getTheme()));
         return new ViewHolder(tv);
     }
 
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/VerticalGridFragment.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/VerticalGridFragment.java
index fe664dd..68de793 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/VerticalGridFragment.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/VerticalGridFragment.java
@@ -13,21 +13,20 @@
  */
 package com.example.android.leanback;
 
+import android.content.Context;
 import android.content.Intent;
 import android.os.Bundle;
 import android.os.Handler;
 import android.support.v17.leanback.widget.ArrayObjectAdapter;
-import android.support.v17.leanback.widget.Presenter;
-import android.support.v17.leanback.widget.RowPresenter;
-import android.support.v17.leanback.widget.VerticalGridPresenter;
-import android.support.v17.leanback.widget.Row;
 import android.support.v17.leanback.widget.OnItemViewClickedListener;
 import android.support.v17.leanback.widget.OnItemViewSelectedListener;
+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.VerticalGridPresenter;
+import android.support.v4.content.res.ResourcesCompat;
 import android.util.Log;
-import android.view.Gravity;
 import android.view.View;
-import android.view.ViewGroup;
-import android.widget.TextView;
 
 public class VerticalGridFragment extends android.support.v17.leanback.app.VerticalGridFragment {
     private static final String TAG = "leanback.VerticalGridFragment";
@@ -52,7 +51,9 @@
         Log.i(TAG, "onCreate");
         super.onCreate(savedInstanceState);
 
-        setBadgeDrawable(getActivity().getResources().getDrawable(R.drawable.ic_title));
+        final Context context = getActivity();
+        setBadgeDrawable(ResourcesCompat.getDrawable(context.getResources(),
+                R.drawable.ic_title, context.getTheme()));
         setTitle("Leanback Vertical Grid Demo");
 
         setupFragment();
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/VerticalGridSupportFragment.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/VerticalGridSupportFragment.java
index cd88f5a..10f4c29 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/VerticalGridSupportFragment.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/VerticalGridSupportFragment.java
@@ -15,21 +15,20 @@
  */
 package com.example.android.leanback;
 
+import android.content.Context;
 import android.content.Intent;
 import android.os.Bundle;
 import android.os.Handler;
 import android.support.v17.leanback.widget.ArrayObjectAdapter;
-import android.support.v17.leanback.widget.Presenter;
-import android.support.v17.leanback.widget.RowPresenter;
-import android.support.v17.leanback.widget.VerticalGridPresenter;
-import android.support.v17.leanback.widget.Row;
 import android.support.v17.leanback.widget.OnItemViewClickedListener;
 import android.support.v17.leanback.widget.OnItemViewSelectedListener;
+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.VerticalGridPresenter;
+import android.support.v4.content.res.ResourcesCompat;
 import android.util.Log;
-import android.view.Gravity;
 import android.view.View;
-import android.view.ViewGroup;
-import android.widget.TextView;
 
 public class VerticalGridSupportFragment extends android.support.v17.leanback.app.VerticalGridSupportFragment {
     private static final String TAG = "leanback.VerticalGridSupportFragment";
@@ -54,7 +53,9 @@
         Log.i(TAG, "onCreate");
         super.onCreate(savedInstanceState);
 
-        setBadgeDrawable(getActivity().getResources().getDrawable(R.drawable.ic_title));
+        final Context context = getActivity();
+        setBadgeDrawable(ResourcesCompat.getDrawable(context.getResources(),
+                R.drawable.ic_title, context.getTheme()));
         setTitle("Leanback Vertical Grid Demo");
 
         setupFragment();
diff --git a/samples/SupportLeanbackShowcase/app/build.gradle b/samples/SupportLeanbackShowcase/app/build.gradle
index 2b817d3..b2ff15b 100644
--- a/samples/SupportLeanbackShowcase/app/build.gradle
+++ b/samples/SupportLeanbackShowcase/app/build.gradle
@@ -1,13 +1,13 @@
 apply plugin: 'com.android.application'
 
 android {
-    compileSdkVersion 'android-N'
-    buildToolsVersion "24.0.0 rc3"
+    compileSdkVersion 24
+    buildToolsVersion "24.0.2"
 
     defaultConfig {
         applicationId "android.support.v17.leanback.supportleanbackshowcase"
-        minSdkVersion '17'
-        targetSdkVersion 'N'
+        minSdkVersion 17
+        targetSdkVersion 24
         versionCode 1
         versionName "1.0"
         multiDexEnabled true
diff --git a/samples/SupportLeanbackShowcase/build.gradle b/samples/SupportLeanbackShowcase/build.gradle
index b8ec678..c4b2177 100644
--- a/samples/SupportLeanbackShowcase/build.gradle
+++ b/samples/SupportLeanbackShowcase/build.gradle
@@ -1,7 +1,7 @@
 // Top-level build file where you can add configuration options common to all sub-projects/modules.
 ext {
   // This will be set by local.properties file. By default it
-  // will use the public release version (23.2.1). You can run
+  // will use the public release version (24.0.0). You can run
   // python build-local.py to build the local verison. That script will
   // figure out the local library version based on maven metadata for leanback
   // library and update local.properties file. Gradle build file in turn
@@ -9,7 +9,7 @@
   Properties properties = new Properties()
   properties.load(project.rootProject.file('local.properties').newDataInputStream())
   supportLibVersion = properties.getProperty('LIBRARY_VERSION')
-  supportLibVersion = supportLibVersion ? supportLibVersion : "23.2.1"
+  supportLibVersion = supportLibVersion ? supportLibVersion : "24.0.0"
   localRepo = properties.getProperty('LOCAL_REPO')
 }
 
@@ -18,7 +18,7 @@
         jcenter()
     }
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.1.0'
+        classpath 'com.android.tools.build:gradle:2.1.3'
 
         // NOTE: Do not place your application dependencies here; they belong
         // in the individual module build.gradle files
diff --git a/samples/SupportLeanbackShowcase/gradle/wrapper/gradle-wrapper.properties b/samples/SupportLeanbackShowcase/gradle/wrapper/gradle-wrapper.properties
index fdb8024..5686dee 100644
--- a/samples/SupportLeanbackShowcase/gradle/wrapper/gradle-wrapper.properties
+++ b/samples/SupportLeanbackShowcase/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
-#Wed Apr 10 15:27:10 PDT 2013
+#Thu Sep 01 17:18:32 PDT 2016
 distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip
diff --git a/samples/SupportPercentDemos/Android.mk b/samples/SupportPercentDemos/Android.mk
index e2d4e4a7..54c980f 100644
--- a/samples/SupportPercentDemos/Android.mk
+++ b/samples/SupportPercentDemos/Android.mk
@@ -18,20 +18,15 @@
 # We need to add some special AAPT flags to generate R classes
 # for resources that are included from the libraries.
 include $(CLEAR_VARS)
+LOCAL_USE_AAPT2 := true
 LOCAL_PACKAGE_NAME := SupportPercentDemos
 LOCAL_MODULE_TAGS := samples
 LOCAL_SDK_VERSION := current
 LOCAL_MIN_SDK_VERSION := 7
 LOCAL_DEX_PREOPT := false
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_STATIC_JAVA_LIBRARIES := \
+LOCAL_STATIC_ANDROID_LIBRARIES := \
         android-support-percent \
         android-support-v4 \
         android-support-v13
-LOCAL_RESOURCE_DIR = \
-        $(LOCAL_PATH)/res \
-        frameworks/support/percent/res
-LOCAL_AAPT_FLAGS := \
-        --auto-add-overlay \
-        --extra-packages android.support.percent
 include $(BUILD_PACKAGE)
diff --git a/samples/SupportPreferenceDemos/res/values/strings.xml b/samples/SupportPreferenceDemos/res/values/strings.xml
index 2fe2c61..e6effdf 100644
--- a/samples/SupportPreferenceDemos/res/values/strings.xml
+++ b/samples/SupportPreferenceDemos/res/values/strings.xml
@@ -22,6 +22,12 @@
 
     <string name="root_title">Demo Preferences</string>
 
+    <string name="title_basic_preference">Basic preference</string>
+    <string name="summary_basic_preference">This is a basic preference</string>
+
+    <string name="title_stylish_preference"><b>Very</b> <i>stylish</i> <u>preference</u></string>
+    <string name="summary_stylish_preference">This is a <b>very</b> <i>stylish</i> <u>preference</u></string>
+
     <string name="inline_preferences">In-line preferences</string>
     <string name="dialog_based_preferences">Dialog-based preferences</string>
     <string name="launch_preferences">Launch preferences</string>
diff --git a/samples/SupportPreferenceDemos/res/xml/preferences.xml b/samples/SupportPreferenceDemos/res/xml/preferences.xml
index 0c79349..f469af2 100644
--- a/samples/SupportPreferenceDemos/res/xml/preferences.xml
+++ b/samples/SupportPreferenceDemos/res/xml/preferences.xml
@@ -21,6 +21,16 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:title="@string/root_title">
 
+    <Preference
+        android:key="basic_preference"
+        android:title="@string/title_basic_preference"
+        android:summary="@string/summary_basic_preference" />
+
+    <Preference
+        android:key="stylish_preference"
+        android:title="@string/title_stylish_preference"
+        android:summary="@string/summary_stylish_preference" />
+
     <PreferenceCategory
         android:title="@string/inline_preferences">
 
diff --git a/samples/SupportTransitionDemos/Android.mk b/samples/SupportTransitionDemos/Android.mk
index abc1ad9..6ebc7af 100644
--- a/samples/SupportTransitionDemos/Android.mk
+++ b/samples/SupportTransitionDemos/Android.mk
@@ -18,25 +18,17 @@
 # We need to add some special AAPT flags to generate R classes
 # for resources that are included from the libraries.
 include $(CLEAR_VARS)
+LOCAL_USE_AAPT2 := true
 LOCAL_PACKAGE_NAME := SupportTransitionDemos
 LOCAL_MODULE_TAGS := samples
 LOCAL_SDK_VERSION := current
 LOCAL_MIN_SDK_VERSION := 14
 LOCAL_DEX_PREOPT := false
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_STATIC_JAVA_LIBRARIES := \
+LOCAL_STATIC_ANDROID_LIBRARIES := \
         android-support-v4 \
         android-support-v7-appcompat \
         android-support-transition
-LOCAL_RESOURCE_DIR = \
-        $(LOCAL_PATH)/res \
-        frameworks/support/v7/appcompat/res \
-        frameworks/support/transition/res
-LOCAL_AAPT_FLAGS := \
-        --auto-add-overlay \
-        --extra-packages android.support.v7.appcompat \
-        --extra-packages android.support.v7.recyclerview \
-        --extra-packages android.support.transition \
-        --no-version-vectors
+LOCAL_AAPT_FLAGS := --no-version-vectors
 LOCAL_PROGUARD_FLAG_FILES := proguard.flags
 include $(BUILD_PACKAGE)
diff --git a/samples/SupportTransitionDemos/AndroidManifest.xml b/samples/SupportTransitionDemos/AndroidManifest.xml
index 479b0a5..4028f47 100644
--- a/samples/SupportTransitionDemos/AndroidManifest.xml
+++ b/samples/SupportTransitionDemos/AndroidManifest.xml
@@ -37,8 +37,8 @@
             </intent-filter>
         </activity>
 
-        <activity android:name=".widget.BasicUsage"
-                  android:label="@string/basic"
+        <activity android:name=".widget.SceneUsage"
+                  android:label="@string/scene"
                   android:theme="@style/Theme.Transition">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
@@ -54,5 +54,14 @@
                 <category android:name="com.example.android.support.transition.SAMPLE_CODE" />
             </intent-filter>
         </activity>
+
+        <activity android:name=".widget.BeginDelayedUsage"
+                  android:label="@string/beginDelayed"
+                  android:theme="@style/Theme.Transition">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="com.example.android.support.transition.SAMPLE_CODE" />
+            </intent-filter>
+        </activity>
     </application>
 </manifest>
diff --git a/samples/SupportTransitionDemos/res/layout/begin_delayed.xml b/samples/SupportTransitionDemos/res/layout/begin_delayed.xml
new file mode 100644
index 0000000..8aa1bba
--- /dev/null
+++ b/samples/SupportTransitionDemos/res/layout/begin_delayed.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     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.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              xmlns:app="http://schemas.android.com/apk/res-auto"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent"
+              android:orientation="vertical">
+
+    <android.support.v7.widget.Toolbar
+            android:id="@+id/toolbar"
+            android:layout_height="wrap_content"
+            android:layout_width="match_parent"
+            android:minHeight="?attr/actionBarSize"
+            android:background="?attr/colorPrimary"
+            android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
+            app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
+            android:elevation="4dp"/>
+
+    <FrameLayout
+            android:id="@+id/root"
+            android:layout_width="match_parent"
+            android:layout_height="0dp"
+            android:layout_weight="1"
+            android:padding="16dp">
+
+        <Button
+                android:id="@+id/button"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/begin"/>
+
+    </FrameLayout>
+
+</LinearLayout>
diff --git a/samples/SupportTransitionDemos/res/layout/basic_usage.xml b/samples/SupportTransitionDemos/res/layout/scene_usage.xml
similarity index 100%
rename from samples/SupportTransitionDemos/res/layout/basic_usage.xml
rename to samples/SupportTransitionDemos/res/layout/scene_usage.xml
diff --git a/samples/SupportTransitionDemos/res/values/strings.xml b/samples/SupportTransitionDemos/res/values/strings.xml
index bc1029d..9e528cd 100644
--- a/samples/SupportTransitionDemos/res/values/strings.xml
+++ b/samples/SupportTransitionDemos/res/values/strings.xml
@@ -16,7 +16,9 @@
 
 <resources>
     <string name="activity_sample_code">Support Transition Demos</string>
-    <string name="basic">Basic</string>
-    <string name="custom">Custom</string>
+    <string name="scene">Scene</string>
+    <string name="custom">Custom Transition</string>
+    <string name="beginDelayed">Begin Delayed Transition</string>
     <string name="toggle">Toggle</string>
+    <string name="begin">Begin</string>
 </resources>
diff --git a/samples/SupportTransitionDemos/src/com/example/android/support/transition/widget/BeginDelayedUsage.java b/samples/SupportTransitionDemos/src/com/example/android/support/transition/widget/BeginDelayedUsage.java
new file mode 100644
index 0000000..713e76d
--- /dev/null
+++ b/samples/SupportTransitionDemos/src/com/example/android/support/transition/widget/BeginDelayedUsage.java
@@ -0,0 +1,61 @@
+/*
+ * 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.support.transition.widget;
+
+import android.os.Bundle;
+import android.support.transition.TransitionManager;
+import android.support.v4.view.GravityCompat;
+import android.view.View;
+import android.widget.Button;
+import android.widget.FrameLayout;
+import com.example.android.support.transition.R;
+
+public class BeginDelayedUsage extends TransitionUsageBase {
+
+    private FrameLayout mRoot;
+    private Button mButton;
+
+    @Override
+    int getLayoutResId() {
+        return R.layout.begin_delayed;
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        mRoot = (FrameLayout) findViewById(R.id.root);
+        mButton = (Button) findViewById(R.id.button);
+        mButton.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View view) {
+                toggle();
+            }
+        });
+    }
+
+    private void toggle() {
+        TransitionManager.beginDelayedTransition(mRoot);
+        FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) mButton.getLayoutParams();
+        if ((params.gravity & GravityCompat.RELATIVE_HORIZONTAL_GRAVITY_MASK) == GravityCompat.END) {
+            params.gravity = params.gravity ^ GravityCompat.END | GravityCompat.START;
+        } else {
+            params.gravity = params.gravity ^ GravityCompat.START | GravityCompat.END;
+        }
+        mButton.setLayoutParams(params);
+    }
+
+}
diff --git a/samples/SupportTransitionDemos/src/com/example/android/support/transition/widget/CustomUsage.java b/samples/SupportTransitionDemos/src/com/example/android/support/transition/widget/CustomUsage.java
index 2bd9d27..53af776 100644
--- a/samples/SupportTransitionDemos/src/com/example/android/support/transition/widget/CustomUsage.java
+++ b/samples/SupportTransitionDemos/src/com/example/android/support/transition/widget/CustomUsage.java
@@ -28,7 +28,7 @@
  * This demonstrates usage of a custom Transition. See {@link ChangeColor} for the actual
  * implementation of a custom Transition.
  */
-public class CustomUsage extends TransitionUsageBase {
+public class CustomUsage extends SceneUsageBase {
 
     private Transition mTransition;
 
diff --git a/samples/SupportTransitionDemos/src/com/example/android/support/transition/widget/BasicUsage.java b/samples/SupportTransitionDemos/src/com/example/android/support/transition/widget/SceneUsage.java
similarity index 91%
rename from samples/SupportTransitionDemos/src/com/example/android/support/transition/widget/BasicUsage.java
rename to samples/SupportTransitionDemos/src/com/example/android/support/transition/widget/SceneUsage.java
index 11b460e..61e209f 100644
--- a/samples/SupportTransitionDemos/src/com/example/android/support/transition/widget/BasicUsage.java
+++ b/samples/SupportTransitionDemos/src/com/example/android/support/transition/widget/SceneUsage.java
@@ -23,9 +23,9 @@
 import android.view.ViewGroup;
 
 /**
- * This demonstrates basic usage of the Transition API.
+ * This demonstrates basic usage of the Transition Scene.
  */
-public class BasicUsage extends TransitionUsageBase {
+public class SceneUsage extends SceneUsageBase {
 
     @Override
     Scene[] setUpScenes(ViewGroup root) {
diff --git a/samples/SupportTransitionDemos/src/com/example/android/support/transition/widget/SceneUsageBase.java b/samples/SupportTransitionDemos/src/com/example/android/support/transition/widget/SceneUsageBase.java
new file mode 100644
index 0000000..f2fd38a
--- /dev/null
+++ b/samples/SupportTransitionDemos/src/com/example/android/support/transition/widget/SceneUsageBase.java
@@ -0,0 +1,69 @@
+/*
+ * 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.support.transition.widget;
+
+import android.os.Bundle;
+import android.support.transition.Scene;
+import android.support.transition.TransitionManager;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+import com.example.android.support.transition.R;
+
+abstract class SceneUsageBase extends TransitionUsageBase {
+
+    private Scene[] mScenes;
+
+    private int mCurrentScene;
+
+    abstract Scene[] setUpScenes(ViewGroup root);
+
+    abstract void go(Scene scene);
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        FrameLayout root = (FrameLayout) findViewById(R.id.root);
+        mScenes = setUpScenes(root);
+        TransitionManager.go(mScenes[0]);
+    }
+
+    @Override
+    int getLayoutResId() {
+        return R.layout.scene_usage;
+    }
+
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        getMenuInflater().inflate(R.menu.basic_usage, menu);
+        return true;
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        switch (item.getItemId()) {
+            case R.id.action_toggle:
+                mCurrentScene = (mCurrentScene + 1) % mScenes.length;
+                go(mScenes[mCurrentScene]);
+                return true;
+        }
+        return false;
+    }
+
+}
diff --git a/samples/SupportTransitionDemos/src/com/example/android/support/transition/widget/TransitionUsageBase.java b/samples/SupportTransitionDemos/src/com/example/android/support/transition/widget/TransitionUsageBase.java
index 83c3a29..0a085f2 100644
--- a/samples/SupportTransitionDemos/src/com/example/android/support/transition/widget/TransitionUsageBase.java
+++ b/samples/SupportTransitionDemos/src/com/example/android/support/transition/widget/TransitionUsageBase.java
@@ -16,6 +16,7 @@
 
 package com.example.android.support.transition.widget;
 
+import android.support.annotation.LayoutRes;
 import com.example.android.support.transition.R;
 
 import android.os.Bundle;
@@ -33,43 +34,17 @@
  */
 abstract class TransitionUsageBase extends AppCompatActivity {
 
-    protected Scene[] mScenes;
-
-    private int mCurrentScene;
-
-    abstract Scene[] setUpScenes(ViewGroup root);
-
-    abstract void go(Scene scene);
+    @LayoutRes
+    abstract int getLayoutResId();
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        setContentView(R.layout.basic_usage);
+        setContentView(getLayoutResId());
 
         // Retrieve the Toolbar from our content view, and set it as the action bar
         Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
         setSupportActionBar(toolbar);
-
-        FrameLayout root = (FrameLayout) findViewById(R.id.root);
-        mScenes = setUpScenes(root);
-        TransitionManager.go(mScenes[0]);
-    }
-
-    @Override
-    public boolean onCreateOptionsMenu(Menu menu) {
-        getMenuInflater().inflate(R.menu.basic_usage, menu);
-        return true;
-    }
-
-    @Override
-    public boolean onOptionsItemSelected(MenuItem item) {
-        switch (item.getItemId()) {
-            case R.id.action_toggle:
-                mCurrentScene = (mCurrentScene + 1) % mScenes.length;
-                go(mScenes[mCurrentScene]);
-                return true;
-        }
-        return false;
     }
 
 }
diff --git a/samples/SupportVectorDrawable/animated/Android.mk b/samples/SupportVectorDrawable/animated/Android.mk
index 1a34f53..ae01691 100644
--- a/samples/SupportVectorDrawable/animated/Android.mk
+++ b/samples/SupportVectorDrawable/animated/Android.mk
@@ -16,6 +16,8 @@
 
 include $(CLEAR_VARS)
 
+LOCAL_USE_AAPT2 := true
+
 LOCAL_MODULE_TAGS := tests
 
 LOCAL_SDK_VERSION := current
@@ -26,13 +28,12 @@
 
 LOCAL_PACKAGE_NAME := SupportAnimatedVectorDrawable
 
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-animatedvectordrawable \
+LOCAL_STATIC_ANDROID_LIBRARIES := \
+        android-support-animatedvectordrawable \
         android-support-vectordrawable \
         android-support-v4
 
-LOCAL_AAPT_FLAGS += --auto-add-overlay \
-        --extra-packages android.support.graphics.drawable \
-        --no-version-vectors
+LOCAL_AAPT_FLAGS += --no-version-vectors
 
 include $(BUILD_PACKAGE)
 
diff --git a/samples/SupportVectorDrawable/static/Android.mk b/samples/SupportVectorDrawable/static/Android.mk
index 88d76c5..bdc102a 100644
--- a/samples/SupportVectorDrawable/static/Android.mk
+++ b/samples/SupportVectorDrawable/static/Android.mk
@@ -1,21 +1,21 @@
 LOCAL_PATH:= $(call my-dir)
 include $(CLEAR_VARS)
 
+LOCAL_USE_AAPT2 := true
+
 LOCAL_MODULE_TAGS := samples tests
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
 LOCAL_PACKAGE_NAME := SupportVectorDrawable
 
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-vectordrawable android-support-v4
+LOCAL_STATIC_ANDROID_LIBRARIES := android-support-vectordrawable android-support-v4
 
 LOCAL_SDK_VERSION := current
 
 LOCAL_MIN_SDK_VERSION := 7
 
-LOCAL_AAPT_FLAGS += --auto-add-overlay \
-        --extra-packages android.support.graphics.drawable \
-        --no-version-vectors
+LOCAL_AAPT_FLAGS += --no-version-vectors
 
 include $(BUILD_PACKAGE)
 
diff --git a/transition/Android.mk b/transition/Android.mk
index a401d77..4f51f3a 100644
--- a/transition/Android.mk
+++ b/transition/Android.mk
@@ -19,6 +19,7 @@
 # SDK version than the resources.  The resources library and the R class that it
 # contains will not be linked into the final static library.
 include $(CLEAR_VARS)
+LOCAL_USE_AAPT2 := true
 LOCAL_MODULE := android-support-transition-res
 LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
 LOCAL_SRC_FILES := $(call all-java-files-under, dummy)
@@ -35,7 +36,7 @@
 LOCAL_SRC_FILES := $(call all-java-files-under, base)
 LOCAL_JAVA_LANGUAGE_VERSION := 1.7
 LOCAL_JAVA_LIBRARIES := android-support-transition-res \
-    android-support-v4
+    android-support-compat
 include $(BUILD_STATIC_JAVA_LIBRARY)
 
 # A helper sub-library that makes direct use of Ice Cream Sandwich APIs
@@ -45,7 +46,7 @@
 LOCAL_SRC_FILES := $(call all-java-files-under, ics)
 LOCAL_STATIC_JAVA_LIBRARIES := android-support-transition-base
 LOCAL_JAVA_LIBRARIES := android-support-transition-res \
-    android-support-v4
+    android-support-compat
 include $(BUILD_STATIC_JAVA_LIBRARY)
 
 # A helper sub-library that makes direct use of KitKat APIs
@@ -55,7 +56,7 @@
 LOCAL_SRC_FILES := $(call all-java-files-under, kitkat)
 LOCAL_STATIC_JAVA_LIBRARIES := android-support-transition-ics
 LOCAL_JAVA_LIBRARIES := android-support-transition-res \
-    android-support-v4
+    android-support-compat
 include $(BUILD_STATIC_JAVA_LIBRARY)
 
 # A helper sub-library that makes direct use of Lollipop APIs
@@ -65,7 +66,7 @@
 LOCAL_SRC_FILES := $(call all-java-files-under, api21)
 LOCAL_STATIC_JAVA_LIBRARIES := android-support-transition-kitkat
 LOCAL_JAVA_LIBRARIES := android-support-transition-res \
-    android-support-v4
+    android-support-compat
 include $(BUILD_STATIC_JAVA_LIBRARY)
 
 # A helper sub-library that makes direct use of Marshmallow APIs
@@ -75,18 +76,24 @@
 LOCAL_SRC_FILES := $(call all-java-files-under, api23)
 LOCAL_STATIC_JAVA_LIBRARIES := android-support-transition-api21
 LOCAL_JAVA_LIBRARIES := android-support-transition-res \
-    android-support-v4
+    android-support-compat
 include $(BUILD_STATIC_JAVA_LIBRARY)
 
 # Here is the final static library that apps can link against.
-# The R class is automatically excluded from the generated library.
-# Applications that use this library must specify LOCAL_RESOURCE_DIR
-# in their makefiles to include the resources in their package.
+# Applications that use this library must specify
+#
+#   LOCAL_STATIC_ANDROID_LIBRARIES := \
+#       android-support-transition \
+#       android-support-compat
+#
+# in their makefiles to include the resources and their dependencies in their package.
 include $(CLEAR_VARS)
+LOCAL_USE_AAPT2 := true
 LOCAL_MODULE := android-support-transition
 LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 LOCAL_STATIC_JAVA_LIBRARIES := android-support-transition-api23
-LOCAL_JAVA_LIBRARIES := android-support-transition-res \
-    android-support-v4
+LOCAL_STATIC_ANDROID_LIBRARIES := android-support-transition-res
+LOCAL_SHARED_ANDROID_LIBRARIES := android-support-compat
+LOCAL_JAR_EXCLUDE_FILES := none
 include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/transition/build.gradle b/transition/build.gradle
index faf8483..f06b0bd 100644
--- a/transition/build.gradle
+++ b/transition/build.gradle
@@ -3,7 +3,7 @@
 archivesBaseName = 'transition'
 
 dependencies {
-    compile project(':support-v4')
+    compile project(':support-compat')
 
     androidTestCompile ("com.android.support.test:runner:${project.rootProject.ext.testRunnerVersion}") {
         exclude module: 'support-annotations'
diff --git a/transition/tests/src/android/support/transition/TransitionActivity.java b/transition/tests/src/android/support/transition/TransitionActivity.java
index 253e11a..ff9dbcc 100644
--- a/transition/tests/src/android/support/transition/TransitionActivity.java
+++ b/transition/tests/src/android/support/transition/TransitionActivity.java
@@ -16,13 +16,13 @@
 
 package android.support.transition;
 
+import android.app.Activity;
 import android.os.Bundle;
 import android.support.transition.test.R;
-import android.support.v4.app.FragmentActivity;
 import android.view.ViewGroup;
 import android.widget.FrameLayout;
 
-public class TransitionActivity extends FragmentActivity {
+public class TransitionActivity extends Activity {
 
     private FrameLayout mRoot;
 
diff --git a/v13/Android.mk b/v13/Android.mk
index e1e6062..00675b7 100644
--- a/v13/Android.mk
+++ b/v13/Android.mk
@@ -46,7 +46,7 @@
 # A helper sub-library that makes direct use of NYC APIs.
 include $(CLEAR_VARS)
 LOCAL_MODULE := android-support-v13-nyc
-LOCAL_SDK_VERSION := current
+LOCAL_SDK_VERSION := 24
 LOCAL_SRC_FILES := $(call all-java-files-under, api24)
 LOCAL_STATIC_JAVA_LIBRARIES := android-support-v13-mnc
 LOCAL_JAVA_LANGUAGE_VERSION := 1.7
diff --git a/v17/leanback/api21/android/support/v17/leanback/transition/TransitionHelperApi21.java b/v17/leanback/api21/android/support/v17/leanback/transition/TransitionHelperApi21.java
index 1206ea8..5c279b5 100644
--- a/v17/leanback/api21/android/support/v17/leanback/transition/TransitionHelperApi21.java
+++ b/v17/leanback/api21/android/support/v17/leanback/transition/TransitionHelperApi21.java
@@ -16,6 +16,7 @@
 import android.R;
 import android.app.Fragment;
 import android.content.Context;
+import android.graphics.Rect;
 import android.transition.ChangeTransform;
 import android.transition.Transition;
 import android.transition.TransitionManager;
@@ -109,4 +110,19 @@
     public static void setTransitionGroup(ViewGroup viewGroup, boolean transitionGroup) {
         viewGroup.setTransitionGroup(transitionGroup);
     }
+
+    public static void setEpicenterCallback(Object transitionObject,
+            final TransitionEpicenterCallback callback) {
+        Transition transition = (Transition) transitionObject;
+        if (callback == null) {
+            transition.setEpicenterCallback(null);
+        } else {
+            transition.setEpicenterCallback(new Transition.EpicenterCallback() {
+                @Override
+                public Rect onGetEpicenter(Transition transition) {
+                    return callback.onGetEpicenter(transition);
+                }
+            });
+        }
+    }
 }
diff --git a/v17/leanback/common/android/support/v17/leanback/transition/TransitionEpicenterCallback.java b/v17/leanback/common/android/support/v17/leanback/transition/TransitionEpicenterCallback.java
new file mode 100644
index 0000000..ec7f84c
--- /dev/null
+++ b/v17/leanback/common/android/support/v17/leanback/transition/TransitionEpicenterCallback.java
@@ -0,0 +1,34 @@
+/*
+ * 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 android.support.v17.leanback.transition;
+
+import android.graphics.Rect;
+
+/**
+ * Class to get the epicenter of Transition.
+ * @hide
+ */
+public abstract class TransitionEpicenterCallback {
+
+    /**
+     * Implementers must override to return the epicenter of the Transition in screen
+     * coordinates.
+     *
+     * @param transition The transition for which the epicenter applies.
+     * @return The Rect region of the epicenter of <code>transition</code> or null if
+     * there is no epicenter.
+     */
+    public abstract Rect onGetEpicenter(Object transition);
+}
+
diff --git a/v17/leanback/generatev4.py b/v17/leanback/generatev4.py
index fb23876..01c1cd9 100755
--- a/v17/leanback/generatev4.py
+++ b/v17/leanback/generatev4.py
@@ -20,7 +20,7 @@
 print "Generate v4 fragment related code for leanback"
 
 cls = ['Background', 'Base', 'BaseRow', 'Browse', 'Details', 'Error', 'Headers',
-      'PlaybackOverlay', 'Rows', 'Search', 'VerticalGrid', 'Branded', 'GuidedStep', 'Onboarding']
+      'PlaybackOverlay', 'Playback', 'Rows', 'Search', 'VerticalGrid', 'Branded', 'GuidedStep', 'Onboarding']
 
 for w in cls:
     print "copy {}Fragment to {}SupportFragment".format(w, w)
@@ -42,14 +42,3 @@
         outfile.write(line)
     file.close()
     outfile.close()
-
-file = open('src/android/support/v17/leanback/app/PlaybackControlGlue.java', 'r')
-outfile = open('src/android/support/v17/leanback/app/PlaybackControlSupportGlue.java', 'w')
-outfile.write("/* This file is auto-generated from PlaybackControlGlue.java.  DO NOT MODIFY. */\n\n")
-for line in file:
-    line = line.replace('PlaybackControlGlue', 'PlaybackControlSupportGlue');
-    line = line.replace('PlaybackOverlayFragment', 'PlaybackOverlaySupportFragment');
-    outfile.write(line)
-file.close()
-outfile.close()
-
diff --git a/v17/leanback/res/animator/lb_playback_now_bar1_animator.xml b/v17/leanback/res/animator/lb_playback_now_bar1_animator.xml
deleted file mode 100644
index 10be669..0000000
--- a/v17/leanback/res/animator/lb_playback_now_bar1_animator.xml
+++ /dev/null
@@ -1,61 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     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.
--->
-
-<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
-                android:duration="2320"
-                android:repeatCount="infinite"
-                android:interpolator="@android:anim/linear_interpolator">
-    <propertyValuesHolder android:propertyName="scaleY" >
-
-        <keyframe android:value="0.417" />
-        <keyframe android:value="0.25" />
-        <keyframe android:value="0.417" />
-        <keyframe android:value="0.583" />
-        <keyframe android:value="0.75" />
-
-        <keyframe android:value="0.833" />
-        <keyframe android:value="0.917" />
-        <keyframe android:value="1.0" />
-        <keyframe android:value="0.917" />
-        <keyframe android:value="1.0" />
-
-        <keyframe android:value="0.833" />
-        <keyframe android:value="0.667" />
-        <keyframe android:value="0.5" />
-        <keyframe android:value="0.333" />
-        <keyframe android:value="0.167" />
-
-        <keyframe android:value="0.333" />
-        <keyframe android:value="0.5" />
-        <keyframe android:value="0.583" />
-        <keyframe android:value="0.75" />
-        <keyframe android:value="0.917" />
-
-        <keyframe android:value="0.75" />
-        <keyframe android:value="0.583" />
-        <keyframe android:value="0.417" />
-        <keyframe android:value="0.25" />
-        <keyframe android:value="0.417" />
-
-        <keyframe android:value="0.667" />
-        <keyframe android:value="0.417" />
-        <keyframe android:value="0.25" />
-        <keyframe android:value="0.333" />
-        <keyframe android:value="0.417" />
-
-    </propertyValuesHolder>
-</objectAnimator>
\ No newline at end of file
diff --git a/v17/leanback/res/animator/lb_playback_now_bar2_animator.xml b/v17/leanback/res/animator/lb_playback_now_bar2_animator.xml
deleted file mode 100644
index 9b583b9..0000000
--- a/v17/leanback/res/animator/lb_playback_now_bar2_animator.xml
+++ /dev/null
@@ -1,58 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     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.
--->
-
-<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
-                android:duration="2080"
-                android:repeatCount="infinite"
-                android:interpolator="@android:anim/linear_interpolator">
-    <propertyValuesHolder android:propertyName="scaleY" >
-
-        <keyframe android:value="1.0" />
-        <keyframe android:value="0.917" />
-        <keyframe android:value="0.833" />
-        <keyframe android:value="0.917" />
-        <keyframe android:value="1.0" />
-
-        <keyframe android:value="0.917" />
-        <keyframe android:value="0.75" />
-        <keyframe android:value="0.583" />
-        <keyframe android:value="0.75" />
-        <keyframe android:value="0.917" />
-
-        <keyframe android:value="1.0" />
-        <keyframe android:value="0.833" />
-        <keyframe android:value="0.667" />
-        <keyframe android:value="0.833" />
-        <keyframe android:value="1.0" />
-
-        <keyframe android:value="0.917" />
-        <keyframe android:value="0.75" />
-        <keyframe android:value="0.417" />
-        <keyframe android:value="0.25" />
-        <keyframe android:value="0.417" />
-
-        <keyframe android:value="0.667" />
-        <keyframe android:value="0.833" />
-        <keyframe android:value="1.0" />
-        <keyframe android:value="0.833" />
-        <keyframe android:value="0.75" />
-
-        <keyframe android:value="0.667" />
-        <keyframe android:value="1.0" />
-
-    </propertyValuesHolder>
-</objectAnimator>
\ No newline at end of file
diff --git a/v17/leanback/res/animator/lb_playback_now_bar3_animator.xml b/v17/leanback/res/animator/lb_playback_now_bar3_animator.xml
deleted file mode 100644
index c842100..0000000
--- a/v17/leanback/res/animator/lb_playback_now_bar3_animator.xml
+++ /dev/null
@@ -1,57 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     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.
--->
-
-<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
-                android:duration="2000"
-                android:repeatCount="infinite"
-                android:interpolator="@android:anim/linear_interpolator">
-    <propertyValuesHolder android:propertyName="scaleY" >
-
-        <keyframe android:value="0.667" />
-        <keyframe android:value="0.75" />
-        <keyframe android:value="0.833" />
-        <keyframe android:value="1.0" />
-        <keyframe android:value="0.917" />
-
-        <keyframe android:value="0.75" />
-        <keyframe android:value="0.583" />
-        <keyframe android:value="0.417" />
-        <keyframe android:value="0.583" />
-        <keyframe android:value="0.667" />
-
-        <keyframe android:value="0.75" />
-        <keyframe android:value="1.0" />
-        <keyframe android:value="0.917" />
-        <keyframe android:value="1.0" />
-        <keyframe android:value="0.75" />
-
-        <keyframe android:value="0.583" />
-        <keyframe android:value="0.75" />
-        <keyframe android:value="0.917" />
-        <keyframe android:value="1.0" />
-        <keyframe android:value="0.833" />
-
-        <keyframe android:value="0.667" />
-        <keyframe android:value="0.75" />
-        <keyframe android:value="0.583" />
-        <keyframe android:value="0.417" />
-        <keyframe android:value="0.25" />
-
-        <keyframe android:value="0.667" />
-
-    </propertyValuesHolder>
-</objectAnimator>
\ No newline at end of file
diff --git a/v17/leanback/res/layout/lb_details_overview.xml b/v17/leanback/res/layout/lb_details_overview.xml
index a32f393..7943150 100644
--- a/v17/leanback/res/layout/lb_details_overview.xml
+++ b/v17/leanback/res/layout/lb_details_overview.xml
@@ -84,7 +84,7 @@
             android:focusableInTouchMode="true"
             android:paddingStart="@dimen/lb_details_overview_description_margin_start"
             android:paddingEnd="@dimen/lb_details_overview_description_margin_end"
-            lb:horizontalMargin="@dimen/lb_details_overview_action_items_margin"
+            android:horizontalSpacing="@dimen/lb_details_overview_action_items_spacing"
             lb:rowHeight="@dimen/lb_details_overview_actions_height" />
 
         </LinearLayout>
diff --git a/v17/leanback/res/layout/lb_divider.xml b/v17/leanback/res/layout/lb_divider.xml
index 389b3ab..e05223b 100644
--- a/v17/leanback/res/layout/lb_divider.xml
+++ b/v17/leanback/res/layout/lb_divider.xml
@@ -23,5 +23,5 @@
     android:layout_height="1dp"
     android:focusable="false"
     android:focusableInTouchMode="false"
-    android:background="?android:attr/listDivider"
-    />
+    android:importantForAccessibility="no"
+    android:background="?android:attr/listDivider" />
diff --git a/v17/leanback/res/layout/lb_fullwidth_details_overview.xml b/v17/leanback/res/layout/lb_fullwidth_details_overview.xml
index 415bd82..234abb2 100644
--- a/v17/leanback/res/layout/lb_fullwidth_details_overview.xml
+++ b/v17/leanback/res/layout/lb_fullwidth_details_overview.xml
@@ -61,7 +61,7 @@
                 android:focusableInTouchMode="true"
                 android:paddingStart="@dimen/lb_details_v2_description_margin_start"
                 android:paddingEnd="@dimen/lb_details_v2_description_margin_end"
-                lb:horizontalMargin="@dimen/lb_details_overview_action_items_margin"
+                android:horizontalSpacing="@dimen/lb_details_overview_action_items_spacing"
                 lb:rowHeight="@dimen/lb_details_v2_actions_height" />
         </LinearLayout>
 
diff --git a/v17/leanback/res/layout/lb_guidedactions.xml b/v17/leanback/res/layout/lb_guidedactions.xml
index e5e2289..9857f22 100644
--- a/v17/leanback/res/layout/lb_guidedactions.xml
+++ b/v17/leanback/res/layout/lb_guidedactions.xml
@@ -31,7 +31,9 @@
         android:visibility="gone"
         android:background="?attr/guidedActionsBackgroundDark" />
 
-    <android.support.v17.leanback.widget.NonOverlappingRelativeLayout
+    <!-- special relativelayout will assign guidedactions_sub_list's topMargin using percentage
+         defined by theme attribute guidedStepKeyline -->
+    <android.support.v17.leanback.widget.GuidedActionsRelativeLayout
         android:id="@+id/guidedactions_content"
         android:transitionName="guidedactions_content"
         android:transitionGroup="false"
@@ -55,9 +57,12 @@
         <android.support.v17.leanback.widget.VerticalGridView
             android:transitionGroup="true"
             android:id="@+id/guidedactions_sub_list"
+            android:layout_width="match_parent"
+            android:layout_height="0dp"
+            android:layout_marginTop="-1dip"
             style="?attr/guidedSubActionsListStyle"
             android:visibility="invisible" />
 
-    </android.support.v17.leanback.widget.NonOverlappingRelativeLayout>
+    </android.support.v17.leanback.widget.GuidedActionsRelativeLayout>
 
 </RelativeLayout>
diff --git a/v17/leanback/res/layout/lb_picker_column.xml b/v17/leanback/res/layout/lb_picker_column.xml
index 1f218a6..afa6dee 100644
--- a/v17/leanback/res/layout/lb_picker_column.xml
+++ b/v17/leanback/res/layout/lb_picker_column.xml
@@ -20,6 +20,7 @@
     android:layout_width="wrap_content"
     android:layout_height="@dimen/picker_item_height"
     android:importantForAccessibility="no"
+    android:verticalSpacing="@dimen/picker_item_spacing"
     lb:columnWidth="wrap_content"
     android:clipToPadding="false"
     android:paddingStart="@dimen/picker_column_horizontal_padding"
diff --git a/v17/leanback/res/layout/lb_playback_fragment.xml b/v17/leanback/res/layout/lb_playback_fragment.xml
new file mode 100644
index 0000000..93cc0c0
--- /dev/null
+++ b/v17/leanback/res/layout/lb_playback_fragment.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<FrameLayout
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
+
+    <FrameLayout
+            xmlns:android="http://schemas.android.com/apk/res/android"
+            android:id="@+id/playback_controls_dock"
+            android:layout_height="match_parent"
+            android:layout_width="match_parent"/>
+</FrameLayout>
diff --git a/v17/leanback/res/layout/lb_row_header.xml b/v17/leanback/res/layout/lb_row_header.xml
index 67da907..8962e9a 100644
--- a/v17/leanback/res/layout/lb_row_header.xml
+++ b/v17/leanback/res/layout/lb_row_header.xml
@@ -15,11 +15,26 @@
      limitations under the License.
 -->
 
-<android.support.v17.leanback.widget.RowHeaderView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/row_header"
-    android:importantForAccessibility="no"
-    android:layout_width="wrap_content"
-    android:layout_height="wrap_content"
-    style="?rowHeaderStyle"
-    />
+<android:LinearLayout
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:orientation="vertical"
+        xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <android.support.v17.leanback.widget.RowHeaderView
+            xmlns:android="http://schemas.android.com/apk/res/android"
+            android:id="@+id/row_header"
+            android:importantForAccessibility="no"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            style="?rowHeaderStyle"/>
+
+    <TextView
+            xmlns:android="http://schemas.android.com/apk/res/android"
+            android:id="@+id/row_header_description"
+            android:importantForAccessibility="no"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            style="?rowHeaderDescriptionStyle" />
+
+</android:LinearLayout>
diff --git a/v17/leanback/res/values-bs-rBA/strings.xml b/v17/leanback/res/values-bs-rBA/strings.xml
index cdfe434..63a76e2 100644
--- a/v17/leanback/res/values-bs-rBA/strings.xml
+++ b/v17/leanback/res/values-bs-rBA/strings.xml
@@ -53,5 +53,5 @@
     <string name="lb_date_separator" msgid="2440386660906697298">"/"</string>
     <string name="lb_time_separator" msgid="2763247350845477227">":"</string>
     <string name="lb_onboarding_get_started" msgid="6961440391306351139">"ZAPOČNITE"</string>
-    <string name="lb_onboarding_accessibility_next" msgid="2918313444257732434">"Sljedeća"</string>
+    <string name="lb_onboarding_accessibility_next" msgid="2918313444257732434">"Naprijed"</string>
 </resources>
diff --git a/v17/leanback/res/values/attrs.xml b/v17/leanback/res/values/attrs.xml
index 0e97f76..870d958 100644
--- a/v17/leanback/res/values/attrs.xml
+++ b/v17/leanback/res/values/attrs.xml
@@ -28,10 +28,14 @@
         <!-- Allow DPAD key to navigate out of last row, for HorizontalGridView, it's the
              bottom edge, for VerticalGridView it's the "end" edge.  Default value is true.  -->
         <attr name="focusOutSideEnd" format="boolean" />
-        <!-- Defining margin between two items horizontally -->
+        <!-- Deprecated, use android:horizontalSpacing -->
         <attr name="horizontalMargin" format="dimension" />
-        <!-- Defining margin between two items vertically -->
+        <!-- Deprecated, use android:verticalSpacing -->
         <attr name="verticalMargin" format="dimension" />
+        <!-- Defining space between two items horizontally -->
+        <attr name="android:horizontalSpacing" />
+        <!-- Defining space between two items vertically -->
+        <attr name="android:verticalSpacing" />
         <!-- Defining gravity of child view -->
         <attr name="android:gravity" />
     </declare-styleable>
@@ -249,6 +253,10 @@
         <attr name="rowHorizontalGridStyle" format="reference" />
         <!-- header style inside a row -->
         <attr name="rowHeaderStyle" format="reference" />
+
+        <!-- header description style inside a row -->
+        <attr name="rowHeaderDescriptionStyle" format="reference" />
+
         <!-- style for the layout that hosting Header inside a row -->
         <attr name="rowHeaderDockStyle" format="reference" />
 
diff --git a/v17/leanback/res/values/colors.xml b/v17/leanback/res/values/colors.xml
index ec9102c..bebb115 100644
--- a/v17/leanback/res/values/colors.xml
+++ b/v17/leanback/res/values/colors.xml
@@ -20,6 +20,7 @@
 
     <color name="lb_browse_title_color">#EEEEEE</color>
     <color name="lb_browse_header_color">#FFFFFF</color>
+    <color name="lb_browse_header_description_color">#AAFFFFFF</color>
 
     <color name="lb_list_item_unselected_text_color">#FFF1F1F1</color>
     <color name="lb_background_protection">#99000000</color>
diff --git a/v17/leanback/res/values/dimens.xml b/v17/leanback/res/values/dimens.xml
index e0a366a..4902585 100644
--- a/v17/leanback/res/values/dimens.xml
+++ b/v17/leanback/res/values/dimens.xml
@@ -38,8 +38,9 @@
     <item name="lb_browse_rows_scale" type="fraction">80%</item>
 
     <!-- Derived from the ux spec of 48dp baseline to baseline -->
-    <dimen name="lb_browse_headers_vertical_margin">21dp</dimen>
+    <dimen name="lb_browse_headers_vertical_spacing">21dp</dimen>
     <dimen name="lb_browse_header_text_size">20sp</dimen>
+    <dimen name="lb_browse_header_description_text_size">14sp</dimen>
     <dimen name="lb_browse_header_height">24dp</dimen>
     <dimen name="lb_browse_section_header_text_size">16sp</dimen>
     <dimen name="lb_browse_header_fading_length">12dp</dimen>
@@ -52,8 +53,8 @@
     <dimen name="lb_browse_row_hovercard_max_width">400dp</dimen>
     <dimen name="lb_browse_row_hovercard_title_font_size">18sp</dimen>
     <dimen name="lb_browse_row_hovercard_description_font_size">14sp</dimen>
-    <dimen name="lb_browse_item_horizontal_margin">8dp</dimen>
-    <dimen name="lb_browse_item_vertical_margin">8dp</dimen>
+    <dimen name="lb_browse_item_horizontal_spacing">8dp</dimen>
+    <dimen name="lb_browse_item_vertical_spacing">8dp</dimen>
     <dimen name="lb_browse_selected_row_top_padding">20dp</dimen>
     <dimen name="lb_browse_expanded_selected_row_top_padding">16dp</dimen>
     <dimen name="lb_browse_expanded_row_no_hovercard_bottom_padding">28dp</dimen>
@@ -75,7 +76,7 @@
     <dimen name="lb_details_overview_description_margin_bottom">12dp</dimen>
     <dimen name="lb_details_overview_image_margin_horizontal">24dp</dimen>
     <dimen name="lb_details_overview_image_margin_vertical">24dp</dimen>
-    <dimen name="lb_details_overview_action_items_margin">16dp</dimen>
+    <dimen name="lb_details_overview_action_items_spacing">16dp</dimen>
     <item name="lb_details_overview_action_select_duration" format="integer" type="dimen">150</item>
     <dimen name="lb_details_overview_actions_padding_start">294dp</dimen>
     <dimen name="lb_details_overview_actions_padding_end">132dp</dimen>
@@ -165,7 +166,7 @@
     <dimen name="lb_control_button_text_size">22sp</dimen>
 
     <dimen name="lb_error_image_max_height">120dp</dimen>
-    <integer name="lb_error_message_max_lines">1</integer>
+    <integer name="lb_error_message_max_lines">3</integer>
     <dimen name="lb_error_message_max_width">600dp</dimen>
     <dimen name="lb_error_message_text_size">16sp</dimen>
     <dimen name="lb_error_under_image_baseline_margin">36dp</dimen>
@@ -277,6 +278,8 @@
     <dimen name="lb_guidedactions_item_space_between_title_and_description">2dp</dimen>
     <dimen name="lb_guidedactions_item_description_font_size">12sp</dimen>
     <dimen name="lb_guidedactions_sublist_bottom_margin">28dp</dimen>
+    <dimen name="lb_guidedactions_sublist_padding_top">8dip</dimen>
+    <dimen name="lb_guidedactions_sublist_padding_bottom">8dip</dimen>
 
     <integer name="lb_guidedactions_item_animation_duration">100</integer>
     <integer name="lb_guidedactions_item_title_min_lines">1</integer>
@@ -285,7 +288,9 @@
     <!-- end GuidedStepFragment -->
 
     <!-- height for picker item. -->
-    <dimen name="picker_item_height">64dp</dimen>
+    <dimen name="picker_item_height">32dp</dimen>
+    <!-- vertical space between two picker item -->
+    <dimen name="picker_item_spacing">32dp</dimen>
     <!-- picker column horizontal padding-->
     <dimen name="picker_column_horizontal_padding">8dp</dimen>
     <!-- picker separator horizontal padding -->
diff --git a/v17/leanback/res/values/styles.xml b/v17/leanback/res/values/styles.xml
index 0666cdd..dbe090a 100644
--- a/v17/leanback/res/values/styles.xml
+++ b/v17/leanback/res/values/styles.xml
@@ -42,6 +42,11 @@
     <style name="TextAppearance.Leanback.Row.Header" parent="TextAppearance.Leanback.Header">
     </style>
 
+    <style name="TextAppearance.Leanback.Row.Header.Description" parent="TextAppearance.Leanback.Header">
+        <item name="android:textSize">@dimen/lb_browse_header_description_text_size</item>
+        <item name="android:textColor">@color/lb_browse_header_description_color</item>
+    </style>
+
     <style name="TextAppearance.Leanback.SearchTextEdit" parent="TextAppearance.Leanback">
         <item name="android:textSize">@dimen/lb_search_bar_text_size</item>
     </style>
@@ -211,7 +216,7 @@
         <item name="android:paddingStart">?attr/browsePaddingStart</item>
         <item name="focusOutFront">true</item>
         <item name="focusOutEnd">true</item>
-        <item name="verticalMargin">@dimen/lb_browse_headers_vertical_margin</item>
+        <item name="android:verticalSpacing">@dimen/lb_browse_headers_vertical_spacing</item>
         <item name="android:focusable">true</item>
         <item name="android:focusableInTouchMode">true</item>
         <item name="android:contentDescription">@string/lb_navigation_menu_contentDescription</item>
@@ -245,10 +250,10 @@
         <item name="android:focusableInTouchMode">true</item>
         <item name="android:paddingStart">?attr/browsePaddingStart</item>
         <item name="android:paddingEnd">?attr/browsePaddingEnd</item>
-        <item name="android:paddingBottom">@dimen/lb_browse_item_vertical_margin</item>
-        <item name="android:paddingTop">@dimen/lb_browse_item_vertical_margin</item>
-        <item name="horizontalMargin">@dimen/lb_browse_item_horizontal_margin</item>
-        <item name="verticalMargin">@dimen/lb_browse_item_vertical_margin</item>
+        <item name="android:paddingBottom">@dimen/lb_browse_item_vertical_spacing</item>
+        <item name="android:paddingTop">@dimen/lb_browse_item_vertical_spacing</item>
+        <item name="android:horizontalSpacing">@dimen/lb_browse_item_horizontal_spacing</item>
+        <item name="android:verticalSpacing">@dimen/lb_browse_item_vertical_spacing</item>
         <item name="focusOutFront">true</item>
     </style>
 
@@ -260,8 +265,8 @@
         <item name="android:paddingBottom">@dimen/lb_vertical_grid_padding_bottom</item>
         <item name="android:paddingTop">?attr/browseRowsMarginTop</item>
         <item name="android:gravity">center_horizontal</item>
-        <item name="horizontalMargin">@dimen/lb_browse_item_horizontal_margin</item>
-        <item name="verticalMargin">@dimen/lb_browse_item_vertical_margin</item>
+        <item name="android:horizontalSpacing">@dimen/lb_browse_item_horizontal_spacing</item>
+        <item name="android:verticalSpacing">@dimen/lb_browse_item_vertical_spacing</item>
         <item name="focusOutFront">true</item>
     </style>
 
@@ -269,6 +274,10 @@
         <item name="android:textAppearance">@style/TextAppearance.Leanback.Row.Header</item>
     </style>
 
+    <style name="Widget.Leanback.Row.Header.Description" parent="Widget.Leanback.Header">
+        <item name="android:textAppearance">@style/TextAppearance.Leanback.Row.Header.Description</item>
+    </style>
+
     <style name="Widget.Leanback.Row.HeaderDock">
         <item name="android:paddingStart">?attr/browsePaddingStart</item>
     </style>
@@ -571,7 +580,7 @@
         <item name="android:focusableInTouchMode">false</item>
         <item name="android:layout_width">match_parent</item>
         <item name="android:layout_height">match_parent</item>
-        <item name="verticalMargin">@dimen/lb_guidedactions_list_vertical_spacing</item>
+        <item name="android:verticalSpacing">@dimen/lb_guidedactions_list_vertical_spacing</item>
         <item name="android:paddingStart">@dimen/lb_guidedactions_list_padding_start</item>
         <item name="android:paddingEnd">@dimen/lb_guidedactions_list_padding_end</item>
         <item name="focusOutEnd">false</item>
@@ -580,6 +589,9 @@
 
     <!-- Style for the vertical grid of sub actions in a GuidedActionsStylist's default layout. -->
     <style name="Widget.Leanback.GuidedSubActionsListStyle" parent="Widget.Leanback.GuidedActionsListStyle">
+        <item name="android:paddingTop">@dimen/lb_guidedactions_sublist_padding_top</item>
+        <item name="android:paddingBottom">@dimen/lb_guidedactions_sublist_padding_bottom</item>
+        <item name="android:clipToPadding">false</item>
         <item name="android:focusable">true</item>
         <item name="android:focusableInTouchMode">true</item>
         <item name="focusOutSideStart">false</item>
diff --git a/v17/leanback/res/values/themes.xml b/v17/leanback/res/values/themes.xml
index 2c2ef3c..c6d6baa 100644
--- a/v17/leanback/res/values/themes.xml
+++ b/v17/leanback/res/values/themes.xml
@@ -60,6 +60,7 @@
         <item name="browseTitleViewStyle">@style/Widget.Leanback.TitleView</item>
 
         <item name="rowHeaderStyle">@style/Widget.Leanback.Row.Header</item>
+        <item name="rowHeaderDescriptionStyle">@style/Widget.Leanback.Row.Header.Description</item>
         <item name="rowHoverCardTitleStyle">@style/Widget.Leanback.Row.HoverCardTitle</item>
         <item name="rowHoverCardDescriptionStyle">@style/Widget.Leanback.Row.HoverCardDescription</item>
         <item name="rowHeaderDockStyle">@style/Widget.Leanback.Row.HeaderDock</item>
diff --git a/v17/leanback/src/android/support/v17/leanback/app/BackgroundManager.java b/v17/leanback/src/android/support/v17/leanback/app/BackgroundManager.java
index 0c490ea..76cfd64 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/BackgroundManager.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/BackgroundManager.java
@@ -13,13 +13,6 @@
  */
 package android.support.v17.leanback.app;
 
-import java.lang.ref.WeakReference;
-
-import android.support.annotation.ColorInt;
-import android.graphics.PixelFormat;
-import android.graphics.PorterDuff;
-import android.graphics.PorterDuffColorFilter;
-import android.support.v17.leanback.R;
 import android.animation.Animator;
 import android.animation.ValueAnimator;
 import android.app.Activity;
@@ -32,11 +25,18 @@
 import android.graphics.ColorFilter;
 import android.graphics.Matrix;
 import android.graphics.Paint;
+import android.graphics.PixelFormat;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffColorFilter;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.LayerDrawable;
 import android.os.Handler;
+import android.support.annotation.ColorInt;
+import android.support.v17.leanback.R;
 import android.support.v17.leanback.widget.BackgroundHelper;
+import android.support.v4.app.FragmentActivity;
+import android.support.v4.content.ContextCompat;
 import android.support.v4.view.animation.FastOutLinearInInterpolator;
 import android.util.Log;
 import android.view.LayoutInflater;
@@ -44,10 +44,10 @@
 import android.view.ViewGroup;
 import android.view.Window;
 import android.view.WindowManager;
-import android.view.animation.Interpolator;
 import android.view.animation.AnimationUtils;
-import android.support.v4.app.FragmentActivity;
-import android.support.v4.content.ContextCompat;
+import android.view.animation.Interpolator;
+
+import java.lang.ref.WeakReference;
 
 /**
  * Supports background image continuity between multiple Activities.
@@ -392,12 +392,12 @@
             DrawableWrapper imageOutWrapper = findWrapperById(R.id.background_imageout);
 
             mColorFilter = null;
-            if (imageInWrapper != null && imageInWrapper.getAlpha() == FULL_ALPHA &&
-                    dimWrapper.getDrawable() instanceof ColorDrawable) {
+            if (imageInWrapper != null && imageInWrapper.getAlpha() == FULL_ALPHA
+                    && dimWrapper.getDrawable() instanceof ColorDrawable) {
                 int dimColor = ((ColorDrawable) dimWrapper.getDrawable()).getColor();
-                if (Color.red(dimColor) == 0 &&
-                        Color.green(dimColor) == 0 &&
-                        Color.blue(dimColor) == 0) {
+                if (Color.red(dimColor) == 0
+                        && Color.green(dimColor) == 0
+                        && Color.blue(dimColor) == 0) {
                     int dimAlpha = 255 - Color.alpha(dimColor);
                     int color = Color.argb(getAlpha(), dimAlpha, dimAlpha, dimAlpha);
                     mColorFilter = new PorterDuffColorFilter(color, PorterDuff.Mode.MULTIPLY);
@@ -416,8 +416,8 @@
         @Override
         public void draw(Canvas canvas) {
             DrawableWrapper imageInWrapper = findWrapperById(R.id.background_imagein);
-            if (imageInWrapper != null && imageInWrapper.getDrawable() != null &&
-                    imageInWrapper.getColorFilter() != null) {
+            if (imageInWrapper != null && imageInWrapper.getDrawable() != null
+                    && imageInWrapper.getColorFilter() != null) {
                 imageInWrapper.getDrawable().draw(canvas);
             } else {
                 super.draw(canvas);
@@ -664,8 +664,8 @@
             activity.getFragmentManager().beginTransaction().add(fragment, FRAGMENT_TAG).commit();
         } else {
             if (fragment.getBackgroundManager() != null) {
-                throw new IllegalStateException("Created duplicated BackgroundManager for same " +
-                        "activity, please use getInstance() instead");
+                throw new IllegalStateException("Created duplicated BackgroundManager for same "
+                        + "activity, please use getInstance() instead");
             }
         }
         fragment.setBackgroundManager(this);
@@ -682,8 +682,8 @@
                     .commit();
         } else {
             if (fragment.getBackgroundManager() != null) {
-                throw new IllegalStateException("Created duplicated BackgroundManager for same " +
-                    "activity, please use getInstance() instead");
+                throw new IllegalStateException("Created duplicated BackgroundManager for same "
+                        + "activity, please use getInstance() instead");
             }
         }
         fragment.setBackgroundManager(this);
@@ -691,23 +691,23 @@
     }
 
     DrawableWrapper getImageInWrapper() {
-        return mLayerDrawable == null ? null :
-                mLayerDrawable.findWrapperById(R.id.background_imagein);
+        return mLayerDrawable == null
+                ? null : mLayerDrawable.findWrapperById(R.id.background_imagein);
     }
 
     DrawableWrapper getImageOutWrapper() {
-        return mLayerDrawable == null ? null :
-                mLayerDrawable.findWrapperById(R.id.background_imageout);
+        return mLayerDrawable == null
+                ? null : mLayerDrawable.findWrapperById(R.id.background_imageout);
     }
 
     DrawableWrapper getDimWrapper() {
-        return mLayerDrawable == null ? null :
-                mLayerDrawable.findWrapperById(R.id.background_dim);
+        return mLayerDrawable == null
+                ? null : mLayerDrawable.findWrapperById(R.id.background_dim);
     }
 
     private DrawableWrapper getColorWrapper() {
-        return mLayerDrawable == null ? null :
-                mLayerDrawable.findWrapperById(R.id.background_color);
+        return mLayerDrawable == null
+                ? null : mLayerDrawable.findWrapperById(R.id.background_color);
     }
 
     /**
@@ -719,12 +719,15 @@
             return;
         }
         if (mLayerDrawable == null) {
-            if (DEBUG) Log.v(TAG, "onActivityStart " + this +
-                    " released state, syncing with service");
+            if (DEBUG) {
+                Log.v(TAG, "onActivityStart " + this + " released state, syncing with service");
+            }
             syncWithService();
         } else {
-            if (DEBUG) Log.v(TAG, "onActivityStart " + this + " updating service color "
-                    + mBackgroundColor + " drawable " + mBackgroundDrawable);
+            if (DEBUG) {
+                Log.v(TAG, "onActivityStart " + this + " updating service color "
+                        + mBackgroundColor + " drawable " + mBackgroundDrawable);
+            }
             mService.setColor(mBackgroundColor);
             mService.setDrawable(mBackgroundDrawable);
         }
@@ -1066,8 +1069,10 @@
             matrix.setScale(scale, scale);
             matrix.preTranslate(-dx, 0);
 
-            if (DEBUG) Log.v(TAG, "original image size " + bitmap.getWidth() + "x" + bitmap.getHeight() +
-                    " scale " + scale + " dx " + dx);
+            if (DEBUG) {
+                Log.v(TAG, "original image size " + bitmap.getWidth() + "x" + bitmap.getHeight()
+                        + " scale " + scale + " dx " + dx);
+            }
         }
 
         BitmapDrawable bitmapDrawable = new BitmapDrawable(mContext.getResources(), bitmap, matrix);
diff --git a/v17/leanback/src/android/support/v17/leanback/app/BackgroundSupportFragment.java b/v17/leanback/src/android/support/v17/leanback/app/BackgroundSupportFragment.java
index 72cb5a1..aef9678 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/BackgroundSupportFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/BackgroundSupportFragment.java
@@ -15,8 +15,8 @@
  */
 package android.support.v17.leanback.app;
 
-import android.support.annotation.RestrictTo;
 import android.support.v4.app.Fragment;
+import android.support.annotation.RestrictTo;
 
 import static android.support.annotation.RestrictTo.Scope.GROUP_ID;
 
diff --git a/v17/leanback/src/android/support/v17/leanback/app/BaseFragment.java b/v17/leanback/src/android/support/v17/leanback/app/BaseFragment.java
index 0f6aae3..3b4c851 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/BaseFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/BaseFragment.java
@@ -13,17 +13,15 @@
  */
 package android.support.v17.leanback.app;
 
+import static android.support.v17.leanback.util.StateMachine.STATUS_EXECUTED;
+
 import android.os.Bundle;
-import android.support.v17.leanback.R;
 import android.support.v17.leanback.transition.TransitionHelper;
 import android.support.v17.leanback.transition.TransitionListener;
-import android.view.View;
-import android.view.ViewTreeObserver;
-
 import android.support.v17.leanback.util.StateMachine;
 import android.support.v17.leanback.util.StateMachine.State;
-
-import static android.support.v17.leanback.util.StateMachine.*;
+import android.view.View;
+import android.view.ViewTreeObserver;
 
 /**
  * @hide
@@ -217,11 +215,14 @@
     void onExecuteEntranceTransition() {
         // wait till views get their initial position before start transition
         final View view = getView();
-        view.getViewTreeObserver().addOnPreDrawListener(
-                new ViewTreeObserver.OnPreDrawListener() {
+        view.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
             @Override
             public boolean onPreDraw() {
                 view.getViewTreeObserver().removeOnPreDrawListener(this);
+                if (getActivity() == null || getView() == null) {
+                    // bail out if fragment is destroyed immediately after startEntranceTransition
+                    return true;
+                }
                 internalCreateEntranceTransition();
                 if (mEntranceTransition != null) {
                     onEntranceTransitionStart();
diff --git a/v17/leanback/src/android/support/v17/leanback/app/BaseRowFragment.java b/v17/leanback/src/android/support/v17/leanback/app/BaseRowFragment.java
index c9489d1..98a8f98 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/BaseRowFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/BaseRowFragment.java
@@ -219,7 +219,7 @@
         }
     }
 
-    final VerticalGridView getVerticalGridView() {
+    public final VerticalGridView getVerticalGridView() {
         return mVerticalGridView;
     }
 
diff --git a/v17/leanback/src/android/support/v17/leanback/app/BaseRowSupportFragment.java b/v17/leanback/src/android/support/v17/leanback/app/BaseRowSupportFragment.java
index 6fc741d..31e5f8d 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/BaseRowSupportFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/BaseRowSupportFragment.java
@@ -221,7 +221,7 @@
         }
     }
 
-    final VerticalGridView getVerticalGridView() {
+    public final VerticalGridView getVerticalGridView() {
         return mVerticalGridView;
     }
 
diff --git a/v17/leanback/src/android/support/v17/leanback/app/BaseSupportFragment.java b/v17/leanback/src/android/support/v17/leanback/app/BaseSupportFragment.java
index 8a818e0..a501baa 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/BaseSupportFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/BaseSupportFragment.java
@@ -15,17 +15,15 @@
  */
 package android.support.v17.leanback.app;
 
+import static android.support.v17.leanback.util.StateMachine.STATUS_EXECUTED;
+
 import android.os.Bundle;
-import android.support.v17.leanback.R;
 import android.support.v17.leanback.transition.TransitionHelper;
 import android.support.v17.leanback.transition.TransitionListener;
-import android.view.View;
-import android.view.ViewTreeObserver;
-
 import android.support.v17.leanback.util.StateMachine;
 import android.support.v17.leanback.util.StateMachine.State;
-
-import static android.support.v17.leanback.util.StateMachine.*;
+import android.view.View;
+import android.view.ViewTreeObserver;
 
 /**
  * @hide
@@ -219,11 +217,14 @@
     void onExecuteEntranceTransition() {
         // wait till views get their initial position before start transition
         final View view = getView();
-        view.getViewTreeObserver().addOnPreDrawListener(
-                new ViewTreeObserver.OnPreDrawListener() {
+        view.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
             @Override
             public boolean onPreDraw() {
                 view.getViewTreeObserver().removeOnPreDrawListener(this);
+                if (getActivity() == null || getView() == null) {
+                    // bail out if fragment is destroyed immediately after startEntranceTransition
+                    return true;
+                }
                 internalCreateEntranceTransition();
                 if (mEntranceTransition != null) {
                     onEntranceTransitionStart();
diff --git a/v17/leanback/src/android/support/v17/leanback/app/BrowseFragment.java b/v17/leanback/src/android/support/v17/leanback/app/BrowseFragment.java
index 0f7cfa0..d6e0566 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/BrowseFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/BrowseFragment.java
@@ -13,6 +13,8 @@
  */
 package android.support.v17.leanback.app;
 
+import static android.support.v7.widget.RecyclerView.NO_POSITION;
+
 import android.app.Fragment;
 import android.app.FragmentManager;
 import android.app.FragmentManager.BackStackEntry;
@@ -52,8 +54,6 @@
 import java.util.HashMap;
 import java.util.Map;
 
-import static android.support.v7.widget.RecyclerView.NO_POSITION;
-
 /**
  * A fragment for creating Leanback browse screens. It is composed of a
  * RowsFragment and a HeadersFragment.
@@ -610,8 +610,8 @@
     /** The headers fragment is disabled and will never be shown. */
     public static final int HEADERS_DISABLED = 3;
 
-    private MainFragmentAdapterRegistry mMainFragmentAdapterRegistry
-            = new MainFragmentAdapterRegistry();
+    private MainFragmentAdapterRegistry mMainFragmentAdapterRegistry =
+            new MainFragmentAdapterRegistry();
     MainFragmentAdapter mMainFragmentAdapter;
     Fragment mMainFragment;
     HeadersFragment mHeadersFragment;
@@ -803,6 +803,13 @@
     }
 
     /**
+     * @return Current main fragment or null if not created.
+     */
+    public Fragment getMainFragment() {
+        return mMainFragment;
+    }
+
+    /**
      * Get currently bound HeadersFragment or null if HeadersFragment has not been created yet.
      * @return Currently bound HeadersFragment or null if HeadersFragment has not been created yet.
      */
@@ -949,14 +956,14 @@
             }
             if (DEBUG) Log.v(TAG, "onFocusSearch focused " + focused + " + direction " + direction);
 
-            if (getTitleView() != null && focused != getTitleView() &&
-                    direction == View.FOCUS_UP) {
+            if (getTitleView() != null && focused != getTitleView()
+                    && direction == View.FOCUS_UP) {
                 return getTitleView();
             }
-            if (getTitleView() != null && getTitleView().hasFocus() &&
-                    direction == View.FOCUS_DOWN) {
-                return mCanShowHeaders && mShowingHeaders ?
-                        mHeadersFragment.getVerticalGridView() : mMainFragment.getView();
+            if (getTitleView() != null && getTitleView().hasFocus()
+                    && direction == View.FOCUS_DOWN) {
+                return mCanShowHeaders && mShowingHeaders
+                        ? mHeadersFragment.getVerticalGridView() : mMainFragment.getView();
             }
 
             boolean isRtl = ViewCompat.getLayoutDirection(focused) == View.LAYOUT_DIRECTION_RTL;
@@ -997,17 +1004,18 @@
             }
             // Make sure not changing focus when requestFocus() is called.
             if (mCanShowHeaders && mShowingHeaders) {
-                if (mHeadersFragment != null && mHeadersFragment.getView() != null &&
-                        mHeadersFragment.getView().requestFocus(direction, previouslyFocusedRect)) {
+                if (mHeadersFragment != null && mHeadersFragment.getView() != null
+                        && mHeadersFragment.getView().requestFocus(
+                                direction, previouslyFocusedRect)) {
                     return true;
                 }
             }
-            if (mMainFragment != null && mMainFragment.getView() != null &&
-                    mMainFragment.getView().requestFocus(direction, previouslyFocusedRect)) {
+            if (mMainFragment != null && mMainFragment.getView() != null
+                    && mMainFragment.getView().requestFocus(direction, previouslyFocusedRect)) {
                 return true;
             }
-            if (getTitleView() != null &&
-                    getTitleView().requestFocus(direction, previouslyFocusedRect)) {
+            if (getTitleView() != null
+                    && getTitleView().requestFocus(direction, previouslyFocusedRect)) {
                 return true;
             }
             return false;
@@ -1120,11 +1128,11 @@
                     .getMainFragmentAdapter();
             mMainFragmentAdapter.setFragmentHost(new FragmentHostImpl());
 
-            mIsPageRow = savedInstanceState != null ?
-                    savedInstanceState.getBoolean(IS_PAGE_ROW, false) : false;
+            mIsPageRow = savedInstanceState != null
+                    ? savedInstanceState.getBoolean(IS_PAGE_ROW, false) : false;
 
-            mSelectedPosition = savedInstanceState != null ?
-                    savedInstanceState.getInt(CURRENT_SELECTED_POSITION, 0) : 0;
+            mSelectedPosition = savedInstanceState != null
+                    ? savedInstanceState.getInt(CURRENT_SELECTED_POSITION, 0) : 0;
 
             if (!mIsPageRow) {
                 if (mMainFragment instanceof MainFragmentRowsAdapterProvider) {
@@ -1212,8 +1220,8 @@
 
     void createHeadersTransition() {
         mHeadersTransition = TransitionHelper.loadTransition(getActivity(),
-                mShowingHeaders ?
-                R.transition.lb_browse_headers_in : R.transition.lb_browse_headers_out);
+                mShowingHeaders
+                        ? R.transition.lb_browse_headers_in : R.transition.lb_browse_headers_out);
 
         TransitionHelper.addTransitionListener(mHeadersTransition, new TransitionListener() {
             @Override
diff --git a/v17/leanback/src/android/support/v17/leanback/app/BrowseSupportFragment.java b/v17/leanback/src/android/support/v17/leanback/app/BrowseSupportFragment.java
index c88438e..d98adb6 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/BrowseSupportFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/BrowseSupportFragment.java
@@ -15,6 +15,8 @@
  */
 package android.support.v17.leanback.app;
 
+import static android.support.v7.widget.RecyclerView.NO_POSITION;
+
 import android.support.v4.app.Fragment;
 import android.support.v4.app.FragmentManager;
 import android.support.v4.app.FragmentManager.BackStackEntry;
@@ -54,8 +56,6 @@
 import java.util.HashMap;
 import java.util.Map;
 
-import static android.support.v7.widget.RecyclerView.NO_POSITION;
-
 /**
  * A fragment for creating Leanback browse screens. It is composed of a
  * RowsSupportFragment and a HeadersSupportFragment.
@@ -612,8 +612,8 @@
     /** The headers fragment is disabled and will never be shown. */
     public static final int HEADERS_DISABLED = 3;
 
-    private MainFragmentAdapterRegistry mMainFragmentAdapterRegistry
-            = new MainFragmentAdapterRegistry();
+    private MainFragmentAdapterRegistry mMainFragmentAdapterRegistry =
+            new MainFragmentAdapterRegistry();
     MainFragmentAdapter mMainFragmentAdapter;
     Fragment mMainFragment;
     HeadersSupportFragment mHeadersSupportFragment;
@@ -805,6 +805,13 @@
     }
 
     /**
+     * @return Current main fragment or null if not created.
+     */
+    public Fragment getMainFragment() {
+        return mMainFragment;
+    }
+
+    /**
      * Get currently bound HeadersSupportFragment or null if HeadersSupportFragment has not been created yet.
      * @return Currently bound HeadersSupportFragment or null if HeadersSupportFragment has not been created yet.
      */
@@ -951,14 +958,14 @@
             }
             if (DEBUG) Log.v(TAG, "onFocusSearch focused " + focused + " + direction " + direction);
 
-            if (getTitleView() != null && focused != getTitleView() &&
-                    direction == View.FOCUS_UP) {
+            if (getTitleView() != null && focused != getTitleView()
+                    && direction == View.FOCUS_UP) {
                 return getTitleView();
             }
-            if (getTitleView() != null && getTitleView().hasFocus() &&
-                    direction == View.FOCUS_DOWN) {
-                return mCanShowHeaders && mShowingHeaders ?
-                        mHeadersSupportFragment.getVerticalGridView() : mMainFragment.getView();
+            if (getTitleView() != null && getTitleView().hasFocus()
+                    && direction == View.FOCUS_DOWN) {
+                return mCanShowHeaders && mShowingHeaders
+                        ? mHeadersSupportFragment.getVerticalGridView() : mMainFragment.getView();
             }
 
             boolean isRtl = ViewCompat.getLayoutDirection(focused) == View.LAYOUT_DIRECTION_RTL;
@@ -999,17 +1006,18 @@
             }
             // Make sure not changing focus when requestFocus() is called.
             if (mCanShowHeaders && mShowingHeaders) {
-                if (mHeadersSupportFragment != null && mHeadersSupportFragment.getView() != null &&
-                        mHeadersSupportFragment.getView().requestFocus(direction, previouslyFocusedRect)) {
+                if (mHeadersSupportFragment != null && mHeadersSupportFragment.getView() != null
+                        && mHeadersSupportFragment.getView().requestFocus(
+                                direction, previouslyFocusedRect)) {
                     return true;
                 }
             }
-            if (mMainFragment != null && mMainFragment.getView() != null &&
-                    mMainFragment.getView().requestFocus(direction, previouslyFocusedRect)) {
+            if (mMainFragment != null && mMainFragment.getView() != null
+                    && mMainFragment.getView().requestFocus(direction, previouslyFocusedRect)) {
                 return true;
             }
-            if (getTitleView() != null &&
-                    getTitleView().requestFocus(direction, previouslyFocusedRect)) {
+            if (getTitleView() != null
+                    && getTitleView().requestFocus(direction, previouslyFocusedRect)) {
                 return true;
             }
             return false;
@@ -1122,11 +1130,11 @@
                     .getMainFragmentAdapter();
             mMainFragmentAdapter.setFragmentHost(new FragmentHostImpl());
 
-            mIsPageRow = savedInstanceState != null ?
-                    savedInstanceState.getBoolean(IS_PAGE_ROW, false) : false;
+            mIsPageRow = savedInstanceState != null
+                    ? savedInstanceState.getBoolean(IS_PAGE_ROW, false) : false;
 
-            mSelectedPosition = savedInstanceState != null ?
-                    savedInstanceState.getInt(CURRENT_SELECTED_POSITION, 0) : 0;
+            mSelectedPosition = savedInstanceState != null
+                    ? savedInstanceState.getInt(CURRENT_SELECTED_POSITION, 0) : 0;
 
             if (!mIsPageRow) {
                 if (mMainFragment instanceof MainFragmentRowsAdapterProvider) {
@@ -1214,8 +1222,8 @@
 
     void createHeadersTransition() {
         mHeadersTransition = TransitionHelper.loadTransition(getActivity(),
-                mShowingHeaders ?
-                R.transition.lb_browse_headers_in : R.transition.lb_browse_headers_out);
+                mShowingHeaders
+                        ? R.transition.lb_browse_headers_in : R.transition.lb_browse_headers_out);
 
         TransitionHelper.addTransitionListener(mHeadersTransition, new TransitionListener() {
             @Override
diff --git a/v17/leanback/src/android/support/v17/leanback/app/DetailsBackgroundParallaxHelper.java b/v17/leanback/src/android/support/v17/leanback/app/DetailsBackgroundParallaxHelper.java
new file mode 100644
index 0000000..b1df41b
--- /dev/null
+++ b/v17/leanback/src/android/support/v17/leanback/app/DetailsBackgroundParallaxHelper.java
@@ -0,0 +1,225 @@
+/*
+ * 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 android.support.v17.leanback.app;
+
+import android.animation.PropertyValuesHolder;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.support.annotation.ColorInt;
+import android.support.annotation.NonNull;
+import android.support.v17.leanback.R;
+import android.support.v17.leanback.graphics.BoundsRule;
+import android.support.v17.leanback.graphics.CompositeDrawable;
+import android.support.v17.leanback.graphics.FitWidthBitmapDrawable;
+import android.support.v17.leanback.widget.Parallax;
+import android.support.v17.leanback.widget.ParallaxRecyclerViewSource;
+import android.util.TypedValue;
+
+/**
+ * Helper class responsible for wiring in parallax effect in
+ * {@link android.support.v17.leanback.app.DetailsFragment}. The default effect will render
+ * a drawable like the following -
+ * <pre>
+ *        ***************************
+ *        *          Bitmap         *
+ *        ***************************
+ *        *    DetailsOverviewRow   *
+ *        *                         *
+ *        ***************************
+ *        *        Solid Color      *
+ *        *         Related         *
+ *        *         Content         *
+ *        ***************************
+ * </pre>
+ * As the user scrolls through the page, the bounds of the bitmap and related content section
+ * will be updated to simulate the parallax effect. Users have to do the following to setup the
+ * parallax -
+ *
+ * <ul>
+ * <li>First users should use {@link ParallaxBuilder} class to set the appropriate attributes
+ * and call build() to create an instance of {@link DetailsBackgroundParallaxHelper}.
+ * Users must set {@link DetailsParallaxManager} on {@link ParallaxBuilder} for it to obtain the
+ * {@link Parallax} instance. Finally they should set the drawable obtained by calling
+ * {@link #getDrawable} as the background of their current activity.
+ * <pre>
+ * {@code
+ *     public void onStart() {
+ *         super.onStart();
+ *         mParallaxHelper = DetailsBackgroundParallaxHelper.ParallaxBuilder
+ *             .newBuilder(parallaxManager, context)
+ *             .setBitmapMinVerticalOffset(-300)
+ *             .build();
+ *          mBackgroundManager.setDrawable(mParallaxHelper.getDrawable());
+ *      }
+ * }
+ * </pre>
+ * </li>
+ * </li>
+ * <li>Finally, users can set the bitmap through {@link #setBitmap(Bitmap)} call.
+ * <pre>
+ * {@code
+ *     public void onBitmapLoaded(Bitmap bitmap) {
+ *         mParallaxHelper.setBitmap(bitmap);
+ *     }
+ * }
+ * </pre>
+ * </li>
+ * </ul>
+ *
+ * In case the color is not set, it will use defaultBrandColorDark from LeanbackTheme.
+ */
+public final class DetailsBackgroundParallaxHelper {
+    private DetailsParallaxManager mDetailsParallaxManager;
+    private CompositeDrawable mCompositeDrawable;
+    private FitWidthBitmapDrawable mFitWidthBitmapDrawable;
+    private ColorDrawable mSolidColorDrawable;
+    private int mBitmapMinVerticalOffset;
+
+    private DetailsBackgroundParallaxHelper(
+            DetailsParallaxManager detailsParallaxManager,
+            int bitmapMinVerticalOffset,
+            int color) {
+        this.mBitmapMinVerticalOffset = bitmapMinVerticalOffset;
+        mCompositeDrawable = new CompositeDrawable();
+        mFitWidthBitmapDrawable = new FitWidthBitmapDrawable();
+        mSolidColorDrawable = new ColorDrawable(color);
+        mCompositeDrawable.addChildDrawable(mFitWidthBitmapDrawable);
+        mCompositeDrawable.addChildDrawable(mSolidColorDrawable);
+        mCompositeDrawable.getChildAt(1).getBoundsRule().mTop = BoundsRule.inheritFromParent(1f);
+        mDetailsParallaxManager = detailsParallaxManager;
+        setupParallaxEffect();
+    }
+
+    /**
+     * Builder class used for creating an instance of {@link DetailsBackgroundParallaxHelper}.
+     */
+    public static class ParallaxBuilder {
+        // Default value for image translation is -100px.
+        private int mBitmapMinVerticalOffset = -100;
+        private int mColor;
+        private boolean mIsColorSet;
+        private final DetailsParallaxManager mDetailsParallaxManager;
+        private final Context mContext;
+
+        /**
+         * Returns an instance of itself.
+         *
+         * @param detailsParallaxManager class responsible for creating {@link Parallax} instance.
+         * @param context Context used for loading resources.
+         */
+        public ParallaxBuilder(@NonNull Context context,
+                               @NonNull DetailsParallaxManager detailsParallaxManager) {
+            if (detailsParallaxManager == null || context == null) {
+                throw new IllegalArgumentException("Must set DetailsParallaxManager and Context.");
+            }
+            this.mDetailsParallaxManager = detailsParallaxManager;
+            this.mContext = context;
+        }
+
+        /**
+         * Sets the minimum top position the image is going to translate to during the
+         * parallax motion.
+         */
+        public ParallaxBuilder setBitmapMinVerticalOffset(int minTop) {
+            this.mBitmapMinVerticalOffset = minTop;
+            return this;
+        }
+
+        /**
+         * Sets the color for the bottom section of the
+         * {@link android.support.v17.leanback.app.DetailsFragment}.
+         */
+        public ParallaxBuilder setColor(int color) {
+            this.mColor = color;
+            mIsColorSet = true;
+            return this;
+        }
+
+        /**
+         * Builds and returns an instance of {@link DetailsBackgroundParallaxHelper}.
+         */
+        public DetailsBackgroundParallaxHelper build() {
+            if (!mIsColorSet) {
+                mColor = getDefaultBackgroundColor(mContext);
+            }
+
+            return new DetailsBackgroundParallaxHelper(
+                    mDetailsParallaxManager, mBitmapMinVerticalOffset, mColor);
+        }
+
+        private int getDefaultBackgroundColor(Context context) {
+            TypedValue outValue = new TypedValue();
+            if (context.getTheme().resolveAttribute(R.attr.defaultBrandColorDark, outValue, true)) {
+                return context.getResources().getColor(outValue.resourceId);
+            }
+            return context.getResources().getColor(R.color.lb_default_brand_color_dark);
+        }
+    }
+
+    /**
+     * Returns the special drawable instance that is used to simulate the parallax effect. Users
+     * must set this drawable as the background for their activity.
+     */
+    public Drawable getDrawable() {
+        return mCompositeDrawable;
+    }
+
+    /**
+     * Sets the bitmap in drawable instance returned during {@link #getDrawable()} call.
+     */
+    public void setBitmap(Bitmap bitmap) {
+        if (bitmap == null) {
+            throw new IllegalArgumentException("Invalid bitmap");
+        }
+        mFitWidthBitmapDrawable.setBitmap(bitmap);
+    }
+
+    /**
+     * Changes the background color of the related content section.
+     */
+    public void setColor(@ColorInt int color) {
+        mSolidColorDrawable.setColor(color);
+    }
+
+    /**
+     * Sets up the cover image parallax effect in {@link DetailsFragment}.
+     */
+    private void setupParallaxEffect() {
+        // Add bitmap parallax effect:
+        // When frameTop moves from half of the screen to top of the screen,
+        // change vertical offset of Bitmap from 0 to -100
+
+        Parallax parallax = mDetailsParallaxManager.getParallax();
+        ParallaxRecyclerViewSource.ChildPositionProperty frameTop =
+                mDetailsParallaxManager.getFrameTop();
+        ParallaxRecyclerViewSource.ChildPositionProperty frameBottom =
+                mDetailsParallaxManager.getFrameBottom();
+        parallax.addEffect(frameTop.atFraction(0.5f), frameTop.atFraction(0f))
+                .target(mFitWidthBitmapDrawable,
+                    PropertyValuesHolder.ofInt("verticalOffset", 0, mBitmapMinVerticalOffset))
+                .target(mCompositeDrawable.getChildAt(0),
+                    PropertyValuesHolder.ofFloat(
+                        CompositeDrawable.ChildDrawable.BOTTOM_FRACTION, 0.5f, 0f));
+
+        // Add solid color parallax effect:
+        // When frameBottom moves from bottom of the screen to top of the screen,
+        // change solid ColorDrawable's top from bottom of screen to top of the screen.
+        parallax.addEffect(frameBottom.atFraction(1f), frameBottom.atFraction(0f))
+                .target(mCompositeDrawable.getChildAt(1),
+                        PropertyValuesHolder.ofFloat(
+                                CompositeDrawable.ChildDrawable.TOP_FRACTION, 1f, 0f));
+    }
+}
diff --git a/v17/leanback/src/android/support/v17/leanback/app/DetailsFragment.java b/v17/leanback/src/android/support/v17/leanback/app/DetailsFragment.java
index ee733a6..8a8c848 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/DetailsFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/DetailsFragment.java
@@ -13,23 +13,22 @@
  */
 package android.support.v17.leanback.app;
 
+import android.os.Bundle;
 import android.support.v17.leanback.R;
 import android.support.v17.leanback.transition.TransitionHelper;
+import android.support.v17.leanback.widget.BaseOnItemViewClickedListener;
+import android.support.v17.leanback.widget.BaseOnItemViewSelectedListener;
 import android.support.v17.leanback.widget.BrowseFrameLayout;
 import android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter;
 import android.support.v17.leanback.widget.ItemAlignmentFacet;
 import android.support.v17.leanback.widget.ItemBridgeAdapter;
 import android.support.v17.leanback.widget.ObjectAdapter;
-import android.support.v17.leanback.widget.BaseOnItemViewClickedListener;
-import android.support.v17.leanback.widget.BaseOnItemViewSelectedListener;
 import android.support.v17.leanback.widget.Presenter;
 import android.support.v17.leanback.widget.PresenterSelector;
 import android.support.v17.leanback.widget.RowPresenter;
 import android.support.v17.leanback.widget.TitleHelper;
 import android.support.v17.leanback.widget.VerticalGridView;
-import android.os.Bundle;
 import android.util.Log;
-import android.util.TypedValue;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -89,7 +88,7 @@
     }
 
     RowsFragment mRowsFragment;
-
+    private DetailsParallaxManager mDetailsParallaxManager;
     private ObjectAdapter mAdapter;
     private int mContainerListAlignTop;
     BaseOnItemViewSelectedListener mExternalOnItemViewSelectedListener;
@@ -315,8 +314,8 @@
 
     void onRowSelected(int selectedPosition, int selectedSubPosition) {
         ObjectAdapter adapter = getAdapter();
-        if (adapter == null || adapter.size() == 0 ||
-                (selectedPosition == 0 && selectedSubPosition == 0)) {
+        if (adapter == null || adapter.size() == 0
+                || (selectedPosition == 0 && selectedSubPosition == 0)) {
             showTitle(true);
         } else {
             showTitle(false);
@@ -426,4 +425,16 @@
     protected void onEntranceTransitionStart() {
         mRowsFragment.onTransitionStart();
     }
+
+    /**
+     * Returns the {@link DetailsParallaxManager} instance used to configure
+     * {@link android.support.v17.leanback.widget.Parallax} instance.
+     */
+    public DetailsParallaxManager getParallaxManager() {
+        if (mDetailsParallaxManager == null) {
+            mDetailsParallaxManager = new DetailsParallaxManager(
+                    getRowsFragment().getVerticalGridView());
+        }
+        return mDetailsParallaxManager;
+    }
 }
diff --git a/v17/leanback/src/android/support/v17/leanback/app/DetailsParallaxManager.java b/v17/leanback/src/android/support/v17/leanback/app/DetailsParallaxManager.java
new file mode 100644
index 0000000..38d3162
--- /dev/null
+++ b/v17/leanback/src/android/support/v17/leanback/app/DetailsParallaxManager.java
@@ -0,0 +1,78 @@
+/*
+ * 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 android.support.v17.leanback.app;
+
+import android.support.v17.leanback.R;
+import android.support.v17.leanback.widget.Parallax;
+import android.support.v17.leanback.widget.ParallaxRecyclerViewSource;
+import android.support.v7.widget.RecyclerView;
+
+/**
+ * Class in charge of managing the {@link Parallax} object for {@link DetailsFragment}. This
+ * can be shared for creating both parallax effect and video animations when transitioning to/from
+ * half/full screen.
+ */
+public class DetailsParallaxManager {
+    private final RecyclerView mRecyclerView;
+    private final ParallaxRecyclerViewSource mParallaxSource;
+    private final ParallaxRecyclerViewSource.ChildPositionProperty mFrameTop;
+    private final ParallaxRecyclerViewSource.ChildPositionProperty mFrameBottom;
+    private Parallax mParallax;
+
+    public DetailsParallaxManager(RecyclerView recyclerView) {
+        this.mRecyclerView = recyclerView;
+        mParallaxSource = new ParallaxRecyclerViewSource(mRecyclerView);
+
+        // track the top edge of details_frame of first item of adapter
+        mFrameTop = mParallaxSource
+                .addProperty("frameTop")
+                .adapterPosition(0)
+                .viewId(R.id.details_frame);
+
+        // track the bottom edge of details_frame of first item of adapter
+        mFrameBottom = mParallaxSource
+                .addProperty("frameBottom")
+                .adapterPosition(0)
+                .viewId(R.id.details_frame)
+                .fraction(1.0f);
+
+        mParallax = new Parallax();
+        mParallax.setSource(mParallaxSource);
+    }
+
+    /**
+     * Returns the {@link Parallax} instance.
+     */
+    public Parallax getParallax() {
+        return mParallax;
+    }
+
+    /**
+     * Returns the top of the details overview row. This is tracked for implementing the
+     * parallax effect.
+     */
+    public ParallaxRecyclerViewSource.ChildPositionProperty getFrameTop() {
+        return mFrameTop;
+    }
+
+    /**
+     * Returns the bottom of the details overview row. This is tracked for implementing the
+     * parallax effect.
+     */
+    public ParallaxRecyclerViewSource.ChildPositionProperty getFrameBottom() {
+        return mFrameBottom;
+    }
+}
diff --git a/v17/leanback/src/android/support/v17/leanback/app/DetailsSupportFragment.java b/v17/leanback/src/android/support/v17/leanback/app/DetailsSupportFragment.java
index af23da9..5ad4a14 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/DetailsSupportFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/DetailsSupportFragment.java
@@ -15,23 +15,22 @@
  */
 package android.support.v17.leanback.app;
 
+import android.os.Bundle;
 import android.support.v17.leanback.R;
 import android.support.v17.leanback.transition.TransitionHelper;
+import android.support.v17.leanback.widget.BaseOnItemViewClickedListener;
+import android.support.v17.leanback.widget.BaseOnItemViewSelectedListener;
 import android.support.v17.leanback.widget.BrowseFrameLayout;
 import android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter;
 import android.support.v17.leanback.widget.ItemAlignmentFacet;
 import android.support.v17.leanback.widget.ItemBridgeAdapter;
 import android.support.v17.leanback.widget.ObjectAdapter;
-import android.support.v17.leanback.widget.BaseOnItemViewClickedListener;
-import android.support.v17.leanback.widget.BaseOnItemViewSelectedListener;
 import android.support.v17.leanback.widget.Presenter;
 import android.support.v17.leanback.widget.PresenterSelector;
 import android.support.v17.leanback.widget.RowPresenter;
 import android.support.v17.leanback.widget.TitleHelper;
 import android.support.v17.leanback.widget.VerticalGridView;
-import android.os.Bundle;
 import android.util.Log;
-import android.util.TypedValue;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -91,7 +90,7 @@
     }
 
     RowsSupportFragment mRowsSupportFragment;
-
+    private DetailsParallaxManager mDetailsParallaxManager;
     private ObjectAdapter mAdapter;
     private int mContainerListAlignTop;
     BaseOnItemViewSelectedListener mExternalOnItemViewSelectedListener;
@@ -317,8 +316,8 @@
 
     void onRowSelected(int selectedPosition, int selectedSubPosition) {
         ObjectAdapter adapter = getAdapter();
-        if (adapter == null || adapter.size() == 0 ||
-                (selectedPosition == 0 && selectedSubPosition == 0)) {
+        if (adapter == null || adapter.size() == 0
+                || (selectedPosition == 0 && selectedSubPosition == 0)) {
             showTitle(true);
         } else {
             showTitle(false);
@@ -428,4 +427,16 @@
     protected void onEntranceTransitionStart() {
         mRowsSupportFragment.onTransitionStart();
     }
+
+    /**
+     * Returns the {@link DetailsParallaxManager} instance used to configure
+     * {@link android.support.v17.leanback.widget.Parallax} instance.
+     */
+    public DetailsParallaxManager getParallaxManager() {
+        if (mDetailsParallaxManager == null) {
+            mDetailsParallaxManager = new DetailsParallaxManager(
+                    getRowsSupportFragment().getVerticalGridView());
+        }
+        return mDetailsParallaxManager;
+    }
 }
diff --git a/v17/leanback/src/android/support/v17/leanback/app/ErrorFragment.java b/v17/leanback/src/android/support/v17/leanback/app/ErrorFragment.java
index ac7b933..c35fcdc 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/ErrorFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/ErrorFragment.java
@@ -13,23 +13,19 @@
  */
 package android.support.v17.leanback.app;
 
+import android.graphics.Paint;
+import android.graphics.Paint.FontMetricsInt;
+import android.graphics.PixelFormat;
+import android.graphics.drawable.Drawable;
 import android.os.Bundle;
 import android.support.v17.leanback.R;
-import android.support.v17.leanback.widget.TitleView;
 import android.text.TextUtils;
-import android.util.Log;
-import android.app.Fragment;
 import android.view.LayoutInflater;
 import android.view.View;
-import android.view.View.OnClickListener;
 import android.view.ViewGroup;
 import android.widget.Button;
 import android.widget.ImageView;
 import android.widget.TextView;
-import android.graphics.Paint;
-import android.graphics.PixelFormat;
-import android.graphics.Paint.FontMetricsInt;
-import android.graphics.drawable.Drawable;
 
 /**
  * A fragment for displaying an error indication.
@@ -75,8 +71,8 @@
         mBackgroundDrawable = drawable;
         if (drawable != null) {
             final int opacity = drawable.getOpacity();
-            mIsBackgroundTranslucent = (opacity == PixelFormat.TRANSLUCENT ||
-                    opacity == PixelFormat.TRANSPARENT);
+            mIsBackgroundTranslucent = (opacity == PixelFormat.TRANSLUCENT
+                    || opacity == PixelFormat.TRANSPARENT);
         }
         updateBackground();
         updateMessage();
@@ -194,9 +190,9 @@
                 mErrorFrame.setBackground(mBackgroundDrawable);
             } else {
                 mErrorFrame.setBackgroundColor(mErrorFrame.getResources().getColor(
-                        mIsBackgroundTranslucent ?
-                        R.color.lb_error_background_color_translucent :
-                        R.color.lb_error_background_color_opaque));
+                        mIsBackgroundTranslucent
+                                ? R.color.lb_error_background_color_translucent
+                                : R.color.lb_error_background_color_opaque));
             }
         }
     }
diff --git a/v17/leanback/src/android/support/v17/leanback/app/ErrorSupportFragment.java b/v17/leanback/src/android/support/v17/leanback/app/ErrorSupportFragment.java
index 1cc5e21..5c3ce98 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/ErrorSupportFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/ErrorSupportFragment.java
@@ -15,23 +15,19 @@
  */
 package android.support.v17.leanback.app;
 
+import android.graphics.Paint;
+import android.graphics.Paint.FontMetricsInt;
+import android.graphics.PixelFormat;
+import android.graphics.drawable.Drawable;
 import android.os.Bundle;
 import android.support.v17.leanback.R;
-import android.support.v17.leanback.widget.TitleView;
 import android.text.TextUtils;
-import android.util.Log;
-import android.support.v4.app.Fragment;
 import android.view.LayoutInflater;
 import android.view.View;
-import android.view.View.OnClickListener;
 import android.view.ViewGroup;
 import android.widget.Button;
 import android.widget.ImageView;
 import android.widget.TextView;
-import android.graphics.Paint;
-import android.graphics.PixelFormat;
-import android.graphics.Paint.FontMetricsInt;
-import android.graphics.drawable.Drawable;
 
 /**
  * A fragment for displaying an error indication.
@@ -77,8 +73,8 @@
         mBackgroundDrawable = drawable;
         if (drawable != null) {
             final int opacity = drawable.getOpacity();
-            mIsBackgroundTranslucent = (opacity == PixelFormat.TRANSLUCENT ||
-                    opacity == PixelFormat.TRANSPARENT);
+            mIsBackgroundTranslucent = (opacity == PixelFormat.TRANSLUCENT
+                    || opacity == PixelFormat.TRANSPARENT);
         }
         updateBackground();
         updateMessage();
@@ -196,9 +192,9 @@
                 mErrorFrame.setBackground(mBackgroundDrawable);
             } else {
                 mErrorFrame.setBackgroundColor(mErrorFrame.getResources().getColor(
-                        mIsBackgroundTranslucent ?
-                        R.color.lb_error_background_color_translucent :
-                        R.color.lb_error_background_color_opaque));
+                        mIsBackgroundTranslucent
+                                ? R.color.lb_error_background_color_translucent
+                                : R.color.lb_error_background_color_opaque));
             }
         }
     }
diff --git a/v17/leanback/src/android/support/v17/leanback/app/GuidedStepFragment.java b/v17/leanback/src/android/support/v17/leanback/app/GuidedStepFragment.java
index 73c9700..db1bed5 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/GuidedStepFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/GuidedStepFragment.java
@@ -13,6 +13,8 @@
  */
 package android.support.v17.leanback.app;
 
+import static android.support.annotation.RestrictTo.Scope.GROUP_ID;
+
 import android.animation.Animator;
 import android.animation.AnimatorSet;
 import android.app.Activity;
@@ -33,7 +35,6 @@
 import android.support.v17.leanback.widget.GuidedActionAdapter;
 import android.support.v17.leanback.widget.GuidedActionAdapterGroup;
 import android.support.v17.leanback.widget.GuidedActionsStylist;
-import android.support.v17.leanback.widget.ViewHolderTask;
 import android.support.v4.app.ActivityCompat;
 import android.support.v7.widget.RecyclerView;
 import android.util.Log;
@@ -49,8 +50,6 @@
 import java.util.ArrayList;
 import java.util.List;
 
-import static android.support.annotation.RestrictTo.Scope.GROUP_ID;
-
 /**
  * A GuidedStepFragment is used to guide the user through a decision or series of decisions.
  * It is composed of a guidance view on the left and a view on the right containing a list of
@@ -141,7 +140,6 @@
 public class GuidedStepFragment extends Fragment implements GuidedActionAdapter.FocusListener {
 
     private static final String TAG_LEAN_BACK_ACTIONS_FRAGMENT = "leanBackGuidedStepFragment";
-    private static final String EXTRA_ACTION_SELECTED_INDEX = "selectedIndex";
     private static final String EXTRA_ACTION_PREFIX = "action_";
     private static final String EXTRA_BUTTON_ACTION_PREFIX = "buttonaction_";
 
@@ -262,8 +260,6 @@
     private GuidedActionAdapterGroup mAdapterGroup;
     private List<GuidedAction> mActions = new ArrayList<GuidedAction>();
     private List<GuidedAction> mButtonActions = new ArrayList<GuidedAction>();
-    private int mSelectedIndex = -1;
-    private int mButtonSelectedIndex = -1;
     private int entranceTransitionType = SLIDE_FROM_SIDE;
 
     public GuidedStepFragment() {
@@ -363,6 +359,14 @@
     }
 
     /**
+     * @return True if is current expanded including subactions list or
+     * action with {@link GuidedAction#hasEditableActivatorView()} is true.
+     */
+    public boolean isExpanded() {
+        return mActionsStylist.isExpanded();
+    }
+
+    /**
      * @return True if the sub actions list is expanded, false otherwise.
      */
     public boolean isSubActionsExpanded() {
@@ -372,21 +376,25 @@
     /**
      * Expand a given action's sub actions list.
      * @param action GuidedAction to expand.
-     * @see GuidedAction#getSubActions()
+     * @see #expandAction(GuidedAction, boolean)
      */
     public void expandSubActions(GuidedAction action) {
-        final int actionPosition = mActions.indexOf(action);
-        if (actionPosition < 0) {
+        if (!action.hasSubActions()) {
             return;
         }
-        mActionsStylist.getActionsGridView().setSelectedPositionSmooth(actionPosition,
-                new ViewHolderTask() {
-            @Override
-            public void run(RecyclerView.ViewHolder vh) {
-                GuidedActionsStylist.ViewHolder avh = (GuidedActionsStylist.ViewHolder) vh;
-                mActionsStylist.setExpandedViewHolder(avh);
-            }
-        });
+        expandAction(action, true);
+    }
+
+    /**
+     * Expand a given action with sub actions list or
+     * {@link GuidedAction#hasEditableActivatorView()} is true. The method must be called after
+     * {@link #onCreateView(LayoutInflater, ViewGroup, Bundle)} creates fragment view.
+     *
+     * @param action GuidedAction to expand.
+     * @param withTransition True to run transition animation, false otherwise.
+     */
+    public void expandAction(GuidedAction action, boolean withTransition) {
+        mActionsStylist.expandAction(action, withTransition);
     }
 
     /**
@@ -394,7 +402,19 @@
      * @see GuidedAction#getSubActions()
      */
     public void collapseSubActions() {
-        mActionsStylist.setExpandedViewHolder(null);
+        collapseAction(true);
+    }
+
+    /**
+     * Collapse action which either has a sub actions list or action with
+     * {@link GuidedAction#hasEditableActivatorView()} is true.
+     *
+     * @param withTransition True to run transition animation, false otherwise.
+     */
+    public void collapseAction(boolean withTransition) {
+        if (mActionsStylist != null && mActionsStylist.getActionsGridView() != null) {
+            mActionsStylist.collapseAction(withTransition);
+        }
     }
 
     /**
@@ -543,7 +563,7 @@
      * @return BackStackEntry name for the GuidedStepFragment or empty String if no entry is
      * associated.
      */
-    String generateStackEntryName() {
+    final String generateStackEntryName() {
         return generateStackEntryName(getUiStyle(), getClass());
     }
 
@@ -555,9 +575,6 @@
      * associated.
      */
     static String generateStackEntryName(int uiStyle, Class guidedStepFragmentClass) {
-        if (!GuidedStepFragment.class.isAssignableFrom(guidedStepFragmentClass)) {
-            return "";
-        }
         switch (uiStyle) {
         case UI_STYLE_REPLACE:
             return ENTRY_NAME_REPLACE + guidedStepFragmentClass.getName();
@@ -618,8 +635,8 @@
         activity.getWindow().getDecorView();
         FragmentManager fragmentManager = activity.getFragmentManager();
         if (fragmentManager.findFragmentByTag(TAG_LEAN_BACK_ACTIONS_FRAGMENT) != null) {
-            Log.w(TAG, "Fragment is already exists, likely calling " +
-                    "addAsRoot() when savedInstanceState is not null in Activity.onCreate().");
+            Log.w(TAG, "Fragment is already exists, likely calling "
+                    + "addAsRoot() when savedInstanceState is not null in Activity.onCreate().");
             return -1;
         }
         FragmentTransaction ft = fragmentManager.beginTransaction();
@@ -865,8 +882,8 @@
                         true);
                 TransitionHelper.setEnterTransition(this, enterTransition);
 
-                Object fade = TransitionHelper.createFadeTransition(TransitionHelper.FADE_IN |
-                        TransitionHelper.FADE_OUT);
+                Object fade = TransitionHelper.createFadeTransition(
+                        TransitionHelper.FADE_IN | TransitionHelper.FADE_OUT);
                 TransitionHelper.include(fade, R.id.guidedactions_sub_list_background);
                 Object changeBounds = TransitionHelper.createChangeBounds(false);
                 Object sharedElementTransition = TransitionHelper.createTransitionSet(false);
@@ -875,11 +892,11 @@
                 TransitionHelper.setSharedElementEnterTransition(this, sharedElementTransition);
             } else if (uiStyle == UI_STYLE_ENTRANCE) {
                 if (entranceTransitionType == SLIDE_FROM_SIDE) {
-                    Object fade = TransitionHelper.createFadeTransition(TransitionHelper.FADE_IN |
-                            TransitionHelper.FADE_OUT);
+                    Object fade = TransitionHelper.createFadeTransition(
+                            TransitionHelper.FADE_IN | TransitionHelper.FADE_OUT);
                     TransitionHelper.include(fade, R.id.guidedstep_background);
-                    Object slideFromSide = TransitionHelper.createFadeAndShortSlide(Gravity.END |
-                            Gravity.START);
+                    Object slideFromSide = TransitionHelper.createFadeAndShortSlide(
+                            Gravity.END | Gravity.START);
                     TransitionHelper.include(slideFromSide, R.id.content_fragment);
                     TransitionHelper.include(slideFromSide, R.id.action_fragment_root);
                     Object enterTransition = TransitionHelper.createTransitionSet(false);
@@ -979,12 +996,7 @@
         if (DEBUG) Log.v(TAG, "onCreate");
         // Set correct transition from saved arguments.
         onProvideFragmentTransitions();
-        Bundle state = (savedInstanceState != null) ? savedInstanceState : getArguments();
-        if (state != null) {
-            if (mSelectedIndex == -1) {
-                mSelectedIndex = state.getInt(EXTRA_ACTION_SELECTED_INDEX, -1);
-            }
-        }
+
         ArrayList<GuidedAction> actions = new ArrayList<GuidedAction>();
         onCreateActions(actions, savedInstanceState);
         if (savedInstanceState != null) {
@@ -1071,10 +1083,10 @@
             @Override
             public void onGuidedActionClicked(GuidedAction action) {
                 GuidedStepFragment.this.onGuidedActionClicked(action);
-                if (isSubActionsExpanded()) {
-                    collapseSubActions();
-                } else if (action.hasSubActions()) {
-                    expandSubActions(action);
+                if (isExpanded()) {
+                    collapseAction(true);
+                } else if (action.hasSubActions() || action.hasEditableActivatorView()) {
+                    expandAction(action, true);
                 }
             }
         }, this, mActionsStylist, false);
@@ -1130,12 +1142,6 @@
             }
         }
 
-        int pos = (mSelectedIndex >= 0 && mSelectedIndex < mActions.size()) ?
-                mSelectedIndex : getFirstCheckedAction();
-        setSelectedActionPosition(pos);
-
-        setSelectedButtonActionPosition(0);
-
         // Add the background view.
         View backgroundView = onCreateBackgroundView(inflater, root, savedInstanceState);
         if (backgroundView != null) {
@@ -1143,6 +1149,7 @@
                 R.id.guidedstep_background_view_root);
             backgroundViewRoot.addView(backgroundView, 0);
         }
+
         return root;
     }
 
@@ -1218,9 +1225,6 @@
         super.onSaveInstanceState(outState);
         onSaveActions(mActions, outState);
         onSaveButtonActions(mButtonActions, outState);
-        outState.putInt(EXTRA_ACTION_SELECTED_INDEX,
-                (mActionsStylist.getActionsGridView() != null) ?
-                        getSelectedActionPosition() : mSelectedIndex);
     }
 
     private static boolean isGuidedStepTheme(Context context) {
@@ -1249,7 +1253,7 @@
                     if (top != null) {
                         top.setUiStyle(UI_STYLE_ENTRANCE);
                     }
-                    fragmentManager.popBackStack(entry.getId(),
+                    fragmentManager.popBackStackImmediate(entry.getId(),
                             FragmentManager.POP_BACK_STACK_INCLUSIVE);
                     return;
                 }
@@ -1275,7 +1279,7 @@
                 BackStackEntry entry = fragmentManager.getBackStackEntryAt(i);
                 String entryClassName = getGuidedStepFragmentClassName(entry.getName());
                 if (className.equals(entryClassName)) {
-                    fragmentManager.popBackStack(entry.getId(), flags);
+                    fragmentManager.popBackStackImmediate(entry.getId(), flags);
                     return;
                 }
             }
diff --git a/v17/leanback/src/android/support/v17/leanback/app/GuidedStepRootLayout.java b/v17/leanback/src/android/support/v17/leanback/app/GuidedStepRootLayout.java
index 6d05fd1..ec34bba 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/GuidedStepRootLayout.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/GuidedStepRootLayout.java
@@ -51,8 +51,8 @@
             if (Util.isDescendant(this, newFocus)) {
                 return newFocus;
             }
-            if (getLayoutDirection() == ViewGroup.LAYOUT_DIRECTION_LTR ?
-                    direction == FOCUS_LEFT : direction == FOCUS_RIGHT) {
+            if (getLayoutDirection() == ViewGroup.LAYOUT_DIRECTION_LTR
+                    ? direction == FOCUS_LEFT : direction == FOCUS_RIGHT) {
                 if (!mFocusOutStart) {
                     return focused;
                 }
diff --git a/v17/leanback/src/android/support/v17/leanback/app/GuidedStepSupportFragment.java b/v17/leanback/src/android/support/v17/leanback/app/GuidedStepSupportFragment.java
index f5b27df..bec5641 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/GuidedStepSupportFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/GuidedStepSupportFragment.java
@@ -15,9 +15,10 @@
  */
 package android.support.v17.leanback.app;
 
+import static android.support.annotation.RestrictTo.Scope.GROUP_ID;
+
 import android.animation.Animator;
 import android.animation.AnimatorSet;
-import android.support.annotation.RestrictTo;
 import android.support.v4.app.FragmentActivity;
 import android.support.v4.app.Fragment;
 import android.support.v4.app.FragmentManager;
@@ -27,6 +28,7 @@
 import android.os.Build;
 import android.os.Bundle;
 import android.support.annotation.NonNull;
+import android.support.annotation.RestrictTo;
 import android.support.v17.leanback.R;
 import android.support.v17.leanback.transition.TransitionHelper;
 import android.support.v17.leanback.widget.GuidanceStylist;
@@ -35,7 +37,6 @@
 import android.support.v17.leanback.widget.GuidedActionAdapter;
 import android.support.v17.leanback.widget.GuidedActionAdapterGroup;
 import android.support.v17.leanback.widget.GuidedActionsStylist;
-import android.support.v17.leanback.widget.ViewHolderTask;
 import android.support.v4.app.ActivityCompat;
 import android.support.v7.widget.RecyclerView;
 import android.util.Log;
@@ -51,8 +52,6 @@
 import java.util.ArrayList;
 import java.util.List;
 
-import static android.support.annotation.RestrictTo.Scope.GROUP_ID;
-
 /**
  * A GuidedStepSupportFragment is used to guide the user through a decision or series of decisions.
  * It is composed of a guidance view on the left and a view on the right containing a list of
@@ -143,7 +142,6 @@
 public class GuidedStepSupportFragment extends Fragment implements GuidedActionAdapter.FocusListener {
 
     private static final String TAG_LEAN_BACK_ACTIONS_FRAGMENT = "leanBackGuidedStepSupportFragment";
-    private static final String EXTRA_ACTION_SELECTED_INDEX = "selectedIndex";
     private static final String EXTRA_ACTION_PREFIX = "action_";
     private static final String EXTRA_BUTTON_ACTION_PREFIX = "buttonaction_";
 
@@ -264,8 +262,6 @@
     private GuidedActionAdapterGroup mAdapterGroup;
     private List<GuidedAction> mActions = new ArrayList<GuidedAction>();
     private List<GuidedAction> mButtonActions = new ArrayList<GuidedAction>();
-    private int mSelectedIndex = -1;
-    private int mButtonSelectedIndex = -1;
     private int entranceTransitionType = SLIDE_FROM_SIDE;
 
     public GuidedStepSupportFragment() {
@@ -365,6 +361,14 @@
     }
 
     /**
+     * @return True if is current expanded including subactions list or
+     * action with {@link GuidedAction#hasEditableActivatorView()} is true.
+     */
+    public boolean isExpanded() {
+        return mActionsStylist.isExpanded();
+    }
+
+    /**
      * @return True if the sub actions list is expanded, false otherwise.
      */
     public boolean isSubActionsExpanded() {
@@ -374,21 +378,25 @@
     /**
      * Expand a given action's sub actions list.
      * @param action GuidedAction to expand.
-     * @see GuidedAction#getSubActions()
+     * @see #expandAction(GuidedAction, boolean)
      */
     public void expandSubActions(GuidedAction action) {
-        final int actionPosition = mActions.indexOf(action);
-        if (actionPosition < 0) {
+        if (!action.hasSubActions()) {
             return;
         }
-        mActionsStylist.getActionsGridView().setSelectedPositionSmooth(actionPosition,
-                new ViewHolderTask() {
-            @Override
-            public void run(RecyclerView.ViewHolder vh) {
-                GuidedActionsStylist.ViewHolder avh = (GuidedActionsStylist.ViewHolder) vh;
-                mActionsStylist.setExpandedViewHolder(avh);
-            }
-        });
+        expandAction(action, true);
+    }
+
+    /**
+     * Expand a given action with sub actions list or
+     * {@link GuidedAction#hasEditableActivatorView()} is true. The method must be called after
+     * {@link #onCreateView(LayoutInflater, ViewGroup, Bundle)} creates fragment view.
+     *
+     * @param action GuidedAction to expand.
+     * @param withTransition True to run transition animation, false otherwise.
+     */
+    public void expandAction(GuidedAction action, boolean withTransition) {
+        mActionsStylist.expandAction(action, withTransition);
     }
 
     /**
@@ -396,7 +404,19 @@
      * @see GuidedAction#getSubActions()
      */
     public void collapseSubActions() {
-        mActionsStylist.setExpandedViewHolder(null);
+        collapseAction(true);
+    }
+
+    /**
+     * Collapse action which either has a sub actions list or action with
+     * {@link GuidedAction#hasEditableActivatorView()} is true.
+     *
+     * @param withTransition True to run transition animation, false otherwise.
+     */
+    public void collapseAction(boolean withTransition) {
+        if (mActionsStylist != null && mActionsStylist.getActionsGridView() != null) {
+            mActionsStylist.collapseAction(withTransition);
+        }
     }
 
     /**
@@ -545,7 +565,7 @@
      * @return BackStackEntry name for the GuidedStepSupportFragment or empty String if no entry is
      * associated.
      */
-    String generateStackEntryName() {
+    final String generateStackEntryName() {
         return generateStackEntryName(getUiStyle(), getClass());
     }
 
@@ -557,9 +577,6 @@
      * associated.
      */
     static String generateStackEntryName(int uiStyle, Class guidedStepFragmentClass) {
-        if (!GuidedStepSupportFragment.class.isAssignableFrom(guidedStepFragmentClass)) {
-            return "";
-        }
         switch (uiStyle) {
         case UI_STYLE_REPLACE:
             return ENTRY_NAME_REPLACE + guidedStepFragmentClass.getName();
@@ -620,8 +637,8 @@
         activity.getWindow().getDecorView();
         FragmentManager fragmentManager = activity.getSupportFragmentManager();
         if (fragmentManager.findFragmentByTag(TAG_LEAN_BACK_ACTIONS_FRAGMENT) != null) {
-            Log.w(TAG, "Fragment is already exists, likely calling " +
-                    "addAsRoot() when savedInstanceState is not null in Activity.onCreate().");
+            Log.w(TAG, "Fragment is already exists, likely calling "
+                    + "addAsRoot() when savedInstanceState is not null in Activity.onCreate().");
             return -1;
         }
         FragmentTransaction ft = fragmentManager.beginTransaction();
@@ -867,8 +884,8 @@
                         true);
                 TransitionHelper.setEnterTransition(this, enterTransition);
 
-                Object fade = TransitionHelper.createFadeTransition(TransitionHelper.FADE_IN |
-                        TransitionHelper.FADE_OUT);
+                Object fade = TransitionHelper.createFadeTransition(
+                        TransitionHelper.FADE_IN | TransitionHelper.FADE_OUT);
                 TransitionHelper.include(fade, R.id.guidedactions_sub_list_background);
                 Object changeBounds = TransitionHelper.createChangeBounds(false);
                 Object sharedElementTransition = TransitionHelper.createTransitionSet(false);
@@ -877,11 +894,11 @@
                 TransitionHelper.setSharedElementEnterTransition(this, sharedElementTransition);
             } else if (uiStyle == UI_STYLE_ENTRANCE) {
                 if (entranceTransitionType == SLIDE_FROM_SIDE) {
-                    Object fade = TransitionHelper.createFadeTransition(TransitionHelper.FADE_IN |
-                            TransitionHelper.FADE_OUT);
+                    Object fade = TransitionHelper.createFadeTransition(
+                            TransitionHelper.FADE_IN | TransitionHelper.FADE_OUT);
                     TransitionHelper.include(fade, R.id.guidedstep_background);
-                    Object slideFromSide = TransitionHelper.createFadeAndShortSlide(Gravity.END |
-                            Gravity.START);
+                    Object slideFromSide = TransitionHelper.createFadeAndShortSlide(
+                            Gravity.END | Gravity.START);
                     TransitionHelper.include(slideFromSide, R.id.content_fragment);
                     TransitionHelper.include(slideFromSide, R.id.action_fragment_root);
                     Object enterTransition = TransitionHelper.createTransitionSet(false);
@@ -981,12 +998,7 @@
         if (DEBUG) Log.v(TAG, "onCreate");
         // Set correct transition from saved arguments.
         onProvideFragmentTransitions();
-        Bundle state = (savedInstanceState != null) ? savedInstanceState : getArguments();
-        if (state != null) {
-            if (mSelectedIndex == -1) {
-                mSelectedIndex = state.getInt(EXTRA_ACTION_SELECTED_INDEX, -1);
-            }
-        }
+
         ArrayList<GuidedAction> actions = new ArrayList<GuidedAction>();
         onCreateActions(actions, savedInstanceState);
         if (savedInstanceState != null) {
@@ -1073,10 +1085,10 @@
             @Override
             public void onGuidedActionClicked(GuidedAction action) {
                 GuidedStepSupportFragment.this.onGuidedActionClicked(action);
-                if (isSubActionsExpanded()) {
-                    collapseSubActions();
-                } else if (action.hasSubActions()) {
-                    expandSubActions(action);
+                if (isExpanded()) {
+                    collapseAction(true);
+                } else if (action.hasSubActions() || action.hasEditableActivatorView()) {
+                    expandAction(action, true);
                 }
             }
         }, this, mActionsStylist, false);
@@ -1132,12 +1144,6 @@
             }
         }
 
-        int pos = (mSelectedIndex >= 0 && mSelectedIndex < mActions.size()) ?
-                mSelectedIndex : getFirstCheckedAction();
-        setSelectedActionPosition(pos);
-
-        setSelectedButtonActionPosition(0);
-
         // Add the background view.
         View backgroundView = onCreateBackgroundView(inflater, root, savedInstanceState);
         if (backgroundView != null) {
@@ -1145,6 +1151,7 @@
                 R.id.guidedstep_background_view_root);
             backgroundViewRoot.addView(backgroundView, 0);
         }
+
         return root;
     }
 
@@ -1220,9 +1227,6 @@
         super.onSaveInstanceState(outState);
         onSaveActions(mActions, outState);
         onSaveButtonActions(mButtonActions, outState);
-        outState.putInt(EXTRA_ACTION_SELECTED_INDEX,
-                (mActionsStylist.getActionsGridView() != null) ?
-                        getSelectedActionPosition() : mSelectedIndex);
     }
 
     private static boolean isGuidedStepTheme(Context context) {
@@ -1251,7 +1255,7 @@
                     if (top != null) {
                         top.setUiStyle(UI_STYLE_ENTRANCE);
                     }
-                    fragmentManager.popBackStack(entry.getId(),
+                    fragmentManager.popBackStackImmediate(entry.getId(),
                             FragmentManager.POP_BACK_STACK_INCLUSIVE);
                     return;
                 }
@@ -1277,7 +1281,7 @@
                 BackStackEntry entry = fragmentManager.getBackStackEntryAt(i);
                 String entryClassName = getGuidedStepSupportFragmentClassName(entry.getName());
                 if (className.equals(entryClassName)) {
-                    fragmentManager.popBackStack(entry.getId(), flags);
+                    fragmentManager.popBackStackImmediate(entry.getId(), flags);
                     return;
                 }
             }
@@ -1317,6 +1321,7 @@
      * For now clients(subclasses) can call this method inside the constructor.
      * @hide
      */
+    @RestrictTo(GROUP_ID)
     public void setEntranceTransitionType(int transitionType) {
       this.entranceTransitionType = transitionType;
     }
diff --git a/v17/leanback/src/android/support/v17/leanback/app/MediaControllerGlue.java b/v17/leanback/src/android/support/v17/leanback/app/MediaControllerGlue.java
index 27ccd06..5c75506 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/MediaControllerGlue.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/MediaControllerGlue.java
@@ -48,14 +48,17 @@
      *
      * <p>The {@link PlaybackOverlayFragment} must be passed in.
      * A {@link android.support.v17.leanback.widget.OnItemViewClickedListener} and
-     * {@link PlaybackOverlayFragment.InputEventHandler}
+     * {@link android.support.v17.leanback.app.PlaybackControlGlue.InputEventHandler}
      * will be set on the fragment.
      * </p>
      *
      * @param context
      * @param fragment
      * @param seekSpeeds Array of seek speeds for fast forward and rewind.
+     * @deprecated Use
+     * {@link #MediaControllerGlue(Context, PlaybackGlue.PlaybackGlueHost, int[], int[])}.
      */
+    @Deprecated
     public MediaControllerGlue(Context context,
                                PlaybackOverlayFragment fragment,
                                int[] seekSpeeds) {
@@ -67,7 +70,7 @@
      *
      * <p>The {@link PlaybackOverlayFragment} must be passed in.
      * A {@link android.support.v17.leanback.widget.OnItemViewClickedListener} and
-     * {@link PlaybackOverlayFragment.InputEventHandler}
+     * {@link android.support.v17.leanback.app.PlaybackControlGlue.InputEventHandler}
      * will be set on the fragment.
      * </p>
      *
@@ -75,7 +78,10 @@
      * @param fragment
      * @param fastForwardSpeeds Array of seek speeds for fast forward.
      * @param rewindSpeeds Array of seek speeds for rewind.
+     * @deprecated Use
+     * {@link #MediaControllerGlue(Context, PlaybackGlue.PlaybackGlueHost, int[], int[])}.
      */
+    @Deprecated
     public MediaControllerGlue(Context context,
                                PlaybackOverlayFragment fragment,
                                int[] fastForwardSpeeds,
@@ -84,6 +90,21 @@
     }
 
     /**
+     * Constructor for the glue.
+     *
+     * @param context
+     * @param host Optional; if using a {@link PlaybackGlue.PlaybackGlueHost}, pass it in.
+     * @param fastForwardSpeeds Array of seek speeds for fast forward.
+     * @param rewindSpeeds Array of seek speeds for rewind.
+     */
+    public MediaControllerGlue(Context context,
+            PlaybackGlueHost host,
+            int[] fastForwardSpeeds,
+            int[] rewindSpeeds) {
+        super(context, host, fastForwardSpeeds, rewindSpeeds);
+    }
+
+    /**
      * Attaches to the given media controller.
      */
     public void attachToMediaController(MediaControllerCompat mediaController) {
diff --git a/v17/leanback/src/android/support/v17/leanback/app/OnboardingFragment.java b/v17/leanback/src/android/support/v17/leanback/app/OnboardingFragment.java
index 16d3ed1..0459ab6 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/OnboardingFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/OnboardingFragment.java
@@ -160,8 +160,8 @@
     private static int sSlideDistance;
 
     private static final TimeInterpolator HEADER_APPEAR_INTERPOLATOR = new DecelerateInterpolator();
-    private static final TimeInterpolator HEADER_DISAPPEAR_INTERPOLATOR
-            = new AccelerateInterpolator();
+    private static final TimeInterpolator HEADER_DISAPPEAR_INTERPOLATOR =
+            new AccelerateInterpolator();
 
     // Keys used to save and restore the states.
     private static final String KEY_CURRENT_PAGE_INDEX = "leanback.onboarding.current_page_index";
diff --git a/v17/leanback/src/android/support/v17/leanback/app/OnboardingSupportFragment.java b/v17/leanback/src/android/support/v17/leanback/app/OnboardingSupportFragment.java
index 076b61e..a17e573 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/OnboardingSupportFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/OnboardingSupportFragment.java
@@ -162,8 +162,8 @@
     private static int sSlideDistance;
 
     private static final TimeInterpolator HEADER_APPEAR_INTERPOLATOR = new DecelerateInterpolator();
-    private static final TimeInterpolator HEADER_DISAPPEAR_INTERPOLATOR
-            = new AccelerateInterpolator();
+    private static final TimeInterpolator HEADER_DISAPPEAR_INTERPOLATOR =
+            new AccelerateInterpolator();
 
     // Keys used to save and restore the states.
     private static final String KEY_CURRENT_PAGE_INDEX = "leanback.onboarding.current_page_index";
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 2cf897f..173791e 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/PlaybackControlGlue.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/PlaybackControlGlue.java
@@ -1,3 +1,16 @@
+/*
+ * 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 android.support.v17.leanback.app;
 
 import android.content.Context;
@@ -21,14 +34,13 @@
 import android.view.KeyEvent;
 import android.view.View;
 
-
 /**
- * A helper class for managing a {@link android.support.v17.leanback.widget.PlaybackControlsRow} and
- * {@link PlaybackOverlayFragment} that implements a recommended approach to handling standard
- * playback control actions such as play/pause, fast forward/rewind at progressive speed levels,
- * and skip to next/previous.  This helper class is a glue layer in that it manages the
- * configuration of and interaction between the leanback UI components by defining a functional
- * interface to the media player.
+ * A helper class for managing a {@link android.support.v17.leanback.widget.PlaybackControlsRow}
+ * and {@link android.support.v17.leanback.app.PlaybackGlue.PlaybackGlueHost} that implements a
+ * recommended approach to handling standard playback control actions such as play/pause,
+ * fast forward/rewind at progressive speed levels, and skip to next/previous. This helper class
+ * is a glue layer in that it manages the configuration of and interaction between the
+ * leanback UI components by defining a functional interface to the media player.
  *
  * <p>You can instantiate a concrete subclass such as {@link MediaControllerGlue} or you must
  * subclass this abstract helper.  To create a subclass you must implement all of the
@@ -37,8 +49,8 @@
  * </p>
  *
  * <p>To use an instance of the glue layer, first construct an instance.  Constructor parameters
- * inform the glue what speed levels are supported for fast forward/rewind.  Providing a
- * {@link android.support.v17.leanback.app.PlaybackOverlayFragment} is optional.
+ * inform the glue what speed levels are supported for fast forward/rewind. Providing a
+ * {@link android.support.v17.leanback.app.PlaybackGlue.PlaybackGlueHost} is optional.
  * </p>
  *
  * <p>If you have your own controls row you must pass it to {@link #setControlsRow}.
@@ -48,7 +60,7 @@
  * </p>
  *
  * <p>The helper sets a {@link android.support.v17.leanback.widget.SparseArrayObjectAdapter}
- * on the controls row as the primary actions adapter, and adds actions to it.  You can provide
+ * on the controls row as the primary actions adapter, and adds actions to it. You can provide
  * additional actions by overriding {@link #createPrimaryActionsAdapter}.  This helper does not
  * deal in secondary actions so those you may add separately.
  * </p>
@@ -59,10 +71,10 @@
  * will be handled.  Your listener will be called only for unhandled actions.
  * </p>
  *
- * <p>The helper implements a key event handler.  If you pass a
- * {@link android.support.v17.leanback.app.PlaybackOverlayFragment} the fragment's input event
- * handler will be set.  Otherwise, you should set the glue object as key event handler to the
- * ViewHolder when bound by your row presenter; see
+ * <p>This helper implements a key event handler. If you pass a
+ * {@link android.support.v17.leanback.app.PlaybackGlue.PlaybackGlueHost}, it will configure it's
+ * fragment to intercept all key events.  Otherwise, you should set the glue object as key event
+ * handler to the ViewHolder when bound by your row presenter; see
  * {@link RowPresenter.ViewHolder#setOnKeyListener(android.view.View.OnKeyListener)}.
  * </p>
  *
@@ -72,7 +84,8 @@
  * </p>
  *
  */
-public abstract class PlaybackControlGlue implements OnActionClickedListener, View.OnKeyListener {
+public abstract class PlaybackControlGlue extends PlaybackGlue
+        implements OnActionClickedListener, View.OnKeyListener {
     /**
      * The adapter key for the first custom control on the left side
      * of the predefined primary controls.
@@ -160,11 +173,9 @@
 
     static final int MSG_UPDATE_PLAYBACK_STATE = 100;
     private static final int UPDATE_PLAYBACK_STATE_DELAY_MS = 2000;
-    private static final int NUMBER_OF_SEEK_SPEEDS = PLAYBACK_SPEED_FAST_L4 -
-            PLAYBACK_SPEED_FAST_L0 + 1;
+    private static final int NUMBER_OF_SEEK_SPEEDS = PLAYBACK_SPEED_FAST_L4
+            - PLAYBACK_SPEED_FAST_L0 + 1;
 
-    private final PlaybackOverlayFragment mFragment;
-    private final Context mContext;
     private final int[] mFastForwardSpeeds;
     private final int[] mRewindSpeeds;
     private PlaybackControlsRow mControlsRow;
@@ -187,22 +198,21 @@
         }
     };
 
-    private final OnItemViewClickedListener mOnItemViewClickedListener =
-            new OnItemViewClickedListener() {
-        @Override
-        public void onItemClicked(Presenter.ViewHolder viewHolder, Object object,
-                                  RowPresenter.ViewHolder viewHolder2, Row row) {
-            if (DEBUG) Log.v(TAG, "onItemClicked " + object);
-            boolean handled = false;
-            if (object instanceof Action) {
-                handled = dispatchAction((Action) object, null);
-            }
-            if (!handled && mExternalOnItemViewClickedListener != null) {
-                mExternalOnItemViewClickedListener.onItemClicked(viewHolder, object,
-                        viewHolder2, row);
-            }
-        }
-    };
+    /**
+     * Interface allowing the application to handle input events.
+     * @deprecated Use
+     * {@link PlaybackGlue.PlaybackGlueHost#setOnKeyInterceptListener(View.OnKeyListener)}.
+     */
+    @Deprecated
+    public interface InputEventHandler {
+        /**
+         * Called when an {@link InputEvent} is received.
+         *
+         * @return If the event should be consumed, return true. To allow the event to
+         * continue on to the next handler, return false.
+         */
+        boolean handleInputEvent(InputEvent event);
+    }
 
     /**
      * Constructor for the glue.
@@ -211,7 +221,7 @@
      * @param seekSpeeds Array of seek speeds for fast forward and rewind.
      */
     public PlaybackControlGlue(Context context, int[] seekSpeeds) {
-        this(context, null, seekSpeeds, seekSpeeds);
+        this(context, (PlaybackGlueHost) null, seekSpeeds, seekSpeeds);
     }
 
     /**
@@ -224,7 +234,7 @@
     public PlaybackControlGlue(Context context,
                                int[] fastForwardSpeeds,
                                int[] rewindSpeeds) {
-        this(context, null, fastForwardSpeeds, rewindSpeeds);
+        this(context, (PlaybackGlueHost) null, fastForwardSpeeds, rewindSpeeds);
     }
 
     /**
@@ -233,7 +243,10 @@
      * @param context
      * @param fragment Optional; if using a {@link PlaybackOverlayFragment}, pass it in.
      * @param seekSpeeds Array of seek speeds for fast forward and rewind.
+     * @deprecated Use
+     * {@link #PlaybackControlGlue(Context, PlaybackGlue.PlaybackGlueHost, int[], int[])}.
      */
+    @Deprecated
     public PlaybackControlGlue(Context context,
                                PlaybackOverlayFragment fragment,
                                int[] seekSpeeds) {
@@ -247,16 +260,32 @@
      * @param fragment Optional; if using a {@link PlaybackOverlayFragment}, pass it in.
      * @param fastForwardSpeeds Array of seek speeds for fast forward.
      * @param rewindSpeeds Array of seek speeds for rewind.
+     * @deprecated Use
+     * {@link #PlaybackControlGlue(Context, PlaybackGlue.PlaybackGlueHost, int[], int[])}.
      */
+    @Deprecated
     public PlaybackControlGlue(Context context,
                                PlaybackOverlayFragment fragment,
                                int[] fastForwardSpeeds,
                                int[] rewindSpeeds) {
-        mContext = context;
-        mFragment = fragment;
-        if (fragment != null) {
-            attachToFragment();
-        }
+        this(context, fragment == null ? (PlaybackGlueHost) null:
+                new PlaybackGlueHostOld(fragment), fastForwardSpeeds, rewindSpeeds);
+    }
+
+    /**
+     * Constructor for the glue.
+     *
+     * @param context
+     * @param host Optional; if using a {@link PlaybackGlue.PlaybackGlueHost}, pass it in.
+     * @param fastForwardSpeeds Array of seek speeds for fast forward.
+     * @param rewindSpeeds Array of seek speeds for rewind.
+     */
+    public PlaybackControlGlue(Context context,
+                               PlaybackGlueHost host,
+                               int[] fastForwardSpeeds,
+                               int[] rewindSpeeds) {
+        super(context);
+        setHost(host);
         if (fastForwardSpeeds.length == 0 || fastForwardSpeeds.length > NUMBER_OF_SEEK_SPEEDS) {
             throw new IllegalStateException("invalid fastForwardSpeeds array size");
         }
@@ -267,32 +296,28 @@
         mRewindSpeeds = rewindSpeeds;
     }
 
-    private final PlaybackOverlayFragment.InputEventHandler mOnInputEventHandler =
-            new PlaybackOverlayFragment.InputEventHandler() {
-        @Override
-        public boolean handleInputEvent(InputEvent event) {
-            if (event instanceof KeyEvent) {
-                KeyEvent keyEvent = (KeyEvent) event;
-                return onKey(null, keyEvent.getKeyCode(), keyEvent);
+    @Override
+    public void setHost(PlaybackGlueHost host) {
+        super.setHost(host);
+        if (mPlaybackGlueHost != null) {
+            if (mPlaybackGlueHost instanceof PlaybackGlueHostOld) {
+                ((PlaybackGlueHostOld) mPlaybackGlueHost).mGlue = this;
             }
-            return false;
+            mPlaybackGlueHost.setOnKeyInterceptListener(this);
+            mPlaybackGlueHost.setOnActionClickedListener(this);
         }
-    };
-
-    private void attachToFragment() {
-        mFragment.setInputEventHandler(mOnInputEventHandler);
     }
 
+
     /**
-     * Helper method for instantiating a
-     * {@link android.support.v17.leanback.widget.PlaybackControlsRow} and corresponding
-     * {@link android.support.v17.leanback.widget.PlaybackControlsRowPresenter}.
+     * Helper method for instantiating a {@link PlaybackControlsRow} and corresponding
+     * {@link PlaybackControlsRowPresenter}.
      */
     public PlaybackControlsRowPresenter createControlsRowAndPresenter() {
         PlaybackControlsRow controlsRow = new PlaybackControlsRow(this);
         setControlsRow(controlsRow);
 
-        AbstractDetailsDescriptionPresenter detailsPresenter =
+        final AbstractDetailsDescriptionPresenter detailsPresenter =
                 new AbstractDetailsDescriptionPresenter() {
             @Override
             protected void onBindDescription(AbstractDetailsDescriptionPresenter.ViewHolder
@@ -307,6 +332,7 @@
                 }
             }
         };
+
         return new PlaybackControlsRowPresenter(detailsPresenter) {
             @Override
             protected void onBindRowViewHolder(RowPresenter.ViewHolder vh, Object item) {
@@ -323,16 +349,14 @@
 
     /**
      * Returns the fragment.
+     * @deprecated The glue is no longer associated with a fragment, use {@link #getHost()}.
      */
+    @Deprecated
     public PlaybackOverlayFragment getFragment() {
-        return mFragment;
-    }
-
-    /**
-     * Returns the context.
-     */
-    public Context getContext() {
-        return mContext;
+        if (mPlaybackGlueHost instanceof PlaybackGlueHostOld) {
+            return ((PlaybackGlueHostOld)mPlaybackGlueHost).mFragment;
+        }
+        return null;
     }
 
     /**
@@ -354,8 +378,8 @@
      */
     public void setFadingEnabled(boolean enable) {
         mFadeWhenPlaying = enable;
-        if (!mFadeWhenPlaying && mFragment != null) {
-            mFragment.setFadingEnabled(false);
+        if (!mFadeWhenPlaying && mPlaybackGlueHost != null) {
+            mPlaybackGlueHost.setFadingEnabled(false);
         }
     }
 
@@ -370,20 +394,18 @@
      * Set the {@link OnItemViewClickedListener} to be called if the click event
      * is not handled internally.
      * @param listener
-     * @deprecated Don't call this.  Instead set the listener on the fragment yourself,
-     * and call {@link #onActionClicked} to handle clicks.
+     * @deprecated Don't call this. Instead use the listener on the fragment yourself.
      */
     @Deprecated
     public void setOnItemViewClickedListener(OnItemViewClickedListener listener) {
         mExternalOnItemViewClickedListener = listener;
-        if (mFragment != null) {
-            mFragment.setOnItemViewClickedListener(mOnItemViewClickedListener);
-        }
     }
 
     /**
      * Returns the {@link OnItemViewClickedListener}.
+     * @deprecated Don't call this. Instead use the listener on the fragment yourself.
      */
+    @Deprecated
     public OnItemViewClickedListener getOnItemViewClickedListener() {
         return mExternalOnItemViewClickedListener;
     }
@@ -454,8 +476,8 @@
             case KeyEvent.KEYCODE_DPAD_LEFT:
             case KeyEvent.KEYCODE_BACK:
             case KeyEvent.KEYCODE_ESCAPE:
-                boolean abortSeek = mPlaybackSpeed >= PLAYBACK_SPEED_FAST_L0 ||
-                        mPlaybackSpeed <= -PLAYBACK_SPEED_FAST_L0;
+                boolean abortSeek = mPlaybackSpeed >= PLAYBACK_SPEED_FAST_L0
+                        || mPlaybackSpeed <= -PLAYBACK_SPEED_FAST_L0;
                 if (abortSeek) {
                     mPlaybackSpeed = PLAYBACK_SPEED_NORMAL;
                     startPlayback(mPlaybackSpeed);
@@ -465,14 +487,15 @@
                 return false;
         }
         Action action = mControlsRow.getActionForKeyCode(mPrimaryActionsAdapter, keyCode);
+
         if (action != null) {
-            if (action == mPrimaryActionsAdapter.lookup(ACTION_PLAY_PAUSE) ||
-                    action == mPrimaryActionsAdapter.lookup(ACTION_REWIND) ||
-                    action == mPrimaryActionsAdapter.lookup(ACTION_FAST_FORWARD) ||
-                    action == mPrimaryActionsAdapter.lookup(ACTION_SKIP_TO_PREVIOUS) ||
-                    action == mPrimaryActionsAdapter.lookup(ACTION_SKIP_TO_NEXT)) {
-                if (((KeyEvent) event).getAction() == KeyEvent.ACTION_DOWN) {
-                    dispatchAction(action, (KeyEvent) event);
+            if (action == mPrimaryActionsAdapter.lookup(ACTION_PLAY_PAUSE)
+                    || action == mPrimaryActionsAdapter.lookup(ACTION_REWIND)
+                    || action == mPrimaryActionsAdapter.lookup(ACTION_FAST_FORWARD)
+                    || action == mPrimaryActionsAdapter.lookup(ACTION_SKIP_TO_PREVIOUS)
+                    || action == mPrimaryActionsAdapter.lookup(ACTION_SKIP_TO_NEXT)) {
+                if (event.getAction() == KeyEvent.ACTION_DOWN) {
+                    dispatchAction(action, event);
                 }
                 return true;
             }
@@ -486,12 +509,12 @@
     boolean dispatchAction(Action action, KeyEvent keyEvent) {
         boolean handled = false;
         if (action == mPlayPauseAction) {
-            boolean canPlay = keyEvent == null ||
-                    keyEvent.getKeyCode() == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE ||
-                    keyEvent.getKeyCode() == KeyEvent.KEYCODE_MEDIA_PLAY;
-            boolean canPause = keyEvent == null ||
-                    keyEvent.getKeyCode() == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE ||
-                    keyEvent.getKeyCode() == KeyEvent.KEYCODE_MEDIA_PAUSE;
+            boolean canPlay = keyEvent == null
+                    || keyEvent.getKeyCode() == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE
+                    || keyEvent.getKeyCode() == KeyEvent.KEYCODE_MEDIA_PLAY;
+            boolean canPause = keyEvent == null
+                    || keyEvent.getKeyCode() == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE
+                    || keyEvent.getKeyCode() == KeyEvent.KEYCODE_MEDIA_PAUSE;
             //            PLAY_PAUSE    PLAY      PAUSE
             // playing    paused                  paused
             // paused     playing       playing
@@ -608,7 +631,7 @@
         final long actions = getSupportedActions();
         if ((actions & ACTION_SKIP_TO_PREVIOUS) != 0) {
             if (mSkipPreviousAction == null) {
-                mSkipPreviousAction = new PlaybackControlsRow.SkipPreviousAction(mContext);
+                mSkipPreviousAction = new PlaybackControlsRow.SkipPreviousAction(getContext());
             }
             mPrimaryActionsAdapter.set(ACTION_SKIP_TO_PREVIOUS, mSkipPreviousAction);
         } else {
@@ -617,7 +640,8 @@
         }
         if ((actions & ACTION_REWIND) != 0) {
             if (mRewindAction == null) {
-                mRewindAction = new PlaybackControlsRow.RewindAction(mContext,
+                mRewindAction = new PlaybackControlsRow.RewindAction(
+                        getContext(),
                         mRewindSpeeds.length);
             }
             mPrimaryActionsAdapter.set(ACTION_REWIND, mRewindAction);
@@ -627,7 +651,7 @@
         }
         if ((actions & ACTION_PLAY_PAUSE) != 0) {
             if (mPlayPauseAction == null) {
-                mPlayPauseAction = new PlaybackControlsRow.PlayPauseAction(mContext);
+                mPlayPauseAction = new PlaybackControlsRow.PlayPauseAction(getContext());
             }
             mPrimaryActionsAdapter.set(ACTION_PLAY_PAUSE, mPlayPauseAction);
         } else {
@@ -636,7 +660,8 @@
         }
         if ((actions & ACTION_FAST_FORWARD) != 0) {
             if (mFastForwardAction == null) {
-                mFastForwardAction = new PlaybackControlsRow.FastForwardAction(mContext,
+                mFastForwardAction = new PlaybackControlsRow.FastForwardAction(
+                        getContext(),
                         mFastForwardSpeeds.length);
             }
             mPrimaryActionsAdapter.set(ACTION_FAST_FORWARD, mFastForwardAction);
@@ -646,7 +671,7 @@
         }
         if ((actions & ACTION_SKIP_TO_NEXT) != 0) {
             if (mSkipNextAction == null) {
-                mSkipNextAction = new PlaybackControlsRow.SkipNextAction(mContext);
+                mSkipNextAction = new PlaybackControlsRow.SkipNextAction(getContext());
             }
             mPrimaryActionsAdapter.set(ACTION_SKIP_TO_NEXT, mSkipNextAction);
         } else {
@@ -682,14 +707,14 @@
             enableProgressUpdating(true);
         }
 
-        if (mFadeWhenPlaying && mFragment != null) {
-            mFragment.setFadingEnabled(playbackSpeed == PLAYBACK_SPEED_NORMAL);
+        if (mFadeWhenPlaying && mPlaybackGlueHost != null) {
+            mPlaybackGlueHost.setFadingEnabled(playbackSpeed == PLAYBACK_SPEED_NORMAL);
         }
 
         if (mPlayPauseAction != null) {
-            int index = playbackSpeed == PLAYBACK_SPEED_PAUSED ?
-                    PlaybackControlsRow.PlayPauseAction.PLAY :
-                    PlaybackControlsRow.PlayPauseAction.PAUSE;
+            int index = playbackSpeed == PLAYBACK_SPEED_PAUSED
+                    ? PlaybackControlsRow.PlayPauseAction.PLAY
+                    : PlaybackControlsRow.PlayPauseAction.PAUSE;
             if (mPlayPauseAction.getIndex() != index) {
                 mPlayPauseAction.setIndex(index);
                 notifyItemChanged(mPrimaryActionsAdapter, mPlayPauseAction);
@@ -853,4 +878,49 @@
         if (DEBUG) Log.v(TAG, "onMetadataChanged");
         updateRowMetadata();
     }
+
+    static final class PlaybackGlueHostOld extends PlaybackGlueHost {
+        final PlaybackOverlayFragment mFragment;
+        PlaybackControlGlue mGlue;
+
+        public PlaybackGlueHostOld(PlaybackOverlayFragment fragment) {
+            mFragment = fragment;
+        }
+
+        @Override
+        public void setFadingEnabled(boolean enable) {
+            mFragment.setFadingEnabled(enable);
+        }
+
+        @Override
+        public void setOnKeyInterceptListener(final View.OnKeyListener onKeyListenerr) {
+            mFragment.setEventHandler( new InputEventHandler() {
+                @Override
+                public boolean handleInputEvent(InputEvent event) {
+                    if (event instanceof KeyEvent) {
+                        KeyEvent keyEvent = (KeyEvent) event;
+                        return onKeyListenerr.onKey(null, keyEvent.getKeyCode(), keyEvent);
+                    }
+                    return false;
+                }
+            });
+        }
+
+        @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);
+                        }
+                    }
+                }
+            });
+        }
+    }
 }
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 1e1eab5..ec3cc1e 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/PlaybackControlSupportGlue.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/PlaybackControlSupportGlue.java
@@ -3,852 +3,103 @@
 package android.support.v17.leanback.app;
 
 import android.content.Context;
-import android.graphics.drawable.Drawable;
-import android.os.Handler;
-import android.os.Message;
-import android.support.v17.leanback.widget.AbstractDetailsDescriptionPresenter;
 import android.support.v17.leanback.widget.Action;
-import android.support.v17.leanback.widget.ControlButtonPresenterSelector;
 import android.support.v17.leanback.widget.OnActionClickedListener;
 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.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;
 import android.view.InputEvent;
 import android.view.KeyEvent;
 import android.view.View;
 
-
 /**
- * A helper class for managing a {@link android.support.v17.leanback.widget.PlaybackControlsRow} and
- * {@link PlaybackOverlaySupportFragment} that implements a recommended approach to handling standard
- * playback control actions such as play/pause, fast forward/rewind at progressive speed levels,
- * and skip to next/previous.  This helper class is a glue layer in that it manages the
- * configuration of and interaction between the leanback UI components by defining a functional
- * interface to the media player.
- *
- * <p>You can instantiate a concrete subclass such as {@link MediaControllerGlue} or you must
- * subclass this abstract helper.  To create a subclass you must implement all of the
- * abstract methods and the subclass must invoke {@link #onMetadataChanged()} and
- * {@link #onStateChanged()} appropriately.
- * </p>
- *
- * <p>To use an instance of the glue layer, first construct an instance.  Constructor parameters
- * inform the glue what speed levels are supported for fast forward/rewind.  Providing a
- * {@link android.support.v17.leanback.app.PlaybackOverlaySupportFragment} is optional.
- * </p>
- *
- * <p>If you have your own controls row you must pass it to {@link #setControlsRow}.
- * The row will be updated by the glue layer based on the media metadata and playback state.
- * Alternatively, you may call {@link #createControlsRowAndPresenter()} which will set a controls
- * row and return a row presenter you can use to present the row.
- * </p>
- *
- * <p>The helper sets a {@link android.support.v17.leanback.widget.SparseArrayObjectAdapter}
- * on the controls row as the primary actions adapter, and adds actions to it.  You can provide
- * additional actions by overriding {@link #createPrimaryActionsAdapter}.  This helper does not
- * deal in secondary actions so those you may add separately.
- * </p>
- *
- * <p>Provide a click listener on your fragment and if an action is clicked, call
- * {@link #onActionClicked}.  There is no need to call {@link #setOnItemViewClickedListener}
- * but if you do a click listener will be installed on the fragment and recognized action clicks
- * will be handled.  Your listener will be called only for unhandled actions.
- * </p>
- *
- * <p>The helper implements a key event handler.  If you pass a
- * {@link android.support.v17.leanback.app.PlaybackOverlaySupportFragment} the fragment's input event
- * handler will be set.  Otherwise, you should set the glue object as key event handler to the
- * ViewHolder when bound by your row presenter; see
- * {@link RowPresenter.ViewHolder#setOnKeyListener(android.view.View.OnKeyListener)}.
- * </p>
- *
- * <p>To update the controls row progress during playback, override {@link #enableProgressUpdating}
- * to manage the lifecycle of a periodic callback to {@link #updateProgress()}.
- * {@link #getUpdatePeriod()} provides a recommended update period.
- * </p>
- *
+ * @deprecated Use {@link PlaybackControlGlue} and {@link PlaybackSupportFragmentGlueHost} for
+ * {@link PlaybackSupportFragment}.
  */
-public abstract class PlaybackControlSupportGlue implements OnActionClickedListener, View.OnKeyListener {
-    /**
-     * The adapter key for the first custom control on the left side
-     * of the predefined primary controls.
-     */
-    public static final int ACTION_CUSTOM_LEFT_FIRST = 0x1;
+@Deprecated
+public abstract class PlaybackControlSupportGlue extends PlaybackControlGlue {
 
-    /**
-     * The adapter key for the skip to previous control.
-     */
-    public static final int ACTION_SKIP_TO_PREVIOUS = 0x10;
-
-    /**
-     * The adapter key for the rewind control.
-     */
-    public static final int ACTION_REWIND = 0x20;
-
-    /**
-     * The adapter key for the play/pause control.
-     */
-    public static final int ACTION_PLAY_PAUSE = 0x40;
-
-    /**
-     * The adapter key for the fast forward control.
-     */
-    public static final int ACTION_FAST_FORWARD = 0x80;
-
-    /**
-     * The adapter key for the skip to next control.
-     */
-    public static final int ACTION_SKIP_TO_NEXT = 0x100;
-
-    /**
-     * The adapter key for the first custom control on the right side
-     * of the predefined primary controls.
-     */
-    public static final int ACTION_CUSTOM_RIGHT_FIRST = 0x1000;
-
-    /**
-     * Invalid playback speed.
-     */
-    public static final int PLAYBACK_SPEED_INVALID = -1;
-
-    /**
-     * Speed representing playback state that is paused.
-     */
-    public static final int PLAYBACK_SPEED_PAUSED = 0;
-
-    /**
-     * Speed representing playback state that is playing normally.
-     */
-    public static final int PLAYBACK_SPEED_NORMAL = 1;
-
-    /**
-     * The initial (level 0) fast forward playback speed.
-     * The negative of this value is for rewind at the same speed.
-     */
-    public static final int PLAYBACK_SPEED_FAST_L0 = 10;
-
-    /**
-     * The level 1 fast forward playback speed.
-     * The negative of this value is for rewind at the same speed.
-     */
-    public static final int PLAYBACK_SPEED_FAST_L1 = 11;
-
-    /**
-     * The level 2 fast forward playback speed.
-     * The negative of this value is for rewind at the same speed.
-     */
-    public static final int PLAYBACK_SPEED_FAST_L2 = 12;
-
-    /**
-     * The level 3 fast forward playback speed.
-     * The negative of this value is for rewind at the same speed.
-     */
-    public static final int PLAYBACK_SPEED_FAST_L3 = 13;
-
-    /**
-     * The level 4 fast forward playback speed.
-     * The negative of this value is for rewind at the same speed.
-     */
-    public static final int PLAYBACK_SPEED_FAST_L4 = 14;
-
-    static final String TAG = "PlaybackControlSupportGlue";
-    static final boolean DEBUG = false;
-
-    static final int MSG_UPDATE_PLAYBACK_STATE = 100;
-    private static final int UPDATE_PLAYBACK_STATE_DELAY_MS = 2000;
-    private static final int NUMBER_OF_SEEK_SPEEDS = PLAYBACK_SPEED_FAST_L4 -
-            PLAYBACK_SPEED_FAST_L0 + 1;
-
-    private final PlaybackOverlaySupportFragment mFragment;
-    private final Context mContext;
-    private final int[] mFastForwardSpeeds;
-    private final int[] mRewindSpeeds;
-    private PlaybackControlsRow mControlsRow;
-    private SparseArrayObjectAdapter mPrimaryActionsAdapter;
-    private PlaybackControlsRow.PlayPauseAction mPlayPauseAction;
-    private PlaybackControlsRow.SkipNextAction mSkipNextAction;
-    private PlaybackControlsRow.SkipPreviousAction mSkipPreviousAction;
-    private PlaybackControlsRow.FastForwardAction mFastForwardAction;
-    private PlaybackControlsRow.RewindAction mRewindAction;
-    OnItemViewClickedListener mExternalOnItemViewClickedListener;
-    private int mPlaybackSpeed = PLAYBACK_SPEED_NORMAL;
-    private boolean mFadeWhenPlaying = true;
-
-    private final Handler mHandler = new Handler() {
-        @Override
-        public void handleMessage(Message msg) {
-            if (msg.what == MSG_UPDATE_PLAYBACK_STATE) {
-                updatePlaybackState();
-            }
-        }
-    };
-
-    private final OnItemViewClickedListener mOnItemViewClickedListener =
-            new OnItemViewClickedListener() {
-        @Override
-        public void onItemClicked(Presenter.ViewHolder viewHolder, Object object,
-                                  RowPresenter.ViewHolder viewHolder2, Row row) {
-            if (DEBUG) Log.v(TAG, "onItemClicked " + object);
-            boolean handled = false;
-            if (object instanceof Action) {
-                handled = dispatchAction((Action) object, null);
-            }
-            if (!handled && mExternalOnItemViewClickedListener != null) {
-                mExternalOnItemViewClickedListener.onItemClicked(viewHolder, object,
-                        viewHolder2, row);
-            }
-        }
-    };
-
-    /**
-     * Constructor for the glue.
-     *
-     * @param context
-     * @param seekSpeeds Array of seek speeds for fast forward and rewind.
-     */
     public PlaybackControlSupportGlue(Context context, int[] seekSpeeds) {
-        this(context, null, seekSpeeds, seekSpeeds);
+        super(context, seekSpeeds);
     }
 
-    /**
-     * Constructor for the glue.
-     *
-     * @param context
-     * @param fastForwardSpeeds Array of seek speeds for fast forward.
-     * @param rewindSpeeds Array of seek speeds for rewind.
-     */
-    public PlaybackControlSupportGlue(Context context,
-                               int[] fastForwardSpeeds,
-                               int[] rewindSpeeds) {
-        this(context, null, fastForwardSpeeds, rewindSpeeds);
+    public PlaybackControlSupportGlue(
+            Context context, int[] fastForwardSpeeds, int[] rewindSpeeds) {
+        super(context, fastForwardSpeeds, rewindSpeeds);
     }
 
-    /**
-     * Constructor for the glue.
-     *
-     * @param context
-     * @param fragment Optional; if using a {@link PlaybackOverlaySupportFragment}, pass it in.
-     * @param seekSpeeds Array of seek speeds for fast forward and rewind.
-     */
-    public PlaybackControlSupportGlue(Context context,
-                               PlaybackOverlaySupportFragment fragment,
-                               int[] seekSpeeds) {
-        this(context, fragment, seekSpeeds, seekSpeeds);
+    public PlaybackControlSupportGlue(
+            Context context,
+            PlaybackOverlaySupportFragment fragment,
+            int[] seekSpeeds) {
+        super(context,
+                fragment == null ? null: new PlaybackSupportGlueHostOld(fragment),
+                seekSpeeds,
+                seekSpeeds);
     }
 
-    /**
-     * Constructor for the glue.
-     *
-     * @param context
-     * @param fragment Optional; if using a {@link PlaybackOverlaySupportFragment}, pass it in.
-     * @param fastForwardSpeeds Array of seek speeds for fast forward.
-     * @param rewindSpeeds Array of seek speeds for rewind.
-     */
-    public PlaybackControlSupportGlue(Context context,
-                               PlaybackOverlaySupportFragment fragment,
-                               int[] fastForwardSpeeds,
-                               int[] rewindSpeeds) {
-        mContext = context;
-        mFragment = fragment;
-        if (fragment != null) {
-            attachToFragment();
+    public PlaybackControlSupportGlue(
+            Context context,
+            PlaybackOverlaySupportFragment fragment,
+            int[] fastForwardSpeeds,
+            int[] rewindSpeeds) {
+        super(context,
+                fragment == null ? null: new PlaybackSupportGlueHostOld(fragment),
+                fastForwardSpeeds,
+                rewindSpeeds);
+    }
+
+    @Override
+    public void setHost(PlaybackGlueHost host) {
+        super.setHost(host);
+        if (host instanceof PlaybackSupportGlueHostOld) {
+            ((PlaybackSupportGlueHostOld) host).mGlue = this;
         }
-        if (fastForwardSpeeds.length == 0 || fastForwardSpeeds.length > NUMBER_OF_SEEK_SPEEDS) {
-            throw new IllegalStateException("invalid fastForwardSpeeds array size");
-        }
-        mFastForwardSpeeds = fastForwardSpeeds;
-        if (rewindSpeeds.length == 0 || rewindSpeeds.length > NUMBER_OF_SEEK_SPEEDS) {
-            throw new IllegalStateException("invalid rewindSpeeds array size");
-        }
-        mRewindSpeeds = rewindSpeeds;
     }
 
-    private final PlaybackOverlaySupportFragment.InputEventHandler mOnInputEventHandler =
-            new PlaybackOverlaySupportFragment.InputEventHandler() {
+    static final class PlaybackSupportGlueHostOld extends PlaybackGlueHost {
+        final PlaybackOverlaySupportFragment mFragment;
+        PlaybackControlGlue mGlue;
+
+        public PlaybackSupportGlueHostOld(PlaybackOverlaySupportFragment fragment) {
+            mFragment = fragment;
+        }
+
         @Override
-        public boolean handleInputEvent(InputEvent event) {
-            if (event instanceof KeyEvent) {
-                KeyEvent keyEvent = (KeyEvent) event;
-                return onKey(null, keyEvent.getKeyCode(), keyEvent);
-            }
-            return false;
+        public void setFadingEnabled(boolean enable) {
+            mFragment.setFadingEnabled(enable);
         }
-    };
 
-    private void attachToFragment() {
-        mFragment.setInputEventHandler(mOnInputEventHandler);
-    }
-
-    /**
-     * Helper method for instantiating a
-     * {@link android.support.v17.leanback.widget.PlaybackControlsRow} and corresponding
-     * {@link android.support.v17.leanback.widget.PlaybackControlsRowPresenter}.
-     */
-    public PlaybackControlsRowPresenter createControlsRowAndPresenter() {
-        PlaybackControlsRow controlsRow = new PlaybackControlsRow(this);
-        setControlsRow(controlsRow);
-
-        AbstractDetailsDescriptionPresenter detailsPresenter =
-                new AbstractDetailsDescriptionPresenter() {
-            @Override
-            protected void onBindDescription(AbstractDetailsDescriptionPresenter.ViewHolder
-                                                     viewHolder, Object object) {
-                PlaybackControlSupportGlue glue = (PlaybackControlSupportGlue) object;
-                if (glue.hasValidMedia()) {
-                    viewHolder.getTitle().setText(glue.getMediaTitle());
-                    viewHolder.getSubtitle().setText(glue.getMediaSubtitle());
-                } else {
-                    viewHolder.getTitle().setText("");
-                    viewHolder.getSubtitle().setText("");
+        @Override
+        public void setOnKeyInterceptListener(final View.OnKeyListener onKeyListenerr) {
+            mFragment.setEventHandler( new InputEventHandler() {
+                @Override
+                public boolean handleInputEvent(InputEvent event) {
+                    if (event instanceof KeyEvent) {
+                        KeyEvent keyEvent = (KeyEvent) event;
+                        return onKeyListenerr.onKey(null, keyEvent.getKeyCode(), keyEvent);
+                    }
+                    return false;
                 }
-            }
-        };
-        return new PlaybackControlsRowPresenter(detailsPresenter) {
-            @Override
-            protected void onBindRowViewHolder(RowPresenter.ViewHolder vh, Object item) {
-                super.onBindRowViewHolder(vh, item);
-                vh.setOnKeyListener(PlaybackControlSupportGlue.this);
-            }
-            @Override
-            protected void onUnbindRowViewHolder(RowPresenter.ViewHolder vh) {
-                super.onUnbindRowViewHolder(vh);
-                vh.setOnKeyListener(null);
-            }
-        };
-    }
-
-    /**
-     * Returns the fragment.
-     */
-    public PlaybackOverlaySupportFragment getFragment() {
-        return mFragment;
-    }
-
-    /**
-     * Returns the context.
-     */
-    public Context getContext() {
-        return mContext;
-    }
-
-    /**
-     * Returns the fast forward speeds.
-     */
-    public int[] getFastForwardSpeeds() {
-        return mFastForwardSpeeds;
-    }
-
-    /**
-     * Returns the rewind speeds.
-     */
-    public int[] getRewindSpeeds() {
-        return mRewindSpeeds;
-    }
-
-    /**
-     * Sets the controls to fade after a timeout when media is playing.
-     */
-    public void setFadingEnabled(boolean enable) {
-        mFadeWhenPlaying = enable;
-        if (!mFadeWhenPlaying && mFragment != null) {
-            mFragment.setFadingEnabled(false);
+            });
         }
-    }
 
-    /**
-     * Returns true if controls are set to fade when media is playing.
-     */
-    public boolean isFadingEnabled() {
-        return mFadeWhenPlaying;
-    }
-
-    /**
-     * Set the {@link OnItemViewClickedListener} to be called if the click event
-     * is not handled internally.
-     * @param listener
-     * @deprecated Don't call this.  Instead set the listener on the fragment yourself,
-     * and call {@link #onActionClicked} to handle clicks.
-     */
-    @Deprecated
-    public void setOnItemViewClickedListener(OnItemViewClickedListener listener) {
-        mExternalOnItemViewClickedListener = listener;
-        if (mFragment != null) {
-            mFragment.setOnItemViewClickedListener(mOnItemViewClickedListener);
-        }
-    }
-
-    /**
-     * Returns the {@link OnItemViewClickedListener}.
-     */
-    public OnItemViewClickedListener getOnItemViewClickedListener() {
-        return mExternalOnItemViewClickedListener;
-    }
-
-    /**
-     * Sets the controls row to be managed by the glue layer.
-     * The primary actions and playback state related aspects of the row
-     * are updated by the glue.
-     */
-    public void setControlsRow(PlaybackControlsRow controlsRow) {
-        mControlsRow = controlsRow;
-        mPrimaryActionsAdapter = createPrimaryActionsAdapter(
-                new ControlButtonPresenterSelector());
-        mControlsRow.setPrimaryActionsAdapter(mPrimaryActionsAdapter);
-        updateControlsRow();
-    }
-
-    /**
-     * Returns the playback controls row managed by the glue layer.
-     */
-    public PlaybackControlsRow getControlsRow() {
-        return mControlsRow;
-    }
-
-    /**
-     * Override this to start/stop a runnable to call {@link #updateProgress} at
-     * an interval such as {@link #getUpdatePeriod}.
-     */
-    public void enableProgressUpdating(boolean enable) {
-    }
-
-    /**
-     * Returns the time period in milliseconds that should be used
-     * to update the progress.  See {@link #updateProgress()}.
-     */
-    public int getUpdatePeriod() {
-        // TODO: calculate a better update period based on total duration and screen size
-        return 500;
-    }
-
-    /**
-     * Updates the progress bar based on the current media playback position.
-     */
-    public void updateProgress() {
-        int position = getCurrentPosition();
-        if (DEBUG) Log.v(TAG, "updateProgress " + position);
-        mControlsRow.setCurrentTime(position);
-    }
-
-    /**
-     * Handles action clicks.  A subclass may override this add support for additional actions.
-     */
-    @Override
-    public void onActionClicked(Action action) {
-        dispatchAction(action, null);
-    }
-
-    /**
-     * Handles key events and returns true if handled.  A subclass may override this to provide
-     * additional support.
-     */
-    @Override
-    public boolean onKey(View v, int keyCode, KeyEvent event) {
-        switch (keyCode) {
-            case KeyEvent.KEYCODE_DPAD_UP:
-            case KeyEvent.KEYCODE_DPAD_DOWN:
-            case KeyEvent.KEYCODE_DPAD_RIGHT:
-            case KeyEvent.KEYCODE_DPAD_LEFT:
-            case KeyEvent.KEYCODE_BACK:
-            case KeyEvent.KEYCODE_ESCAPE:
-                boolean abortSeek = mPlaybackSpeed >= PLAYBACK_SPEED_FAST_L0 ||
-                        mPlaybackSpeed <= -PLAYBACK_SPEED_FAST_L0;
-                if (abortSeek) {
-                    mPlaybackSpeed = PLAYBACK_SPEED_NORMAL;
-                    startPlayback(mPlaybackSpeed);
-                    updatePlaybackStatusAfterUserAction();
-                    return keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_ESCAPE;
+        @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);
+                        }
+                    }
                 }
-                return false;
+            });
         }
-        Action action = mControlsRow.getActionForKeyCode(mPrimaryActionsAdapter, keyCode);
-        if (action != null) {
-            if (action == mPrimaryActionsAdapter.lookup(ACTION_PLAY_PAUSE) ||
-                    action == mPrimaryActionsAdapter.lookup(ACTION_REWIND) ||
-                    action == mPrimaryActionsAdapter.lookup(ACTION_FAST_FORWARD) ||
-                    action == mPrimaryActionsAdapter.lookup(ACTION_SKIP_TO_PREVIOUS) ||
-                    action == mPrimaryActionsAdapter.lookup(ACTION_SKIP_TO_NEXT)) {
-                if (((KeyEvent) event).getAction() == KeyEvent.ACTION_DOWN) {
-                    dispatchAction(action, (KeyEvent) event);
-                }
-                return true;
-            }
-        }
-        return false;
-    }
-
-    /**
-     * Called when the given action is invoked, either by click or keyevent.
-     */
-    boolean dispatchAction(Action action, KeyEvent keyEvent) {
-        boolean handled = false;
-        if (action == mPlayPauseAction) {
-            boolean canPlay = keyEvent == null ||
-                    keyEvent.getKeyCode() == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE ||
-                    keyEvent.getKeyCode() == KeyEvent.KEYCODE_MEDIA_PLAY;
-            boolean canPause = keyEvent == null ||
-                    keyEvent.getKeyCode() == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE ||
-                    keyEvent.getKeyCode() == KeyEvent.KEYCODE_MEDIA_PAUSE;
-            if (mPlaybackSpeed != PLAYBACK_SPEED_NORMAL) {
-                if (canPlay) {
-                    mPlaybackSpeed = PLAYBACK_SPEED_NORMAL;
-                    startPlayback(mPlaybackSpeed);
-                }
-            } else if (canPause) {
-                mPlaybackSpeed = PLAYBACK_SPEED_PAUSED;
-                pausePlayback();
-            }
-            updatePlaybackStatusAfterUserAction();
-            handled = true;
-        } else if (action == mSkipNextAction) {
-            skipToNext();
-            handled = true;
-        } else if (action == mSkipPreviousAction) {
-            skipToPrevious();
-            handled = true;
-        } else if (action == mFastForwardAction) {
-            if (mPlaybackSpeed < getMaxForwardSpeedId()) {
-                switch (mPlaybackSpeed) {
-                    case PLAYBACK_SPEED_FAST_L0:
-                    case PLAYBACK_SPEED_FAST_L1:
-                    case PLAYBACK_SPEED_FAST_L2:
-                    case PLAYBACK_SPEED_FAST_L3:
-                        mPlaybackSpeed++;
-                        break;
-                    default:
-                        mPlaybackSpeed = PLAYBACK_SPEED_FAST_L0;
-                        break;
-                }
-                startPlayback(mPlaybackSpeed);
-                updatePlaybackStatusAfterUserAction();
-            }
-            handled = true;
-        } else if (action == mRewindAction) {
-            if (mPlaybackSpeed > -getMaxRewindSpeedId()) {
-                switch (mPlaybackSpeed) {
-                    case -PLAYBACK_SPEED_FAST_L0:
-                    case -PLAYBACK_SPEED_FAST_L1:
-                    case -PLAYBACK_SPEED_FAST_L2:
-                    case -PLAYBACK_SPEED_FAST_L3:
-                        mPlaybackSpeed--;
-                        break;
-                    default:
-                        mPlaybackSpeed = -PLAYBACK_SPEED_FAST_L0;
-                        break;
-                }
-                startPlayback(mPlaybackSpeed);
-                updatePlaybackStatusAfterUserAction();
-            }
-            handled = true;
-        }
-        return handled;
-    }
-
-    private int getMaxForwardSpeedId() {
-        return PLAYBACK_SPEED_FAST_L0 + (mFastForwardSpeeds.length - 1);
-    }
-
-    private int getMaxRewindSpeedId() {
-        return PLAYBACK_SPEED_FAST_L0 + (mRewindSpeeds.length - 1);
-    }
-
-    private void updateControlsRow() {
-        updateRowMetadata();
-        mHandler.removeMessages(MSG_UPDATE_PLAYBACK_STATE);
-        updatePlaybackState();
-    }
-
-    private void updatePlaybackStatusAfterUserAction() {
-        updatePlaybackState(mPlaybackSpeed);
-        // Sync playback state after a delay
-        mHandler.removeMessages(MSG_UPDATE_PLAYBACK_STATE);
-        mHandler.sendEmptyMessageDelayed(MSG_UPDATE_PLAYBACK_STATE,
-                UPDATE_PLAYBACK_STATE_DELAY_MS);
-    }
-
-    private void updateRowMetadata() {
-        if (mControlsRow == null) {
-            return;
-        }
-
-        if (DEBUG) Log.v(TAG, "updateRowMetadata hasValidMedia " + hasValidMedia());
-
-        if (!hasValidMedia()) {
-            mControlsRow.setImageDrawable(null);
-            mControlsRow.setTotalTime(0);
-            mControlsRow.setCurrentTime(0);
-        } else {
-            mControlsRow.setImageDrawable(getMediaArt());
-            mControlsRow.setTotalTime(getMediaDuration());
-            mControlsRow.setCurrentTime(getCurrentPosition());
-        }
-
-        onRowChanged(mControlsRow);
-    }
-
-    void updatePlaybackState() {
-        if (hasValidMedia()) {
-            mPlaybackSpeed = getCurrentSpeedId();
-            updatePlaybackState(mPlaybackSpeed);
-        }
-    }
-
-    private void updatePlaybackState(int playbackSpeed) {
-        if (mControlsRow == null) {
-            return;
-        }
-
-        final long actions = getSupportedActions();
-        if ((actions & ACTION_SKIP_TO_PREVIOUS) != 0) {
-            if (mSkipPreviousAction == null) {
-                mSkipPreviousAction = new PlaybackControlsRow.SkipPreviousAction(mContext);
-            }
-            mPrimaryActionsAdapter.set(ACTION_SKIP_TO_PREVIOUS, mSkipPreviousAction);
-        } else {
-            mPrimaryActionsAdapter.clear(ACTION_SKIP_TO_PREVIOUS);
-            mSkipPreviousAction = null;
-        }
-        if ((actions & ACTION_REWIND) != 0) {
-            if (mRewindAction == null) {
-                mRewindAction = new PlaybackControlsRow.RewindAction(mContext,
-                        mRewindSpeeds.length);
-            }
-            mPrimaryActionsAdapter.set(ACTION_REWIND, mRewindAction);
-        } else {
-            mPrimaryActionsAdapter.clear(ACTION_REWIND);
-            mRewindAction = null;
-        }
-        if ((actions & ACTION_PLAY_PAUSE) != 0) {
-            if (mPlayPauseAction == null) {
-                mPlayPauseAction = new PlaybackControlsRow.PlayPauseAction(mContext);
-            }
-            mPrimaryActionsAdapter.set(ACTION_PLAY_PAUSE, mPlayPauseAction);
-        } else {
-            mPrimaryActionsAdapter.clear(ACTION_PLAY_PAUSE);
-            mPlayPauseAction = null;
-        }
-        if ((actions & ACTION_FAST_FORWARD) != 0) {
-            if (mFastForwardAction == null) {
-                mFastForwardAction = new PlaybackControlsRow.FastForwardAction(mContext,
-                        mFastForwardSpeeds.length);
-            }
-            mPrimaryActionsAdapter.set(ACTION_FAST_FORWARD, mFastForwardAction);
-        } else {
-            mPrimaryActionsAdapter.clear(ACTION_FAST_FORWARD);
-            mFastForwardAction = null;
-        }
-        if ((actions & ACTION_SKIP_TO_NEXT) != 0) {
-            if (mSkipNextAction == null) {
-                mSkipNextAction = new PlaybackControlsRow.SkipNextAction(mContext);
-            }
-            mPrimaryActionsAdapter.set(ACTION_SKIP_TO_NEXT, mSkipNextAction);
-        } else {
-            mPrimaryActionsAdapter.clear(ACTION_SKIP_TO_NEXT);
-            mSkipNextAction = null;
-        }
-
-        if (mFastForwardAction != null) {
-            int index = 0;
-            if (playbackSpeed >= PLAYBACK_SPEED_FAST_L0) {
-                index = playbackSpeed - PLAYBACK_SPEED_FAST_L0 + 1;
-            }
-            if (mFastForwardAction.getIndex() != index) {
-                mFastForwardAction.setIndex(index);
-                notifyItemChanged(mPrimaryActionsAdapter, mFastForwardAction);
-            }
-        }
-        if (mRewindAction != null) {
-            int index = 0;
-            if (playbackSpeed <= -PLAYBACK_SPEED_FAST_L0) {
-                index = -playbackSpeed - PLAYBACK_SPEED_FAST_L0 + 1;
-            }
-            if (mRewindAction.getIndex() != index) {
-                mRewindAction.setIndex(index);
-                notifyItemChanged(mPrimaryActionsAdapter, mRewindAction);
-            }
-        }
-
-        if (playbackSpeed == PLAYBACK_SPEED_PAUSED) {
-            updateProgress();
-            enableProgressUpdating(false);
-        } else {
-            enableProgressUpdating(true);
-        }
-
-        if (mFadeWhenPlaying && mFragment != null) {
-            mFragment.setFadingEnabled(playbackSpeed == PLAYBACK_SPEED_NORMAL);
-        }
-
-        if (mPlayPauseAction != null) {
-            int index = playbackSpeed == PLAYBACK_SPEED_PAUSED ?
-                    PlaybackControlsRow.PlayPauseAction.PLAY :
-                    PlaybackControlsRow.PlayPauseAction.PAUSE;
-            if (mPlayPauseAction.getIndex() != index) {
-                mPlayPauseAction.setIndex(index);
-                notifyItemChanged(mPrimaryActionsAdapter, mPlayPauseAction);
-            }
-        }
-    }
-
-    private static void notifyItemChanged(SparseArrayObjectAdapter adapter, Object object) {
-        int index = adapter.indexOf(object);
-        if (index >= 0) {
-            adapter.notifyArrayItemRangeChanged(index, 1);
-        }
-    }
-
-    private static String getSpeedString(int speed) {
-        switch (speed) {
-            case PLAYBACK_SPEED_INVALID:
-                return "PLAYBACK_SPEED_INVALID";
-            case PLAYBACK_SPEED_PAUSED:
-                return "PLAYBACK_SPEED_PAUSED";
-            case PLAYBACK_SPEED_NORMAL:
-                return "PLAYBACK_SPEED_NORMAL";
-            case PLAYBACK_SPEED_FAST_L0:
-                return "PLAYBACK_SPEED_FAST_L0";
-            case PLAYBACK_SPEED_FAST_L1:
-                return "PLAYBACK_SPEED_FAST_L1";
-            case PLAYBACK_SPEED_FAST_L2:
-                return "PLAYBACK_SPEED_FAST_L2";
-            case PLAYBACK_SPEED_FAST_L3:
-                return "PLAYBACK_SPEED_FAST_L3";
-            case PLAYBACK_SPEED_FAST_L4:
-                return "PLAYBACK_SPEED_FAST_L4";
-            case -PLAYBACK_SPEED_FAST_L0:
-                return "-PLAYBACK_SPEED_FAST_L0";
-            case -PLAYBACK_SPEED_FAST_L1:
-                return "-PLAYBACK_SPEED_FAST_L1";
-            case -PLAYBACK_SPEED_FAST_L2:
-                return "-PLAYBACK_SPEED_FAST_L2";
-            case -PLAYBACK_SPEED_FAST_L3:
-                return "-PLAYBACK_SPEED_FAST_L3";
-            case -PLAYBACK_SPEED_FAST_L4:
-                return "-PLAYBACK_SPEED_FAST_L4";
-        }
-        return null;
-    }
-
-    /**
-     * Returns true if there is a valid media item.
-     */
-    public abstract boolean hasValidMedia();
-
-    /**
-     * Returns true if media is currently playing.
-     */
-    public abstract boolean isMediaPlaying();
-
-    /**
-     * Returns the title of the media item.
-     */
-    public abstract CharSequence getMediaTitle();
-
-    /**
-     * Returns the subtitle of the media item.
-     */
-    public abstract CharSequence getMediaSubtitle();
-
-    /**
-     * Returns the duration of the media item in milliseconds.
-     */
-    public abstract int getMediaDuration();
-
-    /**
-     * Returns a bitmap of the art for the media item.
-     */
-    public abstract Drawable getMediaArt();
-
-    /**
-     * Returns a bitmask of actions supported by the media player.
-     */
-    public abstract long getSupportedActions();
-
-    /**
-     * Returns the current playback speed.  When playing normally,
-     * {@link #PLAYBACK_SPEED_NORMAL} should be returned.
-     */
-    public abstract int getCurrentSpeedId();
-
-    /**
-     * Returns the current position of the media item in milliseconds.
-     */
-    public abstract int getCurrentPosition();
-
-    /**
-     * Start playback at the given speed.
-     * @param speed The desired playback speed.  For normal playback this will be
-     *              {@link #PLAYBACK_SPEED_NORMAL}; higher positive values for fast forward,
-     *              and negative values for rewind.
-     */
-    protected abstract void startPlayback(int speed);
-
-    /**
-     * Pause playback.
-     */
-    protected abstract void pausePlayback();
-
-    /**
-     * Skip to the next track.
-     */
-    protected abstract void skipToNext();
-
-    /**
-     * Skip to the previous track.
-     */
-    protected abstract void skipToPrevious();
-
-    /**
-     * Invoked when the playback controls row has changed.  The adapter containing this row
-     * should be notified.
-     */
-    protected abstract void onRowChanged(PlaybackControlsRow row);
-
-    /**
-     * Creates the primary action adapter.  May be overridden to add additional primary
-     * actions to the adapter.
-     */
-    protected SparseArrayObjectAdapter createPrimaryActionsAdapter(
-            PresenterSelector presenterSelector) {
-        return new SparseArrayObjectAdapter(presenterSelector);
-    }
-
-    /**
-     * Must be called appropriately by a subclass when the playback state has changed.
-     * It updates the playback state displayed on the media player.
-     */
-    protected void onStateChanged() {
-        if (DEBUG) Log.v(TAG, "onStateChanged");
-        // If a pending control button update is present, delay
-        // the update until the state settles.
-        if (!hasValidMedia()) {
-            return;
-        }
-        if (mHandler.hasMessages(MSG_UPDATE_PLAYBACK_STATE)) {
-            mHandler.removeMessages(MSG_UPDATE_PLAYBACK_STATE);
-            if (getCurrentSpeedId() != mPlaybackSpeed) {
-                if (DEBUG) Log.v(TAG, "Status expectation mismatch, delaying update");
-                mHandler.sendEmptyMessageDelayed(MSG_UPDATE_PLAYBACK_STATE,
-                        UPDATE_PLAYBACK_STATE_DELAY_MS);
-            } else {
-                if (DEBUG) Log.v(TAG, "Update state matches expectation");
-                updatePlaybackState();
-            }
-        } else {
-            updatePlaybackState();
-        }
-    }
-
-    /**
-     * Must be called appropriately by a subclass when the metadata state has changed.
-     */
-    protected void onMetadataChanged() {
-        if (DEBUG) Log.v(TAG, "onMetadataChanged");
-        updateRowMetadata();
     }
 }
diff --git a/v17/leanback/src/android/support/v17/leanback/app/PlaybackFragment.java b/v17/leanback/src/android/support/v17/leanback/app/PlaybackFragment.java
new file mode 100644
index 0000000..170ccf8
--- /dev/null
+++ b/v17/leanback/src/android/support/v17/leanback/app/PlaybackFragment.java
@@ -0,0 +1,797 @@
+/*
+ * 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 android.support.v17.leanback.app;
+
+import android.animation.Animator;
+import android.animation.AnimatorInflater;
+import android.animation.TimeInterpolator;
+import android.animation.ValueAnimator;
+import android.animation.ValueAnimator.AnimatorUpdateListener;
+import android.app.Fragment;
+import android.content.Context;
+import android.graphics.Color;
+import android.graphics.drawable.ColorDrawable;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.support.v17.leanback.R;
+import android.support.v17.leanback.animation.LogAccelerateInterpolator;
+import android.support.v17.leanback.animation.LogDecelerateInterpolator;
+import android.support.v17.leanback.widget.BaseOnItemViewClickedListener;
+import android.support.v17.leanback.widget.ItemBridgeAdapter;
+import android.support.v17.leanback.widget.ObjectAdapter;
+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.RowPresenter;
+import android.support.v17.leanback.widget.VerticalGridView;
+import android.support.v7.widget.RecyclerView;
+import android.util.Log;
+import android.view.InputEvent;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.animation.AccelerateInterpolator;
+
+import java.util.ArrayList;
+
+/**
+ * A fragment for displaying playback controls and related content.
+ * <p>
+ * A PlaybackFragment renders the elements of its {@link ObjectAdapter} as a set
+ * of rows in a vertical list.  The Adapter's {@link PresenterSelector} must maintain subclasses
+ * of {@link RowPresenter}.
+ * </p>
+ * <p>
+ * An instance of {@link android.support.v17.leanback.widget.PlaybackControlsRow} is expected to be
+ * at position 0 in the adapter.
+ * </p>
+ */
+public class PlaybackFragment extends Fragment {
+    /**
+     * No background.
+     */
+    public static final int BG_NONE = 0;
+
+    /**
+     * A dark translucent background.
+     */
+    public static final int BG_DARK = 1;
+
+    private class SetSelectionRunnable implements Runnable {
+        int mPosition;
+        boolean mSmooth = true;
+
+        @Override
+        public void run() {
+            if (mRowsFragment == null) {
+                return;
+            }
+            mRowsFragment.setSelectedPosition(mPosition, mSmooth);
+        }
+    }
+
+    /**
+     * A light translucent background.
+     */
+    public static final int BG_LIGHT = 2;
+    private RowsFragment mRowsFragment;
+    private ObjectAdapter mAdapter;
+    private BaseOnItemViewClickedListener mExternalItemClickedListener;
+    private BaseOnItemViewClickedListener mPlaybackItemClickedListener;
+    private BaseOnItemViewClickedListener mOnItemViewClickedListener = new BaseOnItemViewClickedListener() {
+        @Override
+        public void onItemClicked(Presenter.ViewHolder itemViewHolder,
+                                  Object item,
+                                  RowPresenter.ViewHolder rowViewHolder,
+                                  Object row) {
+            if (mPlaybackItemClickedListener != null
+                    && rowViewHolder instanceof PlaybackRowPresenter.ViewHolder) {
+                mPlaybackItemClickedListener.onItemClicked(
+                        itemViewHolder, item, rowViewHolder, row);
+            }
+            if (mExternalItemClickedListener != null) {
+                mExternalItemClickedListener.onItemClicked(
+                        itemViewHolder, item, rowViewHolder, row);
+            }
+        }
+    };
+    private final SetSelectionRunnable mSetSelectionRunnable = new SetSelectionRunnable();
+
+    public ObjectAdapter getAdapter() {
+        return mAdapter;
+    }
+
+    /**
+     * Listener allowing the application to receive notification of fade in and/or fade out
+     * completion events.
+     */
+    public static class OnFadeCompleteListener {
+        public void onFadeInComplete() {
+        }
+
+        public void onFadeOutComplete() {
+        }
+    }
+
+    private static final String TAG = "PlaybackFragment";
+    private static final boolean DEBUG = false;
+    private static final int ANIMATION_MULTIPLIER = 1;
+
+    private static int START_FADE_OUT = 1;
+
+    // Fading status
+    private static final int IDLE = 0;
+    private static final int IN = 1;
+    private static final int OUT = 2;
+
+    private int mPaddingTop;
+    private int mPaddingBottom;
+    private View mRootView;
+    private int mBackgroundType = BG_DARK;
+    private int mBgDarkColor;
+    private int mBgLightColor;
+    private int mShowTimeMs;
+    private int mMajorFadeTranslateY, mMinorFadeTranslateY;
+    private int mAnimationTranslateY;
+    private OnFadeCompleteListener mFadeCompleteListener;
+    private View.OnKeyListener mInputEventHandler;
+    private boolean mFadingEnabled = true;
+    private int mFadingStatus = IDLE;
+    private int mBgAlpha;
+    private ValueAnimator mBgFadeInAnimator, mBgFadeOutAnimator;
+    private ValueAnimator mControlRowFadeInAnimator, mControlRowFadeOutAnimator;
+    private ValueAnimator mOtherRowFadeInAnimator, mOtherRowFadeOutAnimator;
+
+    private final Animator.AnimatorListener mFadeListener =
+            new Animator.AnimatorListener() {
+                @Override
+                public void onAnimationStart(Animator animation) {
+                    enableVerticalGridAnimations(false);
+                }
+
+                @Override
+                public void onAnimationRepeat(Animator animation) {
+                }
+
+                @Override
+                public void onAnimationCancel(Animator animation) {
+                }
+
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    if (DEBUG) Log.v(TAG, "onAnimationEnd " + mBgAlpha);
+                    if (mBgAlpha > 0) {
+                        enableVerticalGridAnimations(true);
+                        startFadeTimer();
+                        if (mFadeCompleteListener != null) {
+                            mFadeCompleteListener.onFadeInComplete();
+                        }
+                    } else {
+                        VerticalGridView verticalView = getVerticalGridView();
+                        // reset focus to the primary actions only if the selected row was the controls row
+                        if (verticalView != null && verticalView.getSelectedPosition() == 0) {
+                            ItemBridgeAdapter.ViewHolder vh = (ItemBridgeAdapter.ViewHolder)
+                                    verticalView.findViewHolderForAdapterPosition(0);
+                            if (vh != null && vh.getPresenter() instanceof PlaybackRowPresenter) {
+                                ((PlaybackRowPresenter)vh.getPresenter()).onReappear(
+                                        (RowPresenter.ViewHolder) vh.getViewHolder());
+                            }
+                        }
+                        if (mFadeCompleteListener != null) {
+                            mFadeCompleteListener.onFadeOutComplete();
+                        }
+                    }
+                    mFadingStatus = IDLE;
+                }
+            };
+
+    private VerticalGridView getVerticalGridView() {
+        if (mRowsFragment == null) {
+            return null;
+        }
+        return mRowsFragment.getVerticalGridView();
+    }
+
+    private final Handler mHandler = new Handler() {
+        @Override
+        public void handleMessage(Message message) {
+            if (message.what == START_FADE_OUT && mFadingEnabled) {
+                fade(false);
+            }
+        }
+    };
+
+    private final VerticalGridView.OnTouchInterceptListener mOnTouchInterceptListener =
+            new VerticalGridView.OnTouchInterceptListener() {
+                @Override
+                public boolean onInterceptTouchEvent(MotionEvent event) {
+                    return onInterceptInputEvent(event);
+                }
+            };
+
+    private final VerticalGridView.OnKeyInterceptListener mOnKeyInterceptListener =
+            new VerticalGridView.OnKeyInterceptListener() {
+                @Override
+                public boolean onInterceptKeyEvent(KeyEvent event) {
+                    return onInterceptInputEvent(event);
+                }
+            };
+
+    private void setBgAlpha(int alpha) {
+        mBgAlpha = alpha;
+        if (mRootView != null) {
+            mRootView.getBackground().setAlpha(alpha);
+        }
+    }
+
+    private void enableVerticalGridAnimations(boolean enable) {
+        if (getVerticalGridView() != null) {
+            getVerticalGridView().setAnimateChildLayout(enable);
+        }
+    }
+
+    /**
+     * Enables or disables view fading.  If enabled,
+     * the view will be faded in when the fragment starts,
+     * and will fade out after a time period.  The timeout
+     * period is reset each time {@link #tickle} is called.
+     */
+    public void setFadingEnabled(boolean enabled) {
+        if (DEBUG) Log.v(TAG, "setFadingEnabled " + enabled);
+        if (enabled != mFadingEnabled) {
+            mFadingEnabled = enabled;
+            if (mFadingEnabled) {
+                if (isResumed() && mFadingStatus == IDLE
+                        && !mHandler.hasMessages(START_FADE_OUT)) {
+                    startFadeTimer();
+                }
+            } else {
+                // Ensure fully opaque
+                mHandler.removeMessages(START_FADE_OUT);
+                fade(true);
+            }
+        }
+    }
+
+    /**
+     * Returns true if view fading is enabled.
+     */
+    public boolean isFadingEnabled() {
+        return mFadingEnabled;
+    }
+
+    /**
+     * Sets the listener to be called when fade in or out has completed.
+     */
+    public void setFadeCompleteListener(OnFadeCompleteListener listener) {
+        mFadeCompleteListener = listener;
+    }
+
+    /**
+     * Returns the listener to be called when fade in or out has completed.
+     */
+    public OnFadeCompleteListener getFadeCompleteListener() {
+        return mFadeCompleteListener;
+    }
+
+    /**
+     * Sets the input event handler.
+     */
+    public final void setOnKeyInterceptListener(View.OnKeyListener handler) {
+        mInputEventHandler = handler;
+    }
+
+    /**
+     * Returns the input event handler.
+     */
+    public final View.OnKeyListener getEventHandler() {
+        return mInputEventHandler;
+    }
+
+    /**
+     * Tickles the playback controls.  Fades in the view if it was faded out,
+     * otherwise resets the fade out timer.  Tickling on input events is handled
+     * by the fragment.
+     */
+    public void tickle() {
+        if (DEBUG) Log.v(TAG, "tickle enabled " + mFadingEnabled + " isResumed " + isResumed());
+        if (!mFadingEnabled || !isResumed()) {
+            return;
+        }
+        if (mHandler.hasMessages(START_FADE_OUT)) {
+            // Restart the timer
+            startFadeTimer();
+        } else {
+            fade(true);
+        }
+    }
+
+    /**
+     * Fades out the playback overlay immediately.
+     */
+    public void fadeOut() {
+        mHandler.removeMessages(START_FADE_OUT);
+        fade(false);
+    }
+
+    private boolean areControlsHidden() {
+        return mFadingStatus == IDLE && mBgAlpha == 0;
+    }
+
+    private boolean onInterceptInputEvent(InputEvent event) {
+        final boolean controlsHidden = areControlsHidden();
+        if (DEBUG) Log.v(TAG, "onInterceptInputEvent hidden " + controlsHidden + " " + event);
+        boolean consumeEvent = false;
+        int keyCode = KeyEvent.KEYCODE_UNKNOWN;
+
+        if (event instanceof KeyEvent) {
+            keyCode = ((KeyEvent) event).getKeyCode();
+            if (mInputEventHandler != null) {
+                consumeEvent = mInputEventHandler.onKey(getView(), keyCode, (KeyEvent)event);
+            }
+        }
+
+        switch (keyCode) {
+            case KeyEvent.KEYCODE_DPAD_CENTER:
+            case KeyEvent.KEYCODE_DPAD_DOWN:
+            case KeyEvent.KEYCODE_DPAD_UP:
+            case KeyEvent.KEYCODE_DPAD_LEFT:
+            case KeyEvent.KEYCODE_DPAD_RIGHT:
+                // Event may be consumed; regardless, if controls are hidden then these keys will
+                // bring up the controls.
+                if (controlsHidden) {
+                    consumeEvent = true;
+                }
+                tickle();
+                break;
+            case KeyEvent.KEYCODE_BACK:
+            case KeyEvent.KEYCODE_ESCAPE:
+                // If fading enabled and controls are not hidden, back will be consumed to fade
+                // them out (even if the key was consumed by the handler).
+                if (mFadingEnabled && !controlsHidden) {
+                    consumeEvent = true;
+                    mHandler.removeMessages(START_FADE_OUT);
+                    fade(false);
+                } else if (consumeEvent) {
+                    tickle();
+                }
+                break;
+            default:
+                if (consumeEvent) {
+                    tickle();
+                }
+        }
+        return consumeEvent;
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+        if (mFadingEnabled) {
+            setBgAlpha(0);
+            fade(true);
+        }
+        getVerticalGridView().setOnTouchInterceptListener(mOnTouchInterceptListener);
+        getVerticalGridView().setOnKeyInterceptListener(mOnKeyInterceptListener);
+    }
+
+    private void startFadeTimer() {
+        if (mHandler != null) {
+            mHandler.removeMessages(START_FADE_OUT);
+            mHandler.sendEmptyMessageDelayed(START_FADE_OUT, mShowTimeMs);
+        }
+    }
+
+    private static ValueAnimator loadAnimator(Context context, int resId) {
+        ValueAnimator animator = (ValueAnimator) AnimatorInflater.loadAnimator(context, resId);
+        animator.setDuration(animator.getDuration() * ANIMATION_MULTIPLIER);
+        return animator;
+    }
+
+    private void loadBgAnimator() {
+        AnimatorUpdateListener listener = new AnimatorUpdateListener() {
+            @Override
+            public void onAnimationUpdate(ValueAnimator arg0) {
+                setBgAlpha((Integer) arg0.getAnimatedValue());
+            }
+        };
+
+        mBgFadeInAnimator = loadAnimator(getActivity(), R.animator.lb_playback_bg_fade_in);
+        mBgFadeInAnimator.addUpdateListener(listener);
+        mBgFadeInAnimator.addListener(mFadeListener);
+
+        mBgFadeOutAnimator = loadAnimator(getActivity(), R.animator.lb_playback_bg_fade_out);
+        mBgFadeOutAnimator.addUpdateListener(listener);
+        mBgFadeOutAnimator.addListener(mFadeListener);
+    }
+
+    private TimeInterpolator mLogDecelerateInterpolator = new LogDecelerateInterpolator(100, 0);
+    private TimeInterpolator mLogAccelerateInterpolator = new LogAccelerateInterpolator(100, 0);
+
+    private View getControlRowView() {
+        if (getVerticalGridView() == null) {
+            return null;
+        }
+        RecyclerView.ViewHolder vh = getVerticalGridView().findViewHolderForPosition(0);
+        if (vh == null) {
+            return null;
+        }
+        return vh.itemView;
+    }
+
+    private void loadControlRowAnimator() {
+        final AnimatorListener listener = new AnimatorListener() {
+            @Override
+            void getViews(ArrayList<View> views) {
+                View view = getControlRowView();
+                if (view != null) {
+                    views.add(view);
+                }
+            }
+        };
+        final AnimatorUpdateListener updateListener = new AnimatorUpdateListener() {
+            @Override
+            public void onAnimationUpdate(ValueAnimator arg0) {
+                View view = getControlRowView();
+                if (view != null) {
+                    final float fraction = (Float) arg0.getAnimatedValue();
+                    if (DEBUG) Log.v(TAG, "fraction " + fraction);
+                    view.setAlpha(fraction);
+                    view.setTranslationY((float) mAnimationTranslateY * (1f - fraction));
+                }
+            }
+        };
+
+        mControlRowFadeInAnimator = loadAnimator(
+                getActivity(), R.animator.lb_playback_controls_fade_in);
+        mControlRowFadeInAnimator.addUpdateListener(updateListener);
+        mControlRowFadeInAnimator.addListener(listener);
+        mControlRowFadeInAnimator.setInterpolator(mLogDecelerateInterpolator);
+
+        mControlRowFadeOutAnimator = loadAnimator(
+                getActivity(), R.animator.lb_playback_controls_fade_out);
+        mControlRowFadeOutAnimator.addUpdateListener(updateListener);
+        mControlRowFadeOutAnimator.addListener(listener);
+        mControlRowFadeOutAnimator.setInterpolator(mLogAccelerateInterpolator);
+    }
+
+    private void loadOtherRowAnimator() {
+        final AnimatorListener listener = new AnimatorListener() {
+            @Override
+            void getViews(ArrayList<View> views) {
+                if (getVerticalGridView() == null) {
+                    return;
+                }
+                final int count = getVerticalGridView().getChildCount();
+                for (int i = 0; i < count; i++) {
+                    View view = getVerticalGridView().getChildAt(i);
+                    if (view != null) {
+                        views.add(view);
+                    }
+                }
+            }
+        };
+        final AnimatorUpdateListener updateListener = new AnimatorUpdateListener() {
+            @Override
+            public void onAnimationUpdate(ValueAnimator arg0) {
+                if (getVerticalGridView() == null) {
+                    return;
+                }
+                final float fraction = (Float) arg0.getAnimatedValue();
+                for (View view : listener.mViews) {
+                    if (getVerticalGridView().getChildPosition(view) > 0) {
+                        view.setAlpha(fraction);
+                        view.setTranslationY((float) mAnimationTranslateY * (1f - fraction));
+                    }
+                }
+            }
+        };
+
+        mOtherRowFadeInAnimator = loadAnimator(
+                getActivity(), R.animator.lb_playback_controls_fade_in);
+        mOtherRowFadeInAnimator.addListener(listener);
+        mOtherRowFadeInAnimator.addUpdateListener(updateListener);
+        mOtherRowFadeInAnimator.setInterpolator(mLogDecelerateInterpolator);
+
+        mOtherRowFadeOutAnimator = loadAnimator(
+                getActivity(), R.animator.lb_playback_controls_fade_out);
+        mOtherRowFadeOutAnimator.addListener(listener);
+        mOtherRowFadeOutAnimator.addUpdateListener(updateListener);
+        mOtherRowFadeOutAnimator.setInterpolator(new AccelerateInterpolator());
+    }
+
+    private void fade(boolean fadeIn) {
+        if (DEBUG) Log.v(TAG, "fade " + fadeIn);
+        if (getView() == null) {
+            return;
+        }
+        if ((fadeIn && mFadingStatus == IN) || (!fadeIn && mFadingStatus == OUT)) {
+            if (DEBUG) Log.v(TAG, "requested fade in progress");
+            return;
+        }
+        if ((fadeIn && mBgAlpha == 255) || (!fadeIn && mBgAlpha == 0)) {
+            if (DEBUG) Log.v(TAG, "fade is no-op");
+            return;
+        }
+
+        mAnimationTranslateY = getVerticalGridView().getSelectedPosition() == 0
+                ? mMajorFadeTranslateY : mMinorFadeTranslateY;
+
+        if (mFadingStatus == IDLE) {
+            if (fadeIn) {
+                mBgFadeInAnimator.start();
+                mControlRowFadeInAnimator.start();
+                mOtherRowFadeInAnimator.start();
+            } else {
+                mBgFadeOutAnimator.start();
+                mControlRowFadeOutAnimator.start();
+                mOtherRowFadeOutAnimator.start();
+            }
+        } else {
+            if (fadeIn) {
+                mBgFadeOutAnimator.reverse();
+                mControlRowFadeOutAnimator.reverse();
+                mOtherRowFadeOutAnimator.reverse();
+            } else {
+                mBgFadeInAnimator.reverse();
+                mControlRowFadeInAnimator.reverse();
+                mOtherRowFadeInAnimator.reverse();
+            }
+        }
+
+        // If fading in while control row is focused, set initial translationY so
+        // views slide in from below.
+        if (fadeIn && mFadingStatus == IDLE) {
+            final int count = getVerticalGridView().getChildCount();
+            for (int i = 0; i < count; i++) {
+                getVerticalGridView().getChildAt(i).setTranslationY(mAnimationTranslateY);
+            }
+        }
+
+        mFadingStatus = fadeIn ? IN : OUT;
+    }
+
+    /**
+     * Sets the selected row position with smooth animation.
+     */
+    public void setSelectedPosition(int position) {
+        setSelectedPosition(position, true);
+    }
+
+    /**
+     * Sets the selected row position.
+     */
+    public void setSelectedPosition(int position, boolean smooth) {
+        mSetSelectionRunnable.mPosition = position;
+        mSetSelectionRunnable.mSmooth = smooth;
+        if (getView() != null && getView().getHandler() != null) {
+            getView().getHandler().post(mSetSelectionRunnable);
+        }
+    }
+
+    /**
+     * Sets the list of rows for the fragment.
+     */
+    public void setAdapter(ObjectAdapter adapter) {
+        mAdapter = adapter;
+        if (mRowsFragment != null) {
+            mRowsFragment.setAdapter(adapter);
+        }
+    }
+
+    private void setupChildFragmentLayout() {
+        setVerticalGridViewLayout(mRowsFragment.getVerticalGridView());
+    }
+
+    void setVerticalGridViewLayout(VerticalGridView listview) {
+        if (listview == null) {
+            return;
+        }
+        // Padding affects alignment when last row is focused
+        // (last is first when there's only one row).
+        setPadding(listview, mPaddingTop, mPaddingBottom);
+
+        // Item alignment affects focused row that isn't the last.
+        listview.setItemAlignmentOffset(0);
+        listview.setItemAlignmentOffsetPercent(50);
+
+        // Push rows to the bottom.
+        listview.setWindowAlignmentOffset(0);
+        listview.setWindowAlignmentOffsetPercent(50);
+        listview.setWindowAlignment(VerticalGridView.WINDOW_ALIGN_BOTH_EDGE);
+    }
+
+    private static void setPadding(View view, int paddingTop, int paddingBottom) {
+        view.setPadding(view.getPaddingLeft(), paddingTop,
+                view.getPaddingRight(), paddingBottom);
+    }
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        mPaddingTop =
+                getResources().getDimensionPixelSize(R.dimen.lb_playback_controls_padding_top);
+        mPaddingBottom =
+                getResources().getDimensionPixelSize(R.dimen.lb_playback_controls_padding_bottom);
+        mBgDarkColor =
+                getResources().getColor(R.color.lb_playback_controls_background_dark);
+        mBgLightColor =
+                getResources().getColor(R.color.lb_playback_controls_background_light);
+        mShowTimeMs =
+                getResources().getInteger(R.integer.lb_playback_controls_show_time_ms);
+        mMajorFadeTranslateY =
+                getResources().getDimensionPixelSize(R.dimen.lb_playback_major_fade_translate_y);
+        mMinorFadeTranslateY =
+                getResources().getDimensionPixelSize(R.dimen.lb_playback_minor_fade_translate_y);
+
+        loadBgAnimator();
+        loadControlRowAnimator();
+        loadOtherRowAnimator();
+    }
+
+    /**
+     * Sets the background type.
+     *
+     * @param type One of BG_LIGHT, BG_DARK, or BG_NONE.
+     */
+    public void setBackgroundType(int type) {
+        switch (type) {
+            case BG_LIGHT:
+            case BG_DARK:
+            case BG_NONE:
+                if (type != mBackgroundType) {
+                    mBackgroundType = type;
+                    updateBackground();
+                }
+                break;
+            default:
+                throw new IllegalArgumentException("Invalid background type");
+        }
+    }
+
+    /**
+     * Returns the background type.
+     */
+    public int getBackgroundType() {
+        return mBackgroundType;
+    }
+
+    private void updateBackground() {
+        if (mRootView != null) {
+            int color = mBgDarkColor;
+            switch (mBackgroundType) {
+                case BG_DARK:
+                    break;
+                case BG_LIGHT:
+                    color = mBgLightColor;
+                    break;
+                case BG_NONE:
+                    color = Color.TRANSPARENT;
+                    break;
+            }
+            mRootView.setBackground(new ColorDrawable(color));
+        }
+    }
+
+    private final ItemBridgeAdapter.AdapterListener mAdapterListener =
+            new ItemBridgeAdapter.AdapterListener() {
+                @Override
+                public void onAttachedToWindow(ItemBridgeAdapter.ViewHolder vh) {
+                    if (DEBUG) Log.v(TAG, "onAttachedToWindow " + vh.getViewHolder().view);
+                    if ((mFadingStatus == IDLE && mBgAlpha == 0) || mFadingStatus == OUT) {
+                        if (DEBUG) Log.v(TAG, "setting alpha to 0");
+                        vh.getViewHolder().view.setAlpha(0);
+                    }
+                }
+
+                @Override
+                public void onDetachedFromWindow(ItemBridgeAdapter.ViewHolder vh) {
+                    if (DEBUG) Log.v(TAG, "onDetachedFromWindow " + vh.getViewHolder().view);
+                    // Reset animation state
+                    vh.getViewHolder().view.setAlpha(1f);
+                    vh.getViewHolder().view.setTranslationY(0);
+                    vh.getViewHolder().view.setAlpha(1f);
+                }
+
+                @Override
+                public void onBind(ItemBridgeAdapter.ViewHolder vh) {
+                }
+            };
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+                             Bundle savedInstanceState) {
+        mRootView = inflater.inflate(R.layout.lb_playback_fragment, container, false);
+        mRowsFragment = (RowsFragment) getChildFragmentManager().findFragmentById(
+                R.id.playback_controls_dock);
+        if (mRowsFragment == null) {
+            mRowsFragment = new RowsFragment();
+            getChildFragmentManager().beginTransaction()
+                    .replace(R.id.playback_controls_dock, mRowsFragment)
+                    .commit();
+        }
+        mRowsFragment.setAdapter(mAdapter);
+        mRowsFragment.setOnItemViewClickedListener(mOnItemViewClickedListener);
+
+        mBgAlpha = 255;
+        updateBackground();
+        mRowsFragment.setExternalAdapterListener(mAdapterListener);
+        return mRootView;
+    }
+
+    @Override
+    public void onStart() {
+        super.onStart();
+        setupChildFragmentLayout();
+    }
+
+    /**
+     * This listener is called every time there is a click in {@link RowsFragment}. This can
+     * be used by users to take additional actions such as animations.
+     */
+    public void setOnItemViewClickedListener(final BaseOnItemViewClickedListener listener) {
+        mExternalItemClickedListener = listener;
+    }
+
+    /**
+     * Sets the {@link BaseOnItemViewClickedListener} that would be invoked for clicks
+     * only on {@link android.support.v17.leanback.widget.PlaybackRowPresenter.ViewHolder}.
+     */
+    public void setOnPlaybackItemViewClickedListener(final BaseOnItemViewClickedListener listener) {
+        mPlaybackItemClickedListener = listener;
+    }
+
+    @Override
+    public void onDestroyView() {
+        mRootView = null;
+        super.onDestroyView();
+    }
+
+    static abstract class AnimatorListener implements Animator.AnimatorListener {
+        ArrayList<View> mViews = new ArrayList<View>();
+        ArrayList<Integer> mLayerType = new ArrayList<Integer>();
+
+        @Override
+        public void onAnimationCancel(Animator animation) {
+        }
+
+        @Override
+        public void onAnimationRepeat(Animator animation) {
+        }
+
+        @Override
+        public void onAnimationStart(Animator animation) {
+            getViews(mViews);
+            for (View view : mViews) {
+                mLayerType.add(view.getLayerType());
+                view.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+            }
+        }
+
+        @Override
+        public void onAnimationEnd(Animator animation) {
+            for (int i = 0; i < mViews.size(); i++) {
+                mViews.get(i).setLayerType(mLayerType.get(i), null);
+            }
+            mLayerType.clear();
+            mViews.clear();
+        }
+
+        abstract void getViews(ArrayList<View> views);
+    }
+}
diff --git a/v17/leanback/src/android/support/v17/leanback/app/PlaybackFragmentGlueHost.java b/v17/leanback/src/android/support/v17/leanback/app/PlaybackFragmentGlueHost.java
new file mode 100644
index 0000000..785ec22
--- /dev/null
+++ b/v17/leanback/src/android/support/v17/leanback/app/PlaybackFragmentGlueHost.java
@@ -0,0 +1,45 @@
+package android.support.v17.leanback.app;
+
+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.Presenter;
+import android.support.v17.leanback.widget.Row;
+import android.support.v17.leanback.widget.RowPresenter;
+import android.view.View;
+
+/**
+ * {@link PlaybackGlue.PlaybackGlueHost} implementation
+ * the interaction between this class and {@link PlaybackFragment}.
+ */
+public final class PlaybackFragmentGlueHost extends PlaybackGlue.PlaybackGlueHost {
+
+    private final PlaybackFragment mFragment;
+
+    public PlaybackFragmentGlueHost(PlaybackFragment fragment) {
+        this.mFragment = fragment;
+    }
+
+    @Override
+    public void setFadingEnabled(boolean enable) {
+        mFragment.setFadingEnabled(enable);
+    }
+
+    @Override
+    public void setOnKeyInterceptListener(View.OnKeyListener onKeyListener) {
+        mFragment.setOnKeyInterceptListener(onKeyListener);
+    }
+
+    @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);
+                }
+            }
+        });
+    }
+}
diff --git a/v17/leanback/src/android/support/v17/leanback/app/PlaybackGlue.java b/v17/leanback/src/android/support/v17/leanback/app/PlaybackGlue.java
new file mode 100644
index 0000000..5c17b78
--- /dev/null
+++ b/v17/leanback/src/android/support/v17/leanback/app/PlaybackGlue.java
@@ -0,0 +1,71 @@
+/*
+ * 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 android.support.v17.leanback.app;
+
+import android.content.Context;
+import android.support.v17.leanback.widget.OnActionClickedListener;
+import android.support.v17.leanback.widget.OnItemViewClickedListener;
+import android.view.InputEvent;
+import android.view.View;
+
+/**
+ * Base class for {@link PlaybackControlGlue}.
+ */
+public abstract class PlaybackGlue {
+    private final Context mContext;
+    protected PlaybackGlueHost mPlaybackGlueHost;
+
+    /**
+     * This defines the interaction between this class and the fragment hosting the playback
+     * controls.
+     */
+    public static class PlaybackGlueHost {
+
+        public void setFadingEnabled(boolean enable) {
+        }
+
+        public void setOnKeyInterceptListener(View.OnKeyListener onKeyListener) {
+        }
+
+        public void setOnActionClickedListener(OnActionClickedListener listener) {}
+    }
+
+    /**
+     * Constructor.
+     */
+    public PlaybackGlue(Context context) {
+        this.mContext = context;
+    }
+
+    /**
+     * Returns the context.
+     */
+    public Context getContext() {
+        return mContext;
+    }
+
+    /**
+     * Sets the {@link PlaybackGlueHost}.
+     */
+    public void setHost(PlaybackGlueHost host) {
+        mPlaybackGlueHost = host;
+    }
+
+    /**
+     * @return Associated {@link PlaybackGlueHost} or null if not attached to host.
+     */
+    public PlaybackGlueHost getHost() {
+        return mPlaybackGlueHost;
+    }
+}
diff --git a/v17/leanback/src/android/support/v17/leanback/app/PlaybackOverlayFragment.java b/v17/leanback/src/android/support/v17/leanback/app/PlaybackOverlayFragment.java
index 58eb2cb..c2566d6 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/PlaybackOverlayFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/PlaybackOverlayFragment.java
@@ -13,22 +13,17 @@
  */
 package android.support.v17.leanback.app;
 
-import android.graphics.Color;
-import android.graphics.drawable.ColorDrawable;
 import android.animation.Animator;
 import android.animation.AnimatorInflater;
 import android.animation.TimeInterpolator;
 import android.animation.ValueAnimator;
-import android.support.v17.leanback.widget.Action;
-import android.support.v17.leanback.widget.PlaybackControlsRow;
-import android.view.InputEvent;
-import android.view.animation.AccelerateInterpolator;
 import android.animation.ValueAnimator.AnimatorUpdateListener;
 import android.content.Context;
+import android.graphics.Color;
+import android.graphics.drawable.ColorDrawable;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Message;
-import android.support.v7.widget.RecyclerView;
 import android.support.v17.leanback.R;
 import android.support.v17.leanback.animation.LogAccelerateInterpolator;
 import android.support.v17.leanback.animation.LogDecelerateInterpolator;
@@ -40,12 +35,15 @@
 import android.support.v17.leanback.widget.PresenterSelector;
 import android.support.v17.leanback.widget.RowPresenter;
 import android.support.v17.leanback.widget.VerticalGridView;
+import android.support.v7.widget.RecyclerView;
 import android.util.Log;
+import android.view.InputEvent;
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.animation.AccelerateInterpolator;
 
 import java.util.ArrayList;
 
@@ -60,7 +58,12 @@
  * An instance of {@link android.support.v17.leanback.widget.PlaybackControlsRow} is expected to be
  * at position 0 in the adapter.
  * </p>
+ * <p>
+ *  This class is now deprecated, please us
+ * </p>
+ * @deprecated Use {@link PlaybackFragment}.
  */
+@Deprecated
 public class PlaybackOverlayFragment extends DetailsFragment {
 
     /**
@@ -89,19 +92,6 @@
         }
     }
 
-    /**
-     * Interface allowing the application to handle input events.
-     */
-    public interface InputEventHandler {
-        /**
-         * Called when an {@link InputEvent} is received.
-         *
-         * @return If the event should be consumed, return true. To allow the event to
-         * continue on to the next handler, return false.
-         */
-        public boolean handleInputEvent(InputEvent event);
-    }
-
     static final String TAG = "PlaybackOverlayFragment";
     static final boolean DEBUG = false;
     private static final int ANIMATION_MULTIPLIER = 1;
@@ -123,7 +113,7 @@
     private int mMajorFadeTranslateY, mMinorFadeTranslateY;
     int mAnimationTranslateY;
     OnFadeCompleteListener mFadeCompleteListener;
-    private InputEventHandler mInputEventHandler;
+    private PlaybackControlGlue.InputEventHandler mInputEventHandler;
     boolean mFadingEnabled = true;
     int mFadingStatus = IDLE;
     int mBgAlpha;
@@ -266,9 +256,14 @@
         return mFadeCompleteListener;
     }
 
+    @Deprecated
+    public interface InputEventHandler extends PlaybackControlGlue.InputEventHandler {
+    }
+
     /**
      * Sets the input event handler.
      */
+    @Deprecated
     public final void setInputEventHandler(InputEventHandler handler) {
         mInputEventHandler = handler;
     }
@@ -276,7 +271,22 @@
     /**
      * Returns the input event handler.
      */
+    @Deprecated
     public final InputEventHandler getInputEventHandler() {
+        return (InputEventHandler)mInputEventHandler;
+    }
+
+    /**
+     * Sets the input event handler.
+     */
+    public final void setEventHandler(PlaybackControlGlue.InputEventHandler handler) {
+        mInputEventHandler = handler;
+    }
+
+    /**
+     * Returns the input event handler.
+     */
+    public final PlaybackControlGlue.InputEventHandler getEventHandler() {
         return mInputEventHandler;
     }
 
@@ -536,8 +546,8 @@
             return;
         }
 
-        mAnimationTranslateY = getVerticalGridView().getSelectedPosition() == 0 ?
-                mMajorFadeTranslateY : mMinorFadeTranslateY;
+        mAnimationTranslateY = getVerticalGridView().getSelectedPosition() == 0
+                ? mMajorFadeTranslateY : mMinorFadeTranslateY;
 
         if (mFadingStatus == IDLE) {
             if (fadeIn) {
diff --git a/v17/leanback/src/android/support/v17/leanback/app/PlaybackOverlaySupportFragment.java b/v17/leanback/src/android/support/v17/leanback/app/PlaybackOverlaySupportFragment.java
index 2c103a7..9532c36 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/PlaybackOverlaySupportFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/PlaybackOverlaySupportFragment.java
@@ -15,22 +15,17 @@
  */
 package android.support.v17.leanback.app;
 
-import android.graphics.Color;
-import android.graphics.drawable.ColorDrawable;
 import android.animation.Animator;
 import android.animation.AnimatorInflater;
 import android.animation.TimeInterpolator;
 import android.animation.ValueAnimator;
-import android.support.v17.leanback.widget.Action;
-import android.support.v17.leanback.widget.PlaybackControlsRow;
-import android.view.InputEvent;
-import android.view.animation.AccelerateInterpolator;
 import android.animation.ValueAnimator.AnimatorUpdateListener;
 import android.content.Context;
+import android.graphics.Color;
+import android.graphics.drawable.ColorDrawable;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Message;
-import android.support.v7.widget.RecyclerView;
 import android.support.v17.leanback.R;
 import android.support.v17.leanback.animation.LogAccelerateInterpolator;
 import android.support.v17.leanback.animation.LogDecelerateInterpolator;
@@ -42,12 +37,15 @@
 import android.support.v17.leanback.widget.PresenterSelector;
 import android.support.v17.leanback.widget.RowPresenter;
 import android.support.v17.leanback.widget.VerticalGridView;
+import android.support.v7.widget.RecyclerView;
 import android.util.Log;
+import android.view.InputEvent;
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.animation.AccelerateInterpolator;
 
 import java.util.ArrayList;
 
@@ -62,7 +60,12 @@
  * An instance of {@link android.support.v17.leanback.widget.PlaybackControlsRow} is expected to be
  * at position 0 in the adapter.
  * </p>
+ * <p>
+ *  This class is now deprecated, please us
+ * </p>
+ * @deprecated Use {@link PlaybackSupportFragment}.
  */
+@Deprecated
 public class PlaybackOverlaySupportFragment extends DetailsSupportFragment {
 
     /**
@@ -91,19 +94,6 @@
         }
     }
 
-    /**
-     * Interface allowing the application to handle input events.
-     */
-    public interface InputEventHandler {
-        /**
-         * Called when an {@link InputEvent} is received.
-         *
-         * @return If the event should be consumed, return true. To allow the event to
-         * continue on to the next handler, return false.
-         */
-        public boolean handleInputEvent(InputEvent event);
-    }
-
     static final String TAG = "PlaybackOverlaySupportFragment";
     static final boolean DEBUG = false;
     private static final int ANIMATION_MULTIPLIER = 1;
@@ -125,7 +115,7 @@
     private int mMajorFadeTranslateY, mMinorFadeTranslateY;
     int mAnimationTranslateY;
     OnFadeCompleteListener mFadeCompleteListener;
-    private InputEventHandler mInputEventHandler;
+    private PlaybackControlGlue.InputEventHandler mInputEventHandler;
     boolean mFadingEnabled = true;
     int mFadingStatus = IDLE;
     int mBgAlpha;
@@ -268,9 +258,14 @@
         return mFadeCompleteListener;
     }
 
+    @Deprecated
+    public interface InputEventHandler extends PlaybackControlGlue.InputEventHandler {
+    }
+
     /**
      * Sets the input event handler.
      */
+    @Deprecated
     public final void setInputEventHandler(InputEventHandler handler) {
         mInputEventHandler = handler;
     }
@@ -278,7 +273,22 @@
     /**
      * Returns the input event handler.
      */
+    @Deprecated
     public final InputEventHandler getInputEventHandler() {
+        return (InputEventHandler)mInputEventHandler;
+    }
+
+    /**
+     * Sets the input event handler.
+     */
+    public final void setEventHandler(PlaybackControlGlue.InputEventHandler handler) {
+        mInputEventHandler = handler;
+    }
+
+    /**
+     * Returns the input event handler.
+     */
+    public final PlaybackControlGlue.InputEventHandler getEventHandler() {
         return mInputEventHandler;
     }
 
@@ -538,8 +548,8 @@
             return;
         }
 
-        mAnimationTranslateY = getVerticalGridView().getSelectedPosition() == 0 ?
-                mMajorFadeTranslateY : mMinorFadeTranslateY;
+        mAnimationTranslateY = getVerticalGridView().getSelectedPosition() == 0
+                ? mMajorFadeTranslateY : mMinorFadeTranslateY;
 
         if (mFadingStatus == IDLE) {
             if (fadeIn) {
diff --git a/v17/leanback/src/android/support/v17/leanback/app/PlaybackSupportFragment.java b/v17/leanback/src/android/support/v17/leanback/app/PlaybackSupportFragment.java
new file mode 100644
index 0000000..4e0d4f6
--- /dev/null
+++ b/v17/leanback/src/android/support/v17/leanback/app/PlaybackSupportFragment.java
@@ -0,0 +1,799 @@
+/* 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 android.support.v17.leanback.app;
+
+import android.animation.Animator;
+import android.animation.AnimatorInflater;
+import android.animation.TimeInterpolator;
+import android.animation.ValueAnimator;
+import android.animation.ValueAnimator.AnimatorUpdateListener;
+import android.support.v4.app.Fragment;
+import android.content.Context;
+import android.graphics.Color;
+import android.graphics.drawable.ColorDrawable;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.support.v17.leanback.R;
+import android.support.v17.leanback.animation.LogAccelerateInterpolator;
+import android.support.v17.leanback.animation.LogDecelerateInterpolator;
+import android.support.v17.leanback.widget.BaseOnItemViewClickedListener;
+import android.support.v17.leanback.widget.ItemBridgeAdapter;
+import android.support.v17.leanback.widget.ObjectAdapter;
+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.RowPresenter;
+import android.support.v17.leanback.widget.VerticalGridView;
+import android.support.v7.widget.RecyclerView;
+import android.util.Log;
+import android.view.InputEvent;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.animation.AccelerateInterpolator;
+
+import java.util.ArrayList;
+
+/**
+ * A fragment for displaying playback controls and related content.
+ * <p>
+ * A PlaybackSupportFragment renders the elements of its {@link ObjectAdapter} as a set
+ * of rows in a vertical list.  The Adapter's {@link PresenterSelector} must maintain subclasses
+ * of {@link RowPresenter}.
+ * </p>
+ * <p>
+ * An instance of {@link android.support.v17.leanback.widget.PlaybackControlsRow} is expected to be
+ * at position 0 in the adapter.
+ * </p>
+ */
+public class PlaybackSupportFragment extends Fragment {
+    /**
+     * No background.
+     */
+    public static final int BG_NONE = 0;
+
+    /**
+     * A dark translucent background.
+     */
+    public static final int BG_DARK = 1;
+
+    private class SetSelectionRunnable implements Runnable {
+        int mPosition;
+        boolean mSmooth = true;
+
+        @Override
+        public void run() {
+            if (mRowsSupportFragment == null) {
+                return;
+            }
+            mRowsSupportFragment.setSelectedPosition(mPosition, mSmooth);
+        }
+    }
+
+    /**
+     * A light translucent background.
+     */
+    public static final int BG_LIGHT = 2;
+    private RowsSupportFragment mRowsSupportFragment;
+    private ObjectAdapter mAdapter;
+    private BaseOnItemViewClickedListener mExternalItemClickedListener;
+    private BaseOnItemViewClickedListener mPlaybackItemClickedListener;
+    private BaseOnItemViewClickedListener mOnItemViewClickedListener = new BaseOnItemViewClickedListener() {
+        @Override
+        public void onItemClicked(Presenter.ViewHolder itemViewHolder,
+                                  Object item,
+                                  RowPresenter.ViewHolder rowViewHolder,
+                                  Object row) {
+            if (mPlaybackItemClickedListener != null
+                    && rowViewHolder instanceof PlaybackRowPresenter.ViewHolder) {
+                mPlaybackItemClickedListener.onItemClicked(
+                        itemViewHolder, item, rowViewHolder, row);
+            }
+            if (mExternalItemClickedListener != null) {
+                mExternalItemClickedListener.onItemClicked(
+                        itemViewHolder, item, rowViewHolder, row);
+            }
+        }
+    };
+    private final SetSelectionRunnable mSetSelectionRunnable = new SetSelectionRunnable();
+
+    public ObjectAdapter getAdapter() {
+        return mAdapter;
+    }
+
+    /**
+     * Listener allowing the application to receive notification of fade in and/or fade out
+     * completion events.
+     */
+    public static class OnFadeCompleteListener {
+        public void onFadeInComplete() {
+        }
+
+        public void onFadeOutComplete() {
+        }
+    }
+
+    private static final String TAG = "PlaybackSupportFragment";
+    private static final boolean DEBUG = false;
+    private static final int ANIMATION_MULTIPLIER = 1;
+
+    private static int START_FADE_OUT = 1;
+
+    // Fading status
+    private static final int IDLE = 0;
+    private static final int IN = 1;
+    private static final int OUT = 2;
+
+    private int mPaddingTop;
+    private int mPaddingBottom;
+    private View mRootView;
+    private int mBackgroundType = BG_DARK;
+    private int mBgDarkColor;
+    private int mBgLightColor;
+    private int mShowTimeMs;
+    private int mMajorFadeTranslateY, mMinorFadeTranslateY;
+    private int mAnimationTranslateY;
+    private OnFadeCompleteListener mFadeCompleteListener;
+    private View.OnKeyListener mInputEventHandler;
+    private boolean mFadingEnabled = true;
+    private int mFadingStatus = IDLE;
+    private int mBgAlpha;
+    private ValueAnimator mBgFadeInAnimator, mBgFadeOutAnimator;
+    private ValueAnimator mControlRowFadeInAnimator, mControlRowFadeOutAnimator;
+    private ValueAnimator mOtherRowFadeInAnimator, mOtherRowFadeOutAnimator;
+
+    private final Animator.AnimatorListener mFadeListener =
+            new Animator.AnimatorListener() {
+                @Override
+                public void onAnimationStart(Animator animation) {
+                    enableVerticalGridAnimations(false);
+                }
+
+                @Override
+                public void onAnimationRepeat(Animator animation) {
+                }
+
+                @Override
+                public void onAnimationCancel(Animator animation) {
+                }
+
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    if (DEBUG) Log.v(TAG, "onAnimationEnd " + mBgAlpha);
+                    if (mBgAlpha > 0) {
+                        enableVerticalGridAnimations(true);
+                        startFadeTimer();
+                        if (mFadeCompleteListener != null) {
+                            mFadeCompleteListener.onFadeInComplete();
+                        }
+                    } else {
+                        VerticalGridView verticalView = getVerticalGridView();
+                        // reset focus to the primary actions only if the selected row was the controls row
+                        if (verticalView != null && verticalView.getSelectedPosition() == 0) {
+                            ItemBridgeAdapter.ViewHolder vh = (ItemBridgeAdapter.ViewHolder)
+                                    verticalView.findViewHolderForAdapterPosition(0);
+                            if (vh != null && vh.getPresenter() instanceof PlaybackRowPresenter) {
+                                ((PlaybackRowPresenter)vh.getPresenter()).onReappear(
+                                        (RowPresenter.ViewHolder) vh.getViewHolder());
+                            }
+                        }
+                        if (mFadeCompleteListener != null) {
+                            mFadeCompleteListener.onFadeOutComplete();
+                        }
+                    }
+                    mFadingStatus = IDLE;
+                }
+            };
+
+    private VerticalGridView getVerticalGridView() {
+        if (mRowsSupportFragment == null) {
+            return null;
+        }
+        return mRowsSupportFragment.getVerticalGridView();
+    }
+
+    private final Handler mHandler = new Handler() {
+        @Override
+        public void handleMessage(Message message) {
+            if (message.what == START_FADE_OUT && mFadingEnabled) {
+                fade(false);
+            }
+        }
+    };
+
+    private final VerticalGridView.OnTouchInterceptListener mOnTouchInterceptListener =
+            new VerticalGridView.OnTouchInterceptListener() {
+                @Override
+                public boolean onInterceptTouchEvent(MotionEvent event) {
+                    return onInterceptInputEvent(event);
+                }
+            };
+
+    private final VerticalGridView.OnKeyInterceptListener mOnKeyInterceptListener =
+            new VerticalGridView.OnKeyInterceptListener() {
+                @Override
+                public boolean onInterceptKeyEvent(KeyEvent event) {
+                    return onInterceptInputEvent(event);
+                }
+            };
+
+    private void setBgAlpha(int alpha) {
+        mBgAlpha = alpha;
+        if (mRootView != null) {
+            mRootView.getBackground().setAlpha(alpha);
+        }
+    }
+
+    private void enableVerticalGridAnimations(boolean enable) {
+        if (getVerticalGridView() != null) {
+            getVerticalGridView().setAnimateChildLayout(enable);
+        }
+    }
+
+    /**
+     * Enables or disables view fading.  If enabled,
+     * the view will be faded in when the fragment starts,
+     * and will fade out after a time period.  The timeout
+     * period is reset each time {@link #tickle} is called.
+     */
+    public void setFadingEnabled(boolean enabled) {
+        if (DEBUG) Log.v(TAG, "setFadingEnabled " + enabled);
+        if (enabled != mFadingEnabled) {
+            mFadingEnabled = enabled;
+            if (mFadingEnabled) {
+                if (isResumed() && mFadingStatus == IDLE
+                        && !mHandler.hasMessages(START_FADE_OUT)) {
+                    startFadeTimer();
+                }
+            } else {
+                // Ensure fully opaque
+                mHandler.removeMessages(START_FADE_OUT);
+                fade(true);
+            }
+        }
+    }
+
+    /**
+     * Returns true if view fading is enabled.
+     */
+    public boolean isFadingEnabled() {
+        return mFadingEnabled;
+    }
+
+    /**
+     * Sets the listener to be called when fade in or out has completed.
+     */
+    public void setFadeCompleteListener(OnFadeCompleteListener listener) {
+        mFadeCompleteListener = listener;
+    }
+
+    /**
+     * Returns the listener to be called when fade in or out has completed.
+     */
+    public OnFadeCompleteListener getFadeCompleteListener() {
+        return mFadeCompleteListener;
+    }
+
+    /**
+     * Sets the input event handler.
+     */
+    public final void setOnKeyInterceptListener(View.OnKeyListener handler) {
+        mInputEventHandler = handler;
+    }
+
+    /**
+     * Returns the input event handler.
+     */
+    public final View.OnKeyListener getEventHandler() {
+        return mInputEventHandler;
+    }
+
+    /**
+     * Tickles the playback controls.  Fades in the view if it was faded out,
+     * otherwise resets the fade out timer.  Tickling on input events is handled
+     * by the fragment.
+     */
+    public void tickle() {
+        if (DEBUG) Log.v(TAG, "tickle enabled " + mFadingEnabled + " isResumed " + isResumed());
+        if (!mFadingEnabled || !isResumed()) {
+            return;
+        }
+        if (mHandler.hasMessages(START_FADE_OUT)) {
+            // Restart the timer
+            startFadeTimer();
+        } else {
+            fade(true);
+        }
+    }
+
+    /**
+     * Fades out the playback overlay immediately.
+     */
+    public void fadeOut() {
+        mHandler.removeMessages(START_FADE_OUT);
+        fade(false);
+    }
+
+    private boolean areControlsHidden() {
+        return mFadingStatus == IDLE && mBgAlpha == 0;
+    }
+
+    private boolean onInterceptInputEvent(InputEvent event) {
+        final boolean controlsHidden = areControlsHidden();
+        if (DEBUG) Log.v(TAG, "onInterceptInputEvent hidden " + controlsHidden + " " + event);
+        boolean consumeEvent = false;
+        int keyCode = KeyEvent.KEYCODE_UNKNOWN;
+
+        if (event instanceof KeyEvent) {
+            keyCode = ((KeyEvent) event).getKeyCode();
+            if (mInputEventHandler != null) {
+                consumeEvent = mInputEventHandler.onKey(getView(), keyCode, (KeyEvent)event);
+            }
+        }
+
+        switch (keyCode) {
+            case KeyEvent.KEYCODE_DPAD_CENTER:
+            case KeyEvent.KEYCODE_DPAD_DOWN:
+            case KeyEvent.KEYCODE_DPAD_UP:
+            case KeyEvent.KEYCODE_DPAD_LEFT:
+            case KeyEvent.KEYCODE_DPAD_RIGHT:
+                // Event may be consumed; regardless, if controls are hidden then these keys will
+                // bring up the controls.
+                if (controlsHidden) {
+                    consumeEvent = true;
+                }
+                tickle();
+                break;
+            case KeyEvent.KEYCODE_BACK:
+            case KeyEvent.KEYCODE_ESCAPE:
+                // If fading enabled and controls are not hidden, back will be consumed to fade
+                // them out (even if the key was consumed by the handler).
+                if (mFadingEnabled && !controlsHidden) {
+                    consumeEvent = true;
+                    mHandler.removeMessages(START_FADE_OUT);
+                    fade(false);
+                } else if (consumeEvent) {
+                    tickle();
+                }
+                break;
+            default:
+                if (consumeEvent) {
+                    tickle();
+                }
+        }
+        return consumeEvent;
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+        if (mFadingEnabled) {
+            setBgAlpha(0);
+            fade(true);
+        }
+        getVerticalGridView().setOnTouchInterceptListener(mOnTouchInterceptListener);
+        getVerticalGridView().setOnKeyInterceptListener(mOnKeyInterceptListener);
+    }
+
+    private void startFadeTimer() {
+        if (mHandler != null) {
+            mHandler.removeMessages(START_FADE_OUT);
+            mHandler.sendEmptyMessageDelayed(START_FADE_OUT, mShowTimeMs);
+        }
+    }
+
+    private static ValueAnimator loadAnimator(Context context, int resId) {
+        ValueAnimator animator = (ValueAnimator) AnimatorInflater.loadAnimator(context, resId);
+        animator.setDuration(animator.getDuration() * ANIMATION_MULTIPLIER);
+        return animator;
+    }
+
+    private void loadBgAnimator() {
+        AnimatorUpdateListener listener = new AnimatorUpdateListener() {
+            @Override
+            public void onAnimationUpdate(ValueAnimator arg0) {
+                setBgAlpha((Integer) arg0.getAnimatedValue());
+            }
+        };
+
+        mBgFadeInAnimator = loadAnimator(getActivity(), R.animator.lb_playback_bg_fade_in);
+        mBgFadeInAnimator.addUpdateListener(listener);
+        mBgFadeInAnimator.addListener(mFadeListener);
+
+        mBgFadeOutAnimator = loadAnimator(getActivity(), R.animator.lb_playback_bg_fade_out);
+        mBgFadeOutAnimator.addUpdateListener(listener);
+        mBgFadeOutAnimator.addListener(mFadeListener);
+    }
+
+    private TimeInterpolator mLogDecelerateInterpolator = new LogDecelerateInterpolator(100, 0);
+    private TimeInterpolator mLogAccelerateInterpolator = new LogAccelerateInterpolator(100, 0);
+
+    private View getControlRowView() {
+        if (getVerticalGridView() == null) {
+            return null;
+        }
+        RecyclerView.ViewHolder vh = getVerticalGridView().findViewHolderForPosition(0);
+        if (vh == null) {
+            return null;
+        }
+        return vh.itemView;
+    }
+
+    private void loadControlRowAnimator() {
+        final AnimatorListener listener = new AnimatorListener() {
+            @Override
+            void getViews(ArrayList<View> views) {
+                View view = getControlRowView();
+                if (view != null) {
+                    views.add(view);
+                }
+            }
+        };
+        final AnimatorUpdateListener updateListener = new AnimatorUpdateListener() {
+            @Override
+            public void onAnimationUpdate(ValueAnimator arg0) {
+                View view = getControlRowView();
+                if (view != null) {
+                    final float fraction = (Float) arg0.getAnimatedValue();
+                    if (DEBUG) Log.v(TAG, "fraction " + fraction);
+                    view.setAlpha(fraction);
+                    view.setTranslationY((float) mAnimationTranslateY * (1f - fraction));
+                }
+            }
+        };
+
+        mControlRowFadeInAnimator = loadAnimator(
+                getActivity(), R.animator.lb_playback_controls_fade_in);
+        mControlRowFadeInAnimator.addUpdateListener(updateListener);
+        mControlRowFadeInAnimator.addListener(listener);
+        mControlRowFadeInAnimator.setInterpolator(mLogDecelerateInterpolator);
+
+        mControlRowFadeOutAnimator = loadAnimator(
+                getActivity(), R.animator.lb_playback_controls_fade_out);
+        mControlRowFadeOutAnimator.addUpdateListener(updateListener);
+        mControlRowFadeOutAnimator.addListener(listener);
+        mControlRowFadeOutAnimator.setInterpolator(mLogAccelerateInterpolator);
+    }
+
+    private void loadOtherRowAnimator() {
+        final AnimatorListener listener = new AnimatorListener() {
+            @Override
+            void getViews(ArrayList<View> views) {
+                if (getVerticalGridView() == null) {
+                    return;
+                }
+                final int count = getVerticalGridView().getChildCount();
+                for (int i = 0; i < count; i++) {
+                    View view = getVerticalGridView().getChildAt(i);
+                    if (view != null) {
+                        views.add(view);
+                    }
+                }
+            }
+        };
+        final AnimatorUpdateListener updateListener = new AnimatorUpdateListener() {
+            @Override
+            public void onAnimationUpdate(ValueAnimator arg0) {
+                if (getVerticalGridView() == null) {
+                    return;
+                }
+                final float fraction = (Float) arg0.getAnimatedValue();
+                for (View view : listener.mViews) {
+                    if (getVerticalGridView().getChildPosition(view) > 0) {
+                        view.setAlpha(fraction);
+                        view.setTranslationY((float) mAnimationTranslateY * (1f - fraction));
+                    }
+                }
+            }
+        };
+
+        mOtherRowFadeInAnimator = loadAnimator(
+                getActivity(), R.animator.lb_playback_controls_fade_in);
+        mOtherRowFadeInAnimator.addListener(listener);
+        mOtherRowFadeInAnimator.addUpdateListener(updateListener);
+        mOtherRowFadeInAnimator.setInterpolator(mLogDecelerateInterpolator);
+
+        mOtherRowFadeOutAnimator = loadAnimator(
+                getActivity(), R.animator.lb_playback_controls_fade_out);
+        mOtherRowFadeOutAnimator.addListener(listener);
+        mOtherRowFadeOutAnimator.addUpdateListener(updateListener);
+        mOtherRowFadeOutAnimator.setInterpolator(new AccelerateInterpolator());
+    }
+
+    private void fade(boolean fadeIn) {
+        if (DEBUG) Log.v(TAG, "fade " + fadeIn);
+        if (getView() == null) {
+            return;
+        }
+        if ((fadeIn && mFadingStatus == IN) || (!fadeIn && mFadingStatus == OUT)) {
+            if (DEBUG) Log.v(TAG, "requested fade in progress");
+            return;
+        }
+        if ((fadeIn && mBgAlpha == 255) || (!fadeIn && mBgAlpha == 0)) {
+            if (DEBUG) Log.v(TAG, "fade is no-op");
+            return;
+        }
+
+        mAnimationTranslateY = getVerticalGridView().getSelectedPosition() == 0
+                ? mMajorFadeTranslateY : mMinorFadeTranslateY;
+
+        if (mFadingStatus == IDLE) {
+            if (fadeIn) {
+                mBgFadeInAnimator.start();
+                mControlRowFadeInAnimator.start();
+                mOtherRowFadeInAnimator.start();
+            } else {
+                mBgFadeOutAnimator.start();
+                mControlRowFadeOutAnimator.start();
+                mOtherRowFadeOutAnimator.start();
+            }
+        } else {
+            if (fadeIn) {
+                mBgFadeOutAnimator.reverse();
+                mControlRowFadeOutAnimator.reverse();
+                mOtherRowFadeOutAnimator.reverse();
+            } else {
+                mBgFadeInAnimator.reverse();
+                mControlRowFadeInAnimator.reverse();
+                mOtherRowFadeInAnimator.reverse();
+            }
+        }
+
+        // If fading in while control row is focused, set initial translationY so
+        // views slide in from below.
+        if (fadeIn && mFadingStatus == IDLE) {
+            final int count = getVerticalGridView().getChildCount();
+            for (int i = 0; i < count; i++) {
+                getVerticalGridView().getChildAt(i).setTranslationY(mAnimationTranslateY);
+            }
+        }
+
+        mFadingStatus = fadeIn ? IN : OUT;
+    }
+
+    /**
+     * Sets the selected row position with smooth animation.
+     */
+    public void setSelectedPosition(int position) {
+        setSelectedPosition(position, true);
+    }
+
+    /**
+     * Sets the selected row position.
+     */
+    public void setSelectedPosition(int position, boolean smooth) {
+        mSetSelectionRunnable.mPosition = position;
+        mSetSelectionRunnable.mSmooth = smooth;
+        if (getView() != null && getView().getHandler() != null) {
+            getView().getHandler().post(mSetSelectionRunnable);
+        }
+    }
+
+    /**
+     * Sets the list of rows for the fragment.
+     */
+    public void setAdapter(ObjectAdapter adapter) {
+        mAdapter = adapter;
+        if (mRowsSupportFragment != null) {
+            mRowsSupportFragment.setAdapter(adapter);
+        }
+    }
+
+    private void setupChildFragmentLayout() {
+        setVerticalGridViewLayout(mRowsSupportFragment.getVerticalGridView());
+    }
+
+    void setVerticalGridViewLayout(VerticalGridView listview) {
+        if (listview == null) {
+            return;
+        }
+        // Padding affects alignment when last row is focused
+        // (last is first when there's only one row).
+        setPadding(listview, mPaddingTop, mPaddingBottom);
+
+        // Item alignment affects focused row that isn't the last.
+        listview.setItemAlignmentOffset(0);
+        listview.setItemAlignmentOffsetPercent(50);
+
+        // Push rows to the bottom.
+        listview.setWindowAlignmentOffset(0);
+        listview.setWindowAlignmentOffsetPercent(50);
+        listview.setWindowAlignment(VerticalGridView.WINDOW_ALIGN_BOTH_EDGE);
+    }
+
+    private static void setPadding(View view, int paddingTop, int paddingBottom) {
+        view.setPadding(view.getPaddingLeft(), paddingTop,
+                view.getPaddingRight(), paddingBottom);
+    }
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        mPaddingTop =
+                getResources().getDimensionPixelSize(R.dimen.lb_playback_controls_padding_top);
+        mPaddingBottom =
+                getResources().getDimensionPixelSize(R.dimen.lb_playback_controls_padding_bottom);
+        mBgDarkColor =
+                getResources().getColor(R.color.lb_playback_controls_background_dark);
+        mBgLightColor =
+                getResources().getColor(R.color.lb_playback_controls_background_light);
+        mShowTimeMs =
+                getResources().getInteger(R.integer.lb_playback_controls_show_time_ms);
+        mMajorFadeTranslateY =
+                getResources().getDimensionPixelSize(R.dimen.lb_playback_major_fade_translate_y);
+        mMinorFadeTranslateY =
+                getResources().getDimensionPixelSize(R.dimen.lb_playback_minor_fade_translate_y);
+
+        loadBgAnimator();
+        loadControlRowAnimator();
+        loadOtherRowAnimator();
+    }
+
+    /**
+     * Sets the background type.
+     *
+     * @param type One of BG_LIGHT, BG_DARK, or BG_NONE.
+     */
+    public void setBackgroundType(int type) {
+        switch (type) {
+            case BG_LIGHT:
+            case BG_DARK:
+            case BG_NONE:
+                if (type != mBackgroundType) {
+                    mBackgroundType = type;
+                    updateBackground();
+                }
+                break;
+            default:
+                throw new IllegalArgumentException("Invalid background type");
+        }
+    }
+
+    /**
+     * Returns the background type.
+     */
+    public int getBackgroundType() {
+        return mBackgroundType;
+    }
+
+    private void updateBackground() {
+        if (mRootView != null) {
+            int color = mBgDarkColor;
+            switch (mBackgroundType) {
+                case BG_DARK:
+                    break;
+                case BG_LIGHT:
+                    color = mBgLightColor;
+                    break;
+                case BG_NONE:
+                    color = Color.TRANSPARENT;
+                    break;
+            }
+            mRootView.setBackground(new ColorDrawable(color));
+        }
+    }
+
+    private final ItemBridgeAdapter.AdapterListener mAdapterListener =
+            new ItemBridgeAdapter.AdapterListener() {
+                @Override
+                public void onAttachedToWindow(ItemBridgeAdapter.ViewHolder vh) {
+                    if (DEBUG) Log.v(TAG, "onAttachedToWindow " + vh.getViewHolder().view);
+                    if ((mFadingStatus == IDLE && mBgAlpha == 0) || mFadingStatus == OUT) {
+                        if (DEBUG) Log.v(TAG, "setting alpha to 0");
+                        vh.getViewHolder().view.setAlpha(0);
+                    }
+                }
+
+                @Override
+                public void onDetachedFromWindow(ItemBridgeAdapter.ViewHolder vh) {
+                    if (DEBUG) Log.v(TAG, "onDetachedFromWindow " + vh.getViewHolder().view);
+                    // Reset animation state
+                    vh.getViewHolder().view.setAlpha(1f);
+                    vh.getViewHolder().view.setTranslationY(0);
+                    vh.getViewHolder().view.setAlpha(1f);
+                }
+
+                @Override
+                public void onBind(ItemBridgeAdapter.ViewHolder vh) {
+                }
+            };
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+                             Bundle savedInstanceState) {
+        mRootView = inflater.inflate(R.layout.lb_playback_fragment, container, false);
+        mRowsSupportFragment = (RowsSupportFragment) getChildFragmentManager().findFragmentById(
+                R.id.playback_controls_dock);
+        if (mRowsSupportFragment == null) {
+            mRowsSupportFragment = new RowsSupportFragment();
+            getChildFragmentManager().beginTransaction()
+                    .replace(R.id.playback_controls_dock, mRowsSupportFragment)
+                    .commit();
+        }
+        mRowsSupportFragment.setAdapter(mAdapter);
+        mRowsSupportFragment.setOnItemViewClickedListener(mOnItemViewClickedListener);
+
+        mBgAlpha = 255;
+        updateBackground();
+        mRowsSupportFragment.setExternalAdapterListener(mAdapterListener);
+        return mRootView;
+    }
+
+    @Override
+    public void onStart() {
+        super.onStart();
+        setupChildFragmentLayout();
+    }
+
+    /**
+     * This listener is called every time there is a click in {@link RowsSupportFragment}. This can
+     * be used by users to take additional actions such as animations.
+     */
+    public void setOnItemViewClickedListener(final BaseOnItemViewClickedListener listener) {
+        mExternalItemClickedListener = listener;
+    }
+
+    /**
+     * Sets the {@link BaseOnItemViewClickedListener} that would be invoked for clicks
+     * only on {@link android.support.v17.leanback.widget.PlaybackRowPresenter.ViewHolder}.
+     */
+    public void setOnPlaybackItemViewClickedListener(final BaseOnItemViewClickedListener listener) {
+        mPlaybackItemClickedListener = listener;
+    }
+
+    @Override
+    public void onDestroyView() {
+        mRootView = null;
+        super.onDestroyView();
+    }
+
+    static abstract class AnimatorListener implements Animator.AnimatorListener {
+        ArrayList<View> mViews = new ArrayList<View>();
+        ArrayList<Integer> mLayerType = new ArrayList<Integer>();
+
+        @Override
+        public void onAnimationCancel(Animator animation) {
+        }
+
+        @Override
+        public void onAnimationRepeat(Animator animation) {
+        }
+
+        @Override
+        public void onAnimationStart(Animator animation) {
+            getViews(mViews);
+            for (View view : mViews) {
+                mLayerType.add(view.getLayerType());
+                view.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+            }
+        }
+
+        @Override
+        public void onAnimationEnd(Animator animation) {
+            for (int i = 0; i < mViews.size(); i++) {
+                mViews.get(i).setLayerType(mLayerType.get(i), null);
+            }
+            mLayerType.clear();
+            mViews.clear();
+        }
+
+        abstract void getViews(ArrayList<View> views);
+    }
+}
diff --git a/v17/leanback/src/android/support/v17/leanback/app/PlaybackSupportFragmentGlueHost.java b/v17/leanback/src/android/support/v17/leanback/app/PlaybackSupportFragmentGlueHost.java
new file mode 100644
index 0000000..b9e5677
--- /dev/null
+++ b/v17/leanback/src/android/support/v17/leanback/app/PlaybackSupportFragmentGlueHost.java
@@ -0,0 +1,45 @@
+package android.support.v17.leanback.app;
+
+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.Presenter;
+import android.support.v17.leanback.widget.Row;
+import android.support.v17.leanback.widget.RowPresenter;
+import android.view.View;
+
+/**
+ * {@link PlaybackGlue.PlaybackGlueHost} implementation
+ * the interaction between this class and {@link PlaybackSupportFragment}.
+ */
+public final class PlaybackSupportFragmentGlueHost extends PlaybackGlue.PlaybackGlueHost {
+
+    private final PlaybackSupportFragment mFragment;
+
+    public PlaybackSupportFragmentGlueHost(PlaybackSupportFragment fragment) {
+        this.mFragment = fragment;
+    }
+
+    @Override
+    public void setFadingEnabled(boolean enable) {
+        mFragment.setFadingEnabled(enable);
+    }
+
+    @Override
+    public void setOnKeyInterceptListener(View.OnKeyListener onKeyListener) {
+        mFragment.setOnKeyInterceptListener(onKeyListener);
+    }
+
+    @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);
+                }
+            }
+        });
+    }
+}
diff --git a/v17/leanback/src/android/support/v17/leanback/app/RowsFragment.java b/v17/leanback/src/android/support/v17/leanback/app/RowsFragment.java
index 7b93115..6e1c008 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/RowsFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/RowsFragment.java
@@ -17,12 +17,12 @@
 import android.animation.TimeAnimator.TimeListener;
 import android.os.Bundle;
 import android.support.v17.leanback.R;
+import android.support.v17.leanback.widget.BaseOnItemViewClickedListener;
+import android.support.v17.leanback.widget.BaseOnItemViewSelectedListener;
 import android.support.v17.leanback.widget.HorizontalGridView;
 import android.support.v17.leanback.widget.ItemBridgeAdapter;
 import android.support.v17.leanback.widget.ListRowPresenter;
 import android.support.v17.leanback.widget.ObjectAdapter;
-import android.support.v17.leanback.widget.BaseOnItemViewClickedListener;
-import android.support.v17.leanback.widget.BaseOnItemViewSelectedListener;
 import android.support.v17.leanback.widget.OnItemViewClickedListener;
 import android.support.v17.leanback.widget.OnItemViewSelectedListener;
 import android.support.v17.leanback.widget.Presenter;
@@ -201,8 +201,8 @@
             if (DEBUG) Log.v(TAG, "setExpand " + expand + " count " + count);
             for (int i = 0; i < count; i++) {
                 View view = listView.getChildAt(i);
-                ItemBridgeAdapter.ViewHolder vh
-                        = (ItemBridgeAdapter.ViewHolder) listView.getChildViewHolder(view);
+                ItemBridgeAdapter.ViewHolder vh =
+                        (ItemBridgeAdapter.ViewHolder) listView.getChildViewHolder(view);
                 setRowViewExpanded(vh, mExpand);
             }
         }
diff --git a/v17/leanback/src/android/support/v17/leanback/app/RowsSupportFragment.java b/v17/leanback/src/android/support/v17/leanback/app/RowsSupportFragment.java
index 4086658..1cb9a0e 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/RowsSupportFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/RowsSupportFragment.java
@@ -19,12 +19,12 @@
 import android.animation.TimeAnimator.TimeListener;
 import android.os.Bundle;
 import android.support.v17.leanback.R;
+import android.support.v17.leanback.widget.BaseOnItemViewClickedListener;
+import android.support.v17.leanback.widget.BaseOnItemViewSelectedListener;
 import android.support.v17.leanback.widget.HorizontalGridView;
 import android.support.v17.leanback.widget.ItemBridgeAdapter;
 import android.support.v17.leanback.widget.ListRowPresenter;
 import android.support.v17.leanback.widget.ObjectAdapter;
-import android.support.v17.leanback.widget.BaseOnItemViewClickedListener;
-import android.support.v17.leanback.widget.BaseOnItemViewSelectedListener;
 import android.support.v17.leanback.widget.OnItemViewClickedListener;
 import android.support.v17.leanback.widget.OnItemViewSelectedListener;
 import android.support.v17.leanback.widget.Presenter;
@@ -203,8 +203,8 @@
             if (DEBUG) Log.v(TAG, "setExpand " + expand + " count " + count);
             for (int i = 0; i < count; i++) {
                 View view = listView.getChildAt(i);
-                ItemBridgeAdapter.ViewHolder vh
-                        = (ItemBridgeAdapter.ViewHolder) listView.getChildViewHolder(view);
+                ItemBridgeAdapter.ViewHolder vh =
+                        (ItemBridgeAdapter.ViewHolder) listView.getChildViewHolder(view);
                 setRowViewExpanded(vh, mExpand);
             }
         }
diff --git a/v17/leanback/src/android/support/v17/leanback/app/SearchFragment.java b/v17/leanback/src/android/support/v17/leanback/app/SearchFragment.java
index 70393c4..93886f9 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/SearchFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/SearchFragment.java
@@ -13,6 +13,8 @@
  */
 package android.support.v17.leanback.app;
 
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+
 import android.Manifest;
 import android.app.Fragment;
 import android.content.Intent;
@@ -30,6 +32,7 @@
 import android.support.v17.leanback.widget.Row;
 import android.support.v17.leanback.widget.RowPresenter;
 import android.support.v17.leanback.widget.SearchBar;
+import android.support.v17.leanback.widget.SearchOrbView;
 import android.support.v17.leanback.widget.SpeechRecognitionCallback;
 import android.support.v17.leanback.widget.VerticalGridView;
 import android.util.Log;
@@ -42,8 +45,6 @@
 import java.util.ArrayList;
 import java.util.List;
 
-import static android.content.pm.PackageManager.PERMISSION_GRANTED;
-
 /**
  * A fragment to handle searches. An application will supply an implementation
  * of the {@link SearchResultProvider} interface to handle the search and return
@@ -171,8 +172,10 @@
                 if (mResultAdapter != null) {
                     mResultAdapter.registerObserver(mAdapterObserver);
                 }
-                if (DEBUG) Log.v(TAG, "mResultAdapter " + mResultAdapter + " size " +
-                        (mResultAdapter == null ? 0 : mResultAdapter.size()));
+                if (DEBUG) {
+                    Log.v(TAG, "mResultAdapter " + mResultAdapter + " size "
+                            + (mResultAdapter == null ? 0 : mResultAdapter.size()));
+                }
                 // delay the first time to avoid setting a empty result adapter
                 // until we got first onChange() from the provider
                 if (!(firstTime && (mResultAdapter == null || mResultAdapter.size() == 0))) {
@@ -182,9 +185,11 @@
             }
             updateSearchBarNextFocusId();
 
-            if (DEBUG) Log.v(TAG, "mAutoStartRecognition " + mAutoStartRecognition +
-                    " mResultAdapter " + mResultAdapter +
-                    " adapter " + mRowsFragment.getAdapter());
+            if (DEBUG) {
+                Log.v(TAG, "mAutoStartRecognition " + mAutoStartRecognition
+                        + " mResultAdapter " + mResultAdapter
+                        + " adapter " + mRowsFragment.getAdapter());
+            }
             if (mAutoStartRecognition) {
                 mHandler.removeCallbacks(mStartRecognitionRunnable);
                 mHandler.postDelayed(mStartRecognitionRunnable, SPEECH_RECOGNITION_DELAY_MS);
@@ -223,8 +228,8 @@
 
     private boolean mIsPaused;
     private boolean mPendingStartRecognitionWhenPaused;
-    private SearchBar.SearchBarPermissionListener mPermissionListener
-            = new SearchBar.SearchBarPermissionListener() {
+    private SearchBar.SearchBarPermissionListener mPermissionListener =
+            new SearchBar.SearchBarPermissionListener() {
         @Override
         public void requestAudioPermission() {
             PermissionHelper.requestPermissions(SearchFragment.this,
@@ -514,6 +519,28 @@
     }
 
     /**
+     * Sets background color of not-listening state search orb.
+     *
+     * @param colors SearchOrbView.Colors.
+     */
+    public void setSearchAffordanceColors(SearchOrbView.Colors colors) {
+        if (mSearchBar != null) {
+            mSearchBar.setSearchAffordanceColors(colors);
+        }
+    }
+
+    /**
+     * Sets background color of listening state search orb.
+     *
+     * @param colors SearchOrbView.Colors.
+     */
+    public void setSearchAffordanceColorsInListening(SearchOrbView.Colors colors) {
+        if (mSearchBar != null) {
+            mSearchBar.setSearchAffordanceColorsInListening(colors);
+        }
+    }
+
+    /**
      * Displays the completions shown by the IME. An application may provide
      * a list of query completions that the system will show in the IME.
      *
@@ -643,15 +670,15 @@
         if (mSearchBar == null || mResultAdapter == null) {
             return;
         }
-        final int viewId = (mResultAdapter.size() == 0 || mRowsFragment == null ||
-                mRowsFragment.getVerticalGridView() == null) ? 0 :
-                mRowsFragment.getVerticalGridView().getId();
+        final int viewId = (mResultAdapter.size() == 0 || mRowsFragment == null
+                || mRowsFragment.getVerticalGridView() == null)
+                        ? 0 : mRowsFragment.getVerticalGridView().getId();
         mSearchBar.setNextFocusDownId(viewId);
     }
 
     void updateFocus() {
-        if (mResultAdapter != null && mResultAdapter.size() > 0 &&
-                mRowsFragment != null && mRowsFragment.getAdapter() == mResultAdapter) {
+        if (mResultAdapter != null && mResultAdapter.size() > 0
+                && mRowsFragment != null && mRowsFragment.getAdapter() == mResultAdapter) {
             focusOnResults();
         } else {
             mSearchBar.requestFocus();
@@ -659,9 +686,8 @@
     }
 
     private void focusOnResults() {
-        if (mRowsFragment == null ||
-                mRowsFragment.getVerticalGridView() == null ||
-                mResultAdapter.size() == 0) {
+        if (mRowsFragment == null || mRowsFragment.getVerticalGridView() == null
+                || mResultAdapter.size() == 0) {
             return;
         }
         if (mRowsFragment.getVerticalGridView().requestFocus()) {
diff --git a/v17/leanback/src/android/support/v17/leanback/app/SearchSupportFragment.java b/v17/leanback/src/android/support/v17/leanback/app/SearchSupportFragment.java
index 7b9582c..83853e3 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/SearchSupportFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/SearchSupportFragment.java
@@ -15,6 +15,8 @@
  */
 package android.support.v17.leanback.app;
 
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+
 import android.Manifest;
 import android.support.v4.app.Fragment;
 import android.content.Intent;
@@ -32,6 +34,7 @@
 import android.support.v17.leanback.widget.Row;
 import android.support.v17.leanback.widget.RowPresenter;
 import android.support.v17.leanback.widget.SearchBar;
+import android.support.v17.leanback.widget.SearchOrbView;
 import android.support.v17.leanback.widget.SpeechRecognitionCallback;
 import android.support.v17.leanback.widget.VerticalGridView;
 import android.util.Log;
@@ -44,8 +47,6 @@
 import java.util.ArrayList;
 import java.util.List;
 
-import static android.content.pm.PackageManager.PERMISSION_GRANTED;
-
 /**
  * A fragment to handle searches. An application will supply an implementation
  * of the {@link SearchResultProvider} interface to handle the search and return
@@ -173,8 +174,10 @@
                 if (mResultAdapter != null) {
                     mResultAdapter.registerObserver(mAdapterObserver);
                 }
-                if (DEBUG) Log.v(TAG, "mResultAdapter " + mResultAdapter + " size " +
-                        (mResultAdapter == null ? 0 : mResultAdapter.size()));
+                if (DEBUG) {
+                    Log.v(TAG, "mResultAdapter " + mResultAdapter + " size "
+                            + (mResultAdapter == null ? 0 : mResultAdapter.size()));
+                }
                 // delay the first time to avoid setting a empty result adapter
                 // until we got first onChange() from the provider
                 if (!(firstTime && (mResultAdapter == null || mResultAdapter.size() == 0))) {
@@ -184,9 +187,11 @@
             }
             updateSearchBarNextFocusId();
 
-            if (DEBUG) Log.v(TAG, "mAutoStartRecognition " + mAutoStartRecognition +
-                    " mResultAdapter " + mResultAdapter +
-                    " adapter " + mRowsSupportFragment.getAdapter());
+            if (DEBUG) {
+                Log.v(TAG, "mAutoStartRecognition " + mAutoStartRecognition
+                        + " mResultAdapter " + mResultAdapter
+                        + " adapter " + mRowsSupportFragment.getAdapter());
+            }
             if (mAutoStartRecognition) {
                 mHandler.removeCallbacks(mStartRecognitionRunnable);
                 mHandler.postDelayed(mStartRecognitionRunnable, SPEECH_RECOGNITION_DELAY_MS);
@@ -225,8 +230,8 @@
 
     private boolean mIsPaused;
     private boolean mPendingStartRecognitionWhenPaused;
-    private SearchBar.SearchBarPermissionListener mPermissionListener
-            = new SearchBar.SearchBarPermissionListener() {
+    private SearchBar.SearchBarPermissionListener mPermissionListener =
+            new SearchBar.SearchBarPermissionListener() {
         @Override
         public void requestAudioPermission() {
             PermissionHelper.requestPermissions(SearchSupportFragment.this,
@@ -516,6 +521,28 @@
     }
 
     /**
+     * Sets background color of not-listening state search orb.
+     *
+     * @param colors SearchOrbView.Colors.
+     */
+    public void setSearchAffordanceColors(SearchOrbView.Colors colors) {
+        if (mSearchBar != null) {
+            mSearchBar.setSearchAffordanceColors(colors);
+        }
+    }
+
+    /**
+     * Sets background color of listening state search orb.
+     *
+     * @param colors SearchOrbView.Colors.
+     */
+    public void setSearchAffordanceColorsInListening(SearchOrbView.Colors colors) {
+        if (mSearchBar != null) {
+            mSearchBar.setSearchAffordanceColorsInListening(colors);
+        }
+    }
+
+    /**
      * Displays the completions shown by the IME. An application may provide
      * a list of query completions that the system will show in the IME.
      *
@@ -645,15 +672,15 @@
         if (mSearchBar == null || mResultAdapter == null) {
             return;
         }
-        final int viewId = (mResultAdapter.size() == 0 || mRowsSupportFragment == null ||
-                mRowsSupportFragment.getVerticalGridView() == null) ? 0 :
-                mRowsSupportFragment.getVerticalGridView().getId();
+        final int viewId = (mResultAdapter.size() == 0 || mRowsSupportFragment == null
+                || mRowsSupportFragment.getVerticalGridView() == null)
+                        ? 0 : mRowsSupportFragment.getVerticalGridView().getId();
         mSearchBar.setNextFocusDownId(viewId);
     }
 
     void updateFocus() {
-        if (mResultAdapter != null && mResultAdapter.size() > 0 &&
-                mRowsSupportFragment != null && mRowsSupportFragment.getAdapter() == mResultAdapter) {
+        if (mResultAdapter != null && mResultAdapter.size() > 0
+                && mRowsSupportFragment != null && mRowsSupportFragment.getAdapter() == mResultAdapter) {
             focusOnResults();
         } else {
             mSearchBar.requestFocus();
@@ -661,9 +688,8 @@
     }
 
     private void focusOnResults() {
-        if (mRowsSupportFragment == null ||
-                mRowsSupportFragment.getVerticalGridView() == null ||
-                mResultAdapter.size() == 0) {
+        if (mRowsSupportFragment == null || mRowsSupportFragment.getVerticalGridView() == null
+                || mResultAdapter.size() == 0) {
             return;
         }
         if (mRowsSupportFragment.getVerticalGridView().requestFocus()) {
diff --git a/v17/leanback/src/android/support/v17/leanback/graphics/BoundsRule.java b/v17/leanback/src/android/support/v17/leanback/graphics/BoundsRule.java
new file mode 100644
index 0000000..216beb7
--- /dev/null
+++ b/v17/leanback/src/android/support/v17/leanback/graphics/BoundsRule.java
@@ -0,0 +1,162 @@
+/*
+ * 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 android.support.v17.leanback.graphics;
+
+import android.graphics.Rect;
+
+/**
+ * This class contains the rules for updating the bounds of a
+ * {@link CompositeDrawable.ChildDrawable}. It contains four rules, one for each value of the
+ * rectangular bound - left/top/right/bottom.
+ */
+public class BoundsRule {
+    static final int INHERIT_PARENT = 0;
+    static final int ABSOLUTE_VALUE = 1;
+    static final int INHERIT_WITH_OFFSET = 2;
+
+    /**
+     * This class represents individual rules for updating the bounds. Currently we support
+     * 3 different rule types -
+     *
+     * <ul>
+     *     <li>inheritFromParent: it applies a percentage to the parent property to compute
+     *     the final value </li>
+     *     <li>absoluteValue: it always used the supplied absolute value</li>
+     *     <li>inheritFromParentWithOffset: this uses a combination of INHERIT_PARENT
+     *     and ABSOLUTE_VALUE. First it applies the percentage on the parent and then adds the
+     *     offset to compute the final value</li>
+     * </ul>
+     */
+    public final static class ValueRule {
+        private final int type;
+        private float fraction;
+        private int absoluteValue;
+
+        ValueRule(int type, int absoluteValue, float fraction) {
+            this.type = type;
+            this.absoluteValue = absoluteValue;
+            this.fraction = fraction;
+        }
+
+        /**
+         * Sets the fractional value (percentage of parent) for this rule.
+         */
+        public void setFraction(float fraction) {
+            this.fraction = fraction;
+        }
+
+        /**
+         * Returns the current fractional value.
+         */
+        public float getFraction() {
+            return fraction;
+        }
+
+        /**
+         * Sets the absolute value for this rule.
+         */
+        public void setAbsoluteValue(int absoluteValue) {
+            this.absoluteValue = absoluteValue;
+        }
+
+        /**
+         * Returns the current absolute value.
+         */
+        public int getAbsoluteValue() {
+            return absoluteValue;
+        }
+    }
+
+    /**
+     * Factory method for creating ValueRule of type INHERIT_FROM_PARENT.
+     */
+    public static ValueRule inheritFromParent(float fraction) {
+        return new ValueRule(INHERIT_PARENT, 0, fraction);
+    }
+
+    /**
+     * Factory method for creating ValueRule of type ABSOLUTE_VALUE.
+     */
+    public static ValueRule absoluteValue(int value) {
+        return new ValueRule(ABSOLUTE_VALUE, value, 0);
+    }
+
+    /**
+     * Factory method for creating ValueRule of type INHERIT_WITH_OFFSET.
+     */
+    public static ValueRule inheritFromParentWithOffset(float fraction, int value) {
+        return new ValueRule(INHERIT_WITH_OFFSET, value, fraction);
+    }
+
+    /**
+     * Takes in the current bounds and sets the final values based on the individual rules in the
+     * result object.
+     *
+     * @param rect Represents the current bounds.
+     * @param result Represents the final bounds.
+     */
+    public void calculateBounds(Rect rect, Rect result) {
+        if (mLeft == null) {
+            result.left = rect.left;
+        } else {
+            result.left = doCalculate(rect.left, mLeft, rect.width());
+        }
+
+        if (mRight == null) {
+            result.right = rect.right;
+        } else {
+            result.right = doCalculate(rect.left, mRight, rect.width());
+        }
+
+        if (mTop == null) {
+            result.top = rect.top;
+        } else {
+            result.top = doCalculate(rect.top, mTop, rect.height());
+        }
+
+        if (mBottom == null) {
+            result.bottom = rect.bottom;
+        } else {
+            result.bottom = doCalculate(rect.top, mBottom, rect.height());
+        }
+    }
+
+    private int doCalculate(int value, ValueRule rule, int size) {
+        int offset = 0;
+        switch(rule.type) {
+            case INHERIT_WITH_OFFSET:
+                offset = rule.absoluteValue;
+            case INHERIT_PARENT:
+                return value + offset + (int)(rule.fraction * size);
+            case ABSOLUTE_VALUE:
+                return rule.absoluteValue;
+        }
+
+        throw new IllegalArgumentException("Invalid type: "+rule.type);
+    }
+
+    /** {@link ValueRule} for left attribute of {@link BoundsRule} */
+    public ValueRule mLeft;
+
+    /** {@link ValueRule} for top attribute of {@link BoundsRule} */
+    public ValueRule mTop;
+
+    /** {@link ValueRule} for right attribute of {@link BoundsRule} */
+    public ValueRule mRight;
+
+    /** {@link ValueRule} for bottom attribute of {@link BoundsRule} */
+    public ValueRule mBottom;
+}
diff --git a/v17/leanback/src/android/support/v17/leanback/graphics/CompositeDrawable.java b/v17/leanback/src/android/support/v17/leanback/graphics/CompositeDrawable.java
new file mode 100644
index 0000000..7f82b52
--- /dev/null
+++ b/v17/leanback/src/android/support/v17/leanback/graphics/CompositeDrawable.java
@@ -0,0 +1,499 @@
+/*
+ * 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 android.support.v17.leanback.graphics;
+
+import android.annotation.TargetApi;
+import android.content.res.Resources;
+import android.graphics.Canvas;
+import android.graphics.ColorFilter;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.os.Build;
+import android.support.annotation.NonNull;
+import android.support.v4.graphics.drawable.DrawableCompat;
+import android.util.Property;
+
+import java.util.ArrayList;
+
+/**
+ * Generic drawable class that can be composed of multiple children. Whenever the bounds changes
+ * for this class, it updates those of it's children.
+ */
+@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
+public class CompositeDrawable extends Drawable implements Drawable.Callback {
+
+    static class CompositeState extends Drawable.ConstantState {
+
+        final ArrayList<ChildDrawable> mChildren;
+
+        CompositeState() {
+            mChildren = new ArrayList<ChildDrawable>();
+        }
+
+        CompositeState(CompositeState other, CompositeDrawable parent, Resources res) {
+            final int n = other.mChildren.size();
+            mChildren = new ArrayList<ChildDrawable>(n);
+            for (int k = 0; k < n; k++) {
+                mChildren.add(new ChildDrawable(other.mChildren.get(k), parent, res));
+            }
+        }
+
+        @NonNull
+        @Override
+        public Drawable newDrawable() {
+            return new CompositeDrawable(this);
+        }
+
+        @Override
+        public int getChangingConfigurations() {
+            return 0;
+        }
+
+    }
+
+    CompositeState mState;
+    boolean mMutated = false;
+
+    public CompositeDrawable() {
+        mState = new CompositeState();
+    }
+
+    CompositeDrawable(CompositeState state) {
+        mState = state;
+    }
+
+    @Override
+    public ConstantState getConstantState() {
+        return mState;
+    }
+
+    @Override
+    public Drawable mutate() {
+        if (!mMutated && super.mutate() == this) {
+            mState = new CompositeState(mState, this, null);
+            final ArrayList<ChildDrawable> children = mState.mChildren;
+            for (int i = 0, n = children.size(); i < n; i++) {
+                final Drawable dr = children.get(i).mDrawable;
+                if (dr != null) {
+                    dr.mutate();
+                }
+            }
+            mMutated = true;
+        }
+        return this;
+    }
+
+    /**
+     * Adds the supplied region.
+     */
+    public void addChildDrawable(Drawable drawable) {
+        mState.mChildren.add(new ChildDrawable(drawable, this));
+    }
+
+    /**
+     * Returns the {@link Drawable} for the given index.
+     */
+    public Drawable getDrawable(int index) {
+        return mState.mChildren.get(index).mDrawable;
+    }
+
+    /**
+     * Returns the {@link ChildDrawable} at the given index.
+     */
+    public ChildDrawable getChildAt(int index) {
+        return mState.mChildren.get(index);
+    }
+
+    /**
+     * Removes the child corresponding to the given index.
+     */
+    public void removeChild(int index) {
+        mState.mChildren.remove(index);
+    }
+
+    /**
+     * Removes the given region.
+     */
+    public void removeDrawable(Drawable drawable) {
+        final ArrayList<ChildDrawable> children = mState.mChildren;
+        for (int i = 0; i < children.size(); i++) {
+            if (drawable == children.get(i).mDrawable) {
+                children.get(i).mDrawable.setCallback(null);
+                children.remove(i);
+                return;
+            }
+        }
+    }
+
+    /**
+     * Returns the total number of children.
+     */
+    public int getChildCount() {
+        return mState.mChildren.size();
+    }
+
+    @Override
+    public void draw(Canvas canvas) {
+        final ArrayList<ChildDrawable> children = mState.mChildren;
+        for (int i = 0; i < children.size(); i++) {
+            children.get(i).mDrawable.draw(canvas);
+        }
+    }
+
+    @Override
+    protected void onBoundsChange(Rect bounds) {
+        super.onBoundsChange(bounds);
+        updateBounds(bounds);
+    }
+
+    @Override
+    public void setColorFilter(ColorFilter colorFilter) {
+        final ArrayList<ChildDrawable> children = mState.mChildren;
+        for (int i = 0; i < children.size(); i++) {
+            children.get(i).mDrawable.setColorFilter(colorFilter);
+        }
+    }
+
+    @Override
+    public int getOpacity() {
+        return PixelFormat.UNKNOWN;
+    }
+
+    @Override
+    public void setAlpha(int alpha) {
+        final ArrayList<ChildDrawable> children = mState.mChildren;
+        for (int i = 0; i < children.size(); i++) {
+            children.get(i).mDrawable.setAlpha(alpha);
+        }
+    }
+
+    /**
+     * @return Alpha value between 0(inclusive) and 255(inclusive)
+     */
+    public int getAlpha() {
+        final Drawable dr = getFirstNonNullDrawable();
+        if (dr != null) {
+            return DrawableCompat.getAlpha(dr);
+        } else {
+            return 0xFF;
+        }
+    }
+
+    final Drawable getFirstNonNullDrawable() {
+        final ArrayList<ChildDrawable> children = mState.mChildren;
+        for (int i = 0, n = children.size(); i < n; i++) {
+            final Drawable dr = children.get(i).mDrawable;
+            if (dr != null) {
+                return dr;
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public void invalidateDrawable(Drawable who) {
+        invalidateSelf();
+    }
+
+    @Override
+    public void scheduleDrawable(Drawable who, Runnable what, long when) {
+        scheduleSelf(what, when);
+    }
+
+    @Override
+    public void unscheduleDrawable(Drawable who, Runnable what) {
+        unscheduleSelf(what);
+    }
+
+    /**
+     * Updates the bounds based on the {@link BoundsRule}.
+     */
+    void updateBounds(Rect bounds) {
+        final ArrayList<ChildDrawable> children = mState.mChildren;
+        for (int i = 0; i < children.size(); i++) {
+            ChildDrawable childDrawable = children.get(i);
+            childDrawable.updateBounds(bounds);
+        }
+    }
+
+    /**
+     * Wrapper class holding a drawable object and {@link BoundsRule} to update drawable bounds
+     * when parent bound changes.
+     */
+    @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
+    public static final class ChildDrawable {
+        private final BoundsRule boundsRule = new BoundsRule();
+        private final Drawable mDrawable;
+        private final Rect adjustedBounds = new Rect();
+        private final CompositeDrawable mParent;
+
+        public ChildDrawable(Drawable drawable, CompositeDrawable parent) {
+            this.mDrawable = drawable;
+            this.mParent = parent;
+            drawable.setCallback(parent);
+        }
+
+        ChildDrawable(ChildDrawable orig, CompositeDrawable parent, Resources res) {
+            final Drawable dr = orig.mDrawable;
+            final Drawable clone;
+            if (dr != null) {
+                final ConstantState cs = dr.getConstantState();
+                if (res != null) {
+                    clone = cs.newDrawable(res);
+                } else {
+                    clone = cs.newDrawable();
+                }
+                clone.setCallback(parent);
+                DrawableCompat.setLayoutDirection(clone, DrawableCompat.getLayoutDirection(dr));
+                clone.setBounds(dr.getBounds());
+                clone.setLevel(dr.getLevel());
+            } else {
+                clone = null;
+            }
+            mDrawable = clone;
+            mParent = parent;
+        }
+
+        /**
+         * Returns the instance of {@link BoundsRule}.
+         */
+        public BoundsRule getBoundsRule() {
+            return this.boundsRule;
+        }
+
+        /**
+         * Returns the {@link Drawable}.
+         */
+        public Drawable getDrawable() {
+            return mDrawable;
+        }
+
+        /**
+         * Updates the bounds based on the {@link BoundsRule}.
+         */
+        void updateBounds(Rect bounds) {
+            boundsRule.calculateBounds(bounds, adjustedBounds);
+            mDrawable.setBounds(adjustedBounds);
+        }
+
+        /**
+         * After changing the {@link BoundsRule}, user should call this function
+         * for the drawable to recalculate its bounds.
+         */
+        public void recomputeBounds() {
+            updateBounds(mParent.getBounds());
+        }
+
+        /**
+         * Implementation of {@link Property} for overrideTop attribute.
+         */
+        public static final Property<CompositeDrawable.ChildDrawable, Integer> TOP_ABSOLUTE =
+                new Property<CompositeDrawable.ChildDrawable, Integer>(
+                        Integer.class, "absoluteTop") {
+            @Override
+            public void set(CompositeDrawable.ChildDrawable obj, Integer value) {
+                if (obj.getBoundsRule().mTop == null) {
+                    obj.getBoundsRule().mTop = BoundsRule.absoluteValue(value);
+                } else {
+                    obj.getBoundsRule().mTop.setAbsoluteValue(value);
+                }
+
+                obj.recomputeBounds();
+            }
+
+            @Override
+            public Integer get(CompositeDrawable.ChildDrawable obj) {
+                return obj.getBoundsRule().mTop.getAbsoluteValue();
+            }
+        };
+
+        /**
+         * Implementation of {@link Property} for overrideBottom attribute.
+         */
+        public static final Property<CompositeDrawable.ChildDrawable, Integer> BOTTOM_ABSOLUTE =
+                new Property<CompositeDrawable.ChildDrawable, Integer>(
+                        Integer.class, "absoluteBottom") {
+            @Override
+            public void set(CompositeDrawable.ChildDrawable obj, Integer value) {
+                if (obj.getBoundsRule().mBottom == null) {
+                    obj.getBoundsRule().mBottom = BoundsRule.absoluteValue(value);
+                } else {
+                    obj.getBoundsRule().mBottom.setAbsoluteValue(value);
+                }
+
+                obj.recomputeBounds();
+            }
+
+            @Override
+            public Integer get(CompositeDrawable.ChildDrawable obj) {
+                return obj.getBoundsRule().mBottom.getAbsoluteValue();
+            }
+        };
+
+
+        /**
+         * Implementation of {@link Property} for overrideLeft attribute.
+         */
+        public static final Property<CompositeDrawable.ChildDrawable, Integer> LEFT_ABSOLUTE =
+                new Property<CompositeDrawable.ChildDrawable, Integer>(
+                        Integer.class, "absoluteLeft") {
+            @Override
+            public void set(CompositeDrawable.ChildDrawable obj, Integer value) {
+                if (obj.getBoundsRule().mLeft == null) {
+                    obj.getBoundsRule().mLeft = BoundsRule.absoluteValue(value);
+                } else {
+                    obj.getBoundsRule().mLeft.setAbsoluteValue(value);
+                }
+
+                obj.recomputeBounds();
+            }
+
+            @Override
+            public Integer get(CompositeDrawable.ChildDrawable obj) {
+                return obj.getBoundsRule().mLeft.getAbsoluteValue();
+            }
+        };
+
+        /**
+         * Implementation of {@link Property} for overrideRight attribute.
+         */
+        public static final Property<CompositeDrawable.ChildDrawable, Integer> RIGHT_ABSOLUTE =
+                new Property<CompositeDrawable.ChildDrawable, Integer>(
+                        Integer.class, "absoluteRight") {
+            @Override
+            public void set(CompositeDrawable.ChildDrawable obj, Integer value) {
+                if (obj.getBoundsRule().mRight == null) {
+                    obj.getBoundsRule().mRight = BoundsRule.absoluteValue(value);
+                } else {
+                    obj.getBoundsRule().mRight.setAbsoluteValue(value);
+                }
+
+                obj.recomputeBounds();
+            }
+
+            @Override
+            public Integer get(CompositeDrawable.ChildDrawable obj) {
+                return obj.getBoundsRule().mRight.getAbsoluteValue();
+            }
+        };
+
+        /**
+         * Implementation of {@link Property} for overwriting the bottom attribute of
+         * {@link BoundsRule} associated with this {@link ChildDrawable}. This allows users to
+         * change the bounds rules as a percentage of parent size. This is preferable over
+         * {@see PROPERTY_TOP_ABSOLUTE} when the exact start/end position of scroll movement
+         * isn't available at compile time.
+         */
+        public static final Property<CompositeDrawable.ChildDrawable, Float> TOP_FRACTION =
+                new Property<CompositeDrawable.ChildDrawable, Float>(Float.class, "fractionTop") {
+            @Override
+            public void set(CompositeDrawable.ChildDrawable obj, Float value) {
+                if (obj.getBoundsRule().mTop == null) {
+                    obj.getBoundsRule().mTop = BoundsRule.inheritFromParent(value);
+                } else {
+                    obj.getBoundsRule().mTop.setFraction(value);
+                }
+
+                obj.recomputeBounds();
+            }
+
+            @Override
+            public Float get(CompositeDrawable.ChildDrawable obj) {
+                return obj.getBoundsRule().mTop.getFraction();
+            }
+        };
+
+        /**
+         * Implementation of {@link Property} for overwriting the bottom attribute of
+         * {@link BoundsRule} associated with this {@link ChildDrawable}. This allows users to
+         * change the bounds rules as a percentage of parent size. This is preferable over
+         * {@see PROPERTY_BOTTOM_ABSOLUTE} when the exact start/end position of scroll movement
+         * isn't available at compile time.
+         */
+        public static final Property<CompositeDrawable.ChildDrawable, Float> BOTTOM_FRACTION =
+                new Property<CompositeDrawable.ChildDrawable, Float>(
+                        Float.class, "fractionBottom") {
+            @Override
+            public void set(CompositeDrawable.ChildDrawable obj, Float value) {
+                if (obj.getBoundsRule().mBottom == null) {
+                    obj.getBoundsRule().mBottom = BoundsRule.inheritFromParent(value);
+                } else {
+                    obj.getBoundsRule().mBottom.setFraction(value);
+                }
+
+                obj.recomputeBounds();
+            }
+
+            @Override
+            public Float get(CompositeDrawable.ChildDrawable obj) {
+                return obj.getBoundsRule().mBottom.getFraction();
+            }
+        };
+
+        /**
+         * Implementation of {@link Property} for overwriting the bottom attribute of
+         * {@link BoundsRule} associated with this {@link ChildDrawable}. This allows users to
+         * change the bounds rules as a percentage of parent size. This is preferable over
+         * {@see PROPERTY_LEFT_ABSOLUTE} when the exact start/end position of scroll movement
+         * isn't available at compile time.
+         */
+        public static final Property<CompositeDrawable.ChildDrawable, Float> LEFT_FRACTION =
+                new Property<CompositeDrawable.ChildDrawable, Float>(Float.class, "fractionLeft") {
+            @Override
+            public void set(CompositeDrawable.ChildDrawable obj, Float value) {
+                if (obj.getBoundsRule().mLeft == null) {
+                    obj.getBoundsRule().mLeft = BoundsRule.inheritFromParent(value);
+                } else {
+                    obj.getBoundsRule().mLeft.setFraction(value);
+                }
+
+                obj.recomputeBounds();
+            }
+
+            @Override
+            public Float get(CompositeDrawable.ChildDrawable obj) {
+                return obj.getBoundsRule().mLeft.getFraction();
+            }
+        };
+
+        /**
+         * Implementation of {@link Property} for overwriting the bottom attribute of
+         * {@link BoundsRule} associated with this {@link ChildDrawable}. This allows users to
+         * change the bounds rules as a percentage of parent size. This is preferable over
+         * {@see PROPERTY_RIGHT_ABSOLUTE} when the exact start/end position of scroll movement
+         * isn't available at compile time.
+         */
+        public static final Property<CompositeDrawable.ChildDrawable, Float> RIGHT_FRACTION =
+                new Property<CompositeDrawable.ChildDrawable, Float>(Float.class, "fractoinRight") {
+            @Override
+            public void set(CompositeDrawable.ChildDrawable obj, Float value) {
+                if (obj.getBoundsRule().mRight == null) {
+                    obj.getBoundsRule().mRight = BoundsRule.inheritFromParent(value);
+                } else {
+                    obj.getBoundsRule().mRight.setFraction(value);
+                }
+
+                obj.recomputeBounds();
+            }
+
+            @Override
+            public Float get(CompositeDrawable.ChildDrawable obj) {
+                return obj.getBoundsRule().mRight.getFraction();
+            }
+        };
+    }
+}
diff --git a/v17/leanback/src/android/support/v17/leanback/graphics/FitWidthBitmapDrawable.java b/v17/leanback/src/android/support/v17/leanback/graphics/FitWidthBitmapDrawable.java
new file mode 100644
index 0000000..7320701
--- /dev/null
+++ b/v17/leanback/src/android/support/v17/leanback/graphics/FitWidthBitmapDrawable.java
@@ -0,0 +1,196 @@
+/*
+ * 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 android.support.v17.leanback.graphics;
+
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.ColorFilter;
+import android.graphics.Paint;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.support.annotation.NonNull;
+
+/**
+ * Subclass of {@link Drawable} that can be used to draw a bitmap into a region. Bitmap
+ * will be scaled to fit the full width of the region and will be aligned to the top left corner.
+ * Any region outside the bounds will be clipped during {@link #draw(Canvas)} call. Top
+ * position of the bitmap can be controlled by {@link #setVerticalOffset(int)} call.
+ */
+public class FitWidthBitmapDrawable extends Drawable {
+
+    static class BitmapState extends Drawable.ConstantState {
+        Paint mPaint;
+        Bitmap mBitmap;
+        Rect mSource;
+        final Rect mDefaultSource = new Rect();
+        int mOffset;
+
+        BitmapState() {
+            mPaint = new Paint();
+        }
+
+        BitmapState(BitmapState other) {
+            mBitmap = other.mBitmap;
+            mPaint = new Paint(other.mPaint);
+            mSource = other.mSource != null ? new Rect(other.mSource) : null;
+            mDefaultSource.set(other.mDefaultSource);
+            mOffset = other.mOffset;
+        }
+
+        @NonNull
+        @Override
+        public Drawable newDrawable() {
+            return new FitWidthBitmapDrawable(this);
+        }
+
+        @Override
+        public int getChangingConfigurations() {
+            return 0;
+        }
+    }
+
+    final Rect mDest = new Rect();
+    BitmapState mBitmapState;
+    boolean mMutated = false;
+
+    public FitWidthBitmapDrawable() {
+        mBitmapState = new BitmapState();
+    }
+
+    FitWidthBitmapDrawable(BitmapState state) {
+        mBitmapState = state;
+    }
+
+    @Override
+    public ConstantState getConstantState() {
+        return mBitmapState;
+    }
+
+    @Override
+    public Drawable mutate() {
+        if (!mMutated && super.mutate() == this) {
+            mBitmapState = new BitmapState(mBitmapState);
+            mMutated = true;
+        }
+        return this;
+    }
+
+    /**
+     * Sets the bitmap.
+     */
+    public void setBitmap(Bitmap bitmap) {
+        mBitmapState.mBitmap = bitmap;
+        if (bitmap != null) {
+            mBitmapState.mDefaultSource.set(0, 0, bitmap.getWidth(), bitmap.getHeight());
+        } else {
+            mBitmapState.mDefaultSource.set(0, 0, 0, 0);
+        }
+        mBitmapState.mSource = null;
+    }
+
+    /**
+     * Returns the bitmap.
+     */
+    public Bitmap getBitmap() {
+        return mBitmapState.mBitmap;
+    }
+
+    /**
+     * Sets the {@link Rect} used for extracting the bitmap.
+     */
+    public void setSource(Rect source) {
+        mBitmapState.mSource = source;
+    }
+
+    /**
+     * Returns the {@link Rect} used for extracting the bitmap.
+     */
+    public Rect getSource() {
+        return mBitmapState.mSource;
+    }
+
+    /**
+     * Sets the vertical offset which will be used for drawing the bitmap. The bitmap drawing
+     * will start the provided vertical offset.
+     */
+    public void setVerticalOffset(int offset) {
+        mBitmapState.mOffset = offset;
+        invalidateSelf();
+    }
+
+    /**
+     * Returns the current vertical offset.
+     */
+    public int getVerticalOffset() {
+        return mBitmapState.mOffset;
+    }
+
+    @Override
+    public void draw(Canvas canvas) {
+        if (mBitmapState.mBitmap != null) {
+            Rect bounds = getBounds();
+            mDest.left = 0;
+            mDest.top = mBitmapState.mOffset;
+            mDest.right = bounds.width();
+
+            Rect source = validateSource();
+            float scale = (float) bounds.width() / source.width();
+            mDest.bottom = mDest.top + (int) (source.height() * scale);
+            int i = canvas.save();
+            canvas.clipRect(bounds);
+            canvas.drawBitmap(mBitmapState.mBitmap, source, mDest, mBitmapState.mPaint);
+            canvas.restoreToCount(i);
+        }
+    }
+
+    @Override
+    public void setAlpha(int alpha) {
+        final int oldAlpha = mBitmapState.mPaint.getAlpha();
+        if (alpha != oldAlpha) {
+            mBitmapState.mPaint.setAlpha(alpha);
+            invalidateSelf();
+        }
+    }
+
+    /**
+     * @return Alpha value between 0(inclusive) and 255(inclusive)
+     */
+    public int getAlpha() {
+        return mBitmapState.mPaint.getAlpha();
+    }
+
+    @Override
+    public void setColorFilter(ColorFilter colorFilter) {
+        mBitmapState.mPaint.setColorFilter(colorFilter);
+        invalidateSelf();
+    }
+
+    @Override
+    public int getOpacity() {
+        final Bitmap bitmap = mBitmapState.mBitmap;
+        return (bitmap == null || bitmap.hasAlpha() || mBitmapState.mPaint.getAlpha() < 255)
+                ? PixelFormat.TRANSLUCENT : PixelFormat.OPAQUE;
+    }
+
+    private Rect validateSource() {
+        if (mBitmapState.mSource == null) {
+            return mBitmapState.mDefaultSource;
+        } else {
+            return mBitmapState.mSource;
+        }
+    }
+}
diff --git a/v17/leanback/src/android/support/v17/leanback/system/Settings.java b/v17/leanback/src/android/support/v17/leanback/system/Settings.java
index ec0316c..cdd2633 100644
--- a/v17/leanback/src/android/support/v17/leanback/system/Settings.java
+++ b/v17/leanback/src/android/support/v17/leanback/system/Settings.java
@@ -16,6 +16,8 @@
 
 package android.support.v17.leanback.system;
 
+import static android.support.annotation.RestrictTo.Scope.GROUP_ID;
+
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ApplicationInfo;
@@ -26,8 +28,6 @@
 import android.support.v17.leanback.widget.ShadowOverlayContainer;
 import android.util.Log;
 
-import static android.support.annotation.RestrictTo.Scope.GROUP_ID;
-
 /**
  * Provides various preferences affecting Leanback runtime behavior.
  * <p>Note this class is not thread safe and its methods should only
@@ -129,8 +129,9 @@
     private Customizations getCustomizations(Context context) {
         final PackageManager pm = context.getPackageManager();
         final Intent intent = new Intent(ACTION_PARTNER_CUSTOMIZATION);
-        if (DEBUG) Log.v(TAG, "getting oem customizations by intent: " +
-                ACTION_PARTNER_CUSTOMIZATION);
+        if (DEBUG) {
+            Log.v(TAG, "getting oem customizations by intent: " + ACTION_PARTNER_CUSTOMIZATION);
+        }
 
         Resources resources = null;
         String packageName = null;
@@ -151,7 +152,7 @@
     }
 
     private static boolean isSystemApp(ResolveInfo info) {
-        return (info.activityInfo != null &&
-                (info.activityInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0);
+        return (info.activityInfo != null
+                && (info.activityInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0);
     }
 }
diff --git a/v17/leanback/src/android/support/v17/leanback/transition/TransitionHelper.java b/v17/leanback/src/android/support/v17/leanback/transition/TransitionHelper.java
index 5b72643..c514323 100644
--- a/v17/leanback/src/android/support/v17/leanback/transition/TransitionHelper.java
+++ b/v17/leanback/src/android/support/v17/leanback/transition/TransitionHelper.java
@@ -157,6 +157,9 @@
         public void beginDelayedTransition(ViewGroup sceneRoot, Object transitionObject);
 
         public void setTransitionGroup(ViewGroup viewGroup, boolean transitionGroup);
+
+        public void setEpicenterCallback(Object transitionObject,
+                TransitionEpicenterCallback callback);
     }
 
     /**
@@ -393,6 +396,11 @@
         @Override
         public void setTransitionGroup(ViewGroup viewGroup, boolean transitionGroup) {
         }
+
+        @Override
+        public void setEpicenterCallback(Object transitionObject,
+                TransitionEpicenterCallback callback) {
+        }
     }
 
     /**
@@ -636,6 +644,11 @@
             return TransitionHelperApi21.createChangeTransform();
         }
 
+        @Override
+        public void setEpicenterCallback(Object transitionObject,
+                TransitionEpicenterCallback callback) {
+            TransitionHelperApi21.setEpicenterCallback(transitionObject, callback);
+        }
     }
 
     static {
@@ -847,6 +860,11 @@
         sImpl.setTransitionGroup(viewGroup, transitionGroup);
     }
 
+    public static void setEpicenterCallback(Object transition,
+            TransitionEpicenterCallback callback) {
+        sImpl.setEpicenterCallback(transition, callback);
+    }
+
     /**
      * @deprecated Use static calls.
      */
diff --git a/v17/leanback/src/android/support/v17/leanback/util/MathUtil.java b/v17/leanback/src/android/support/v17/leanback/util/MathUtil.java
new file mode 100644
index 0000000..523bd4c
--- /dev/null
+++ b/v17/leanback/src/android/support/v17/leanback/util/MathUtil.java
@@ -0,0 +1,40 @@
+/*
+ * 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 android.support.v17.leanback.util;
+
+import java.lang.Exception;
+
+/**
+ * Math Utilities for leanback library.
+ * @hide
+ */
+public final class MathUtil {
+
+    private MathUtil() {
+        // Prevent construction of this util class
+    }
+
+    /**
+     * Convert long to int safely. Similar with Math.toIntExact() in Java 8.
+     * @param numLong Number of type long to convert.
+     * @return int version of input.
+     * @throws ArithmeticException If input overflows int.
+     */
+    public static int safeLongToInt(long numLong) {
+        if ((int) numLong != numLong) {
+            throw new ArithmeticException("Input overflows int.\n");
+        }
+        return (int) numLong;
+    }
+}
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/AbstractDetailsDescriptionPresenter.java b/v17/leanback/src/android/support/v17/leanback/widget/AbstractDetailsDescriptionPresenter.java
index f603536..8d176c4 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/AbstractDetailsDescriptionPresenter.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/AbstractDetailsDescriptionPresenter.java
@@ -101,9 +101,9 @@
             mPreDrawListener = new ViewTreeObserver.OnPreDrawListener() {
                 @Override
                 public boolean onPreDraw() {
-                    if (mSubtitle.getVisibility() == View.VISIBLE &&
-                            mSubtitle.getTop() > view.getHeight() &&
-                            mTitle.getLineCount() > 1) {
+                    if (mSubtitle.getVisibility() == View.VISIBLE
+                            && mSubtitle.getTop() > view.getHeight()
+                            && mTitle.getLineCount() > 1) {
                         mTitle.setMaxLines(mTitle.getLineCount() - 1);
                         return false;
                     }
@@ -166,8 +166,8 @@
             hasTitle = false;
         } else {
             vh.mTitle.setVisibility(View.VISIBLE);
-            vh.mTitle.setLineSpacing(vh.mTitleLineSpacing - vh.mTitle.getLineHeight() +
-                    vh.mTitle.getLineSpacingExtra(), vh.mTitle.getLineSpacingMultiplier());
+            vh.mTitle.setLineSpacing(vh.mTitleLineSpacing - vh.mTitle.getLineHeight()
+                    + vh.mTitle.getLineSpacingExtra(), vh.mTitle.getLineSpacingMultiplier());
             vh.mTitle.setMaxLines(vh.mTitleMaxLines);
         }
         setTopMargin(vh.mTitle, vh.mTitleMargin);
@@ -179,8 +179,8 @@
         } else {
             vh.mSubtitle.setVisibility(View.VISIBLE);
             if (hasTitle) {
-                setTopMargin(vh.mSubtitle, vh.mUnderTitleBaselineMargin +
-                        vh.mSubtitleFontMetricsInt.ascent - vh.mTitleFontMetricsInt.descent);
+                setTopMargin(vh.mSubtitle, vh.mUnderTitleBaselineMargin
+                        + vh.mSubtitleFontMetricsInt.ascent - vh.mTitleFontMetricsInt.descent);
             } else {
                 setTopMargin(vh.mSubtitle, 0);
             }
@@ -190,15 +190,15 @@
             vh.mBody.setVisibility(View.GONE);
         } else {
             vh.mBody.setVisibility(View.VISIBLE);
-            vh.mBody.setLineSpacing(vh.mBodyLineSpacing - vh.mBody.getLineHeight() +
-                    vh.mBody.getLineSpacingExtra(), vh.mBody.getLineSpacingMultiplier());
+            vh.mBody.setLineSpacing(vh.mBodyLineSpacing - vh.mBody.getLineHeight()
+                    + vh.mBody.getLineSpacingExtra(), vh.mBody.getLineSpacingMultiplier());
 
             if (hasSubtitle) {
-                setTopMargin(vh.mBody, vh.mUnderSubtitleBaselineMargin +
-                        vh.mBodyFontMetricsInt.ascent - vh.mSubtitleFontMetricsInt.descent);
+                setTopMargin(vh.mBody, vh.mUnderSubtitleBaselineMargin
+                        + vh.mBodyFontMetricsInt.ascent - vh.mSubtitleFontMetricsInt.descent);
             } else if (hasTitle) {
-                setTopMargin(vh.mBody, vh.mUnderTitleBaselineMargin +
-                        vh.mBodyFontMetricsInt.ascent - vh.mTitleFontMetricsInt.descent);
+                setTopMargin(vh.mBody, vh.mUnderTitleBaselineMargin
+                        + vh.mBodyFontMetricsInt.ascent - vh.mTitleFontMetricsInt.descent);
             } else {
                 setTopMargin(vh.mBody, 0);
             }
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/AbstractMediaItemPresenter.java b/v17/leanback/src/android/support/v17/leanback/widget/AbstractMediaItemPresenter.java
index 87652dc..c607d64 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/AbstractMediaItemPresenter.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/AbstractMediaItemPresenter.java
@@ -203,9 +203,10 @@
             TypedValue typedValue = new TypedValue();
             boolean found = view.getContext().getTheme().resolveAttribute(
                     R.attr.playbackMediaItemNumberViewFlipperLayout, typedValue, true);
-            View mergeView = LayoutInflater.from(view.getContext()).
-                    inflate(found ? typedValue.resourceId :
-                            R.layout.lb_media_item_number_view_flipper,
+            View mergeView = LayoutInflater.from(view.getContext())
+                    .inflate(found
+                            ? typedValue.resourceId
+                            : R.layout.lb_media_item_number_view_flipper,
                             mMediaItemNumberViewFlipper, true);
 
             mMediaItemNumberView = (TextView) mergeView.findViewById(R.id.initial);
@@ -241,8 +242,8 @@
             mMediaItemRowActions = actionList;
             for (int i = mActionViewHolders.size(); i < actionList.length; i++) {
                 final int actionIndex = i;
-                final Presenter.ViewHolder actionViewHolder = actionPresenter.
-                        onCreateViewHolder(getMediaItemActionsContainer());
+                final Presenter.ViewHolder actionViewHolder =
+                        actionPresenter.onCreateViewHolder(getMediaItemActionsContainer());
                 getMediaItemActionsContainer().addView(actionViewHolder.view);
                 mActionViewHolders.add(actionViewHolder);
                 actionViewHolder.view.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@@ -426,8 +427,8 @@
         if (mThemeId != 0) {
             context = new ContextThemeWrapper(context, mThemeId);
         }
-        View view = LayoutInflater.from(context).
-                inflate(R.layout.lb_row_media_item, parent, false);
+        View view =
+                LayoutInflater.from(context).inflate(R.layout.lb_row_media_item, parent, false);
         final ViewHolder vh = new ViewHolder(view);
         vh.mRowPresenter = this;
         if (mBackgroundColorSet) {
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/BaseCardView.java b/v17/leanback/src/android/support/v17/leanback/widget/BaseCardView.java
index 20308c5..b9c4948 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/BaseCardView.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/BaseCardView.java
@@ -19,6 +19,7 @@
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.graphics.drawable.Drawable;
+import android.support.annotation.VisibleForTesting;
 import android.support.v17.leanback.R;
 import android.util.AttributeSet;
 import android.util.Log;
@@ -125,9 +126,12 @@
     private final int mActivatedAnimDuration;
     private final int mSelectedAnimDuration;
 
+    /**
+     * Distance of top of info view to bottom of MainView, it will shift up when extra view appears.
+     */
     float mInfoOffset;
     float mInfoVisFraction;
-    float mInfoAlpha = 1.0f;
+    float mInfoAlpha;
     private Animation mAnim;
 
     private final static int[] LB_PRESSED_STATE_SET = new int[]{
@@ -195,7 +199,8 @@
         mExtraViewList = new ArrayList<View>();
 
         mInfoOffset = 0.0f;
-        mInfoVisFraction = 0.0f;
+        mInfoVisFraction = getFinalInfoVisFraction();
+        mInfoAlpha = getFinalInfoAlpha();
     }
 
     /**
@@ -242,8 +247,8 @@
                 // Valid card type
                 mCardType = type;
             } else {
-                Log.e(TAG, "Invalid card type specified: " + type +
-                        ". Defaulting to type CARD_TYPE_MAIN_ONLY.");
+                Log.e(TAG, "Invalid card type specified: " + type
+                        + ". Defaulting to type CARD_TYPE_MAIN_ONLY.");
                 mCardType = CARD_TYPE_MAIN_ONLY;
             }
             requestLayout();
@@ -269,16 +274,30 @@
      */
     public void setInfoVisibility(int visibility) {
         if (mInfoVisibility != visibility) {
+            cancelAnimations();
             mInfoVisibility = visibility;
-            if (mInfoVisibility == CARD_REGION_VISIBLE_SELECTED && isSelected()) {
-                mInfoVisFraction = 1.0f;
-            } else {
-                mInfoVisFraction = 0.0f;
-            }
+            mInfoVisFraction = getFinalInfoVisFraction();
             requestLayout();
+            float newInfoAlpha = getFinalInfoAlpha();
+            if (newInfoAlpha != mInfoAlpha) {
+                mInfoAlpha = newInfoAlpha;
+                for (int i = 0; i < mInfoViewList.size(); i++) {
+                    mInfoViewList.get(i).setAlpha(mInfoAlpha);
+                }
+            }
         }
     }
 
+    final float getFinalInfoVisFraction() {
+        return mCardType == CARD_TYPE_INFO_UNDER && mInfoVisibility == CARD_REGION_VISIBLE_SELECTED
+                && !isSelected() ? 0.0f : 1.0f;
+    }
+
+    final float getFinalInfoAlpha() {
+        return mCardType == CARD_TYPE_INFO_OVER && mInfoVisibility == CARD_REGION_VISIBLE_SELECTED
+                && !isSelected() ? 0.0f : 1.0f;
+    }
+
     /**
      * Returns the visibility of the info region of the card.
      */
@@ -293,17 +312,20 @@
      *     be one of {@link #CARD_REGION_VISIBLE_ALWAYS},
      *     {@link #CARD_REGION_VISIBLE_SELECTED}, or
      *     {@link #CARD_REGION_VISIBLE_ACTIVATED}.
+     * @deprecated Extra view's visibility is controlled by {@link #setInfoVisibility(int)}
      */
+    @Deprecated
     public void setExtraVisibility(int visibility) {
         if (mExtraVisibility != visibility) {
             mExtraVisibility = visibility;
-            requestLayout();
         }
     }
 
     /**
      * Returns the visibility of the extra region of the card.
+     * @deprecated Extra view's visibility is controlled by {@link #getInfoVisibility()}
      */
+    @Deprecated
     public int getExtraVisibility() {
         return mExtraVisibility;
     }
@@ -400,13 +422,13 @@
         }
 
         boolean infoAnimating = hasInfoRegion() && mInfoVisibility == CARD_REGION_VISIBLE_SELECTED;
-        mMeasuredHeight = (int) (mainHeight +
-                (infoAnimating ? (infoHeight * mInfoVisFraction) : infoHeight)
+        mMeasuredHeight = (int) (mainHeight
+                + (infoAnimating ? (infoHeight * mInfoVisFraction) : infoHeight)
                 + extraHeight - (infoAnimating ? 0 : mInfoOffset));
 
         // Report our final dimensions.
-        setMeasuredDimension(View.resolveSizeAndState(mMeasuredWidth + getPaddingLeft() +
-                getPaddingRight(), widthMeasureSpec, state),
+        setMeasuredDimension(View.resolveSizeAndState(mMeasuredWidth + getPaddingLeft()
+                + getPaddingRight(), widthMeasureSpec, state),
                 View.resolveSizeAndState(mMeasuredHeight + getPaddingTop() + getPaddingBottom(),
                         heightMeasureSpec, state << View.MEASURED_HEIGHT_STATE_SHIFT));
     }
@@ -488,8 +510,6 @@
         super.onDetachedFromWindow();
         removeCallbacks(mAnimationTrigger);
         cancelAnimations();
-        mInfoOffset = 0.0f;
-        mInfoVisFraction = 0.0f;
     }
 
     private boolean hasInfoRegion() {
@@ -500,6 +520,9 @@
         return mCardType == CARD_TYPE_INFO_UNDER_WITH_EXTRA;
     }
 
+    /**
+     * Returns target visibility of info region.
+     */
     private boolean isRegionVisible(int regionVisibility) {
         switch (regionVisibility) {
             case CARD_REGION_VISIBLE_ALWAYS:
@@ -507,7 +530,28 @@
             case CARD_REGION_VISIBLE_ACTIVATED:
                 return isActivated();
             case CARD_REGION_VISIBLE_SELECTED:
-                return isActivated() && isSelected();
+                return isSelected();
+            default:
+                if (DEBUG) Log.e(TAG, "invalid region visibility state: " + regionVisibility);
+                return false;
+        }
+    }
+
+    /**
+     * Unlike isRegionVisible(), this method returns true when it is fading out when unselected.
+     */
+    private boolean isCurrentRegionVisible(int regionVisibility) {
+        switch (regionVisibility) {
+            case CARD_REGION_VISIBLE_ALWAYS:
+                return true;
+            case CARD_REGION_VISIBLE_ACTIVATED:
+                return isActivated();
+            case CARD_REGION_VISIBLE_SELECTED:
+                if (mCardType == CARD_TYPE_INFO_UNDER) {
+                    return mInfoVisFraction > 0f;
+                } else {
+                    return isSelected();
+                }
             default:
                 if (DEBUG) Log.e(TAG, "invalid region visibility state: " + regionVisibility);
                 return false;
@@ -521,13 +565,9 @@
 
         final int count = getChildCount();
 
-        boolean infoVisible = isRegionVisible(mInfoVisibility);
+        boolean infoVisible = hasInfoRegion() && isCurrentRegionVisible(mInfoVisibility);
         boolean extraVisible = hasExtraRegion() && mInfoOffset > 0f;
 
-        if (mCardType == CARD_TYPE_INFO_UNDER && mInfoVisibility == CARD_REGION_VISIBLE_SELECTED) {
-            infoVisible = infoVisible && mInfoVisFraction > 0f;
-        }
-
         for (int i = 0; i < count; i++) {
             final View child = getChildAt(i);
 
@@ -538,6 +578,7 @@
             BaseCardView.LayoutParams lp = (BaseCardView.LayoutParams) child
                     .getLayoutParams();
             if (lp.viewType == LayoutParams.VIEW_TYPE_INFO) {
+                child.setAlpha(mInfoAlpha);
                 mInfoViewList.add(child);
                 child.setVisibility(infoVisible ? View.VISIBLE : View.GONE);
             } else if (lp.viewType == LayoutParams.VIEW_TYPE_EXTRA) {
@@ -579,11 +620,8 @@
     }
 
     private void applyActiveState(boolean active) {
-        if (hasInfoRegion() && mInfoVisibility <= CARD_REGION_VISIBLE_ACTIVATED) {
-            setInfoViewVisibility(active);
-        }
-        if (hasExtraRegion() && mExtraVisibility <= CARD_REGION_VISIBLE_ACTIVATED) {
-            //setExtraVisibility(active);
+        if (hasInfoRegion() && mInfoVisibility == CARD_REGION_VISIBLE_ACTIVATED) {
+            setInfoViewVisibility(isRegionVisible(mInfoVisibility));
         }
     }
 
@@ -643,6 +681,7 @@
         if (mAnim != null) {
             mAnim.cancel();
             mAnim = null;
+            clearAnimation();
         }
     }
 
@@ -695,32 +734,30 @@
     private void animateInfoHeight(boolean shown) {
         cancelAnimations();
 
-        int extraHeight = 0;
         if (shown) {
-            int widthSpec = MeasureSpec.makeMeasureSpec(mMeasuredWidth, MeasureSpec.EXACTLY);
-            int heightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
-
-            for (int i = 0; i < mExtraViewList.size(); i++) {
-                View extraView = mExtraViewList.get(i);
+            for (int i = 0; i < mInfoViewList.size(); i++) {
+                View extraView = mInfoViewList.get(i);
                 extraView.setVisibility(View.VISIBLE);
-                extraView.measure(widthSpec, heightSpec);
-                extraHeight = Math.max(extraHeight, extraView.getMeasuredHeight());
             }
         }
 
-        mAnim = new InfoHeightAnimation(mInfoVisFraction, shown ? 1.0f : 0f);
+        float targetFraction = shown ? 1.0f : 0f;
+        if (mInfoVisFraction == targetFraction) {
+            return;
+        }
+        mAnim = new InfoHeightAnimation(mInfoVisFraction, targetFraction);
         mAnim.setDuration(mSelectedAnimDuration);
         mAnim.setInterpolator(new AccelerateDecelerateInterpolator());
         mAnim.setAnimationListener(new Animation.AnimationListener() {
-                @Override
+            @Override
             public void onAnimationStart(Animation animation) {
             }
 
-                @Override
+            @Override
             public void onAnimationEnd(Animation animation) {
-                if (mInfoOffset == 0f) {
-                    for (int i = 0; i < mExtraViewList.size(); i++) {
-                        mExtraViewList.get(i).setVisibility(View.GONE);
+                if (mInfoVisFraction == 0f) {
+                    for (int i = 0; i < mInfoViewList.size(); i++) {
+                        mInfoViewList.get(i).setVisibility(View.GONE);
                     }
                 }
             }
@@ -745,6 +782,10 @@
                 mInfoViewList.get(i).setVisibility(View.VISIBLE);
             }
         }
+        float targetAlpha = shown ? 1.0f : 0.0f;
+        if (targetAlpha == mInfoAlpha) {
+            return;
+        }
 
         mAnim = new InfoAlphaAnimation(mInfoAlpha, shown ? 1.0f : 0.0f);
         mAnim.setDuration(mActivatedAnimDuration);
@@ -854,9 +895,23 @@
         }
     }
 
+    class AnimationBase extends Animation {
+
+        @VisibleForTesting
+        final void mockStart() {
+            getTransformation(0, null);
+        }
+
+        @VisibleForTesting
+        final void mockEnd() {
+            applyTransformation(1f, null);
+            cancelAnimations();
+        }
+    }
+
     // Helper animation class used in the animation of the info and extra
     // fields vertically within the card
-    private class InfoOffsetAnimation extends Animation {
+    final class InfoOffsetAnimation extends AnimationBase {
         private float mStartValue;
         private float mDelta;
 
@@ -874,7 +929,7 @@
 
     // Helper animation class used in the animation of the visible height
     // for the info fields.
-    private class InfoHeightAnimation extends Animation {
+    final class InfoHeightAnimation extends AnimationBase {
         private float mStartValue;
         private float mDelta;
 
@@ -892,7 +947,7 @@
 
     // Helper animation class used to animate the alpha for the info views
     // when they are fading in or out of view.
-    private class InfoAlphaAnimation extends Animation {
+    final class InfoAlphaAnimation extends AnimationBase {
         private float mStartValue;
         private float mDelta;
 
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/BaseGridView.java b/v17/leanback/src/android/support/v17/leanback/widget/BaseGridView.java
index 82f5cfb..0fcfda1 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/BaseGridView.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/BaseGridView.java
@@ -226,10 +226,12 @@
         boolean throughSideStart = a.getBoolean(R.styleable.lbBaseGridView_focusOutSideStart, true);
         boolean throughSideEnd = a.getBoolean(R.styleable.lbBaseGridView_focusOutSideEnd, true);
         mLayoutManager.setFocusOutSideAllowed(throughSideStart, throughSideEnd);
-        mLayoutManager.setVerticalMargin(
-                a.getDimensionPixelSize(R.styleable.lbBaseGridView_verticalMargin, 0));
-        mLayoutManager.setHorizontalMargin(
-                a.getDimensionPixelSize(R.styleable.lbBaseGridView_horizontalMargin, 0));
+        mLayoutManager.setVerticalSpacing(
+                a.getDimensionPixelSize(R.styleable.lbBaseGridView_android_verticalSpacing,
+                        a.getDimensionPixelSize(R.styleable.lbBaseGridView_verticalMargin, 0)));
+        mLayoutManager.setHorizontalSpacing(
+                a.getDimensionPixelSize(R.styleable.lbBaseGridView_android_horizontalSpacing,
+                        a.getDimensionPixelSize(R.styleable.lbBaseGridView_horizontalMargin, 0)));
         if (a.hasValue(R.styleable.lbBaseGridView_android_gravity)) {
             setGravity(a.getInt(R.styleable.lbBaseGridView_android_gravity, Gravity.NO_GRAVITY));
         }
@@ -430,41 +432,86 @@
     }
 
     /**
-     * Sets the margin in pixels between two child items.
+     * Sets the spacing in pixels between two child items.
+     * @deprecated use {@link #setItemSpacing(int)}
      */
+    @Deprecated
     public void setItemMargin(int margin) {
-        mLayoutManager.setItemMargin(margin);
+        setItemSpacing(margin);
+    }
+
+    /**
+     * Sets the spacing in pixels between two child items.
+     */
+    public void setItemSpacing(int spacing) {
+        mLayoutManager.setItemSpacing(spacing);
         requestLayout();
     }
 
     /**
-     * Sets the margin in pixels between two child items vertically.
+     * Sets the spacing in pixels between two child items vertically.
+     * @deprecated Use {@link #setVerticalSpacing(int)}
      */
+    @Deprecated
     public void setVerticalMargin(int margin) {
-        mLayoutManager.setVerticalMargin(margin);
-        requestLayout();
+        setVerticalSpacing(margin);
     }
 
     /**
-     * Returns the margin in pixels between two child items vertically.
+     * Returns the spacing in pixels between two child items vertically.
+     * @deprecated Use {@link #getVerticalSpacing()}
      */
+    @Deprecated
     public int getVerticalMargin() {
-        return mLayoutManager.getVerticalMargin();
+        return mLayoutManager.getVerticalSpacing();
     }
 
     /**
-     * Sets the margin in pixels between two child items horizontally.
+     * Sets the spacing in pixels between two child items horizontally.
+     * @deprecated Use {@link #setHorizontalSpacing(int)}
      */
+    @Deprecated
     public void setHorizontalMargin(int margin) {
-        mLayoutManager.setHorizontalMargin(margin);
+        setHorizontalSpacing(margin);
+    }
+
+    /**
+     * Returns the spacing in pixels between two child items horizontally.
+     * @deprecated Use {@link #getHorizontalSpacing()}
+     */
+    @Deprecated
+    public int getHorizontalMargin() {
+        return mLayoutManager.getHorizontalSpacing();
+    }
+
+    /**
+     * Sets the spacing in pixels between two child items vertically.
+     */
+    public void setVerticalSpacing(int spacing) {
+        mLayoutManager.setVerticalSpacing(spacing);
         requestLayout();
     }
 
     /**
-     * Returns the margin in pixels between two child items horizontally.
+     * Returns the spacing in pixels between two child items vertically.
      */
-    public int getHorizontalMargin() {
-        return mLayoutManager.getHorizontalMargin();
+    public int getVerticalSpacing() {
+        return mLayoutManager.getVerticalSpacing();
+    }
+
+    /**
+     * Sets the spacing in pixels between two child items horizontally.
+     */
+    public void setHorizontalSpacing(int spacing) {
+        mLayoutManager.setHorizontalSpacing(spacing);
+        requestLayout();
+    }
+
+    /**
+     * Returns the spacing in pixels between two child items horizontally.
+     */
+    public int getHorizontalSpacing() {
+        return mLayoutManager.getHorizontalSpacing();
     }
 
     /**
@@ -610,7 +657,7 @@
             if (vh == null || hasPendingAdapterUpdates()) {
                 addOnChildViewHolderSelectedListener(new OnChildViewHolderSelectedListener() {
                     @Override
-                    public void onChildViewHolderSelected(RecyclerView parent,
+                    public void onChildViewHolderSelectedAndPositioned(RecyclerView parent,
                             RecyclerView.ViewHolder child, int selectedPosition, int subposition) {
                         if (selectedPosition == position) {
                             removeOnChildViewHolderSelectedListener(this);
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/BaseOnItemViewClickedListener.java b/v17/leanback/src/android/support/v17/leanback/widget/BaseOnItemViewClickedListener.java
index 0613667..738d0e9 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/BaseOnItemViewClickedListener.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/BaseOnItemViewClickedListener.java
@@ -25,7 +25,6 @@
      * @param rowViewHolder The view holder of the row which the clicked item belongs to.
      * @param row The row which the clicked item belongs to.
      */
-    public void onItemClicked(Presenter.ViewHolder itemViewHolder, Object item,
+    void onItemClicked(Presenter.ViewHolder itemViewHolder, Object item,
                               RowPresenter.ViewHolder rowViewHolder, T row);
-
 }
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/ControlBarPresenter.java b/v17/leanback/src/android/support/v17/leanback/widget/ControlBarPresenter.java
index f79f02f..4314fce 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/ControlBarPresenter.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/ControlBarPresenter.java
@@ -19,7 +19,6 @@
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
-import android.widget.LinearLayout;
 
 /**
  * A presenter that assumes a LinearLayout container for a series
@@ -127,8 +126,8 @@
             int adapterSize = adapter == null ? 0 : adapter.size();
             // Shrink the number of attached views
             View focusedView = mControlBar.getFocusedChild();
-            if (focusedView != null && adapterSize > 0 &&
-                    mControlBar.indexOfChild(focusedView) >= adapterSize) {
+            if (focusedView != null && adapterSize > 0
+                    && mControlBar.indexOfChild(focusedView) >= adapterSize) {
                 mControlBar.getChildAt(adapter.size() - 1).requestFocus();
             }
             for (int i = mControlBar.getChildCount() - 1; i >= adapterSize; i--) {
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/ControlButtonPresenterSelector.java b/v17/leanback/src/android/support/v17/leanback/widget/ControlButtonPresenterSelector.java
index 35a36b1..eef6c9c 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/ControlButtonPresenterSelector.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/ControlButtonPresenterSelector.java
@@ -101,8 +101,8 @@
                     vh.mLabel.setText(null);
                 }
             }
-            CharSequence contentDescription = TextUtils.isEmpty(action.getLabel2()) ?
-                action.getLabel1() : action.getLabel2();
+            CharSequence contentDescription = TextUtils.isEmpty(action.getLabel2())
+                    ? action.getLabel1() : action.getLabel2();
             if (!TextUtils.equals(vh.mFocusableView.getContentDescription(), contentDescription)) {
                 vh.mFocusableView.setContentDescription(contentDescription);
                 vh.mFocusableView.sendAccessibilityEvent(
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/DetailsOverviewLogoPresenter.java b/v17/leanback/src/android/support/v17/leanback/widget/DetailsOverviewLogoPresenter.java
index 6ae9995..22dba9c 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/DetailsOverviewLogoPresenter.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/DetailsOverviewLogoPresenter.java
@@ -1,12 +1,9 @@
 package android.support.v17.leanback.widget;
 
 import android.support.v17.leanback.R;
-
-import android.graphics.drawable.Drawable;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
-import android.view.ViewGroup.MarginLayoutParams;
 import android.widget.ImageView;
 
 /**
@@ -96,8 +93,8 @@
         View view = onCreateView(parent);
         ViewHolder vh = new ViewHolder(view);
         ViewGroup.LayoutParams lp = view.getLayoutParams();
-        vh.setSizeFromDrawableIntrinsic(lp.width == ViewGroup.LayoutParams.WRAP_CONTENT &&
-                lp.width == ViewGroup.LayoutParams.WRAP_CONTENT);
+        vh.setSizeFromDrawableIntrinsic(lp.width == ViewGroup.LayoutParams.WRAP_CONTENT
+                && lp.width == ViewGroup.LayoutParams.WRAP_CONTENT);
         return vh;
     }
 
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/DetailsOverviewRowPresenter.java b/v17/leanback/src/android/support/v17/leanback/widget/DetailsOverviewRowPresenter.java
index 88d7195..d484bcc 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/DetailsOverviewRowPresenter.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/DetailsOverviewRowPresenter.java
@@ -15,11 +15,9 @@
 
 import android.app.Activity;
 import android.content.Context;
-import android.graphics.Bitmap;
 import android.graphics.Color;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
 import android.os.Handler;
 import android.support.annotation.ColorInt;
 import android.support.v17.leanback.R;
@@ -33,8 +31,6 @@
 import android.widget.FrameLayout;
 import android.widget.ImageView;
 
-import java.util.Collection;
-
 /**
  * Renders a {@link DetailsOverviewRow} to display an overview of an item.
  * Typically this row will be the first row in a fragment
@@ -80,8 +76,8 @@
 
         @Override
         public void onBind(final ItemBridgeAdapter.ViewHolder ibvh) {
-            if (mViewHolder.getOnItemViewClickedListener() != null ||
-                    mActionClickedListener != null) {
+            if (mViewHolder.getOnItemViewClickedListener() != null
+                    || mActionClickedListener != null) {
                 ibvh.getPresenter().setOnClickListener(
                         ibvh.getViewHolder(), new View.OnClickListener() {
                             @Override
@@ -100,8 +96,8 @@
         }
         @Override
         public void onUnbind(final ItemBridgeAdapter.ViewHolder ibvh) {
-            if (mViewHolder.getOnItemViewClickedListener() != null ||
-                    mActionClickedListener != null) {
+            if (mViewHolder.getOnItemViewClickedListener() != null
+                    || mActionClickedListener != null) {
                 ibvh.getPresenter().setOnClickListener(ibvh.getViewHolder(), null);
             }
         }
@@ -195,9 +191,9 @@
             if (!isSelected()) {
                 return;
             }
-            ItemBridgeAdapter.ViewHolder ibvh = (ItemBridgeAdapter.ViewHolder) (view != null ?
-                    mActionsRow.getChildViewHolder(view) :
-                    mActionsRow.findViewHolderForPosition(mActionsRow.getSelectedPosition()));
+            ItemBridgeAdapter.ViewHolder ibvh = (ItemBridgeAdapter.ViewHolder) (view != null
+                    ? mActionsRow.getChildViewHolder(view)
+                    : mActionsRow.findViewHolderForPosition(mActionsRow.getSelectedPosition()));
             if (ibvh == null) {
                 if (getOnItemViewSelectedListener() != null) {
                     getOnItemViewSelectedListener().onItemSelected(null, null,
@@ -231,14 +227,16 @@
             RecyclerView.ViewHolder viewHolder;
 
             viewHolder = mActionsRow.findViewHolderForPosition(mNumItems - 1);
-            boolean showRight = (viewHolder == null ||
-                    viewHolder.itemView.getRight() > mActionsRow.getWidth());
+            boolean showRight = (viewHolder == null
+                    || viewHolder.itemView.getRight() > mActionsRow.getWidth());
 
             viewHolder = mActionsRow.findViewHolderForPosition(0);
             boolean showLeft = (viewHolder == null || viewHolder.itemView.getLeft() < 0);
 
-            if (DEBUG) Log.v(TAG, "checkFirstAndLast fromScroll " + fromScroll +
-                    " showRight " + showRight + " showLeft " + showLeft);
+            if (DEBUG) {
+                Log.v(TAG, "checkFirstAndLast fromScroll " + fromScroll
+                        + " showRight " + showRight + " showLeft " + showLeft);
+            }
 
             showMoreRight(showRight);
             showMoreLeft(showLeft);
@@ -487,8 +485,8 @@
                 }
             }
             // If long dimension bigger than the card height we scale down.
-            if ((landscape && drawableWidth > cardHeight) ||
-                    (!landscape && drawableHeight > cardHeight)) {
+            if ((landscape && drawableWidth > cardHeight)
+                    || (!landscape && drawableHeight > cardHeight)) {
                 scaleImage = true;
             }
             // If we're not scaling to fit the card height then we always use margin.
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/DetailsOverviewSharedElementHelper.java b/v17/leanback/src/android/support/v17/leanback/widget/DetailsOverviewSharedElementHelper.java
index 937d328..98bcb3b 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/DetailsOverviewSharedElementHelper.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/DetailsOverviewSharedElementHelper.java
@@ -13,22 +13,20 @@
  */
 package android.support.v17.leanback.widget;
 
+import android.app.Activity;
+import android.graphics.Matrix;
 import android.os.Handler;
+import android.support.v17.leanback.transition.TransitionHelper;
+import android.support.v17.leanback.transition.TransitionListener;
+import android.support.v17.leanback.widget.DetailsOverviewRowPresenter.ViewHolder;
 import android.support.v4.app.ActivityCompat;
 import android.support.v4.app.SharedElementCallback;
 import android.support.v4.view.ViewCompat;
-import android.support.v17.leanback.R;
-import android.support.v17.leanback.transition.TransitionListener;
-import android.support.v17.leanback.transition.TransitionHelper;
-import android.support.v17.leanback.widget.DetailsOverviewRowPresenter.ViewHolder;
-import android.app.Activity;
-import android.content.Intent;
-import android.graphics.Matrix;
 import android.text.TextUtils;
 import android.util.Log;
 import android.view.View;
-import android.view.ViewGroup;
 import android.view.View.MeasureSpec;
+import android.view.ViewGroup;
 import android.widget.ImageView;
 import android.widget.ImageView.ScaleType;
 
@@ -163,12 +161,12 @@
 
     void setSharedElementEnterTransition(Activity activity, String sharedElementName,
             long timeoutMs) {
-        if (activity == null && !TextUtils.isEmpty(sharedElementName) ||
-                activity != null && TextUtils.isEmpty(sharedElementName)) {
+        if (activity == null && !TextUtils.isEmpty(sharedElementName)
+                || activity != null && TextUtils.isEmpty(sharedElementName)) {
             throw new IllegalArgumentException();
         }
-        if (activity == mActivityToRunTransition &&
-                TextUtils.equals(sharedElementName, mSharedElementName)) {
+        if (activity == mActivityToRunTransition
+                && TextUtils.equals(sharedElementName, mSharedElementName)) {
             return;
         }
         if (mActivityToRunTransition != null) {
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/FullWidthDetailsOverviewRowPresenter.java b/v17/leanback/src/android/support/v17/leanback/widget/FullWidthDetailsOverviewRowPresenter.java
index 4b02418..189dfe6 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/FullWidthDetailsOverviewRowPresenter.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/FullWidthDetailsOverviewRowPresenter.java
@@ -13,30 +13,21 @@
  */
 package android.support.v17.leanback.widget;
 
-import android.app.Activity;
-import android.content.Context;
 import android.content.res.Resources;
-import android.graphics.Bitmap;
 import android.graphics.Color;
 import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
 import android.os.Handler;
 import android.support.v17.leanback.R;
-import android.support.v17.leanback.widget.ListRowPresenter.ViewHolder;
 import android.support.v7.widget.RecyclerView;
 import android.util.Log;
-import android.util.TypedValue;
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewGroup.MarginLayoutParams;
 import android.widget.FrameLayout;
-import android.widget.ImageView;
-
-import java.util.Collection;
 
 /**
  * Renders a {@link DetailsOverviewRow} to display an overview of an item. Typically this row will
@@ -126,8 +117,8 @@
 
         @Override
         public void onBind(final ItemBridgeAdapter.ViewHolder ibvh) {
-            if (mViewHolder.getOnItemViewClickedListener() != null ||
-                    mActionClickedListener != null) {
+            if (mViewHolder.getOnItemViewClickedListener() != null
+                    || mActionClickedListener != null) {
                 ibvh.getPresenter().setOnClickListener(
                         ibvh.getViewHolder(), new View.OnClickListener() {
                             @Override
@@ -146,8 +137,8 @@
         }
         @Override
         public void onUnbind(final ItemBridgeAdapter.ViewHolder ibvh) {
-            if (mViewHolder.getOnItemViewClickedListener() != null ||
-                    mActionClickedListener != null) {
+            if (mViewHolder.getOnItemViewClickedListener() != null
+                    || mActionClickedListener != null) {
                 ibvh.getPresenter().setOnClickListener(ibvh.getViewHolder(), null);
             }
         }
@@ -258,9 +249,9 @@
             if (!isSelected()) {
                 return;
             }
-            ItemBridgeAdapter.ViewHolder ibvh = (ItemBridgeAdapter.ViewHolder) (view != null ?
-                    mActionsRow.getChildViewHolder(view) :
-                    mActionsRow.findViewHolderForPosition(mActionsRow.getSelectedPosition()));
+            ItemBridgeAdapter.ViewHolder ibvh = (ItemBridgeAdapter.ViewHolder) (view != null
+                    ? mActionsRow.getChildViewHolder(view)
+                    : mActionsRow.findViewHolderForPosition(mActionsRow.getSelectedPosition()));
             if (ibvh == null) {
                 if (getOnItemViewSelectedListener() != null) {
                     getOnItemViewSelectedListener().onItemSelected(null, null,
@@ -294,14 +285,16 @@
             RecyclerView.ViewHolder viewHolder;
 
             viewHolder = mActionsRow.findViewHolderForPosition(mNumItems - 1);
-            boolean showRight = (viewHolder == null ||
-                    viewHolder.itemView.getRight() > mActionsRow.getWidth());
+            boolean showRight = (viewHolder == null
+                    || viewHolder.itemView.getRight() > mActionsRow.getWidth());
 
             viewHolder = mActionsRow.findViewHolderForPosition(0);
             boolean showLeft = (viewHolder == null || viewHolder.itemView.getLeft() < 0);
 
-            if (DEBUG) Log.v(TAG, "checkFirstAndLast fromScroll " + fromScroll +
-                    " showRight " + showRight + " showLeft " + showLeft);
+            if (DEBUG) {
+                Log.v(TAG, "checkFirstAndLast fromScroll " + fromScroll
+                        + " showRight " + showRight + " showLeft " + showLeft);
+            }
 
         }
 
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/FullWidthDetailsOverviewSharedElementHelper.java b/v17/leanback/src/android/support/v17/leanback/widget/FullWidthDetailsOverviewSharedElementHelper.java
index 9fd8815..96379d7 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/FullWidthDetailsOverviewSharedElementHelper.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/FullWidthDetailsOverviewSharedElementHelper.java
@@ -13,26 +13,15 @@
  */
 package android.support.v17.leanback.widget;
 
-import android.os.Handler;
-import android.support.v4.app.ActivityCompat;
-import android.support.v4.app.SharedElementCallback;
-import android.support.v4.view.ViewCompat;
-import android.support.v17.leanback.R;
-import android.support.v17.leanback.transition.TransitionListener;
-import android.support.v17.leanback.transition.TransitionHelper;
-import android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter.ViewHolder;
 import android.app.Activity;
-import android.content.Intent;
-import android.graphics.Matrix;
+import android.os.Handler;
+import android.support.v17.leanback.transition.TransitionHelper;
+import android.support.v17.leanback.transition.TransitionListener;
+import android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter.ViewHolder;
+import android.support.v4.app.ActivityCompat;
+import android.support.v4.view.ViewCompat;
 import android.text.TextUtils;
 import android.util.Log;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.View.MeasureSpec;
-import android.widget.ImageView;
-import android.widget.ImageView.ScaleType;
-
-import java.util.List;
 
 /**
  * Helper class to assist delayed shared element activity transition for view created by
@@ -63,12 +52,12 @@
 
     public void setSharedElementEnterTransition(Activity activity, String sharedElementName,
             long timeoutMs) {
-        if (activity == null && !TextUtils.isEmpty(sharedElementName) ||
-                activity != null && TextUtils.isEmpty(sharedElementName)) {
+        if (activity == null && !TextUtils.isEmpty(sharedElementName)
+                || activity != null && TextUtils.isEmpty(sharedElementName)) {
             throw new IllegalArgumentException();
         }
-        if (activity == mActivityToRunTransition &&
-                TextUtils.equals(sharedElementName, mSharedElementName)) {
+        if (activity == mActivityToRunTransition
+                && TextUtils.equals(sharedElementName, mSharedElementName)) {
             return;
         }
         mActivityToRunTransition = activity;
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/Grid.java b/v17/leanback/src/android/support/v17/leanback/widget/Grid.java
index 5df965d..64d151f 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/Grid.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/Grid.java
@@ -107,7 +107,7 @@
 
     protected Provider mProvider;
     protected boolean mReversedFlow;
-    protected int mMargin;
+    protected int mSpacing;
     protected int mNumRows;
     protected int mFirstVisibleIndex = -1;
     protected int mLastVisibleIndex = -1;
@@ -133,10 +133,10 @@
     }
 
     /**
-     * Sets the margin between items in a row
+     * Sets the space between items in a row
      */
-    public final void setMargin(int margin) {
-        mMargin = margin;
+    public final void setSpacing(int spacing) {
+        mSpacing = spacing;
     }
 
     /**
@@ -292,8 +292,8 @@
         if (mLastVisibleIndex < 0) {
             return false;
         }
-        return mReversedFlow ? findRowMin(true, null) <= toLimit + mMargin :
-                    findRowMax(false, null) >= toLimit - mMargin;
+        return mReversedFlow ? findRowMin(true, null) <= toLimit + mSpacing :
+                    findRowMax(false, null) >= toLimit - mSpacing;
     }
 
     /**
@@ -303,8 +303,8 @@
         if (mLastVisibleIndex < 0) {
             return false;
         }
-        return mReversedFlow ? findRowMax(false, null) >= toLimit - mMargin :
-                    findRowMin(true, null) <= toLimit + mMargin;
+        return mReversedFlow ? findRowMax(false, null) >= toLimit - mSpacing :
+                    findRowMin(true, null) <= toLimit + mSpacing;
     }
 
     /**
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/GridLayoutManager.java b/v17/leanback/src/android/support/v17/leanback/widget/GridLayoutManager.java
index 0a21ddd..a52555b 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/GridLayoutManager.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/GridLayoutManager.java
@@ -13,12 +13,18 @@
  */
 package android.support.v17.leanback.widget;
 
+import static android.support.v7.widget.RecyclerView.HORIZONTAL;
+import static android.support.v7.widget.RecyclerView.NO_ID;
+import static android.support.v7.widget.RecyclerView.NO_POSITION;
+import static android.support.v7.widget.RecyclerView.VERTICAL;
+
 import android.content.Context;
 import android.graphics.PointF;
 import android.graphics.Rect;
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.support.v17.leanback.os.TraceHelper;
 import android.support.v4.util.CircularIntArray;
 import android.support.v4.view.ViewCompat;
 import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
@@ -27,21 +33,14 @@
 import android.support.v7.widget.RecyclerView;
 import android.support.v7.widget.RecyclerView.Recycler;
 import android.support.v7.widget.RecyclerView.State;
-import android.support.v17.leanback.os.TraceHelper;
-
-import static android.support.v7.widget.RecyclerView.NO_ID;
-import static android.support.v7.widget.RecyclerView.NO_POSITION;
-import static android.support.v7.widget.RecyclerView.HORIZONTAL;
-import static android.support.v7.widget.RecyclerView.VERTICAL;
-
 import android.util.AttributeSet;
 import android.util.Log;
 import android.view.FocusFinder;
 import android.view.Gravity;
 import android.view.View;
 import android.view.View.MeasureSpec;
-import android.view.ViewGroup.MarginLayoutParams;
 import android.view.ViewGroup;
+import android.view.ViewGroup.MarginLayoutParams;
 
 import java.io.PrintWriter;
 import java.io.StringWriter;
@@ -213,6 +212,7 @@
                 mInSelection = false;
             }
             dispatchChildSelected();
+            dispatchChildSelectedAndPositioned();
             super.onStop();
         }
 
@@ -220,8 +220,8 @@
         protected int calculateTimeForScrolling(int dx) {
             int ms = super.calculateTimeForScrolling(dx);
             if (mWindowAlignment.mainAxis().getSize() > 0) {
-                float minMs = (float) MIN_MS_SMOOTH_SCROLL_MAIN_SCREEN /
-                        mWindowAlignment.mainAxis().getSize() * dx;
+                float minMs = (float) MIN_MS_SMOOTH_SCROLL_MAIN_SCREEN
+                        / mWindowAlignment.mainAxis().getSize() * dx;
                 if (ms < minMs) {
                     ms = (int) minMs;
                 }
@@ -345,8 +345,8 @@
             if (mPendingMoves == 0) {
                 return null;
             }
-            int direction = (mReverseFlowPrimary ? mPendingMoves > 0 : mPendingMoves < 0) ?
-                    -1 : 1;
+            int direction = (mReverseFlowPrimary ? mPendingMoves > 0 : mPendingMoves < 0)
+                    ? -1 : 1;
             if (mOrientation == HORIZONTAL) {
                 return new PointF(direction, 0);
             } else {
@@ -516,19 +516,19 @@
     /**
      * Margin between items.
      */
-    private int mHorizontalMargin;
+    private int mHorizontalSpacing;
     /**
      * Margin between items vertically.
      */
-    private int mVerticalMargin;
+    private int mVerticalSpacing;
     /**
      * Margin in main direction.
      */
-    private int mMarginPrimary;
+    private int mSpacingPrimary;
     /**
      * Margin in second direction.
      */
-    private int mMarginSecondary;
+    private int mSpacingSecondary;
     /**
      * How to position child in secondary direction.
      */
@@ -758,33 +758,33 @@
         }
     }
 
-    public void setItemMargin(int margin) {
-        mVerticalMargin = mHorizontalMargin = margin;
-        mMarginPrimary = mMarginSecondary = margin;
+    public void setItemSpacing(int space) {
+        mVerticalSpacing = mHorizontalSpacing = space;
+        mSpacingPrimary = mSpacingSecondary = space;
     }
 
-    public void setVerticalMargin(int margin) {
-        if (mOrientation == HORIZONTAL) {
-            mMarginSecondary = mVerticalMargin = margin;
+    public void setVerticalSpacing(int space) {
+        if (mOrientation == VERTICAL) {
+            mSpacingPrimary = mVerticalSpacing = space;
         } else {
-            mMarginPrimary = mVerticalMargin = margin;
+            mSpacingSecondary = mVerticalSpacing = space;
         }
     }
 
-    public void setHorizontalMargin(int margin) {
+    public void setHorizontalSpacing(int space) {
         if (mOrientation == HORIZONTAL) {
-            mMarginPrimary = mHorizontalMargin = margin;
+            mSpacingPrimary = mHorizontalSpacing = space;
         } else {
-            mMarginSecondary = mHorizontalMargin = margin;
+            mSpacingSecondary = mHorizontalSpacing = space;
         }
     }
 
-    public int getVerticalMargin() {
-        return mVerticalMargin;
+    public int getVerticalSpacing() {
+        return mVerticalSpacing;
     }
 
-    public int getHorizontalMargin() {
-        return mHorizontalMargin;
+    public int getHorizontalSpacing() {
+        return mHorizontalSpacing;
     }
 
     public void setGravity(int gravity) {
@@ -827,8 +827,8 @@
     }
 
     boolean hasOnChildViewHolderSelectedListener() {
-        return mChildViewHolderSelectedListeners != null &&
-                mChildViewHolderSelectedListeners.size() > 0;
+        return mChildViewHolderSelectedListeners != null
+                && mChildViewHolderSelectedListeners.size() > 0;
     }
 
     void fireOnChildViewHolderSelected(RecyclerView parent, RecyclerView.ViewHolder child,
@@ -842,6 +842,17 @@
         }
     }
 
+    void fireOnChildViewHolderSelectedAndPositioned(RecyclerView parent, RecyclerView.ViewHolder
+            child, int position, int subposition) {
+        if (mChildViewHolderSelectedListeners == null) {
+            return;
+        }
+        for (int i = mChildViewHolderSelectedListeners.size() - 1; i >= 0 ; i--) {
+            mChildViewHolderSelectedListeners.get(i).onChildViewHolderSelectedAndPositioned(parent,
+                    child, position, subposition);
+        }
+    }
+
     void setOnChildLaidOutListener(OnChildLaidOutListener listener) {
         mChildLaidOutListener = listener;
     }
@@ -929,6 +940,27 @@
         }
     }
 
+    private void dispatchChildSelectedAndPositioned() {
+        if (!hasOnChildViewHolderSelectedListener()) {
+            return;
+        }
+
+        if (TRACE) TraceHelper.beginSection("onChildSelectedAndPositioned");
+        View view = mFocusPosition == NO_POSITION ? null : findViewByPosition(mFocusPosition);
+        if (view != null) {
+            RecyclerView.ViewHolder vh = mBaseGridView.getChildViewHolder(view);
+            fireOnChildViewHolderSelectedAndPositioned(mBaseGridView, vh, mFocusPosition,
+                    mSubFocusPosition);
+        } else {
+            if (mChildSelectedListener != null) {
+                mChildSelectedListener.onChildSelected(mBaseGridView, null, NO_POSITION, NO_ID);
+            }
+            fireOnChildViewHolderSelectedAndPositioned(mBaseGridView, null, NO_POSITION, 0);
+        }
+        if (TRACE) TraceHelper.endSection();
+
+    }
+
     @Override
     public boolean canScrollHorizontally() {
         // We can scroll horizontally if we have horizontal orientation, or if
@@ -999,14 +1031,14 @@
 
     @Override
     public int getDecoratedRight(View child) {
-        return super.getDecoratedRight(child) -
-                ((LayoutParams) child.getLayoutParams()).mRightInset;
+        return super.getDecoratedRight(child)
+                - ((LayoutParams) child.getLayoutParams()).mRightInset;
     }
 
     @Override
     public int getDecoratedBottom(View child) {
-        return super.getDecoratedBottom(child) -
-                ((LayoutParams) child.getLayoutParams()).mBottomInset;
+        return super.getDecoratedBottom(child)
+                - ((LayoutParams) child.getLayoutParams()).mBottomInset;
     }
 
     @Override
@@ -1091,11 +1123,11 @@
             mFocusPosition = 0;
             mSubFocusPosition = 0;
         }
-        if (!mState.didStructureChange() && mGrid.getFirstVisibleIndex() >= 0 &&
-                !mForceFullLayout && mGrid != null && mGrid.getNumRows() == mNumRows) {
+        if (!mState.didStructureChange() && mGrid.getFirstVisibleIndex() >= 0
+                && !mForceFullLayout && mGrid != null && mGrid.getNumRows() == mNumRows) {
             updateScrollController();
             updateScrollSecondAxis();
-            mGrid.setMargin(mMarginPrimary);
+            mGrid.setSpacing(mSpacingPrimary);
             if (!focusViewWasInTree && mFocusPosition != NO_POSITION) {
                 mGrid.setStart(mFocusPosition);
             }
@@ -1104,15 +1136,15 @@
             mForceFullLayout = false;
             int firstVisibleIndex = focusViewWasInTree ? mGrid.getFirstVisibleIndex() : 0;
 
-            if (mGrid == null || mNumRows != mGrid.getNumRows() ||
-                    mReverseFlowPrimary != mGrid.isReversedFlow()) {
+            if (mGrid == null || mNumRows != mGrid.getNumRows()
+                    || mReverseFlowPrimary != mGrid.isReversedFlow()) {
                 mGrid = Grid.createGrid(mNumRows);
                 mGrid.setProvider(mGridProvider);
                 mGrid.setReversedFlow(mReverseFlowPrimary);
             }
             initScrollController();
             updateScrollSecondAxis();
-            mGrid.setMargin(mMarginPrimary);
+            mGrid.setSpacing(mSpacingPrimary);
             detachAndScrapAttachedViews(mRecycler);
             mGrid.resetVisibleIndex();
             if (mFocusPosition == NO_POSITION) {
@@ -1148,11 +1180,11 @@
         // in RTL flow
         if (mReverseFlowSecondary) {
             for (int i = mNumRows-1; i > rowIndex; i--) {
-                start += getRowSizeSecondary(i) + mMarginSecondary;
+                start += getRowSizeSecondary(i) + mSpacingSecondary;
             }
         } else {
             for (int i = 0; i < rowIndex; i++) {
-                start += getRowSizeSecondary(i) + mMarginSecondary;
+                start += getRowSizeSecondary(i) + mSpacingSecondary;
             }
         }
         return start;
@@ -1221,8 +1253,8 @@
                     if (measure) {
                         measureChild(view);
                     }
-                    final int secondarySize = mOrientation == HORIZONTAL ?
-                            getDecoratedMeasuredHeightWithMargin(view)
+                    final int secondarySize = mOrientation == HORIZONTAL
+                            ? getDecoratedMeasuredHeightWithMargin(view)
                             : getDecoratedMeasuredWidthWithMargin(view);
                     if (secondarySize > rowSize) {
                         rowSize = secondarySize;
@@ -1247,8 +1279,10 @@
                             mMeasuredDimension);
                     scrapChildWidth = mMeasuredDimension[0];
                     scrapChildHeight = mMeasuredDimension[1];
-                    if (DEBUG) Log.v(TAG, "measured scrap child: " + scrapChildWidth +
-                            " " + scrapChildHeight);
+                    if (DEBUG) {
+                        Log.v(TAG, "measured scrap child: " + scrapChildWidth + " "
+                                + scrapChildHeight);
+                    }
                 }
                 rowSize = mOrientation == HORIZONTAL ? scrapChildHeight : scrapChildWidth;
             }
@@ -1256,8 +1290,10 @@
                 rowSize = 0;
             }
             if (mRowSizeSecondary[rowIndex] != rowSize) {
-                if (DEBUG) Log.v(getTag(), "row size secondary changed: " + mRowSizeSecondary[rowIndex] +
-                        ", " + rowSize);
+                if (DEBUG) {
+                    Log.v(getTag(), "row size secondary changed: " + mRowSizeSecondary[rowIndex]
+                            + ", " + rowSize);
+                }
                 mRowSizeSecondary[rowIndex] = rowSize;
                 changed = true;
             }
@@ -1316,10 +1352,12 @@
             modeSecondary = MeasureSpec.getMode(widthSpec);
             paddingSecondary = getPaddingLeft() + getPaddingRight();
         }
-        if (DEBUG) Log.v(getTag(), "onMeasure widthSpec " + Integer.toHexString(widthSpec) +
-                " heightSpec " + Integer.toHexString(heightSpec) +
-                " modeSecondary " + Integer.toHexString(modeSecondary) +
-                " sizeSecondary " + sizeSecondary + " " + this);
+        if (DEBUG) {
+            Log.v(getTag(), "onMeasure widthSpec " + Integer.toHexString(widthSpec)
+                    + " heightSpec " + Integer.toHexString(heightSpec)
+                    + " modeSecondary " + Integer.toHexString(modeSecondary)
+                    + " sizeSecondary " + sizeSecondary + " " + this);
+        }
 
         mMaxSizeSecondary = sizeSecondary;
 
@@ -1351,41 +1389,41 @@
 
         } else {
             switch (modeSecondary) {
-            case MeasureSpec.UNSPECIFIED:
-                mFixedRowSizeSecondary = mRowSizeSecondaryRequested == 0 ?
-                        sizeSecondary - paddingSecondary: mRowSizeSecondaryRequested;
-                mNumRows = mNumRowsRequested == 0 ? 1 : mNumRowsRequested;
-                measuredSizeSecondary = mFixedRowSizeSecondary * mNumRows + mMarginSecondary
-                    * (mNumRows - 1) + paddingSecondary;
-                break;
-            case MeasureSpec.AT_MOST:
-            case MeasureSpec.EXACTLY:
-                if (mNumRowsRequested == 0 && mRowSizeSecondaryRequested == 0) {
-                    mNumRows = 1;
-                    mFixedRowSizeSecondary = sizeSecondary - paddingSecondary;
-                } else if (mNumRowsRequested == 0) {
-                    mFixedRowSizeSecondary = mRowSizeSecondaryRequested;
-                    mNumRows = (sizeSecondary + mMarginSecondary)
-                        / (mRowSizeSecondaryRequested + mMarginSecondary);
-                } else if (mRowSizeSecondaryRequested == 0) {
-                    mNumRows = mNumRowsRequested;
-                    mFixedRowSizeSecondary = (sizeSecondary - paddingSecondary - mMarginSecondary
-                            * (mNumRows - 1)) / mNumRows;
-                } else {
-                    mNumRows = mNumRowsRequested;
-                    mFixedRowSizeSecondary = mRowSizeSecondaryRequested;
-                }
-                measuredSizeSecondary = sizeSecondary;
-                if (modeSecondary == MeasureSpec.AT_MOST) {
-                    int childrenSize = mFixedRowSizeSecondary * mNumRows + mMarginSecondary
+                case MeasureSpec.UNSPECIFIED:
+                    mFixedRowSizeSecondary = mRowSizeSecondaryRequested == 0
+                            ? sizeSecondary - paddingSecondary : mRowSizeSecondaryRequested;
+                    mNumRows = mNumRowsRequested == 0 ? 1 : mNumRowsRequested;
+                    measuredSizeSecondary = mFixedRowSizeSecondary * mNumRows + mSpacingSecondary
                         * (mNumRows - 1) + paddingSecondary;
-                    if (childrenSize < measuredSizeSecondary) {
-                        measuredSizeSecondary = childrenSize;
+                    break;
+                case MeasureSpec.AT_MOST:
+                case MeasureSpec.EXACTLY:
+                    if (mNumRowsRequested == 0 && mRowSizeSecondaryRequested == 0) {
+                        mNumRows = 1;
+                        mFixedRowSizeSecondary = sizeSecondary - paddingSecondary;
+                    } else if (mNumRowsRequested == 0) {
+                        mFixedRowSizeSecondary = mRowSizeSecondaryRequested;
+                        mNumRows = (sizeSecondary + mSpacingSecondary)
+                            / (mRowSizeSecondaryRequested + mSpacingSecondary);
+                    } else if (mRowSizeSecondaryRequested == 0) {
+                        mNumRows = mNumRowsRequested;
+                        mFixedRowSizeSecondary = (sizeSecondary - paddingSecondary
+                                - mSpacingSecondary * (mNumRows - 1)) / mNumRows;
+                    } else {
+                        mNumRows = mNumRowsRequested;
+                        mFixedRowSizeSecondary = mRowSizeSecondaryRequested;
                     }
-                }
-                break;
-            default:
-                throw new IllegalStateException("wrong spec");
+                    measuredSizeSecondary = sizeSecondary;
+                    if (modeSecondary == MeasureSpec.AT_MOST) {
+                        int childrenSize = mFixedRowSizeSecondary * mNumRows + mSpacingSecondary
+                                * (mNumRows - 1) + paddingSecondary;
+                        if (childrenSize < measuredSizeSecondary) {
+                            measuredSizeSecondary = childrenSize;
+                        }
+                    }
+                    break;
+                default:
+                    throw new IllegalStateException("wrong spec");
             }
         }
         if (mOrientation == HORIZONTAL) {
@@ -1394,10 +1432,10 @@
             setMeasuredDimension(measuredSizeSecondary, sizePrimary);
         }
         if (DEBUG) {
-            Log.v(getTag(), "onMeasure sizePrimary " + sizePrimary +
-                    " measuredSizeSecondary " + measuredSizeSecondary +
-                    " mFixedRowSizeSecondary " + mFixedRowSizeSecondary +
-                    " mNumRows " + mNumRows);
+            Log.v(getTag(), "onMeasure sizePrimary " + sizePrimary
+                    + " measuredSizeSecondary " + measuredSizeSecondary
+                    + " mFixedRowSizeSecondary " + mFixedRowSizeSecondary
+                    + " mNumRows " + mNumRows);
         }
         leaveContext();
     }
@@ -1409,9 +1447,10 @@
         int widthUsed = lp.leftMargin + lp.rightMargin + sTempRect.left + sTempRect.right;
         int heightUsed = lp.topMargin + lp.bottomMargin + sTempRect.top + sTempRect.bottom;
 
-        final int secondarySpec = (mRowSizeSecondaryRequested == ViewGroup.LayoutParams.WRAP_CONTENT) ?
-                MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED) :
-                MeasureSpec.makeMeasureSpec(mFixedRowSizeSecondary, MeasureSpec.EXACTLY);
+        final int secondarySpec =
+                (mRowSizeSecondaryRequested == ViewGroup.LayoutParams.WRAP_CONTENT)
+                        ? MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)
+                        : MeasureSpec.makeMeasureSpec(mFixedRowSizeSecondary, MeasureSpec.EXACTLY);
         int widthSpec, heightSpec;
 
         if (mOrientation == HORIZONTAL) {
@@ -1424,11 +1463,13 @@
             widthSpec = ViewGroup.getChildMeasureSpec(secondarySpec, widthUsed, lp.width);
         }
         child.measure(widthSpec, heightSpec);
-        if (DEBUG) Log.v(getTag(), "measureChild secondarySpec " + Integer.toHexString(secondarySpec) +
-                " widthSpec " + Integer.toHexString(widthSpec) +
-                " heightSpec " + Integer.toHexString(heightSpec) +
-                " measuredWidth " + child.getMeasuredWidth() +
-                " measuredHeight " + child.getMeasuredHeight());
+        if (DEBUG) {
+            Log.v(getTag(), "measureChild secondarySpec " + Integer.toHexString(secondarySpec)
+                    + " widthSpec " + Integer.toHexString(widthSpec)
+                    + " heightSpec " + Integer.toHexString(heightSpec)
+                    + " measuredWidth " + child.getMeasuredWidth()
+                    + " measuredHeight " + child.getMeasuredHeight());
+        }
         if (DEBUG) Log.v(getTag(), "child lp width " + lp.width + " height " + lp.height);
         if (TRACE) TraceHelper.endSection();
     }
@@ -1602,9 +1643,10 @@
             sizeSecondary = Math.min(sizeSecondary, mFixedRowSizeSecondary);
         }
         final int verticalGravity = mGravity & Gravity.VERTICAL_GRAVITY_MASK;
-        final int horizontalGravity = (mReverseFlowPrimary || mReverseFlowSecondary) ?
-                Gravity.getAbsoluteGravity(mGravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK, View.LAYOUT_DIRECTION_RTL) :
-                mGravity & Gravity.HORIZONTAL_GRAVITY_MASK;
+        final int horizontalGravity = (mReverseFlowPrimary || mReverseFlowSecondary)
+                ? Gravity.getAbsoluteGravity(mGravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK,
+                        View.LAYOUT_DIRECTION_RTL)
+                : mGravity & Gravity.HORIZONTAL_GRAVITY_MASK;
         if (mOrientation == HORIZONTAL && verticalGravity == Gravity.TOP
                 || mOrientation == VERTICAL && horizontalGravity == Gravity.LEFT) {
             // do nothing
@@ -1911,8 +1953,8 @@
                 prependVisibleItems();
                 removeInvisibleViewsAtFront();
                 removeInvisibleViewsAtEnd();
-            } while (mGrid.getFirstVisibleIndex() != oldFirstVisible ||
-                    mGrid.getLastVisibleIndex() != oldLastVisible);
+            } while (mGrid.getFirstVisibleIndex() != oldFirstVisible
+                    || mGrid.getLastVisibleIndex() != oldLastVisible);
         }
 
         if (scrollToFocus) {
@@ -1938,14 +1980,15 @@
         }
 
         // For fastRelayout, only dispatch event when focus position changes.
-        if (mInFastRelayout && (mFocusPosition != savedFocusPos || mSubFocusPosition !=
-                savedSubFocusPos || findViewByPosition(mFocusPosition) != savedFocusView)) {
+        if (mInFastRelayout && (mFocusPosition != savedFocusPos || mSubFocusPosition
+                != savedSubFocusPos || findViewByPosition(mFocusPosition) != savedFocusView)) {
             dispatchChildSelected();
         } else if (!mInFastRelayout && mInLayoutSearchFocus) {
             // For full layout we dispatchChildSelected() in createItem() unless searched all
             // children and found none is focusable then dispatchChildSelected() here.
             dispatchChildSelected();
         }
+        dispatchChildSelectedAndPositioned();
 
         mInLayout = false;
         leaveContext();
@@ -2111,12 +2154,16 @@
         if (highAvailable) {
             mWindowAlignment.mainAxis().setMaxEdge(maxEdge);
             mWindowAlignment.mainAxis().setMaxScroll(maxScroll);
-            if (DEBUG) Log.v(getTag(), "updating scroll maxEdge to " + maxEdge +
-                    " scrollMax to " + maxScroll);
+            if (DEBUG) {
+                Log.v(getTag(), "updating scroll maxEdge to " + maxEdge
+                        + " scrollMax to " + maxScroll);
+            }
         } else {
             mWindowAlignment.mainAxis().invalidateScrollMax();
-            if (DEBUG) Log.v(getTag(), "Invalidate scrollMax since it should be "
-                    + "greater than " + maxScroll);
+            if (DEBUG) {
+                Log.v(getTag(), "Invalidate scrollMax since it should be "
+                        + "greater than " + maxScroll);
+            }
         }
     }
 
@@ -2143,12 +2190,16 @@
         if (lowAvailable) {
             mWindowAlignment.mainAxis().setMinEdge(minEdge);
             mWindowAlignment.mainAxis().setMinScroll(minScroll);
-            if (DEBUG) Log.v(getTag(), "updating scroll minEdge to " + minEdge +
-                    " scrollMin to " + minScroll);
+            if (DEBUG) {
+                Log.v(getTag(), "updating scroll minEdge to " + minEdge
+                        + " scrollMin to " + minScroll);
+            }
         } else {
             mWindowAlignment.mainAxis().invalidateScrollMin();
-            if (DEBUG) Log.v(getTag(), "Invalidate scrollMin, since it should be "
-                    + "less than " + minScroll);
+            if (DEBUG) {
+                Log.v(getTag(), "Invalidate scrollMin, since it should be "
+                        + "less than " + minScroll);
+            }
         }
     }
 
@@ -2261,8 +2312,8 @@
             }
             if (smooth) {
                 if (!hasDoneFirstLayout()) {
-                    Log.w(getTag(), "setSelectionSmooth should " +
-                            "not be called before first layout pass");
+                    Log.w(getTag(), "setSelectionSmooth should "
+                            + "not be called before first layout pass");
                     return;
                 }
                 startPositionSmoothScroller(position);
@@ -2441,12 +2492,12 @@
         boolean isMin, isMax;
         if (!mReverseFlowPrimary) {
             isMin = mGrid.getFirstVisibleIndex() == 0;
-            isMax = mGrid.getLastVisibleIndex() == (mState == null ?
-                    getItemCount() : mState.getItemCount()) - 1;
+            isMax = mGrid.getLastVisibleIndex() == (mState == null
+                    ? getItemCount() : mState.getItemCount()) - 1;
         } else {
             isMax = mGrid.getFirstVisibleIndex() == 0;
-            isMin = mGrid.getLastVisibleIndex() == (mState == null ?
-                    getItemCount() : mState.getItemCount()) - 1;
+            isMin = mGrid.getLastVisibleIndex() == (mState == null
+                    ? getItemCount() : mState.getItemCount()) - 1;
         }
         for (int i = getChildCount() - 1; (isMin || isMax) && i >= 0; i--) {
             View v = getChildAt(i);
@@ -2669,6 +2720,7 @@
                 mBaseGridView.smoothScrollBy(scrollX, scrollY);
             } else {
                 mBaseGridView.scrollBy(scrollX, scrollY);
+                dispatchChildSelectedAndPositioned();
             }
         }
     }
@@ -2863,8 +2915,8 @@
                 return true;
             }
             // Add focusables of neighbor depending on the focus search direction.
-            final int focusedRow = mGrid != null && focusedPos != NO_POSITION ?
-                    mGrid.getLocation(focusedPos).row : NO_POSITION;
+            final int focusedRow = mGrid != null && focusedPos != NO_POSITION
+                    ? mGrid.getLocation(focusedPos).row : NO_POSITION;
             final int focusableCount = views.size();
             int inc = movement == NEXT_ITEM || movement == NEXT_ROW ? 1 : -1;
             int loop_end = inc > 0 ? getChildCount() - 1 : 0;
@@ -3290,8 +3342,8 @@
             return moves;
         }
         int focusPosition = mFocusPosition;
-        int focusedRow = focusPosition != NO_POSITION ?
-                mGrid.getRowIndex(focusPosition) : NO_POSITION;
+        int focusedRow = focusPosition != NO_POSITION
+                ? mGrid.getRowIndex(focusPosition) : NO_POSITION;
         View newSelected = null;
         for (int i = 0, count = getChildCount(); i < count && moves != 0; i++) {
             int index = moves > 0 ? i : count - 1 - i;
@@ -3346,12 +3398,12 @@
             info.addAction(AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD);
             info.setScrollable(true);
         }
-        final AccessibilityNodeInfoCompat.CollectionInfoCompat collectionInfo
-                = AccessibilityNodeInfoCompat.CollectionInfoCompat
-                .obtain(getRowCountForAccessibility(recycler, state),
-                        getColumnCountForAccessibility(recycler, state),
-                        isLayoutHierarchical(recycler, state),
-                        getSelectionModeForAccessibility(recycler, state));
+        final AccessibilityNodeInfoCompat.CollectionInfoCompat collectionInfo =
+                AccessibilityNodeInfoCompat.CollectionInfoCompat
+                        .obtain(getRowCountForAccessibility(recycler, state),
+                                getColumnCountForAccessibility(recycler, state),
+                                isLayoutHierarchical(recycler, state),
+                                getSelectionModeForAccessibility(recycler, state));
         info.setCollectionInfo(collectionInfo);
         leaveContext();
     }
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/GuidanceStylingRelativeLayout.java b/v17/leanback/src/android/support/v17/leanback/widget/GuidanceStylingRelativeLayout.java
index 2bd7d28..2600470 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/GuidanceStylingRelativeLayout.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/GuidanceStylingRelativeLayout.java
@@ -30,15 +30,15 @@
 
     public GuidanceStylingRelativeLayout(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
-        init();
+        mTitleKeylinePercent = getKeyLinePercent(context);
     }
 
-    private void init() {
-        TypedArray ta = getContext().getTheme().obtainStyledAttributes(
+    public static float getKeyLinePercent(Context context) {
+        TypedArray ta = context.getTheme().obtainStyledAttributes(
                 R.styleable.LeanbackGuidedStepTheme);
-        mTitleKeylinePercent = ta.getFloat(R.styleable.LeanbackGuidedStepTheme_guidedStepKeyline,
-                40);
+        float percent = ta.getFloat(R.styleable.LeanbackGuidedStepTheme_guidedStepKeyline, 40);
         ta.recycle();
+        return percent;
     }
 
     @Override
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/GuidedActionAdapter.java b/v17/leanback/src/android/support/v17/leanback/widget/GuidedActionAdapter.java
index f0cc699..66335f4 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/GuidedActionAdapter.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/GuidedActionAdapter.java
@@ -13,32 +13,24 @@
  */
 package android.support.v17.leanback.widget;
 
-import android.content.Context;
-import android.database.DataSetObserver;
-import android.media.AudioManager;
+import static android.support.annotation.RestrictTo.Scope.GROUP_ID;
+
 import android.support.annotation.RestrictTo;
-import android.support.v17.leanback.R;
 import android.support.v7.widget.RecyclerView;
 import android.support.v7.widget.RecyclerView.ViewHolder;
 import android.util.Log;
 import android.view.KeyEvent;
-import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewParent;
 import android.view.inputmethod.EditorInfo;
-import android.view.inputmethod.InputMethodManager;
-import android.widget.AdapterView.OnItemSelectedListener;
 import android.widget.EditText;
-import android.widget.ImageView;
 import android.widget.TextView;
 import android.widget.TextView.OnEditorActionListener;
 
 import java.util.ArrayList;
 import java.util.List;
 
-import static android.support.annotation.RestrictTo.Scope.GROUP_ID;
-
 /**
  * GuidedActionAdapter instantiates views for guided actions, and manages their interactions.
  * Presentation (view creation and state animation) is delegated to a {@link
@@ -122,8 +114,7 @@
                     mGroup.openIme(GuidedActionAdapter.this, avh);
                 } else if (action.hasEditableActivatorView()) {
                     if (DEBUG_EDIT) Log.v(TAG_EDIT, "toggle editing mode by click");
-                    getGuidedActionsStylist().setEditingMode(avh, avh.getAction(),
-                            !avh.isInEditingActivatorView());
+                    performOnActionClick(avh);
                 } else {
                     handleCheckedActions(avh);
                     if (action.isEnabled() && !action.infoOnly()) {
@@ -469,8 +460,8 @@
         public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
             if (DEBUG_EDIT) Log.v(TAG_EDIT, "IME action: " + actionId);
             boolean handled = false;
-            if (actionId == EditorInfo.IME_ACTION_NEXT ||
-                actionId == EditorInfo.IME_ACTION_DONE) {
+            if (actionId == EditorInfo.IME_ACTION_NEXT
+                    || actionId == EditorInfo.IME_ACTION_DONE) {
                 mGroup.fillAndGoNext(GuidedActionAdapter.this, v);
                 handled = true;
             } else if (actionId == EditorInfo.IME_ACTION_NONE) {
@@ -488,8 +479,8 @@
             if (keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_UP) {
                 mGroup.fillAndStay(GuidedActionAdapter.this, editText);
                 return true;
-            } else if (keyCode == KeyEvent.KEYCODE_ENTER && event.getAction() ==
-                    KeyEvent.ACTION_UP) {
+            } else if (keyCode == KeyEvent.KEYCODE_ENTER
+                    && event.getAction() == KeyEvent.ACTION_UP) {
                 mGroup.fillAndGoNext(GuidedActionAdapter.this, editText);
                 return true;
             }
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/GuidedActionAdapterGroup.java b/v17/leanback/src/android/support/v17/leanback/widget/GuidedActionAdapterGroup.java
index dafa49b..075232a 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/GuidedActionAdapterGroup.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/GuidedActionAdapterGroup.java
@@ -124,7 +124,7 @@
     }
 
     public void openIme(GuidedActionAdapter adapter, GuidedActionsStylist.ViewHolder avh) {
-        adapter.getGuidedActionsStylist().setEditingMode(avh, avh.getAction(), true);
+        adapter.getGuidedActionsStylist().setEditingMode(avh, true);
         View v = avh.getEditingView();
         if (v == null || !avh.isInEditingText()) {
             return;
@@ -156,7 +156,7 @@
         GuidedActionsStylist.ViewHolder avh = adapter.findSubChildViewHolder(v);
         updateTextIntoAction(avh, v);
         mEditListener.onGuidedActionEditCanceled(avh.getAction());
-        adapter.getGuidedActionsStylist().setEditingMode(avh, avh.getAction(), false);
+        adapter.getGuidedActionsStylist().setEditingMode(avh, false);
         closeIme(v);
         avh.itemView.requestFocus();
     }
@@ -167,7 +167,7 @@
         updateTextIntoAction(avh, v);
         adapter.performOnActionClick(avh);
         long nextActionId = mEditListener.onGuidedActionEditedAndProceed(avh.getAction());
-        adapter.getGuidedActionsStylist().setEditingMode(avh, avh.getAction(), false);
+        adapter.getGuidedActionsStylist().setEditingMode(avh, false);
         if (nextActionId != GuidedAction.ACTION_ID_CURRENT
                 && nextActionId != avh.getAction().getId()) {
             handled = focusToNextAction(adapter, avh.getAction(), nextActionId);
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/GuidedActionsRelativeLayout.java b/v17/leanback/src/android/support/v17/leanback/widget/GuidedActionsRelativeLayout.java
new file mode 100644
index 0000000..6870b48
--- /dev/null
+++ b/v17/leanback/src/android/support/v17/leanback/widget/GuidedActionsRelativeLayout.java
@@ -0,0 +1,85 @@
+package android.support.v17.leanback.widget;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.support.v17.leanback.R;
+import android.util.AttributeSet;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.RelativeLayout;
+
+/**
+ * Relative layout implementation that assign subactions list topMargin based on a percentage
+ * given by "guidedStepKeyline" theme attribute when the topMargin is set to a negative value.
+ */
+class GuidedActionsRelativeLayout extends RelativeLayout {
+
+    interface InterceptKeyEventListener {
+        public boolean onInterceptKeyEvent(KeyEvent event);
+    }
+
+    private float mKeyLinePercent;
+    private boolean mInOverride = false;
+    private InterceptKeyEventListener mInterceptKeyEventListener;
+
+    public GuidedActionsRelativeLayout(Context context) {
+        this(context, null);
+    }
+
+    public GuidedActionsRelativeLayout(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public GuidedActionsRelativeLayout(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+        mKeyLinePercent = GuidanceStylingRelativeLayout.getKeyLinePercent(context);
+    }
+
+    private void init() {
+        TypedArray ta = getContext().getTheme().obtainStyledAttributes(
+                R.styleable.LeanbackGuidedStepTheme);
+        mKeyLinePercent = ta.getFloat(R.styleable.LeanbackGuidedStepTheme_guidedStepKeyline,
+                40);
+        ta.recycle();
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        final int heightSize = MeasureSpec.getSize(heightMeasureSpec);
+        if (heightSize > 0) {
+            View view = findViewById(R.id.guidedactions_sub_list);
+            if (view != null) {
+                ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams)
+                        view.getLayoutParams();
+                if (lp.topMargin < 0 && !mInOverride) {
+                    mInOverride = true;
+                }
+                if (mInOverride) {
+                    lp.topMargin = (int) (mKeyLinePercent * heightSize / 100);
+                }
+            }
+        }
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int l, int t, int r, int b) {
+        super.onLayout(changed, l, t, r, b);
+        mInOverride = false;
+    }
+
+    public void setInterceptKeyEventListener(InterceptKeyEventListener l) {
+        mInterceptKeyEventListener = l;
+    }
+
+    @Override
+    public boolean dispatchKeyEvent(KeyEvent event) {
+        if (mInterceptKeyEventListener != null) {
+            if (mInterceptKeyEventListener.onInterceptKeyEvent(event)) {
+                return true;
+            }
+        }
+        return super.dispatchKeyEvent(event);
+    }
+}
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/GuidedActionsStylist.java b/v17/leanback/src/android/support/v17/leanback/widget/GuidedActionsStylist.java
index 9c0b43e..faf537d 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/GuidedActionsStylist.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/GuidedActionsStylist.java
@@ -13,15 +13,24 @@
  */
 package android.support.v17.leanback.widget;
 
+import static android.support.annotation.RestrictTo.Scope.GROUP_ID;
+import static android.support.v17.leanback.widget.GuidedAction.EDITING_ACTIVATOR_VIEW;
+import static android.support.v17.leanback.widget.GuidedAction.EDITING_DESCRIPTION;
+import static android.support.v17.leanback.widget.GuidedAction.EDITING_NONE;
+import static android.support.v17.leanback.widget.GuidedAction.EDITING_TITLE;
+
 import android.animation.Animator;
 import android.animation.AnimatorInflater;
 import android.content.Context;
 import android.content.res.TypedArray;
+import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.os.Build.VERSION;
+import android.support.annotation.CallSuper;
 import android.support.annotation.NonNull;
 import android.support.annotation.RestrictTo;
 import android.support.v17.leanback.R;
+import android.support.v17.leanback.transition.TransitionEpicenterCallback;
 import android.support.v17.leanback.transition.TransitionHelper;
 import android.support.v17.leanback.transition.TransitionListener;
 import android.support.v17.leanback.widget.GuidedActionAdapter.EditListener;
@@ -31,6 +40,7 @@
 import android.text.TextUtils;
 import android.util.TypedValue;
 import android.view.Gravity;
+import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.View.AccessibilityDelegate;
@@ -48,12 +58,6 @@
 import java.util.Collections;
 import java.util.List;
 
-import static android.support.annotation.RestrictTo.Scope.GROUP_ID;
-import static android.support.v17.leanback.widget.GuidedAction.EDITING_ACTIVATOR_VIEW;
-import static android.support.v17.leanback.widget.GuidedAction.EDITING_DESCRIPTION;
-import static android.support.v17.leanback.widget.GuidedAction.EDITING_NONE;
-import static android.support.v17.leanback.widget.GuidedAction.EDITING_TITLE;
-
 /**
  * GuidedActionsStylist is used within a {@link android.support.v17.leanback.app.GuidedStepFragment}
  * to supply the right-side panel where users can take actions. It consists of a container for the
@@ -389,6 +393,10 @@
 
     private GuidedAction mExpandedAction = null;
     Object mExpandTransition;
+    private boolean mBackToCollapseSubActions = true;
+    private boolean mBackToCollapseActivatorView = true;
+
+    private float mKeyLinePercent;
 
     /**
      * Creates a view appropriate for displaying a list of GuidedActions, using the provided
@@ -414,8 +422,8 @@
         if (mMainView instanceof VerticalGridView) {
             mActionsGridView = (VerticalGridView) mMainView;
         } else {
-            mActionsGridView = (VerticalGridView) mMainView.findViewById(mButtonActions ?
-                    R.id.guidedactions_list2 : R.id.guidedactions_list);
+            mActionsGridView = (VerticalGridView) mMainView.findViewById(mButtonActions
+                    ? R.id.guidedactions_list2 : R.id.guidedactions_list);
             if (mActionsGridView == null) {
                 throw new IllegalStateException("No ListView exists.");
             }
@@ -451,6 +459,29 @@
                 .lb_guidedactions_item_unselected_description_text_alpha));
         mDisabledDescriptionAlpha = Float.valueOf(ctx.getResources().getString(R.string
                 .lb_guidedactions_item_disabled_description_text_alpha));
+
+        mKeyLinePercent = GuidanceStylingRelativeLayout.getKeyLinePercent(ctx);
+        if (mContentView instanceof GuidedActionsRelativeLayout) {
+            ((GuidedActionsRelativeLayout) mContentView).setInterceptKeyEventListener(
+                    new GuidedActionsRelativeLayout.InterceptKeyEventListener() {
+                        @Override
+                        public boolean onInterceptKeyEvent(KeyEvent event) {
+                            if (event.getKeyCode() == KeyEvent.KEYCODE_BACK
+                                    && event.getAction() == KeyEvent.ACTION_UP
+                                    && mExpandedAction != null) {
+                                if ((mExpandedAction.hasSubActions()
+                                        && isBackKeyToCollapseSubActions())
+                                        || (mExpandedAction.hasEditableActivatorView()
+                                        && isBackKeyToCollapseActivatorView())) {
+                                    collapseAction(true);
+                                    return true;
+                                }
+                            }
+                            return false;
+                        }
+                    }
+            );
+        }
         return mMainView;
     }
 
@@ -571,8 +602,8 @@
         } else if (viewType == VIEW_TYPE_DATE_PICKER) {
             return R.layout.lb_guidedactions_datepicker_item;
         } else {
-            throw new RuntimeException("ViewType " + viewType +
-                    " not supported in GuidedActionsStylist");
+            throw new RuntimeException("ViewType " + viewType
+                    + " not supported in GuidedActionsStylist");
         }
     }
 
@@ -629,8 +660,8 @@
         }
         if (vh.mDescriptionView != null) {
             vh.mDescriptionView.setText(action.getDescription());
-            vh.mDescriptionView.setVisibility(TextUtils.isEmpty(action.getDescription()) ?
-                    View.GONE : View.VISIBLE);
+            vh.mDescriptionView.setVisibility(TextUtils.isEmpty(action.getDescription())
+                    ? View.GONE : View.VISIBLE);
             vh.mDescriptionView.setAlpha(action.isEnabled() ? mEnabledDescriptionAlpha :
                 mDisabledDescriptionAlpha);
             vh.mDescriptionView.setFocusable(false);
@@ -662,7 +693,7 @@
         if (vh.mActivatorView != null) {
             onBindActivatorView(vh, action);
         }
-        setEditingMode(vh, action, false);
+        setEditingMode(vh, false /*editing*/, false /*withTransition*/);
         if (action.isFocusable()) {
             vh.itemView.setFocusable(true);
             ((ViewGroup) vh.itemView).setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS);
@@ -703,14 +734,34 @@
         }
     }
 
-    public void setEditingMode(ViewHolder vh, GuidedAction action, boolean editing) {
+    void setEditingMode(ViewHolder vh, boolean editing) {
+        setEditingMode(vh, editing, true /*withTransition*/);
+    }
+
+    void setEditingMode(ViewHolder vh, boolean editing, boolean withTransition) {
         if (editing != vh.isInEditing() && !isInExpandTransition()) {
-            onEditingModeChange(vh, action, editing);
+            onEditingModeChange(vh, editing, withTransition);
         }
     }
 
+    /**
+     * @deprecated Use {@link #onEditingModeChange(ViewHolder, boolean, boolean)}.
+     */
+    @Deprecated
     protected void onEditingModeChange(ViewHolder vh, GuidedAction action, boolean editing) {
-        action = vh.getAction();
+    }
+
+    /**
+     * Called when editing mode of an ViewHolder is changed.  Subclass must call
+     * <code>super.onEditingModeChange(vh,editing,withTransition)</code>.
+     *
+     * @param vh                ViewHolder to change editing mode.
+     * @param editing           True to enable editing, false to stop editing
+     * @param withTransition    True to run expand transiiton, false otherwise.
+     */
+    @CallSuper
+    protected void onEditingModeChange(ViewHolder vh, boolean editing, boolean withTransition) {
+        GuidedAction action = vh.getAction();
         TextView titleView = vh.getTitleView();
         TextView descriptionView = vh.getDescriptionView();
         if (editing) {
@@ -734,7 +785,7 @@
                 }
                 vh.mEditingMode = EDITING_TITLE;
             } else if (vh.mActivatorView != null) {
-                onEditActivatorView(vh, action, editing);
+                onEditActivatorView(vh, editing, withTransition);
                 vh.mEditingMode = EDITING_ACTIVATOR_VIEW;
             }
         } else {
@@ -746,8 +797,8 @@
             }
             if (vh.mEditingMode == EDITING_DESCRIPTION) {
                 if (descriptionView != null) {
-                    descriptionView.setVisibility(TextUtils.isEmpty(action.getDescription()) ?
-                            View.GONE : View.VISIBLE);
+                    descriptionView.setVisibility(TextUtils.isEmpty(action.getDescription())
+                            ? View.GONE : View.VISIBLE);
                     descriptionView.setInputType(action.getDescriptionInputType());
                 }
             } else if (vh.mEditingMode == EDITING_TITLE) {
@@ -756,11 +807,13 @@
                 }
             } else if (vh.mEditingMode == EDITING_ACTIVATOR_VIEW) {
                 if (vh.mActivatorView != null) {
-                    onEditActivatorView(vh, action, editing);
+                    onEditActivatorView(vh, editing, withTransition);
                 }
             }
             vh.mEditingMode = EDITING_NONE;
         }
+        // call deprecated method for backward compatible
+        onEditingModeChange(vh, action, editing);
     }
 
     /**
@@ -827,9 +880,9 @@
     public void onBindCheckMarkView(ViewHolder vh, GuidedAction action) {
         if (action.getCheckSetId() != GuidedAction.NO_CHECK_SET) {
             vh.mCheckmarkView.setVisibility(View.VISIBLE);
-            int attrId = action.getCheckSetId() == GuidedAction.CHECKBOX_CHECK_SET_ID ?
-                    android.R.attr.listChoiceIndicatorMultiple :
-                    android.R.attr.listChoiceIndicatorSingle;
+            int attrId = action.getCheckSetId() == GuidedAction.CHECKBOX_CHECK_SET_ID
+                    ? android.R.attr.listChoiceIndicatorMultiple
+                    : android.R.attr.listChoiceIndicatorSingle;
             final Context context = vh.mCheckmarkView.getContext();
             Drawable drawable = null;
             TypedValue typedValue = new TypedValue();
@@ -897,29 +950,29 @@
         mEditListener = listener;
     }
 
-    void onEditActivatorView(final ViewHolder vh, final GuidedAction action,
-            boolean editing) {
+    void onEditActivatorView(final ViewHolder vh, boolean editing, final boolean withTransition) {
         if (editing) {
             vh.itemView.setFocusable(false);
             vh.mActivatorView.requestFocus();
-            setExpandedViewHolder(vh);
+            startExpanded(vh, withTransition);
             vh.mActivatorView.setOnClickListener(new View.OnClickListener() {
                 @Override
                 public void onClick(View v) {
                     if (!isInExpandTransition()) {
-                        setEditingMode(vh, action, false);
+                        ((GuidedActionAdapter) getActionsGridView().getAdapter())
+                                .performOnActionClick(vh);
                     }
                 }
             });
         } else {
-            if (onUpdateActivatorView(vh, action)) {
+            if (onUpdateActivatorView(vh, vh.getAction())) {
                 if (mEditListener != null) {
-                    mEditListener.onGuidedActionEditedAndProceed(action);
+                    mEditListener.onGuidedActionEditedAndProceed(vh.getAction());
                 }
             }
             vh.itemView.setFocusable(true);
             vh.itemView.requestFocus();
-            setExpandedViewHolder(null);
+            startExpanded(null, withTransition);
             vh.mActivatorView.setOnClickListener(null);
             vh.mActivatorView.setClickable(false);
         }
@@ -955,19 +1008,15 @@
     }
 
     /**
-     * Expands or collapse the sub actions list view.
+     * Expands or collapse the sub actions list view with transition animation
      * @param avh When not null, fill sub actions list of this ViewHolder into sub actions list and
      * hide the other items in main list.  When null, collapse the sub actions list.
+     * @deprecated use {@link #expandAction(GuidedAction, boolean)} and
+     * {@link #collapseAction(boolean)}
      */
+    @Deprecated
     public void setExpandedViewHolder(ViewHolder avh) {
-        if (isInExpandTransition()) {
-            return;
-        }
-        if (isExpandTransitionSupported()) {
-            startExpandedTransition(avh);
-        } else {
-            onUpdateExpandedViewHolder(avh);
-        }
+        expandAction(avh == null ? null : avh.getAction(), isExpandTransitionSupported());
     }
 
     /**
@@ -992,8 +1041,144 @@
      * Start transition to expand or collapse GuidedActionStylist.
      * @param avh When not null, the GuidedActionStylist expands the sub actions of avh.  When null
      * the GuidedActionStylist will collapse sub actions.
+     * @deprecated use {@link #expandAction(GuidedAction, boolean)} and
+     * {@link #collapseAction(boolean)}
      */
+    @Deprecated
     public void startExpandedTransition(ViewHolder avh) {
+        expandAction(avh == null ? null : avh.getAction(), isExpandTransitionSupported());
+    }
+
+    /**
+     * Enable or disable using BACK key to collapse sub actions list. Default is enabled.
+     *
+     * @param backToCollapse True to enable using BACK key to collapse sub actions list, false
+     *                       to disable.
+     * @see GuidedAction#hasSubActions
+     * @see GuidedAction#getSubActions
+     */
+    public final void setBackKeyToCollapseSubActions(boolean backToCollapse) {
+        mBackToCollapseSubActions = backToCollapse;
+    }
+
+    /**
+     * @return True if using BACK key to collapse sub actions list, false otherwise. Default value
+     * is true.
+     *
+     * @see GuidedAction#hasSubActions
+     * @see GuidedAction#getSubActions
+     */
+    public final boolean isBackKeyToCollapseSubActions() {
+        return mBackToCollapseSubActions;
+    }
+
+    /**
+     * Enable or disable using BACK key to collapse {@link GuidedAction} with editable activator
+     * view. Default is enabled.
+     *
+     * @param backToCollapse True to enable using BACK key to collapse {@link GuidedAction} with
+     *                       editable activator view.
+     * @see GuidedAction#hasEditableActivatorView
+     */
+    public final void setBackKeyToCollapseActivatorView(boolean backToCollapse) {
+        mBackToCollapseActivatorView = backToCollapse;
+    }
+
+    /**
+     * @return True if using BACK key to collapse {@link GuidedAction} with editable activator
+     * view, false otherwise. Default value is true.
+     *
+     * @see GuidedAction#hasEditableActivatorView
+     */
+    public final boolean isBackKeyToCollapseActivatorView() {
+        return mBackToCollapseActivatorView;
+    }
+
+    /**
+     * Expand an action. Do nothing if it is in animation or there is action expanded.
+     *
+     * @param action         Action to expand.
+     * @param withTransition True to run transition animation, false otherwsie.
+     */
+    public void expandAction(GuidedAction action, final boolean withTransition) {
+        if (isInExpandTransition() || mExpandedAction != null) {
+            return;
+        }
+        int actionPosition =
+                ((GuidedActionAdapter) getActionsGridView().getAdapter()).indexOf(action);
+        if (actionPosition < 0) {
+            return;
+        }
+        boolean runTransition = isExpandTransitionSupported() && withTransition;
+        if (!runTransition) {
+            getActionsGridView().setSelectedPosition(actionPosition,
+                    new ViewHolderTask() {
+                        @Override
+                        public void run(RecyclerView.ViewHolder vh) {
+                            GuidedActionsStylist.ViewHolder avh =
+                                    (GuidedActionsStylist.ViewHolder)vh;
+                            if (avh.getAction().hasEditableActivatorView()) {
+                                setEditingMode(avh, true /*editing*/, false /*withTransition*/);
+                            } else {
+                                onUpdateExpandedViewHolder(avh);
+                            }
+                        }
+                    });
+            if (action.hasSubActions()) {
+                onUpdateSubActionsGridView(action, true);
+            }
+        } else {
+            getActionsGridView().setSelectedPosition(actionPosition,
+                    new ViewHolderTask() {
+                        @Override
+                        public void run(RecyclerView.ViewHolder vh) {
+                            GuidedActionsStylist.ViewHolder avh =
+                                    (GuidedActionsStylist.ViewHolder)vh;
+                            if (avh.getAction().hasEditableActivatorView()) {
+                                setEditingMode(avh, true /*editing*/, true /*withTransition*/);
+                            } else {
+                                startExpanded(avh, true);
+                            }
+                        }
+                    });
+        }
+
+    }
+
+    /**
+     * Collapse expanded action. Do nothing if it is in animation or there is no action expanded.
+     *
+     * @param withTransition True to run transition animation, false otherwsie.
+     */
+    public void collapseAction(boolean withTransition) {
+        if (isInExpandTransition() || mExpandedAction == null) {
+            return;
+        }
+        boolean runTransition = isExpandTransitionSupported() && withTransition;
+        int actionPosition =
+                ((GuidedActionAdapter) getActionsGridView().getAdapter()).indexOf(mExpandedAction);
+        if (actionPosition < 0) {
+            return;
+        }
+        if (mExpandedAction.hasEditableActivatorView()) {
+            setEditingMode(
+                    ((ViewHolder) getActionsGridView().findViewHolderForPosition(actionPosition)),
+                    false /*editing*/,
+                    runTransition);
+        } else {
+            startExpanded(null, runTransition);
+        }
+    }
+
+    int getKeyLine() {
+        return (int) (mKeyLinePercent * mActionsGridView.getHeight() / 100);
+    }
+
+    /**
+     * Internal method with assumption we already scroll to the new ViewHolder or is currently
+     * expanded.
+     */
+    void startExpanded(ViewHolder avh, final boolean withTransition) {
         ViewHolder focusAvh = null; // expand / collapse view holder
         final int count = mActionsGridView.getChildCount();
         for (int i = 0; i < count; i++) {
@@ -1011,102 +1196,101 @@
         }
         if (focusAvh == null) {
             // huh?
-            onUpdateExpandedViewHolder(avh);
             return;
         }
+        boolean isExpand = avh != null;
         boolean isSubActionTransition = focusAvh.getAction().hasSubActions();
-        Object set = TransitionHelper.createTransitionSet(false);
-        float slideDistance = isSubActionTransition ? focusAvh.itemView.getHeight() :
-                focusAvh.itemView.getHeight() * 0.5f;
-        Object slideAndFade = TransitionHelper.createFadeAndShortSlide(Gravity.TOP | Gravity.BOTTOM,
-                slideDistance);
-        Object changeFocusItemTransform = TransitionHelper.createChangeTransform();
-        Object changeFocusItemBounds = TransitionHelper.createChangeBounds(false);
-        Object fade = TransitionHelper.createFadeTransition(TransitionHelper.FADE_IN |
-                TransitionHelper.FADE_OUT);
-        Object changeGridBounds = TransitionHelper.createChangeBounds(false);
-        if (avh == null) {
-            TransitionHelper.setStartDelay(slideAndFade, 150);
-            TransitionHelper.setStartDelay(changeFocusItemTransform, 100);
-            TransitionHelper.setStartDelay(changeFocusItemBounds, 100);
-        } else {
-            TransitionHelper.setStartDelay(fade, 100);
-            TransitionHelper.setStartDelay(changeGridBounds, 100);
-            TransitionHelper.setStartDelay(changeFocusItemTransform, 50);
-            TransitionHelper.setStartDelay(changeFocusItemBounds, 50);
-        }
-        for (int i = 0; i < count; i++) {
-            ViewHolder vh = (ViewHolder) mActionsGridView
-                    .getChildViewHolder(mActionsGridView.getChildAt(i));
-            if (vh == focusAvh) {
-                // going to expand/collapse this one.
-                if (isSubActionTransition) {
-                    TransitionHelper.include(changeFocusItemTransform, vh.itemView);
-                    TransitionHelper.include(changeFocusItemBounds, vh.itemView);
-                }
-            } else {
-                // going to slide this item to top / bottom.
-                TransitionHelper.include(slideAndFade, vh.itemView);
-                TransitionHelper.exclude(fade, vh.itemView, true);
-            }
-        }
-        TransitionHelper.include(changeGridBounds, mSubActionsGridView);
-        TransitionHelper.include(changeGridBounds, mSubActionsBackground);
-        TransitionHelper.addTransition(set, slideAndFade);
-        // note that we don't run ChangeBounds for activating view due to the rounding problem
-        // of multiple level views ChangeBounds animation causing vertical jittering.
-        if (isSubActionTransition) {
-            TransitionHelper.addTransition(set, changeFocusItemTransform);
-            TransitionHelper.addTransition(set, changeFocusItemBounds);
-        }
-        TransitionHelper.addTransition(set, fade);
-        TransitionHelper.addTransition(set, changeGridBounds);
-        mExpandTransition = set;
-        TransitionHelper.addTransitionListener(mExpandTransition, new TransitionListener() {
-            @Override
-            public void onTransitionEnd(Object transition) {
-                mExpandTransition = null;
-            }
-        });
-        if (avh != null && mSubActionsGridView.getTop() != avh.itemView.getTop()) {
-            // For expanding, set the initial position of subActionsGridView before running
-            // a ChangeBounds on it.
-            final ViewHolder toUpdate = avh;
-            mSubActionsGridView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
+        if (withTransition) {
+            Object set = TransitionHelper.createTransitionSet(false);
+            float slideDistance = isSubActionTransition ? focusAvh.itemView.getHeight()
+                    : focusAvh.itemView.getHeight() * 0.5f;
+            Object slideAndFade = TransitionHelper.createFadeAndShortSlide(
+                    Gravity.TOP | Gravity.BOTTOM,
+                    slideDistance);
+            TransitionHelper.setEpicenterCallback(slideAndFade, new TransitionEpicenterCallback() {
+                Rect mRect = new Rect();
                 @Override
-                public void onLayoutChange(View v, int left, int top, int right, int bottom,
-                        int oldLeft, int oldTop, int oldRight, int oldBottom) {
-                    if (mSubActionsGridView == null) {
-                        return;
-                    }
-                    mSubActionsGridView.removeOnLayoutChangeListener(this);
-                    mMainView.post(new Runnable() {
-                        @Override
-                        public void run() {
-                            if (mMainView == null) {
-                                return;
-                            }
-                            TransitionHelper.beginDelayedTransition(mMainView, mExpandTransition);
-                            onUpdateExpandedViewHolder(toUpdate);
-                        }
-                    });
+                public Rect onGetEpicenter(Object transition) {
+                    int centerY = getKeyLine();
+                    int centerX = 0;
+                    mRect.set(centerX, centerY, centerX, centerY);
+                    return mRect;
                 }
             });
-            ViewGroup.MarginLayoutParams lp =
-                    (ViewGroup.MarginLayoutParams) mSubActionsGridView.getLayoutParams();
-            lp.topMargin = avh.itemView.getTop();
-            lp.height = 0;
-            mSubActionsGridView.setLayoutParams(lp);
-            return;
+            Object changeFocusItemTransform = TransitionHelper.createChangeTransform();
+            Object changeFocusItemBounds = TransitionHelper.createChangeBounds(false);
+            Object fade = TransitionHelper.createFadeTransition(TransitionHelper.FADE_IN
+                    | TransitionHelper.FADE_OUT);
+            Object changeGridBounds = TransitionHelper.createChangeBounds(false);
+            if (avh == null) {
+                TransitionHelper.setStartDelay(slideAndFade, 150);
+                TransitionHelper.setStartDelay(changeFocusItemTransform, 100);
+                TransitionHelper.setStartDelay(changeFocusItemBounds, 100);
+                TransitionHelper.setStartDelay(changeGridBounds, 100);
+            } else {
+                TransitionHelper.setStartDelay(fade, 100);
+                TransitionHelper.setStartDelay(changeGridBounds, 50);
+                TransitionHelper.setStartDelay(changeFocusItemTransform, 50);
+                TransitionHelper.setStartDelay(changeFocusItemBounds, 50);
+            }
+            for (int i = 0; i < count; i++) {
+                ViewHolder vh = (ViewHolder) mActionsGridView
+                        .getChildViewHolder(mActionsGridView.getChildAt(i));
+                if (vh == focusAvh) {
+                    // going to expand/collapse this one.
+                    if (isSubActionTransition) {
+                        TransitionHelper.include(changeFocusItemTransform, vh.itemView);
+                        TransitionHelper.include(changeFocusItemBounds, vh.itemView);
+                    }
+                } else {
+                    // going to slide this item to top / bottom.
+                    TransitionHelper.include(slideAndFade, vh.itemView);
+                    TransitionHelper.exclude(fade, vh.itemView, true);
+                }
+            }
+            TransitionHelper.include(changeGridBounds, mSubActionsGridView);
+            TransitionHelper.include(changeGridBounds, mSubActionsBackground);
+            TransitionHelper.addTransition(set, slideAndFade);
+            // note that we don't run ChangeBounds for activating view due to the rounding problem
+            // of multiple level views ChangeBounds animation causing vertical jittering.
+            if (isSubActionTransition) {
+                TransitionHelper.addTransition(set, changeFocusItemTransform);
+                TransitionHelper.addTransition(set, changeFocusItemBounds);
+            }
+            TransitionHelper.addTransition(set, fade);
+            TransitionHelper.addTransition(set, changeGridBounds);
+            mExpandTransition = set;
+            TransitionHelper.addTransitionListener(mExpandTransition, new TransitionListener() {
+                @Override
+                public void onTransitionEnd(Object transition) {
+                    mExpandTransition = null;
+                }
+            });
+            if (isExpand && isSubActionTransition) {
+                // To expand sub actions, move original position of sub actions to bottom of item
+                int startY = avh.itemView.getBottom();
+                mSubActionsGridView.offsetTopAndBottom(startY - mSubActionsGridView.getTop());
+                mSubActionsBackground.offsetTopAndBottom(startY - mSubActionsBackground.getTop());
+            }
+            TransitionHelper.beginDelayedTransition(mMainView, mExpandTransition);
         }
-        TransitionHelper.beginDelayedTransition(mMainView, mExpandTransition);
         onUpdateExpandedViewHolder(avh);
+        if (isSubActionTransition) {
+            onUpdateSubActionsGridView(focusAvh.getAction(), isExpand);
+        }
     }
 
     /**
      * @return True if sub actions list is expanded.
      */
     public boolean isSubActionsExpanded() {
+        return mExpandedAction != null && mExpandedAction.hasSubActions();
+    }
+
+    /**
+     * @return True if there is {@link #getExpandedAction()} is not null, false otherwise.
+     */
+    public boolean isExpanded() {
         return mExpandedAction != null;
     }
 
@@ -1147,28 +1331,35 @@
                     .getChildViewHolder(mActionsGridView.getChildAt(i));
             updateChevronAndVisibility(vh);
         }
+    }
+
+    void onUpdateSubActionsGridView(GuidedAction action, boolean expand) {
         if (mSubActionsGridView != null) {
-            if (avh != null && avh.getAction().hasSubActions()) {
-                ViewGroup.MarginLayoutParams lp =
-                        (ViewGroup.MarginLayoutParams) mSubActionsGridView.getLayoutParams();
-                lp.topMargin = avh.itemView.getTop();
+            ViewGroup.MarginLayoutParams lp =
+                    (ViewGroup.MarginLayoutParams) mSubActionsGridView.getLayoutParams();
+            GuidedActionAdapter adapter = (GuidedActionAdapter) mSubActionsGridView.getAdapter();
+            if (expand) {
+                // set to negative value so GuidedActionRelativeLayout will override with
+                // keyLine percentage.
+                lp.topMargin = -2;
                 lp.height = ViewGroup.MarginLayoutParams.MATCH_PARENT;
                 mSubActionsGridView.setLayoutParams(lp);
                 mSubActionsGridView.setVisibility(View.VISIBLE);
                 mSubActionsBackground.setVisibility(View.VISIBLE);
                 mSubActionsGridView.requestFocus();
-                mSubActionsGridView.setSelectedPosition(0);
-                ((GuidedActionAdapter) mSubActionsGridView.getAdapter())
-                        .setActions(avh.getAction().getSubActions());
-            } else if (mSubActionsGridView.getVisibility() == View.VISIBLE) {
+                adapter.setActions(action.getSubActions());
+            } else {
+                // set to explicit value, which will disable the keyLine percentage calculation
+                // in GuidedRelativeLayout.
+                int actionPosition = ((GuidedActionAdapter) mActionsGridView.getAdapter())
+                        .indexOf(action);
+                lp.topMargin = mActionsGridView.getLayoutManager()
+                        .findViewByPosition(actionPosition).getBottom();
+                lp.height = 0;
                 mSubActionsGridView.setVisibility(View.INVISIBLE);
                 mSubActionsBackground.setVisibility(View.INVISIBLE);
-                ViewGroup.MarginLayoutParams lp =
-                        (ViewGroup.MarginLayoutParams) mSubActionsGridView.getLayoutParams();
-                lp.height = 0;
                 mSubActionsGridView.setLayoutParams(lp);
-                ((GuidedActionAdapter) mSubActionsGridView.getAdapter())
-                        .setActions(Collections.EMPTY_LIST);
+                adapter.setActions(Collections.EMPTY_LIST);
                 mActionsGridView.requestFocus();
             }
         }
@@ -1185,7 +1376,7 @@
             } else if (vh.getAction() == mExpandedAction) {
                 vh.itemView.setVisibility(View.VISIBLE);
                 if (vh.getAction().hasSubActions()) {
-                    vh.itemView.setTranslationY(- vh.itemView.getHeight());
+                    vh.itemView.setTranslationY(getKeyLine() - vh.itemView.getBottom());
                 } else if (vh.mActivatorView != null) {
                     vh.itemView.setTranslationY(0);
                     vh.setActivated(true);
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/HeaderItem.java b/v17/leanback/src/android/support/v17/leanback/widget/HeaderItem.java
index f4e5954..00c4660 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/HeaderItem.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/HeaderItem.java
@@ -23,6 +23,7 @@
 
     private final long mId;
     private final String mName;
+    private CharSequence mDescription;
     private CharSequence mContentDescription;
 
     /**
@@ -70,4 +71,19 @@
     public void setContentDescription(CharSequence contentDescription) {
         mContentDescription = contentDescription;
     }
+
+    /**
+     * Sets the description for the current header item. This will be visible when
+     * the row receives focus.
+     */
+    public void setDescription(CharSequence description) {
+        this.mDescription = description;
+    }
+
+    /**
+     * Returns the description for the current row.
+     */
+    public CharSequence getDescription() {
+        return mDescription;
+    }
 }
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/HorizontalGridView.java b/v17/leanback/src/android/support/v17/leanback/widget/HorizontalGridView.java
index 6bdae61..4d6a7dc 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/HorizontalGridView.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/HorizontalGridView.java
@@ -255,8 +255,7 @@
         final int c = getChildCount();
         for (int i = 0; i < c; i++) {
             View view = getChildAt(i);
-            if (mLayoutManager.getOpticalLeft(view) <
-                    getPaddingLeft() - mLowFadeShaderOffset) {
+            if (mLayoutManager.getOpticalLeft(view) < getPaddingLeft() - mLowFadeShaderOffset) {
                 return true;
             }
         }
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/HorizontalHoverCardSwitcher.java b/v17/leanback/src/android/support/v17/leanback/widget/HorizontalHoverCardSwitcher.java
index f85af1e..eff822b 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/HorizontalHoverCardSwitcher.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/HorizontalHoverCardSwitcher.java
@@ -16,8 +16,8 @@
 import android.graphics.Rect;
 import android.support.v4.view.ViewCompat;
 import android.view.View;
-import android.view.ViewGroup;
 import android.view.View.MeasureSpec;
+import android.view.ViewGroup;
 import android.view.ViewGroup.MarginLayoutParams;
 
 /**
@@ -41,8 +41,7 @@
 
     @Override
     protected void onViewSelected(View view) {
-        int rightLimit = getParentViewGroup().getWidth() -
-                getParentViewGroup().getPaddingRight();
+        int rightLimit = getParentViewGroup().getWidth() - getParentViewGroup().getPaddingRight();
         int leftLimit = getParentViewGroup().getPaddingLeft();
         // measure the hover card width; if it's too large, align hover card
         // end edge with row view's end edge, otherwise align start edges.
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/ItemAlignmentFacet.java b/v17/leanback/src/android/support/v17/leanback/widget/ItemAlignmentFacet.java
index cc51d54..f1d2b95 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/ItemAlignmentFacet.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/ItemAlignmentFacet.java
@@ -13,11 +13,8 @@
  */
 package android.support.v17.leanback.widget;
 
-import android.view.View;
-
-import static android.support.v17.leanback.widget.BaseGridView.ITEM_ALIGN_OFFSET_PERCENT_DISABLED;
-
 import android.support.v7.widget.RecyclerView;
+import android.view.View;
 
 /**
  * Optional facet provided by {@link RecyclerView.Adapter} or {@link RecyclerView.ViewHolder} for
@@ -92,8 +89,8 @@
          * to disable.
          */
         public final void setItemAlignmentOffsetPercent(float percent) {
-            if ( (percent < 0 || percent > 100) &&
-                    percent != ITEM_ALIGN_OFFSET_PERCENT_DISABLED) {
+            if ((percent < 0 || percent > 100)
+                    && percent != ITEM_ALIGN_OFFSET_PERCENT_DISABLED) {
                 throw new IllegalArgumentException();
             }
             mOffsetPercent = percent;
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/ItemBridgeAdapter.java b/v17/leanback/src/android/support/v17/leanback/widget/ItemBridgeAdapter.java
index d2d3356..eba207e 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/ItemBridgeAdapter.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/ItemBridgeAdapter.java
@@ -243,8 +243,8 @@
 
     @Override
     public int getItemViewType(int position) {
-        PresenterSelector presenterSelector = mPresenterSelector != null ?
-                mPresenterSelector : mAdapter.getPresenterSelector();
+        PresenterSelector presenterSelector = mPresenterSelector != null
+                ? mPresenterSelector : mAdapter.getPresenterSelector();
         Object item = mAdapter.get(position);
         Presenter presenter = presenterSelector.getPresenter(item);
         int type = mPresenters.indexOf(presenter);
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/ListRowPresenter.java b/v17/leanback/src/android/support/v17/leanback/widget/ListRowPresenter.java
index 200b6d9..790cee3 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/ListRowPresenter.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/ListRowPresenter.java
@@ -435,16 +435,16 @@
         });
         rowViewHolder.mGridView.setOnUnhandledKeyListener(
                 new BaseGridView.OnUnhandledKeyListener() {
-            @Override
-            public boolean onUnhandledKey(KeyEvent event) {
-                if (rowViewHolder.getOnKeyListener() != null &&
-                        rowViewHolder.getOnKeyListener().onKey(
-                                rowViewHolder.view, event.getKeyCode(), event)) {
-                    return true;
-                }
-                return false;
-            }
-        });
+                    @Override
+                    public boolean onUnhandledKey(KeyEvent event) {
+                        if (rowViewHolder.getOnKeyListener() != null
+                                && rowViewHolder.getOnKeyListener().onKey(
+                                        rowViewHolder.view, event.getKeyCode(), event)) {
+                            return true;
+                        }
+                        return false;
+                    }
+                });
         rowViewHolder.mGridView.setNumRows(mNumRows);
     }
 
@@ -538,10 +538,10 @@
         if (vh.isExpanded()) {
             int headerSpaceUnderBaseline = getSpaceUnderBaseline(vh);
             if (DEBUG) Log.v(TAG, "headerSpaceUnderBaseline " + headerSpaceUnderBaseline);
-            paddingTop = (vh.isSelected() ? sExpandedSelectedRowTopPadding : vh.mPaddingTop) -
-                    headerSpaceUnderBaseline;
-            paddingBottom = mHoverCardPresenterSelector == null ?
-                    sExpandedRowNoHovercardBottomPadding : vh.mPaddingBottom;
+            paddingTop = (vh.isSelected() ? sExpandedSelectedRowTopPadding : vh.mPaddingTop)
+                    - headerSpaceUnderBaseline;
+            paddingBottom = mHoverCardPresenterSelector == null
+                    ? sExpandedRowNoHovercardBottomPadding : vh.mPaddingBottom;
         } else if (vh.isSelected()) {
             paddingTop = sSelectedRowTopPadding - vh.mPaddingBottom;
             paddingBottom = sSelectedRowTopPadding;
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/MediaItemActionPresenter.java b/v17/leanback/src/android/support/v17/leanback/widget/MediaItemActionPresenter.java
index 2cb8174..1a98059 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/MediaItemActionPresenter.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/MediaItemActionPresenter.java
@@ -48,9 +48,8 @@
     @Override
     public Presenter.ViewHolder onCreateViewHolder(ViewGroup parent) {
         Context context = parent.getContext();
-        View actionView = LayoutInflater.from(context).
-                inflate(R.layout.lb_row_media_item_action, parent,
-                        false);
+        View actionView = LayoutInflater.from(context)
+                .inflate(R.layout.lb_row_media_item_action, parent, false);
         return new ViewHolder(actionView);
     }
 
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/MediaNowPlayingView.java b/v17/leanback/src/android/support/v17/leanback/widget/MediaNowPlayingView.java
index cb2691c..901ff55 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/MediaNowPlayingView.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/MediaNowPlayingView.java
@@ -13,19 +13,20 @@
  */
 package android.support.v17.leanback.widget;
 
+import static android.support.annotation.RestrictTo.Scope.GROUP_ID;
+
 import android.animation.Animator;
-import android.animation.AnimatorInflater;
 import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
 import android.content.Context;
 import android.support.annotation.RestrictTo;
+import android.support.v17.leanback.R;
 import android.util.AttributeSet;
 import android.view.LayoutInflater;
 import android.view.View;
+import android.view.animation.LinearInterpolator;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
-import android.support.v17.leanback.R;
-
-import static android.support.annotation.RestrictTo.Scope.GROUP_ID;
 
 /**
  * The view displaying 3 animated peak meters next to each other when a media item is playing.
@@ -40,6 +41,7 @@
     private final ObjectAnimator mObjectAnimator1;
     private final ObjectAnimator mObjectAnimator2;
     private final ObjectAnimator mObjectAnimator3;
+    protected final LinearInterpolator mLinearInterpolator = new LinearInterpolator();
 
     public MediaNowPlayingView(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -57,17 +59,31 @@
         setDropScale(mImage2);
         setDropScale(mImage3);
 
-        mObjectAnimator1 = (ObjectAnimator) AnimatorInflater.loadAnimator(context,
-                R.animator.lb_playback_now_bar1_animator);
-        mObjectAnimator1.setTarget(mImage1);
+        mObjectAnimator1 = ObjectAnimator.ofFloat(mImage1, "scaleY", 5f / 12f, 3f / 12f, 5f / 12f,
+                7f / 12f, 9f / 12f, 10f / 12f, 11f / 12f, 12f / 12f, 11f / 12f, 12f / 12f,
+                10f / 12f, 8f / 12f, 6f / 12f, 4f / 12f, 2f / 12f, 4f / 12f, 6f / 12f, 7f / 12f,
+                9f / 12f, 11f / 12f, 9f / 12f, 7f / 12f, 5f / 12f, 3f / 12f, 5f / 12f, 8f / 12f,
+                5f / 12f, 3f / 12f, 4f / 12f, 5f / 12f);
+        mObjectAnimator1.setRepeatCount(ValueAnimator.INFINITE);
+        mObjectAnimator1.setDuration(2320);
+        mObjectAnimator1.setInterpolator(mLinearInterpolator);
 
-        mObjectAnimator2 = (ObjectAnimator) AnimatorInflater.loadAnimator(context,
-                R.animator.lb_playback_now_bar2_animator);
-        mObjectAnimator2.setTarget(mImage2);
+        mObjectAnimator2 = ObjectAnimator.ofFloat(mImage2, "scaleY", 12f / 12f, 11f / 12f,
+                10f / 12f, 11f / 12f, 12f / 12f, 11f / 12f, 9f / 12f, 7f / 12f, 9f / 12f, 11f / 12f,
+                12f / 12f, 10f / 12f, 8f / 12f, 10f / 12f, 12f / 12f, 11f / 12f, 9f / 12f, 5f / 12f,
+                3f / 12f, 5f / 12f, 8f / 12f, 10f / 12f, 12f / 12f, 10f / 12f, 9f / 12f, 8f / 12f,
+                12f / 12f);
+        mObjectAnimator2.setRepeatCount(ValueAnimator.INFINITE);
+        mObjectAnimator2.setDuration(2080);
+        mObjectAnimator2.setInterpolator(mLinearInterpolator);
 
-        mObjectAnimator3 = (ObjectAnimator) AnimatorInflater.loadAnimator(context,
-                R.animator.lb_playback_now_bar3_animator);
-        mObjectAnimator3.setTarget(mImage3);
+        mObjectAnimator3 = ObjectAnimator.ofFloat(mImage3, "scaleY", 8f / 12f, 9f / 12f, 10f / 12f,
+                12f / 12f, 11f / 12f, 9f / 12f, 7f / 12f, 5f / 12f, 7f / 12f, 8f / 12f, 9f / 12f,
+                12f / 12f, 11f / 12f, 12f / 12f, 9f / 12f, 7f / 12f, 9f / 12f, 11f / 12f, 12f / 12f,
+                10f / 12f, 8f / 12f, 9f / 12f, 7f / 12f, 5f / 12f, 3f / 12f, 8f / 12f);
+        mObjectAnimator3.setRepeatCount(ValueAnimator.INFINITE);
+        mObjectAnimator3.setDuration(2000);
+        mObjectAnimator3.setInterpolator(mLinearInterpolator);
     }
 
     static void setDropScale(View view) {
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/MediaRowFocusView.java b/v17/leanback/src/android/support/v17/leanback/widget/MediaRowFocusView.java
index 6ec93f2..1418a2a 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/MediaRowFocusView.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/MediaRowFocusView.java
@@ -23,6 +23,7 @@
 
 /**
  * Creates a view for a media item row in a playlist
+ * @hide
  */
 class MediaRowFocusView extends View {
 
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/OnActionClickedListener.java b/v17/leanback/src/android/support/v17/leanback/widget/OnActionClickedListener.java
index 2d59f3b..d065119 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/OnActionClickedListener.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/OnActionClickedListener.java
@@ -18,6 +18,8 @@
  */
 public interface OnActionClickedListener {
 
-    public void onActionClicked(Action action);
-
+    /**
+     * Callback fired when the host fragment receives an action.
+     */
+    void onActionClicked(Action action);
 }
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/OnChildViewHolderSelectedListener.java b/v17/leanback/src/android/support/v17/leanback/widget/OnChildViewHolderSelectedListener.java
index f94bc11..ae9d436 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/OnChildViewHolderSelectedListener.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/OnChildViewHolderSelectedListener.java
@@ -19,13 +19,25 @@
 import android.view.ViewGroup;
 
 /**
- * Interface for receiving notification when a child of this
- * ViewGroup has been selected.
+ * Interface for receiving notification when a child of this ViewGroup has been selected.
+ * There are two methods:
+ * <li>
+ *     {link {@link #onChildViewHolderSelected(RecyclerView, RecyclerView.ViewHolder, int, int)}}
+ *     is called when the view holder is about to be selected.  The listener could change size
+ *     of the view holder in this callback.
+ * </li>
+ * <li>
+ *     {link {@link #onChildViewHolderSelectedAndPositioned(RecyclerView, RecyclerView.ViewHolder,
+ *     int, int)} is called when view holder has been selected and laid out in RecyclerView.
+ *
+ * </li>
  */
 public abstract class OnChildViewHolderSelectedListener {
     /**
-     * Callback method to be invoked when a child of this ViewGroup has been
-     * selected.
+     * Callback method to be invoked when a child of this ViewGroup has been selected. Listener
+     * might change the size of the child and the position of the child is not finalized. To get
+     * the final layout position of child, overide {@link #onChildViewHolderSelectedAndPositioned(
+     * RecyclerView, RecyclerView.ViewHolder, int, int)}.
      *
      * @param parent The RecyclerView where the selection happened.
      * @param child The ViewHolder within the RecyclerView that is selected, or null if no
@@ -38,4 +50,21 @@
     public void onChildViewHolderSelected(RecyclerView parent, RecyclerView.ViewHolder child,
             int position, int subposition) {
     }
+
+    /**
+     * Callback method to be invoked when a child of this ViewGroup has been selected and
+     * positioned.
+     *
+     * @param parent The RecyclerView where the selection happened.
+     * @param child The ViewHolder within the RecyclerView that is selected, or null if no
+     *        view is selected.
+     * @param position The position of the view in the adapter, or NO_POSITION
+     *        if no view is selected.
+     * @param subposition The index of which {@link ItemAlignmentDef} being used,
+     *                    0 if there is no ItemAlignmentDef defined for the item.
+     */
+    public void onChildViewHolderSelectedAndPositioned(RecyclerView parent,
+            RecyclerView.ViewHolder child, int position, int subposition) {
+    }
+
 }
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/PagingIndicator.java b/v17/leanback/src/android/support/v17/leanback/widget/PagingIndicator.java
index 78afa37..ea39399 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/PagingIndicator.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/PagingIndicator.java
@@ -16,6 +16,8 @@
 
 package android.support.v17.leanback.widget;
 
+import static android.support.annotation.RestrictTo.Scope.GROUP_ID;
+
 import android.animation.Animator;
 import android.animation.AnimatorSet;
 import android.animation.ObjectAnimator;
@@ -39,8 +41,6 @@
 import android.view.View;
 import android.view.animation.DecelerateInterpolator;
 
-import static android.support.annotation.RestrictTo.Scope.GROUP_ID;
-
 /**
  * A page indicator with dots.
  * @hide
@@ -52,8 +52,8 @@
     private static final long DURATION_TRANSLATION_X = DURATION_DIAMETER;
     private static final TimeInterpolator DECELERATE_INTERPOLATOR = new DecelerateInterpolator();
 
-    private static final Property<Dot, Float> DOT_ALPHA
-            = new Property<Dot, Float>(Float.class, "alpha") {
+    private static final Property<Dot, Float> DOT_ALPHA =
+            new Property<Dot, Float>(Float.class, "alpha") {
         @Override
         public Float get(Dot dot) {
             return dot.getAlpha();
@@ -65,8 +65,8 @@
         }
     };
 
-    private static final Property<Dot, Float> DOT_DIAMETER
-            = new Property<Dot, Float>(Float.class, "diameter") {
+    private static final Property<Dot, Float> DOT_DIAMETER =
+            new Property<Dot, Float>(Float.class, "diameter") {
         @Override
         public Float get(Dot dot) {
             return dot.getDiameter();
@@ -78,8 +78,8 @@
         }
     };
 
-    private static final Property<Dot, Float> DOT_TRANSLATION_X
-            = new Property<Dot, Float>(Float.class, "translation_x") {
+    private static final Property<Dot, Float> DOT_TRANSLATION_X =
+            new Property<Dot, Float>(Float.class, "translation_x") {
         @Override
         public Float get(Dot dot) {
             return dot.getTranslationX();
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/Parallax.java b/v17/leanback/src/android/support/v17/leanback/widget/Parallax.java
new file mode 100644
index 0000000..58cfe63
--- /dev/null
+++ b/v17/leanback/src/android/support/v17/leanback/widget/Parallax.java
@@ -0,0 +1,130 @@
+/*
+ * 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 android.support.v17.leanback.widget;
+
+import java.util.List;
+import java.util.ArrayList;
+
+import android.support.v17.leanback.widget.ParallaxSource.IntPropertyKeyValue;
+import android.support.v17.leanback.widget.ParallaxSource.FloatPropertyKeyValue;
+import android.support.v17.leanback.widget.ParallaxEffect.FloatEffect;
+import android.support.v17.leanback.widget.ParallaxEffect.IntEffect;
+
+/**
+ * Parallax listens to {@link ParallaxSource} changes and invokes performMapping on each
+ * {@link ParallaxEffect} object.
+ */
+public final class Parallax {
+
+    private ParallaxSource mSource;
+    private final List<ParallaxEffect> mEffects = new ArrayList<ParallaxEffect>(4);
+
+    private final ParallaxSource.Listener mSourceListener = new ParallaxSource.Listener() {
+        @Override
+        public void onPropertiesChanged(ParallaxSource source) {
+            for (int i = 0; i < mEffects.size(); i++) {
+                mEffects.get(i).performMapping(source);
+            }
+        }
+    };
+
+    /**
+     * Sets a {@link ParallaxSource} object and starts listening on it. Stops listening to the
+     * previous {@link ParallaxSource} object if it exists.
+     *
+     * @param source New {@link ParallaxSource} object.
+     */
+    public void setSource(ParallaxSource source) {
+        if (mSource != null) {
+            mSource.setListener(null);
+        }
+        mSource = source;
+        if (mSource != null) {
+            mSource.setListener(mSourceListener);
+        }
+    }
+
+    /**
+     * Gets the current {@link ParallaxSource} object.
+     *
+     * @return The current {@link ParallaxSource} Object.
+     */
+    public ParallaxSource getSource() {
+        return mSource;
+    }
+
+    /**
+     * Adds a {@link ParallaxEffect} object which defines rules to perform mapping from
+     * {@link ParallaxSource} to multiple {@link ParallaxTarget}s.
+     *
+     * @param effect A {@link ParallaxEffect} object.
+     */
+    public void addEffect(ParallaxEffect effect) {
+        mEffects.add(effect);
+    }
+
+    /**
+     * Returns a list of {@link ParallaxEffect} object which defines rules to perform mapping from
+     * {@link ParallaxSource} to multiple {@link ParallaxTarget}s.
+     *
+     * @return A list of {@link ParallaxEffect} object.
+     */
+    public List<ParallaxEffect> getEffects() {
+        return mEffects;
+    }
+
+    /**
+     * Remove the {@link ParallaxEffect} object.
+     *
+     * @param effect The {@link ParallaxEffect} object to remove.
+     */
+    public void removeEffect(ParallaxEffect effect) {
+        mEffects.remove(effect);
+    }
+
+    /**
+     * Remove all {@link ParallaxEffect} objects.
+     */
+    public void removeAllEffects() {
+        mEffects.clear();
+    }
+
+    /**
+     * Create a {@link ParallaxEffect} object that will track source variable changes within a
+     * provided set of ranges.
+     *
+     * @param ranges A list of key values that defines the ranges.
+     * @return Newly created ParallaxEffect object.
+     */
+    public ParallaxEffect addEffect(IntPropertyKeyValue... ranges) {
+        IntEffect effect = new IntEffect();
+        effect.setPropertyRanges(ranges);
+        addEffect(effect);
+        return effect;
+    }
+
+    /**
+     * Create a {@link ParallaxEffect} object that will track source variable changes within a
+     * provided set of ranges.
+     *
+     * @param ranges A list of key values that defines the ranges.
+     * @return Newly created ParallaxEffect object.
+     */
+    public ParallaxEffect addEffect(FloatPropertyKeyValue... ranges) {
+        FloatEffect effect = new FloatEffect();
+        effect.setPropertyRanges(ranges);
+        addEffect(effect);
+        return effect;
+    }
+}
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/ParallaxEffect.java b/v17/leanback/src/android/support/v17/leanback/widget/ParallaxEffect.java
new file mode 100644
index 0000000..615c11e
--- /dev/null
+++ b/v17/leanback/src/android/support/v17/leanback/widget/ParallaxEffect.java
@@ -0,0 +1,360 @@
+/*
+ * 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 android.support.v17.leanback.widget;
+
+import android.animation.PropertyValuesHolder;
+import android.support.v17.leanback.widget.ParallaxSource.FloatProperty;
+import android.support.v17.leanback.widget.ParallaxSource.FloatPropertyKeyValue;
+import android.support.v17.leanback.widget.ParallaxSource.IntProperty;
+import android.support.v17.leanback.widget.ParallaxSource.IntPropertyKeyValue;
+import android.support.v17.leanback.widget.ParallaxSource.PropertyKeyValue;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * ParallaxEffect class drives changes in {@link ParallaxTarget} in response to changes in
+ * variables defined in {@link ParallaxSource}.
+ * <p>
+ * ParallaxEffect has a list of {@link PropertyKeyValue}s which represents the range of values that
+ * source variables can take. The main function is
+ * {@link ParallaxEffect#performMapping(ParallaxSource)} which computes a fraction between 0 and 1
+ * based on the current values of variables in {@link ParallaxSource}. As the parallax effect goes
+ * on, the fraction increases from 0 at beginning to 1 at the end. Then the fraction is passed on
+ * to {@link ParallaxTarget#update(float)}.
+ * <p>
+ * ParallaxEffect has two concrete subclasses, {@link IntEffect} and {@link FloatEffect}.
+ */
+public abstract class ParallaxEffect<ParallaxEffectT extends ParallaxEffect,
+        PropertyKeyValueT extends ParallaxSource.PropertyKeyValue> {
+
+    final List<PropertyKeyValueT> mKeyValues = new ArrayList<PropertyKeyValueT>(2);
+    final List<Float> mWeights = new ArrayList<Float>(2);
+    final List<Float> mTotalWeights = new ArrayList<Float>(2);
+    final List<ParallaxTarget> mTargets = new ArrayList<ParallaxTarget>(4);
+
+    /**
+     * Returns the list of {@link PropertyKeyValue}s, which represents the range of values that
+     * source variables can take.
+     *
+     * @return A list of {@link PropertyKeyValue}s.
+     * @see #performMapping(ParallaxSource)
+     */
+    public final List<PropertyKeyValueT> getPropertyRanges() {
+        return mKeyValues;
+    }
+
+    /**
+     * Returns a list of Float objects that represents weight associated with each variable range.
+     * Weights are used when there are three or more key values.
+     *
+     * @return A list of Float objects that represents weight associated with each variable range.
+     * @hide
+     */
+    public final List<Float> getWeights() {
+        return mWeights;
+    }
+
+    /**
+     * Sets the list of {@link PropertyKeyValue}s, which represents the range of values that
+     * source variables can take.
+     *
+     * @param keyValues A list of {@link PropertyKeyValue}s.
+     * @see #performMapping(ParallaxSource)
+     */
+    public final void setPropertyRanges(PropertyKeyValueT... keyValues) {
+        mKeyValues.clear();
+        for (PropertyKeyValueT keyValue : keyValues) {
+            mKeyValues.add(keyValue);
+        }
+    }
+
+    /**
+     * Sets a list of Float objects that represents weight associated with each variable range.
+     * Weights are used when there are three or more key values.
+     *
+     * @param weights A list of Float objects that represents weight associated with each variable
+     *                range.
+     * @hide
+     */
+    public final void setWeights(float... weights) {
+        for (float weight : weights) {
+            if (weight <= 0) {
+                throw new IllegalArgumentException();
+            }
+        }
+        mWeights.clear();
+        mTotalWeights.clear();
+        float totalWeight = 0f;
+        for (float weight : weights) {
+            mWeights.add(weight);
+            totalWeight += weight;
+            mTotalWeights.add(totalWeight);
+        }
+    }
+
+    /**
+     * Sets a list of Float objects that represents weight associated with each variable range.
+     * Weights are used when there are three or more key values.
+     *
+     * @param weights A list of Float objects that represents weight associated with each variable
+     *                range.
+     * @return This ParallaxEffect object, allowing calls to methods in this class to be chained.
+     * @hide
+     */
+    public final ParallaxEffect weights(float... weights) {
+        setWeights(weights);
+        return this;
+    }
+
+    /**
+     * Add a ParallaxTarget to run parallax effect.
+     *
+     * @param target ParallaxTarget to add.
+     */
+    public final void addTarget(ParallaxTarget target) {
+        mTargets.add(target);
+    }
+
+    /**
+     * Add a ParallaxTarget to run parallax effect.
+     *
+     * @param target ParallaxTarget to add.
+     * @return This ParallaxEffect object, allowing calls to methods in this class to be chained.
+     */
+    public final ParallaxEffect target(ParallaxTarget target) {
+        mTargets.add(target);
+        return this;
+    }
+
+    /**
+     * Creates a {@link ParallaxTarget} from {@link PropertyValuesHolder} and adds it to the list
+     * of targets.
+     *
+     * @param targetObject Target object for PropertyValuesHolderTarget.
+     * @param values       PropertyValuesHolder for PropertyValuesHolderTarget.
+     * @return This ParallaxEffect object, allowing calls to methods in this class to be chained.
+     */
+    public final ParallaxEffect target(Object targetObject, PropertyValuesHolder values) {
+        mTargets.add(new ParallaxTarget.PropertyValuesHolderTarget(targetObject, values));
+        return this;
+    }
+
+    /**
+     * Returns the list of {@link ParallaxTarget} objects.
+     *
+     * @return The list of {@link ParallaxTarget} objects.
+     */
+    public final List<ParallaxTarget> getTargets() {
+        return mTargets;
+    }
+
+    /**
+     * Remove a {@link ParallaxTarget} object from the list.
+     * @param target The {@link ParallaxTarget} object to be removed.
+     */
+    public final void removeTarget(ParallaxTarget target) {
+        mTargets.remove(target);
+    }
+
+    /**
+     * Perform mapping from {@link ParallaxSource} to list of {@link ParallaxTarget}.
+     */
+    public final void performMapping(ParallaxSource source) {
+        if (mKeyValues.size() < 2) {
+            return;
+        }
+        source.verifyProperties();
+        float fraction = calculateFraction(source);
+        for (int i = 0; i < mTargets.size(); i++) {
+            mTargets.get(i).update(fraction);
+        }
+    }
+
+    /**
+     * This method is expected to compute a fraction between 0 and 1 based on the current values of
+     * variables in {@link ParallaxSource}. As the parallax effect goes on, the fraction increases
+     * from 0 at beginning to 1 at the end.
+     *
+     * @return Float value between 0 and 1.
+     */
+    protected abstract float calculateFraction(ParallaxSource source);
+
+    /**
+     * When there are multiple ranges (aka three or more keyvalues),  this method adjust the
+     * fraction inside a range to fraction of whole range.
+     * e.g. four key values, three weight values: 6, 2, 2.  totalWeights are 6, 8, 10
+     * When keyValueIndex is 3, the fraction is inside last range.
+     * adjusted_fraction = 8 / 10 + 2 / 10 * fraction.
+     */
+    final float getFractionWithWeightAdjusted(float fraction, int keyValueIndex) {
+        // when there are three or more KeyValues, take weight into consideration.
+        if (mKeyValues.size() >= 3) {
+            final boolean hasWeightsDefined = mWeights.size() == mKeyValues.size() - 1;
+            if (hasWeightsDefined) {
+                // use weights user defined
+                final float allWeights = mTotalWeights.get(mTotalWeights.size() - 1);
+                fraction = fraction * mWeights.get(keyValueIndex - 1) / allWeights;
+                if (keyValueIndex >= 2) {
+                    fraction += mTotalWeights.get(keyValueIndex - 2) / allWeights;
+                }
+            } else {
+                // assume each range has same weight.
+                final float allWeights = mKeyValues.size() - 1;
+                fraction = fraction / allWeights;
+                if (keyValueIndex >= 2) {
+                    fraction += (float)(keyValueIndex - 1) / allWeights;
+                }
+            }
+        }
+        return fraction;
+    }
+
+    /**
+     * Implementation of {@link ParallaxEffect} for integer type.
+     */
+    public static final class IntEffect extends ParallaxEffect<IntEffect, IntPropertyKeyValue> {
+
+        @Override
+        protected float calculateFraction(ParallaxSource s) {
+            ParallaxSource.IntSource source = (ParallaxSource.IntSource) s;
+            int lastIndex = 0;
+            int lastValue = 0;
+            int lastKeyValue = 0;
+            // go through all KeyValues, find first KeyValue that current value is less than.
+            for (int i = 0; i < mKeyValues.size(); i++) {
+                IntPropertyKeyValue k = mKeyValues.get(i);
+                int index = k.getProperty().getIndex();
+                int keyValue = k.getKeyValue(source);
+                int currentValue = source.getPropertyValue(index);
+
+                float fraction;
+                if (i == 0) {
+                    if (currentValue >= keyValue) {
+                        return 0f;
+                    }
+                } else {
+                    if (lastIndex == index && lastKeyValue < keyValue) {
+                        throw new IllegalStateException("KeyValue of same variable must be "
+                                + "descendant order");
+                    }
+                    if (currentValue == IntProperty.UNKNOWN_AFTER) {
+                        // Implies lastValue is less than lastKeyValue and lastValue is not
+                        // UNKNWON_AFTER.  Estimates based on distance of two variables is screen
+                        // size.
+                        fraction = (float) (lastKeyValue - lastValue)
+                                / source.getMaxParentVisibleSize();
+                        return getFractionWithWeightAdjusted(fraction, i);
+                    } else if (currentValue >= keyValue) {
+                        if (lastIndex == index) {
+                            // same variable index,  same UI element at two different KeyValues,
+                            // e.g. UI element moves from lastkeyValue=500 to keyValue=0,
+                            // fraction moves from 0 to 1.
+                            fraction = (float) (lastKeyValue - currentValue)
+                                    / (lastKeyValue - keyValue);
+                        } else if (lastValue != IntProperty.UNKNOWN_BEFORE) {
+                            // e.g. UIElement_1 at 300 scroll to UIElement_2 at 400, figure out when
+                            // UIElement_1 is at keyValue=300,  keyValue of UIElement_2 by adding
+                            // delta of values to keyValue of UIElement_2.
+                            lastKeyValue = lastKeyValue + (currentValue - lastValue);
+                            fraction = (float) (lastKeyValue - currentValue)
+                                    / (lastKeyValue - keyValue);
+                        } else {
+                            // Last variable is UNKNOWN_BEFORE.  Estimates based on assumption total
+                            // travel distance from last variable to this variable is screen visible
+                            // size.
+                            fraction = 1f - (float) (currentValue - keyValue)
+                                    / source.getMaxParentVisibleSize();
+                        }
+                        return getFractionWithWeightAdjusted(fraction, i);
+                    }
+                }
+                lastValue = currentValue;
+                lastIndex = index;
+                lastKeyValue = keyValue;
+            }
+            return 1f;
+        }
+    }
+
+    /**
+     * Implementation of {@link ParallaxEffect} for float type.
+     */
+    public static final class FloatEffect extends ParallaxEffect<FloatEffect,
+            FloatPropertyKeyValue> {
+
+        @Override
+        protected float calculateFraction(ParallaxSource s) {
+            ParallaxSource.FloatSource source = (ParallaxSource.FloatSource) s;
+            int lastIndex = 0;
+            float lastValue = 0;
+            float lastKeyValue = 0;
+            // go through all KeyValues, find first KeyValue that current value is less than.
+            for (int i = 0; i < mKeyValues.size(); i++) {
+                FloatPropertyKeyValue k = mKeyValues.get(i);
+                int index = k.getProperty().getIndex();
+                float keyValue = k.getKeyValue(source);
+                float currentValue = source.getPropertyValue(index);
+
+                float fraction;
+                if (i == 0) {
+                    if (currentValue >= keyValue) {
+                        return 0f;
+                    }
+                } else {
+                    if (lastIndex == index && lastKeyValue < keyValue) {
+                        throw new IllegalStateException("KeyValue of same variable must be "
+                                + "descendant order");
+                    }
+                    if (currentValue == FloatProperty.UNKNOWN_AFTER) {
+                        // Implies lastValue is less than lastKeyValue and lastValue is not
+                        // UNKNOWN_AFTER.  Estimates based on distance of two variables is screen
+                        // size.
+                        fraction = (float) (lastKeyValue - lastValue)
+                                / source.getMaxParentVisibleSize();
+                        return getFractionWithWeightAdjusted(fraction, i);
+                    } else if (currentValue >= keyValue) {
+                        if (lastIndex == index) {
+                            // same variable index,  same UI element at two different KeyValues,
+                            // e.g. UI element moves from lastkeyValue=500 to keyValue=0,
+                            // fraction moves from 0 to 1.
+                            fraction = (float) (lastKeyValue - currentValue)
+                                    / (lastKeyValue - keyValue);
+                        } else if (lastValue != FloatProperty.UNKNOWN_BEFORE) {
+                            // e.g. UIElement_1 at 300 scroll to UIElement_2 at 400, figure out when
+                            // UIElement_1 is at keyValue=300,  keyValue of UIElement_2 by adding
+                            // delta of values to keyValue of UIElement_2.
+                            lastKeyValue = lastKeyValue + (currentValue - lastValue);
+                            fraction = (float) (lastKeyValue - currentValue)
+                                    / (lastKeyValue - keyValue);
+                        } else {
+                            // Last variable is UNKNOWN_BEFORE.  Estimates based on assumption total
+                            // travel distance from last variable to this variable is screen visible
+                            // size.
+                            fraction = 1f - (float) (currentValue - keyValue)
+                                    / source.getMaxParentVisibleSize();
+                        }
+                        return getFractionWithWeightAdjusted(fraction, i);
+                    }
+                }
+                lastValue = currentValue;
+                lastIndex = index;
+                lastKeyValue = keyValue;
+            }
+            return 1f;
+        }
+    }
+
+}
+
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/ParallaxRecyclerViewSource.java b/v17/leanback/src/android/support/v17/leanback/widget/ParallaxRecyclerViewSource.java
new file mode 100644
index 0000000..7f1fd41
--- /dev/null
+++ b/v17/leanback/src/android/support/v17/leanback/widget/ParallaxRecyclerViewSource.java
@@ -0,0 +1,206 @@
+/*
+ * 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 android.support.v17.leanback.widget;
+
+import static android.support.v7.widget.RecyclerView.LayoutManager;
+import static android.support.v7.widget.RecyclerView.OnScrollListener;
+import static android.support.v7.widget.RecyclerView.ViewHolder;
+
+import android.graphics.Rect;
+import android.support.v7.widget.RecyclerView;
+import android.view.View;
+
+/**
+ * Implementation of {@link ParallaxSource} class for {@link RecyclerView}. This class
+ * allows users to track position of specific views inside {@link RecyclerView} relative to
+ * itself. @see {@link ChildPositionProperty} for details.
+ */
+public class ParallaxRecyclerViewSource extends
+        ParallaxSource.IntSource<ParallaxRecyclerViewSource.ChildPositionProperty> {
+    private final RecyclerView mRecylerView;
+    private Listener mListener;
+    private final boolean mIsVertical;
+
+    /**
+     * Subclass of {@link ParallaxSource.IntProperty}. Using this Property, users can track a
+     * RecylerView child's position inside recyclerview. i.e.
+     *
+     * tracking_pos = view.top + fraction * view.height() + offset
+     *
+     * This way we can track top using fraction 0 and bottom using fraction 1.
+     */
+    public static final class ChildPositionProperty extends ParallaxSource.IntProperty {
+        int mAdapterPosition;
+        int mViewId;
+        int mOffset;
+        float mFraction;
+
+        ChildPositionProperty(String name, int index) {
+            super(name, index);
+        }
+
+        /**
+         * Sets adapter position of the recyclerview child to track.
+         *
+         * @param adapterPosition Zero based position in adapter.
+         * @return This ChildPositionProperty object.
+         */
+        public ChildPositionProperty adapterPosition(int adapterPosition) {
+            mAdapterPosition = adapterPosition;
+            return this;
+        };
+
+        /**
+         * Sets view Id of a descendant of recyclerview child to track.
+         *
+         * @param viewId Id of a descendant of recyclerview child.
+         * @return This ChildPositionProperty object.
+         */
+        public ChildPositionProperty viewId(int viewId) {
+            mViewId = viewId;
+            return this;
+        }
+
+        /**
+         * Sets offset in pixels added to the view's start position.
+         *
+         * @param offset Offset in pixels added to the view's start position.
+         * @return This ChildPositionProperty object.
+         */
+        public ChildPositionProperty offset(int offset) {
+            mOffset = offset;
+            return this;
+        }
+
+        /**
+         * Sets fraction of size to be added to view's start position.  e.g. to track the
+         * center position of the view, use fraction 0.5; to track the end position of the view
+         * use fraction 1.
+         *
+         * @param fraction Fraction of size of the view.
+         * @return This ChildPositionProperty object.
+         */
+        public ChildPositionProperty fraction(float fraction) {
+            mFraction = fraction;
+            return this;
+        }
+
+        /**
+         * Returns adapter position of the recyclerview child to track.
+         */
+        public int getAdapterPosition() {
+            return mAdapterPosition;
+        }
+
+        /**
+         * Returns view Id of a descendant of recyclerview child to track.
+         */
+        public int getViewId() {
+            return mViewId;
+        }
+
+        /**
+         * Returns offset in pixels added to the view's start position.
+         */
+        public int getOffset() {
+            return mOffset;
+        }
+
+        /**
+         * Returns fraction of size to be added to view's start position.  e.g. to track the
+         * center position of the view, use fraction 0.5; to track the end position of the view
+         * use fraction 1.
+         */
+        public float getFraction() {
+            return mFraction;
+        }
+
+        void updateValue(ParallaxRecyclerViewSource source) {
+            RecyclerView recyclerView = source.mRecylerView;
+            ViewHolder viewHolder =
+                    recyclerView.findViewHolderForAdapterPosition(mAdapterPosition);
+            if (viewHolder == null) {
+                if (recyclerView.getLayoutManager().getChildCount() == 0) {
+                    source.setPropertyValue(getIndex(), IntProperty.UNKNOWN_AFTER);
+                    return;
+                }
+                View firstChild = recyclerView.getLayoutManager().getChildAt(0);
+                ViewHolder vh = recyclerView.findContainingViewHolder(firstChild);
+                int firstPosition = vh.getAdapterPosition();
+                if (firstPosition < mAdapterPosition) {
+                    source.setPropertyValue(getIndex(), IntProperty.UNKNOWN_AFTER);
+                } else {
+                    source.setPropertyValue(getIndex(), IntProperty.UNKNOWN_BEFORE);
+                }
+            } else {
+                View trackingView = viewHolder.itemView.findViewById(mViewId);
+                if (trackingView == null) {
+                    return;
+                }
+
+                Rect rect = new Rect(
+                        0, 0, trackingView.getWidth(), trackingView.getHeight());
+                recyclerView.offsetDescendantRectToMyCoords(trackingView, rect);
+                if (source.mIsVertical) {
+                    source.setPropertyValue(getIndex(), rect.top + mOffset
+                            + (int) (mFraction * rect.height()));
+                } else {
+                    source.setPropertyValue(getIndex(), rect.left + mOffset
+                            + (int) (mFraction * rect.width()));
+                }
+            }
+        }
+    }
+
+    @Override
+    public ChildPositionProperty createProperty(String name, int index) {
+        return new ChildPositionProperty(name, index);
+    }
+
+    @Override
+    public void setListener(Listener listener) {
+        mListener = listener;
+    }
+
+    @Override
+    public int getMaxParentVisibleSize() {
+        if (mRecylerView == null) {
+            return 0;
+        }
+        return mIsVertical ? mRecylerView.getHeight() : mRecylerView.getWidth();
+    }
+
+    /**
+     * Constructor.
+     */
+    public ParallaxRecyclerViewSource(RecyclerView parent) {
+        this.mRecylerView = parent;
+        LayoutManager.Properties properties = mRecylerView.getLayoutManager()
+                .getProperties(mRecylerView.getContext(), null, 0, 0);
+        mIsVertical = properties.orientation == RecyclerView.VERTICAL;
+        setupScrollListener();
+    }
+
+    private void setupScrollListener() {
+        mRecylerView.addOnScrollListener(new OnScrollListener() {
+            @Override
+            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
+                for (ChildPositionProperty prop: getProperties()) {
+                    prop.updateValue(ParallaxRecyclerViewSource.this);
+                }
+                mListener.onPropertiesChanged(ParallaxRecyclerViewSource.this);
+            }
+        });
+    }
+}
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/ParallaxSource.java b/v17/leanback/src/android/support/v17/leanback/widget/ParallaxSource.java
new file mode 100644
index 0000000..02809af
--- /dev/null
+++ b/v17/leanback/src/android/support/v17/leanback/widget/ParallaxSource.java
@@ -0,0 +1,518 @@
+/*
+ * 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 android.support.v17.leanback.widget;
+
+import android.util.Property;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+
+/**
+ * ParallaxSource tracks a list of dynamic {@link Property}s typically representing foreground UI
+ * element positions on screen. App should subclass either {@link ParallaxSource.IntSource} or
+ * {@link ParallaxSource.FloatSource}. App may subclass {@link ParallaxSource.IntProperty} or
+ * {@link ParallaxSource.FloatProperty} to supply additional information about how to retrieve
+ * Property value.  For reference implementation, see {@link ParallaxRecyclerViewSource}.
+ *
+ * <p>
+ * <ul>Restrictions
+ * <li>Values must be in ascending order.</li>
+ * <li>If the UI element is unknown above screen, use UNKNOWN_BEFORE.</li>
+ * <li>if the UI element is unknown below screen, use UNKNOWN_AFTER.</li>
+ * <li>UNKNOWN_BEFORE and USE_UNKNOWN_AFTER are not allowed to be next to each other.</li>
+ * </ul>
+ *
+ * These rules can be verified by {@link #verifyProperties()}.
+ * </p>
+ */
+public abstract class ParallaxSource<PropertyT extends Property> {
+
+    /**
+     * Listener for tracking Property value changes.
+     */
+    public static abstract class Listener {
+        /**
+         * Called when the value for any of the property in ParallaxSource changes.
+         */
+        public void onPropertiesChanged(ParallaxSource source) {
+        }
+    }
+
+    /**
+     * Class holding a fixed key value for a Property in {@link ParallaxSource}.
+     * Base class for {@link IntPropertyKeyValue} and {@link FloatPropertyKeyValue}.
+     */
+    public static class PropertyKeyValue<PropertyT extends Property> {
+        private final PropertyT mProperty;
+
+        public PropertyKeyValue(PropertyT property) {
+            mProperty = property;
+        }
+
+        /**
+         * @return Associated property.
+         */
+        public PropertyT getProperty() {
+            return mProperty;
+        }
+    }
+
+    /**
+     * IntProperty provide access to an index based integer type property inside {@link IntSource}.
+     * The IntProperty typically represents UI element position inside {@link IntSource}.
+     */
+    public static class IntProperty extends Property<IntSource, Integer> {
+
+        /**
+         * Property value is unknown and it's above screen.
+         */
+        public static final int UNKNOWN_BEFORE = Integer.MIN_VALUE;
+
+        /**
+         * Property value is unknown and it's bellow screen.
+         */
+        public static final int UNKNOWN_AFTER = Integer.MAX_VALUE;
+
+        private final int mIndex;
+
+        /**
+         * Constructor.
+         *
+         * @param name Name of this Property.
+         * @param index Index of this Property inside {@link IntSource}.
+         */
+        public IntProperty(String name, int index) {
+            super(Integer.class, name);
+            mIndex = index;
+        }
+
+        @Override
+        public final Integer get(IntSource object) {
+            return getIntValue(object);
+        }
+
+        @Override
+        public final void set(IntSource object, Integer value) {
+            setIntValue(object, value);
+        }
+
+        final int getIntValue(IntSource source) {
+            return source.getPropertyValue(mIndex);
+        }
+
+        final void setIntValue(IntSource source, int value) {
+            source.setPropertyValue(mIndex, value);
+        }
+
+        /**
+         * @return Index of this Property in {@link IntSource}.
+         */
+        public final int getIndex() {
+            return mIndex;
+        }
+
+        /**
+         * Creates an {@link IntPropertyKeyValue} object for the absolute keyValue.
+         *
+         * @param keyValue The integer key value.
+         * @return A new {@link IntPropertyKeyValue} object.
+         */
+        public final IntPropertyKeyValue atAbsolute(int keyValue) {
+            return new IntPropertyKeyValue(this, keyValue, 0f);
+        }
+
+        /**
+         * Creates an {@link IntPropertyKeyValue} object for a fraction of
+         * {@link IntSource#getMaxParentVisibleSize()}.
+         *
+         * @param fractionOfMaxParentVisibleSize 0 to 1 fraction to multiply with
+         *                                       {@link IntSource#getMaxParentVisibleSize()} for
+         *                                       the key value.
+         * @return A new {@link IntPropertyKeyValue} object.
+         */
+        public final IntPropertyKeyValue atFraction(float fractionOfMaxParentVisibleSize) {
+            return new IntPropertyKeyValue(this, 0, fractionOfMaxParentVisibleSize);
+        }
+
+        /**
+         * Create an {@link IntPropertyKeyValue} object by multiplying the fraction with
+         * {@link IntSource#getMaxParentVisibleSize()} and adding offsetValue to it.
+         *
+         * @param offsetValue                    An offset integer value to be added to key value.
+         * @param fractionOfMaxParentVisibleSize 0 to 1 fraction to multiply with
+         *                                       {@link IntSource#getMaxParentVisibleSize()} for
+         *                                       the key value.
+         * @return A new {@link IntPropertyKeyValue} object.
+         */
+        public final IntPropertyKeyValue at(int offsetValue,
+                float fractionOfMaxParentVisibleSize) {
+            return new IntPropertyKeyValue(this, offsetValue, fractionOfMaxParentVisibleSize);
+        }
+    }
+
+    /**
+     * Manages a list of {@link IntProperty}. App should override this class with a specific
+     * {@link IntProperty} subclass.
+     *
+     * @param <IntPropertyT> Type of {@link IntProperty} or subclass.
+     */
+    public abstract static class IntSource<IntPropertyT extends IntProperty>
+            extends ParallaxSource<IntPropertyT> {
+
+        private int[] mValues = new int[4];
+
+        /**
+         * Get index based property value.
+         *
+         * @param index Index of the property.
+         * @return Value of the property.
+         */
+        public final int getPropertyValue(int index) {
+            return mValues[index];
+        }
+
+        /**
+         * Set index based property value.
+         *
+         * @param index Index of the property.
+         * @param value Value of the property.
+         */
+        public final void setPropertyValue(int index, int value) {
+            mValues[index] = value;
+        }
+
+        /**
+         * Return the size of parent visible area, e.g. parent view's height if we are tracking Y
+         * position of a child. The size can be used to calculate key value using the provided
+         * fraction.
+         *
+         * @return Size of parent visible area.
+         * @see IntPropertyKeyValue
+         */
+        public abstract int getMaxParentVisibleSize();
+
+        @Override
+        public final IntPropertyT addProperty(String name) {
+            int newPropertyIndex = mProperties.size();
+            IntPropertyT property = createProperty(name, newPropertyIndex);
+            mProperties.add(property);
+            int size = mValues.length;
+            if (size == newPropertyIndex) {
+                int[] newValues = new int[size * 2];
+                for (int i = 0; i < size; i++) {
+                    newValues[i] = mValues[i];
+                }
+                mValues = newValues;
+            }
+            mValues[newPropertyIndex] = IntProperty.UNKNOWN_AFTER;
+            return property;
+        }
+
+        @Override
+        public final void verifyProperties() throws IllegalStateException {
+            if (mProperties.size() < 2) {
+                return;
+            }
+            int last = mProperties.get(0).getIntValue(this);
+            for (int i = 1; i < mProperties.size(); i++) {
+                int v = mProperties.get(i).getIntValue(this);
+                if (v < last) {
+                    throw new IllegalStateException(String.format("Parallax Property[%d]\"%s\" is"
+                                    + " smaller than Property[%d]\"%s\"",
+                            i, mProperties.get(i).getName(),
+                            i - 1, mProperties.get(i - 1).getName()));
+                } else if (last == IntProperty.UNKNOWN_BEFORE && v == IntProperty.UNKNOWN_AFTER) {
+                    throw new IllegalStateException(String.format("Parallax Property[%d]\"%s\" is"
+                                    + " UNKNOW_BEFORE and Property[%d]\"%s\" is UNKNOWN_AFTER",
+                            i - 1, mProperties.get(i - 1).getName(),
+                            i, mProperties.get(i).getName()));
+                }
+                last = v;
+            }
+        }
+
+    }
+
+    /**
+     * Implementation of {@link PropertyKeyValue} for {@link IntProperty}.
+     */
+    public static class IntPropertyKeyValue extends PropertyKeyValue<IntProperty> {
+        private final int mValue;
+        private final float mFactionOfMax;
+
+        public IntPropertyKeyValue(IntProperty property, int value) {
+            this(property, value, 0f);
+        }
+
+        public IntPropertyKeyValue(IntProperty property, int value, float fractionOfMax) {
+            super(property);
+            mValue = value;
+            mFactionOfMax = fractionOfMax;
+        }
+
+        /**
+         * @return The key value of integer type.
+         */
+        public final int getKeyValue(IntSource source) {
+            return mFactionOfMax == 0 ? mValue : mValue + Math.round(source
+                    .getMaxParentVisibleSize() * mFactionOfMax);
+        }
+    }
+
+    /**
+     * FloatProperty provide access to an index based integer type property inside
+     * {@link FloatSource}. The FloatProperty typically represents UI element position inside
+     * {@link FloatSource}.
+     */
+    public static class FloatProperty extends Property<FloatSource, Float> {
+
+        /**
+         * Property value is unknown and it's above screen.
+         */
+        public static final float UNKNOWN_BEFORE = -Float.MAX_VALUE;
+        /**
+         * Property value is unknown and it's bellow screen.
+         */
+        public static final float UNKNOWN_AFTER = Float.MAX_VALUE;
+
+        private final int mIndex;
+
+        /**
+         * Constructor.
+         *
+         * @param name Name of this Property.
+         * @param index Index of this Property inside {@link FloatSource}.
+         */
+        public FloatProperty(String name, int index) {
+            super(Float.class, name);
+            mIndex = index;
+        }
+
+        @Override
+        public final Float get(FloatSource object) {
+            return getFloatValue(object);
+        }
+
+        @Override
+        public final void set(FloatSource object, Float value) {
+            setFloatValue(object, value);
+        }
+
+        final float getFloatValue(FloatSource source) {
+            return source.getPropertyValue(mIndex);
+        }
+
+        final void setFloatValue(FloatSource source, float value) {
+            source.setPropertyValue(mIndex, value);
+        }
+
+        /**
+         * @return Index of this Property in {@link FloatSource}.
+         */
+        public final int getIndex() {
+            return mIndex;
+        }
+
+        /**
+         * Creates an {@link FloatPropertyKeyValue} object for the absolute keyValue.
+         *
+         * @param keyValue The float key value.
+         * @return A new {@link FloatPropertyKeyValue} object.
+         */
+        public final FloatPropertyKeyValue atAbsolute(float keyValue) {
+            return new FloatPropertyKeyValue(this, keyValue, 0f);
+        }
+
+        /**
+         * Creates an {@link FloatPropertyKeyValue} object for a fraction of
+         * {@link FloatSource#getMaxParentVisibleSize()}.
+         *
+         * @param fractionOfMaxParentVisibleSize 0 to 1 fraction to multiply with
+         *                                       {@link FloatSource#getMaxParentVisibleSize()} for
+         *                                       the key value.
+         * @return A new {@link FloatPropertyKeyValue} object.
+         */
+        public final FloatPropertyKeyValue atFraction(float fractionOfMaxParentVisibleSize) {
+            return new FloatPropertyKeyValue(this, 0, fractionOfMaxParentVisibleSize);
+        }
+
+        /**
+         * Create an {@link FloatPropertyKeyValue} object by multiplying the fraction with
+         * {@link FloatSource#getMaxParentVisibleSize()} and adding offsetValue to it.
+         *
+         * @param offsetValue                    An offset float value to be added to key value.
+         * @param fractionOfMaxParentVisibleSize 0 to 1 fraction to multiply with
+         *                                       {@link FloatSource#getMaxParentVisibleSize()} for
+         *                                       the key value.
+         * @return A new {@link FloatPropertyKeyValue} object.
+         */
+        public final FloatPropertyKeyValue at(float offsetValue,
+                float fractionOfMaxParentVisibleSize) {
+            return new FloatPropertyKeyValue(this, offsetValue, fractionOfMaxParentVisibleSize);
+        }
+    }
+
+    /**
+     * Manages a list of {@link FloatProperty}. App should override this class with a specific
+     * {@link FloatProperty} subclass.
+     *
+     * @param <FloatPropertyT> Type of {@link FloatProperty} or subclass.
+     */
+    public abstract static class FloatSource<FloatPropertyT extends FloatProperty> extends
+            ParallaxSource<FloatPropertyT> {
+
+        private float[] mValues = new float[4];
+
+        /**
+         * Get index based property value.
+         *
+         * @param index Index of the property.
+         * @return Value of the property.
+         */
+        public final float getPropertyValue(int index) {
+            return mValues[index];
+        }
+
+        /**
+         * Set index based property value.
+         *
+         * @param index Index of the property.
+         * @param value Value of the property.
+         */
+        public final void setPropertyValue(int index, float value) {
+            mValues[index] = value;
+        }
+
+        /**
+         * Return the size of parent visible area, e.g. parent view's height if we are tracking Y
+         * position of a child. The size can be used to calculate key value using the provided
+         * fraction.
+         *
+         * @return Size of parent visible area.
+         * @see FloatPropertyKeyValue
+         */
+        public abstract float getMaxParentVisibleSize();
+
+        @Override
+        public final FloatPropertyT addProperty(String name) {
+            int newPropertyIndex = mProperties.size();
+            FloatPropertyT property = createProperty(name, newPropertyIndex);
+            mProperties.add(property);
+            int size = mValues.length;
+            if (size == newPropertyIndex) {
+                float[] newValues = new float[size * 2];
+                for (int i = 0; i < size; i++) {
+                    newValues[i] = mValues[i];
+                }
+                mValues = newValues;
+            }
+            mValues[newPropertyIndex] = FloatProperty.UNKNOWN_AFTER;
+            return property;
+        }
+
+        @Override
+        public final void verifyProperties() throws IllegalStateException {
+            if (mProperties.size() < 2) {
+                return;
+            }
+            float last = mProperties.get(0).getFloatValue(this);
+            for (int i = 1; i < mProperties.size(); i++) {
+                float v = mProperties.get(i).getFloatValue(this);
+                if (v < last) {
+                    throw new IllegalStateException(String.format("Parallax Property[%d]\"%s\" is"
+                                    + " smaller than Property[%d]\"%s\"",
+                            i, mProperties.get(i).getName(),
+                            i - 1, mProperties.get(i - 1).getName()));
+                } else if (last == FloatProperty.UNKNOWN_BEFORE && v
+                        == FloatProperty.UNKNOWN_AFTER) {
+                    throw new IllegalStateException(String.format("Parallax Property[%d]\"%s\" is"
+                                    + " UNKNOW_BEFORE and Property[%d]\"%s\" is UNKNOWN_AFTER",
+                            i - 1, mProperties.get(i - 1).getName(),
+                            i, mProperties.get(i).getName()));
+                }
+                last = v;
+            }
+        }
+
+    }
+
+    /**
+     * Implementation of {@link PropertyKeyValue} for {@link FloatProperty}.
+     */
+    public static class FloatPropertyKeyValue extends PropertyKeyValue<FloatProperty> {
+        private final float mValue;
+        private final float mFactionOfMax;
+
+        public FloatPropertyKeyValue(FloatProperty property, float value) {
+            this(property, value, 0f);
+        }
+
+        public FloatPropertyKeyValue(FloatProperty property, float value, float fractionOfMax) {
+            super(property);
+            mValue = value;
+            mFactionOfMax = fractionOfMax;
+        }
+
+        /**
+         * @return The key value.
+         */
+        public final float getKeyValue(FloatSource source) {
+            return mFactionOfMax == 0 ? mValue : mValue + source.getMaxParentVisibleSize()
+                    * mFactionOfMax;
+        }
+    }
+
+    final List<PropertyT> mProperties = new ArrayList<PropertyT>();
+    final List<PropertyT> mPropertiesReadOnly = Collections.unmodifiableList(mProperties);
+
+    /**
+     * @return A unmodifiable list of properties.
+     */
+    public final List<PropertyT> getProperties() {
+        return mPropertiesReadOnly;
+    }
+
+    /**
+     * Add a new Property in the ParallaxSource.
+     *
+     * @return Newly created Property.
+     */
+    public abstract PropertyT addProperty(String name);
+
+    /**
+     * Create a new Property object. App does not directly call this method.  See
+     * {@link #addProperty(String)}.
+     *
+     * @param index  Index of the property in this ParallaxSource object.
+     * @return Newly created Property object.
+     */
+    public abstract PropertyT createProperty(String name, int index);
+
+    /**
+     * Verify sanity of property values, throws RuntimeException if fails. The property values
+     * must be in ascending order. UNKNOW_BEFORE and UNKNOWN_AFTER are not allowed to be next to
+     * each other.
+     */
+    public abstract void verifyProperties() throws IllegalStateException;
+
+    /**
+     * Sets listener to monitor property value changes.
+     *
+     * @param listener The listener to set on {@link ParallaxSource} object.
+     */
+    public abstract void setListener(Listener listener);
+
+}
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/ParallaxTarget.java b/v17/leanback/src/android/support/v17/leanback/widget/ParallaxTarget.java
new file mode 100644
index 0000000..1fbd54e
--- /dev/null
+++ b/v17/leanback/src/android/support/v17/leanback/widget/ParallaxTarget.java
@@ -0,0 +1,79 @@
+/*
+ * 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 android.support.v17.leanback.widget;
+
+import android.animation.ObjectAnimator;
+import android.animation.PropertyValuesHolder;
+import android.view.animation.LinearInterpolator;
+
+import java.util.List;
+
+/**
+ * ParallaxTarget is reponsible for updating the target through the {@link #update(float)} method.
+ * {@link ParallaxEffect} transforms the values of {@link ParallaxSource}, which represents the
+ * current state of UI, into a float value between 0 and 1. That float value is passed into
+ * {@link #update(float)} method.
+ */
+public abstract class ParallaxTarget {
+
+    /**
+     * Implementation class is supposed to update target with the provided fraction
+     * (between 0 and 1). The fraction represents percentage of completed change (e.g. scroll) on
+     * target.
+     *
+     * @param fraction Fraction between 0 to 1.
+     */
+    public abstract void update(float fraction);
+
+    /**
+     * Returns the current fraction (between 0 and 1). The fraction represents percentage of
+     * completed change (e.g. scroll) on target.
+     *
+     * @return Current fraction value.
+     */
+    public abstract float getFraction();
+
+    /**
+     * PropertyValuesHolderTarget is an implementation of {@link ParallaxTarget} that uses
+     * {@link PropertyValuesHolder} to update the target object.
+     */
+    public static final class PropertyValuesHolderTarget extends ParallaxTarget {
+
+        /**
+         * We simulate a parallax effect on target object using an ObjectAnimator. PSEUDO_DURATION
+         * is used on the ObjectAnimator.
+         */
+        private static final long PSEUDO_DURATION = 1000000;
+
+        private final ObjectAnimator mAnimator;
+        private float mFraction;
+
+        public PropertyValuesHolderTarget(Object targetObject, PropertyValuesHolder values) {
+            mAnimator = ObjectAnimator.ofPropertyValuesHolder(targetObject, values);
+            mAnimator.setInterpolator(new LinearInterpolator());
+            mAnimator.setDuration(PSEUDO_DURATION);
+        }
+
+        @Override
+        public void update(float fraction) {
+            mFraction = fraction;
+            mAnimator.setCurrentPlayTime((long) (PSEUDO_DURATION * fraction));
+        }
+
+        @Override
+        public float getFraction() {
+            return mFraction;
+        }
+    }
+}
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/PersistentFocusWrapper.java b/v17/leanback/src/android/support/v17/leanback/widget/PersistentFocusWrapper.java
index ed057de..8a3d886 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/PersistentFocusWrapper.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/PersistentFocusWrapper.java
@@ -83,15 +83,16 @@
     }
 
     private boolean shouldPersistFocusFromDirection(int direction) {
-        return ((mPersistFocusVertical && (direction == FOCUS_UP || direction == FOCUS_DOWN)) ||
-                (!mPersistFocusVertical && (direction == FOCUS_LEFT || direction == FOCUS_RIGHT)));
+        return ((mPersistFocusVertical && (direction == FOCUS_UP || direction == FOCUS_DOWN))
+                || (!mPersistFocusVertical
+                && (direction == FOCUS_LEFT || direction == FOCUS_RIGHT)));
     }
 
     @Override
     public void addFocusables(ArrayList<View> views, int direction, int focusableMode) {
         if (DEBUG) Log.v(TAG, "addFocusables");
-        if (hasFocus() || getGrandChildCount() == 0 ||
-                !shouldPersistFocusFromDirection(direction)) {
+        if (hasFocus() || getGrandChildCount() == 0
+                || !shouldPersistFocusFromDirection(direction)) {
             super.addFocusables(views, direction, focusableMode);
         } else {
             // Select a child in requestFocus
@@ -107,7 +108,10 @@
             view = (View) view.getParent();
         }
         mSelectedPosition = view == null ? -1 : ((ViewGroup) child).indexOfChild(view);
-        if (DEBUG) Log.v(TAG, "requestChildFocus focused " + focused + " mSelectedPosition " + mSelectedPosition);
+        if (DEBUG) {
+            Log.v(TAG, "requestChildFocus focused " + focused + " mSelectedPosition "
+                    + mSelectedPosition);
+        }
     }
 
     @Override
@@ -142,8 +146,8 @@
             dest.writeInt(mSelectedPosition);
         }
 
-        public static final Parcelable.Creator<SavedState> CREATOR
-                = new Parcelable.Creator<SavedState>() {
+        public static final Parcelable.Creator<SavedState> CREATOR =
+                new Parcelable.Creator<SavedState>() {
             @Override
             public SavedState createFromParcel(Parcel in) {
                 return new SavedState(in);
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/PlaybackControlsPresenter.java b/v17/leanback/src/android/support/v17/leanback/widget/PlaybackControlsPresenter.java
index da6c98d..79d1407 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/PlaybackControlsPresenter.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/PlaybackControlsPresenter.java
@@ -13,21 +13,19 @@
  */
 package android.support.v17.leanback.widget;
 
-import android.animation.ValueAnimator;
 import android.content.Context;
-import android.content.res.Resources;
 import android.graphics.drawable.ClipDrawable;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.LayerDrawable;
 import android.support.annotation.ColorInt;
 import android.support.v17.leanback.R;
+import android.support.v17.leanback.util.MathUtil;
 import android.view.Gravity;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewGroup.MarginLayoutParams;
-import android.view.animation.LinearInterpolator;
 import android.widget.FrameLayout;
 import android.widget.ProgressBar;
 import android.widget.TextView;
@@ -58,7 +56,9 @@
         final TextView mCurrentTime;
         final TextView mTotalTime;
         final ProgressBar mProgressBar;
-        int mCurrentTimeInSeconds = -1;
+        long mCurrentTimeInMs = -1;         // Hold current time in milliseconds
+        long mTotalTimeInMs = -1;           // Hold total time in milliseconds
+        long mSecondaryProgressInMs = -1;   // Hold secondary progress in milliseconds
         StringBuilder mTotalTimeStringBuilder = new StringBuilder();
         StringBuilder mCurrentTimeStringBuilder = new StringBuilder();
         int mCurrentTimeMarginStart;
@@ -110,8 +110,8 @@
                 if (mMoreActionsViewHolder.view.getParent() == null) {
                     mMoreActionsDock.addView(mMoreActionsViewHolder.view);
                 }
-            } else if (mMoreActionsViewHolder != null &&
-                    mMoreActionsViewHolder.view.getParent() != null) {
+            } else if (mMoreActionsViewHolder != null
+                    && mMoreActionsViewHolder.view.getParent() != null) {
                 mMoreActionsDock.removeView(mMoreActionsViewHolder.view);
             }
         }
@@ -139,49 +139,57 @@
             return margin;
         }
 
-        void setTotalTime(int totalTimeMs) {
+        void setTotalTime(long totalTimeMs) {
             if (totalTimeMs <= 0) {
                 mTotalTime.setVisibility(View.GONE);
                 mProgressBar.setVisibility(View.GONE);
             } else {
                 mTotalTime.setVisibility(View.VISIBLE);
                 mProgressBar.setVisibility(View.VISIBLE);
+                mTotalTimeInMs = totalTimeMs;
                 formatTime(totalTimeMs / 1000, mTotalTimeStringBuilder);
                 mTotalTime.setText(mTotalTimeStringBuilder.toString());
-                mProgressBar.setMax(totalTimeMs);
+                mProgressBar.setMax(Integer.MAX_VALUE);//current progress will be a fraction of this
             }
         }
 
-        int getTotalTime() {
-            return mProgressBar.getMax();
+        long getTotalTime() {
+            return mTotalTimeInMs;
         }
 
-        void setCurrentTime(int currentTimeMs) {
-            int seconds = currentTimeMs / 1000;
-            if (seconds != mCurrentTimeInSeconds) {
-                mCurrentTimeInSeconds = seconds;
-                formatTime(mCurrentTimeInSeconds, mCurrentTimeStringBuilder);
+        void setCurrentTime(long currentTimeMs) {
+            long seconds = currentTimeMs / 1000;
+            if (currentTimeMs != mCurrentTimeInMs) {
+                mCurrentTimeInMs = currentTimeMs;
+                formatTime(seconds, mCurrentTimeStringBuilder);
                 mCurrentTime.setText(mCurrentTimeStringBuilder.toString());
             }
-            mProgressBar.setProgress(currentTimeMs);
+            // Use ratio to represent current progres
+            double ratio = (double) mCurrentTimeInMs / mTotalTimeInMs;     // Range: [0, 1]
+            double progressRatio = ratio * Integer.MAX_VALUE;   // Could safely cast to int
+            mProgressBar.setProgress((int)progressRatio);
         }
 
-        int getCurrentTime() {
-            return mProgressBar.getProgress();
+        long getCurrentTime() {
+            return mTotalTimeInMs;
         }
 
-        void setSecondaryProgress(int progressMs) {
-            mProgressBar.setSecondaryProgress(progressMs);
+        void setSecondaryProgress(long progressMs) {
+            mSecondaryProgressInMs = progressMs;
+            // Solve the progress bar by using ratio
+            double ratio = (double) progressMs / mTotalTimeInMs;           // Range: [0, 1]
+            double progressRatio = ratio * Integer.MAX_VALUE;   // Could safely cast to int
+            mProgressBar.setSecondaryProgress((int) progressRatio);
         }
 
-        int getSecondaryProgress() {
-            return mProgressBar.getSecondaryProgress();
+        long getSecondaryProgress() {
+            return mSecondaryProgressInMs;
         }
     }
 
-    static void formatTime(int seconds, StringBuilder sb) {
-        int minutes = seconds / 60;
-        int hours = minutes / 60;
+    static void formatTime(long seconds, StringBuilder sb) {
+        long minutes = seconds / 60;
+        long hours = minutes / 60;
         seconds -= minutes * 60;
         minutes -= hours * 60;
 
@@ -236,26 +244,50 @@
     }
 
     public void setTotalTime(ViewHolder vh, int ms) {
+        setTotalTimeLong(vh, (long) ms);
+    }
+
+    public void setTotalTimeLong(ViewHolder vh, long ms) {
         vh.setTotalTime(ms);
     }
 
     public int getTotalTime(ViewHolder vh) {
+        return MathUtil.safeLongToInt(getTotalTimeLong(vh));
+    }
+
+    public long getTotalTimeLong(ViewHolder vh) {
         return vh.getTotalTime();
     }
 
     public void setCurrentTime(ViewHolder vh, int ms) {
+        setCurrentTimeLong(vh, (long) ms);
+    }
+
+    public void setCurrentTimeLong(ViewHolder vh, long ms) {
         vh.setCurrentTime(ms);
     }
 
     public int getCurrentTime(ViewHolder vh) {
+        return MathUtil.safeLongToInt(getCurrentTimeLong(vh));
+    }
+
+    public long getCurrentTimeLong(ViewHolder vh) {
         return vh.getCurrentTime();
     }
 
     public void setSecondaryProgress(ViewHolder vh, int progressMs) {
+        setSecondaryProgressLong(vh, (long) progressMs);
+    }
+
+    public void setSecondaryProgressLong(ViewHolder vh, long progressMs) {
         vh.setSecondaryProgress(progressMs);
     }
 
     public int getSecondaryProgress(ViewHolder vh) {
+        return MathUtil.safeLongToInt(getSecondaryProgressLong(vh));
+    }
+
+    public long getSecondaryProgressLong(ViewHolder vh) {
         return vh.getSecondaryProgress();
     }
 
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/PlaybackControlsRow.java b/v17/leanback/src/android/support/v17/leanback/widget/PlaybackControlsRow.java
index 098cf60..83aff47 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/PlaybackControlsRow.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/PlaybackControlsRow.java
@@ -14,6 +14,7 @@
 package android.support.v17.leanback.widget;
 
 import android.support.v17.leanback.R;
+import android.support.v17.leanback.util.MathUtil;
 import android.util.TypedValue;
 import android.content.Context;
 import android.content.res.TypedArray;
@@ -622,9 +623,9 @@
     private Drawable mImageDrawable;
     private ObjectAdapter mPrimaryActionsAdapter;
     private ObjectAdapter mSecondaryActionsAdapter;
-    private int mTotalTimeMs;
-    private int mCurrentTimeMs;
-    private int mBufferedProgressMs;
+    private long mTotalTimeMs;
+    private long mCurrentTimeMs;
+    private long mBufferedProgressMs;
     private OnPlaybackStateChangedListener mListener;
 
     /**
@@ -721,13 +722,29 @@
      * this row has changed.</p>
      */
     public void setTotalTime(int ms) {
+        setTotalTimeLong((long) ms);
+    }
+
+    /**
+     * Sets the total time in milliseconds (long type) for the playback controls row.
+     * @param ms Total time in milliseconds of long type.
+     */
+    public void setTotalTimeLong(long ms) {
         mTotalTimeMs = ms;
     }
 
     /**
      * Returns the total time in milliseconds for the playback controls row.
+     * @throws ArithmeticException If total time in milliseconds overflows int.
      */
     public int getTotalTime() {
+        return MathUtil.safeLongToInt(getTotalTimeLong());
+    }
+
+    /**
+     * Returns the total time in milliseconds of long type for the playback controls row.
+     */
+    public long getTotalTimeLong() {
         return mTotalTimeMs;
     }
 
@@ -737,6 +754,14 @@
      * be updated to reflect the new value.
      */
     public void setCurrentTime(int ms) {
+        setCurrentTimeLong((long) ms);
+    }
+
+    /**
+     * Sets the current time in milliseconds for playback controls row in long type.
+     * @param ms Current time in milliseconds of long type.
+     */
+    public void setCurrentTimeLong(long ms) {
         if (mCurrentTimeMs != ms) {
             mCurrentTimeMs = ms;
             currentTimeChanged();
@@ -745,8 +770,16 @@
 
     /**
      * Returns the current time in milliseconds for the playback controls row.
+     * @throws ArithmeticException If current time in milliseconds overflows int.
      */
     public int getCurrentTime() {
+        return MathUtil.safeLongToInt(getCurrentTimeLong());
+    }
+
+    /**
+     * Returns the current time in milliseconds of long type for playback controls row.
+     */
+    public long getCurrentTimeLong() {
         return mCurrentTimeMs;
     }
 
@@ -756,6 +789,14 @@
      * be updated to reflect the new value.
      */
     public void setBufferedProgress(int ms) {
+        setBufferedProgressLong((long) ms);
+    }
+
+    /**
+     * Sets the buffered progress for the playback controls row.
+     * @param ms Buffered progress in milliseconds of long type.
+     */
+    public void setBufferedProgressLong(long ms) {
         if (mBufferedProgressMs != ms) {
             mBufferedProgressMs = ms;
             bufferedProgressChanged();
@@ -764,8 +805,16 @@
 
     /**
      * Returns the buffered progress for the playback controls row.
+     * @throws ArithmeticException If buffered progress in milliseconds overflows int.
      */
     public int getBufferedProgress() {
+        return MathUtil.safeLongToInt(getBufferedProgressLong());
+    }
+
+    /**
+     * Returns the buffered progress of long type for the playback controls row.
+     */
+    public long getBufferedProgressLong() {
         return mBufferedProgressMs;
     }
 
@@ -798,8 +847,8 @@
     }
 
     interface OnPlaybackStateChangedListener {
-        public void onCurrentTimeChanged(int currentTimeMs);
-        public void onBufferedProgressChanged(int bufferedProgressMs);
+        public void onCurrentTimeChanged(long currentTimeMs);
+        public void onBufferedProgressChanged(long bufferedProgressMs);
     }
 
     /**
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/PlaybackControlsRowPresenter.java b/v17/leanback/src/android/support/v17/leanback/widget/PlaybackControlsRowPresenter.java
index fc4163e..db7f8a9 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/PlaybackControlsRowPresenter.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/PlaybackControlsRowPresenter.java
@@ -13,13 +13,12 @@
  */
 package android.support.v17.leanback.widget;
 
-import android.graphics.drawable.Drawable;
+import android.content.Context;
+import android.graphics.Color;
 import android.support.annotation.ColorInt;
 import android.support.v17.leanback.R;
 import android.support.v17.leanback.widget.ControlBarPresenter.OnControlClickedListener;
 import android.support.v17.leanback.widget.ControlBarPresenter.OnControlSelectedListener;
-import android.content.Context;
-import android.graphics.Color;
 import android.util.TypedValue;
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
@@ -41,7 +40,7 @@
  * detailed description ViewHolder from {@link ViewHolder#mDescriptionViewHolder}.
  * </p>
  */
-public class PlaybackControlsRowPresenter extends RowPresenter {
+public class PlaybackControlsRowPresenter extends PlaybackRowPresenter {
 
     static class BoundData extends PlaybackControlsPresenter.BoundData {
         ViewHolder mRowViewHolder;
@@ -50,7 +49,7 @@
     /**
      * A ViewHolder for the PlaybackControlsRow.
      */
-    public class ViewHolder extends RowPresenter.ViewHolder {
+    public class ViewHolder extends PlaybackRowPresenter.ViewHolder {
         public final Presenter.ViewHolder mDescriptionViewHolder;
         final ViewGroup mCard;
         final ViewGroup mCardRightPanel;
@@ -72,12 +71,12 @@
         final PlaybackControlsRow.OnPlaybackStateChangedListener mListener =
                 new PlaybackControlsRow.OnPlaybackStateChangedListener() {
             @Override
-            public void onCurrentTimeChanged(int ms) {
-                mPlaybackControlsPresenter.setCurrentTime(mControlsVh, ms);
+            public void onCurrentTimeChanged(long ms) {
+                mPlaybackControlsPresenter.setCurrentTimeLong(mControlsVh, ms);
             }
             @Override
-            public void onBufferedProgressChanged(int ms) {
-                mPlaybackControlsPresenter.setSecondaryProgress(mControlsVh, ms);
+            public void onBufferedProgressChanged(long ms) {
+                mPlaybackControlsPresenter.setSecondaryProgressLong(mControlsVh, ms);
             }
         };
 
@@ -117,17 +116,17 @@
         };
 
         Presenter getPresenter(boolean primary) {
-            ObjectAdapter adapter = primary ?
-                    ((PlaybackControlsRow) getRow()).getPrimaryActionsAdapter() :
-                            ((PlaybackControlsRow) getRow()).getSecondaryActionsAdapter();
+            ObjectAdapter adapter = primary
+                    ? ((PlaybackControlsRow) getRow()).getPrimaryActionsAdapter()
+                    : ((PlaybackControlsRow) getRow()).getSecondaryActionsAdapter();
             if (adapter == null) {
                 return null;
             }
             if (adapter.getPresenterSelector() instanceof ControlButtonPresenterSelector) {
                 ControlButtonPresenterSelector selector =
                         (ControlButtonPresenterSelector) adapter.getPresenterSelector();
-                return primary ? selector.getPrimaryPresenter() :
-                    selector.getSecondaryPresenter();
+                return primary ? selector.getPrimaryPresenter()
+                        : selector.getSecondaryPresenter();
             }
             return adapter.getPresenter(adapter.size() > 0 ? adapter.get(0) : null);
         }
@@ -298,6 +297,11 @@
         mPlaybackControlsPresenter.resetFocus(vh.mControlsVh);
     }
 
+    @Override
+    public void onReappear(RowPresenter.ViewHolder rowViewHolder) {
+        showPrimaryActions((ViewHolder) rowViewHolder);
+    }
+
     private int getDefaultBackgroundColor(Context context) {
         TypedValue outValue = new TypedValue();
         if (context.getTheme().resolveAttribute(R.attr.defaultBrandColor, outValue, true)) {
@@ -331,10 +335,10 @@
 
         vh.mControlsVh = (PlaybackControlsPresenter.ViewHolder)
                 mPlaybackControlsPresenter.onCreateViewHolder(vh.mControlsDock);
-        mPlaybackControlsPresenter.setProgressColor(vh.mControlsVh, mProgressColorSet ?
-                mProgressColor : getDefaultProgressColor(vh.mControlsDock.getContext()));
-        mPlaybackControlsPresenter.setBackgroundColor(vh.mControlsVh, mBackgroundColorSet ?
-                mBackgroundColor : getDefaultBackgroundColor(vh.view.getContext()));
+        mPlaybackControlsPresenter.setProgressColor(vh.mControlsVh, mProgressColorSet
+                ? mProgressColor : getDefaultProgressColor(vh.mControlsDock.getContext()));
+        mPlaybackControlsPresenter.setBackgroundColor(vh.mControlsVh, mBackgroundColorSet
+                ? mBackgroundColor : getDefaultBackgroundColor(vh.view.getContext()));
         vh.mControlsDock.addView(vh.mControlsVh.view);
 
         vh.mSecondaryControlsVh =
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/PlaybackRowPresenter.java b/v17/leanback/src/android/support/v17/leanback/widget/PlaybackRowPresenter.java
new file mode 100644
index 0000000..bb1edb3
--- /dev/null
+++ b/v17/leanback/src/android/support/v17/leanback/widget/PlaybackRowPresenter.java
@@ -0,0 +1,27 @@
+package android.support.v17.leanback.widget;
+
+import android.view.View;
+
+/**
+ * Subclass of {@link RowPresenter} that can define the desired behavior when the view
+ * reappears. This is presently used by {@link PlaybackControlsRowPresenter} to update the UI
+ * after we show/hide the controls view.
+ */
+public abstract class PlaybackRowPresenter extends RowPresenter {
+
+    /**
+     * This container is used for trapping click events and passing them to the
+     * playback controls.
+     */
+    public static class ViewHolder extends RowPresenter.ViewHolder {
+        public ViewHolder(View view) {
+            super(view);
+        }
+    }
+
+    /**
+     * Provides hook to update the UI when the view reappears.
+     */
+    public void onReappear(RowPresenter.ViewHolder rowViewHolder) {
+    }
+}
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/ResizingTextView.java b/v17/leanback/src/android/support/v17/leanback/widget/ResizingTextView.java
index 6b4f875..5888552 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/ResizingTextView.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/ResizingTextView.java
@@ -15,13 +15,12 @@
 
 import android.content.Context;
 import android.content.res.TypedArray;
+import android.support.v17.leanback.R;
 import android.text.Layout;
 import android.util.AttributeSet;
 import android.util.TypedValue;
 import android.widget.TextView;
 
-import android.support.v17.leanback.R;
-
 /**
  * <p>A {@link android.widget.TextView} that adjusts text size automatically in response
  * to certain trigger conditions, such as text that wraps over multiple lines.</p>
@@ -230,8 +229,8 @@
                 remeasure = true;
             }
             // Check for other desired adjustments in addition to the text size
-            final float targetLineSpacingExtra = mDefaultLineSpacingExtra +
-                    mDefaultTextSize - mResizedTextSize;
+            final float targetLineSpacingExtra = mDefaultLineSpacingExtra
+                    + mDefaultTextSize - mResizedTextSize;
             if (mMaintainLineSpacing && getLineSpacingExtra() != targetLineSpacingExtra) {
                 setLineSpacing(targetLineSpacingExtra, getLineSpacingMultiplier());
                 remeasure = true;
@@ -252,8 +251,8 @@
                 setLineSpacing(mDefaultLineSpacingExtra, getLineSpacingMultiplier());
                 remeasure = true;
             }
-            if (getPaddingTop() != mDefaultPaddingTop ||
-                    getPaddingBottom() != mDefaultPaddingBottom) {
+            if (getPaddingTop() != mDefaultPaddingTop
+                    || getPaddingBottom() != mDefaultPaddingBottom) {
                 setPaddingTopAndBottom(mDefaultPaddingTop, mDefaultPaddingBottom);
                 remeasure = true;
             }
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/RowHeaderPresenter.java b/v17/leanback/src/android/support/v17/leanback/widget/RowHeaderPresenter.java
index 53a51a4..c3a2cce 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/RowHeaderPresenter.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/RowHeaderPresenter.java
@@ -13,6 +13,8 @@
  */
 package android.support.v17.leanback.widget;
 
+import static android.support.annotation.RestrictTo.Scope.GROUP_ID;
+
 import android.graphics.Paint;
 import android.support.annotation.RestrictTo;
 import android.support.v17.leanback.R;
@@ -21,8 +23,6 @@
 import android.view.ViewGroup;
 import android.widget.TextView;
 
-import static android.support.annotation.RestrictTo.Scope.GROUP_ID;
-
 /**
  * RowHeaderPresenter provides a default presentation for {@link HeaderItem} using a
  * {@link RowHeaderView}. If a subclass creates its own view, the subclass must also override
@@ -77,10 +77,15 @@
         float mSelectLevel;
         int mOriginalTextColor;
         float mUnselectAlpha;
+        RowHeaderView mTitleView;
+        TextView mDescriptionView;
 
         public ViewHolder(View view) {
             super(view);
+            mTitleView = (RowHeaderView)view.findViewById(R.id.row_header);
+            mDescriptionView = (TextView)view.findViewById(R.id.row_header_description);
         }
+
         public final float getSelectLevel() {
             return mSelectLevel;
         }
@@ -88,11 +93,12 @@
 
     @Override
     public Presenter.ViewHolder onCreateViewHolder(ViewGroup parent) {
-        RowHeaderView headerView = (RowHeaderView) LayoutInflater.from(parent.getContext())
+        View root = LayoutInflater.from(parent.getContext())
                 .inflate(mLayoutResourceId, parent, false);
 
-        ViewHolder viewHolder = new ViewHolder(headerView);
-        viewHolder.mOriginalTextColor = headerView.getCurrentTextColor();
+        ViewHolder viewHolder = new ViewHolder(root);
+        viewHolder.mOriginalTextColor = viewHolder.mTitleView.getCurrentTextColor();
+
         viewHolder.mUnselectAlpha = parent.getResources().getFraction(
                 R.fraction.lb_browse_header_unselect_alpha, 1, 1);
         if (mAnimateSelect) {
@@ -104,22 +110,37 @@
     @Override
     public void onBindViewHolder(Presenter.ViewHolder viewHolder, Object item) {
         HeaderItem headerItem = item == null ? null : ((Row) item).getHeaderItem();
+        RowHeaderPresenter.ViewHolder vh = (RowHeaderPresenter.ViewHolder)viewHolder;
         if (headerItem == null) {
-            ((RowHeaderView) viewHolder.view).setText(null);
+            vh.mTitleView.setText(null);
+
+            if (vh.mDescriptionView != null) {
+                vh.mDescriptionView.setText(null);
+            }
+
             viewHolder.view.setContentDescription(null);
             if (mNullItemVisibilityGone) {
                 viewHolder.view.setVisibility(View.GONE);
             }
         } else {
-            viewHolder.view.setVisibility(View.VISIBLE);
-            ((RowHeaderView) viewHolder.view).setText(headerItem.getName());
+            vh.mTitleView.setText(headerItem.getName());
+            if (vh.mDescriptionView != null) {
+                vh.mDescriptionView.setText(headerItem.getDescription());
+            }
             viewHolder.view.setContentDescription(headerItem.getContentDescription());
+            viewHolder.view.setVisibility(View.VISIBLE);
         }
     }
 
     @Override
     public void onUnbindViewHolder(Presenter.ViewHolder viewHolder) {
-        ((RowHeaderView) viewHolder.view).setText(null);
+        RowHeaderPresenter.ViewHolder vh = (ViewHolder)viewHolder;
+        vh.mTitleView.setText(null);
+
+        if (vh.mDescriptionView != null) {
+            vh.mDescriptionView.setText(null);
+        }
+
         if (mAnimateSelect) {
             setSelectLevel((ViewHolder) viewHolder, 0);
         }
@@ -138,8 +159,8 @@
      */
     protected void onSelectLevelChanged(ViewHolder holder) {
         if (mAnimateSelect) {
-            holder.view.setAlpha(holder.mUnselectAlpha + holder.mSelectLevel *
-                    (1f - holder.mUnselectAlpha));
+            holder.view.setAlpha(holder.mUnselectAlpha + holder.mSelectLevel
+                    * (1f - holder.mUnselectAlpha));
         }
     }
 
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/RowPresenter.java b/v17/leanback/src/android/support/v17/leanback/widget/RowPresenter.java
index 68f0787..8267145 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/RowPresenter.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/RowPresenter.java
@@ -663,10 +663,10 @@
      *                       should be set to visible, false otherwise.
      */
     public void setEntranceTransitionState(ViewHolder holder, boolean afterEntrance) {
-        if (holder.mHeaderViewHolder != null &&
-                holder.mHeaderViewHolder.view.getVisibility() != View.GONE) {
-            holder.mHeaderViewHolder.view.setVisibility(afterEntrance ?
-                    View.VISIBLE : View.INVISIBLE);
+        if (holder.mHeaderViewHolder != null
+                && holder.mHeaderViewHolder.view.getVisibility() != View.GONE) {
+            holder.mHeaderViewHolder.view.setVisibility(afterEntrance
+                    ? View.VISIBLE : View.INVISIBLE);
         }
     }
 }
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/ScaleFrameLayout.java b/v17/leanback/src/android/support/v17/leanback/widget/ScaleFrameLayout.java
index 50fd737..047d83c 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/ScaleFrameLayout.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/ScaleFrameLayout.java
@@ -13,6 +13,8 @@
  */
 package android.support.v17.leanback.widget;
 
+import static android.support.annotation.RestrictTo.Scope.GROUP_ID;
+
 import android.content.Context;
 import android.graphics.drawable.Drawable;
 import android.support.annotation.RestrictTo;
@@ -22,8 +24,6 @@
 import android.view.ViewGroup;
 import android.widget.FrameLayout;
 
-import static android.support.annotation.RestrictTo.Scope.GROUP_ID;
-
 /**
  * Subclass of FrameLayout that support scale layout area size for children.
  * @hide
@@ -99,9 +99,9 @@
 
         final int parentLeft, parentRight;
         final int layoutDirection = getLayoutDirection();
-        final float pivotX = (layoutDirection == View.LAYOUT_DIRECTION_RTL) ?
-                getWidth() - getPivotX() :
-                getPivotX();
+        final float pivotX = (layoutDirection == View.LAYOUT_DIRECTION_RTL)
+                ? getWidth() - getPivotX()
+                : getPivotX();
         if (mLayoutScaleX != 1f) {
             parentLeft = getPaddingLeft() + (int)(pivotX - pivotX / mLayoutScaleX + 0.5f);
             parentRight = (int)(pivotX + (right - left - pivotX) / mLayoutScaleX + 0.5f)
@@ -143,8 +143,8 @@
 
                 switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
                     case Gravity.CENTER_HORIZONTAL:
-                        childLeft = parentLeft + (parentRight - parentLeft - width) / 2 +
-                                lp.leftMargin - lp.rightMargin;
+                        childLeft = parentLeft + (parentRight - parentLeft - width) / 2
+                                + lp.leftMargin - lp.rightMargin;
                         break;
                     case Gravity.RIGHT:
                         childLeft = parentRight - width - lp.rightMargin;
@@ -159,8 +159,8 @@
                         childTop = parentTop + lp.topMargin;
                         break;
                     case Gravity.CENTER_VERTICAL:
-                        childTop = parentTop + (parentBottom - parentTop - height) / 2 +
-                                lp.topMargin - lp.bottomMargin;
+                        childTop = parentTop + (parentBottom - parentTop - height) / 2
+                                + lp.topMargin - lp.bottomMargin;
                         break;
                     case Gravity.BOTTOM:
                         childTop = parentBottom - height - lp.bottomMargin;
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/SearchBar.java b/v17/leanback/src/android/support/v17/leanback/widget/SearchBar.java
index 09706bb..6d627b3 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/SearchBar.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/SearchBar.java
@@ -29,26 +29,25 @@
 import android.speech.RecognitionListener;
 import android.speech.RecognizerIntent;
 import android.speech.SpeechRecognizer;
+import android.support.v17.leanback.R;
 import android.text.Editable;
 import android.text.TextUtils;
 import android.text.TextWatcher;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.util.SparseIntArray;
+import android.view.KeyEvent;
 import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.View;
 import android.view.ViewGroup;
 import android.view.inputmethod.CompletionInfo;
 import android.view.inputmethod.EditorInfo;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
-import android.view.View;
-import android.widget.ImageView;
 import android.view.inputmethod.InputMethodManager;
+import android.widget.ImageView;
 import android.widget.RelativeLayout;
 import android.widget.TextView;
 
-import android.support.v17.leanback.R;
-
 import java.util.ArrayList;
 import java.util.List;
 
@@ -261,8 +260,8 @@
             public boolean onEditorAction(TextView textView, int action, KeyEvent keyEvent) {
                 if (DEBUG) Log.v(TAG, "onEditorAction: " + action + " event: " + keyEvent);
                 boolean handled = true;
-                if ((EditorInfo.IME_ACTION_SEARCH == action ||
-                        EditorInfo.IME_NULL == action) && null != mSearchBarListener) {
+                if ((EditorInfo.IME_ACTION_SEARCH == action
+                        || EditorInfo.IME_NULL == action) && null != mSearchBarListener) {
                     if (DEBUG) Log.v(TAG, "Action or enter pressed");
                     hideNativeKeyboard();
                     mHandler.postDelayed(new Runnable() {
@@ -388,6 +387,28 @@
     }
 
     /**
+     * Sets background color of not-listening state search orb.
+     *
+     * @param colors SearchOrbView.Colors.
+     */
+    public void setSearchAffordanceColors(SearchOrbView.Colors colors) {
+        if (mSpeechOrbView != null) {
+            mSpeechOrbView.setNotListeningOrbColors(colors);
+        }
+    }
+
+    /**
+     * Sets background color of listening state search orb.
+     *
+     * @param colors SearchOrbView.Colors.
+     */
+    public void setSearchAffordanceColorsInListening(SearchOrbView.Colors colors) {
+        if (mSpeechOrbView != null) {
+            mSpeechOrbView.setListeningOrbColors(colors);
+        }
+    }
+
+    /**
      * Returns the current title
      */
     public String getTitle() {
@@ -595,8 +616,8 @@
                 mPermissionListener.requestAudioPermission();
                 return;
             } else {
-                throw new IllegalStateException(Manifest.permission.RECORD_AUDIO +
-                        " required for search");
+                throw new IllegalStateException(Manifest.permission.RECORD_AUDIO
+                        + " required for search");
             }
         }
 
@@ -712,8 +733,10 @@
             public void onPartialResults(Bundle bundle) {
                 ArrayList<String> results = bundle.getStringArrayList(
                         SpeechRecognizer.RESULTS_RECOGNITION);
-                if (DEBUG) Log.v(TAG, "onPartialResults " + bundle + " results " +
-                        (results == null ? results : results.size()));
+                if (DEBUG) {
+                    Log.v(TAG, "onPartialResults " + bundle + " results "
+                            + (results == null ? results : results.size()));
+                }
                 if (results == null || results.size() == 0) {
                     return;
                 }
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/ShadowOverlayContainer.java b/v17/leanback/src/android/support/v17/leanback/widget/ShadowOverlayContainer.java
index 3e9f320..156d42c 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/ShadowOverlayContainer.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/ShadowOverlayContainer.java
@@ -14,17 +14,16 @@
 package android.support.v17.leanback.widget;
 
 import android.content.Context;
-import android.support.annotation.ColorInt;
-import android.support.v17.leanback.R;
-import android.util.AttributeSet;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.FrameLayout;
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.Paint;
 import android.graphics.Rect;
+import android.support.annotation.ColorInt;
+import android.support.v17.leanback.R;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
 
 /**
  * Provides an SDK version-independent wrapper to support shadows, color overlays, and rounded
@@ -288,10 +287,10 @@
             ViewGroup.LayoutParams wrapped_lp = new FrameLayout.LayoutParams(lp.width, lp.height);
             // Uses MATCH_PARENT for MATCH_PARENT, WRAP_CONTENT for WRAP_CONTENT and fixed size,
             // App can still change wrapped view fixed width/height afterwards.
-            lp.width = lp.width == LayoutParams.MATCH_PARENT ?
-                    LayoutParams.MATCH_PARENT : LayoutParams.WRAP_CONTENT;
-            lp.height = lp.height == LayoutParams.MATCH_PARENT ?
-                    LayoutParams.MATCH_PARENT : LayoutParams.WRAP_CONTENT;
+            lp.width = lp.width == LayoutParams.MATCH_PARENT
+                    ? LayoutParams.MATCH_PARENT : LayoutParams.WRAP_CONTENT;
+            lp.height = lp.height == LayoutParams.MATCH_PARENT
+                    ? LayoutParams.MATCH_PARENT : LayoutParams.WRAP_CONTENT;
             this.setLayoutParams(lp);
             addView(view, wrapped_lp);
         } else {
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/SingleRow.java b/v17/leanback/src/android/support/v17/leanback/widget/SingleRow.java
index 52666ac..0300c6f 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/SingleRow.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/SingleRow.java
@@ -82,9 +82,9 @@
                 mLastVisibleIndex = mFirstVisibleIndex = index;
             } else {
                 if (mReversedFlow) {
-                    edge = mProvider.getEdge(index + 1) + mMargin + size;
+                    edge = mProvider.getEdge(index + 1) + mSpacing + size;
                 } else {
-                    edge = mProvider.getEdge(index + 1) - mMargin - size;
+                    edge = mProvider.getEdge(index + 1) - mSpacing - size;
                 }
                 mFirstVisibleIndex = index;
             }
@@ -115,9 +115,9 @@
                 mLastVisibleIndex = mFirstVisibleIndex = index;
             } else {
                 if (mReversedFlow) {
-                    edge = mProvider.getEdge(index - 1) - mProvider.getSize(index - 1) - mMargin;
+                    edge = mProvider.getEdge(index - 1) - mProvider.getSize(index - 1) - mSpacing;
                 } else {
-                    edge = mProvider.getEdge(index - 1) + mProvider.getSize(index - 1) + mMargin;
+                    edge = mProvider.getEdge(index - 1) + mProvider.getSize(index - 1) + mSpacing;
                 }
                 mLastVisibleIndex = index;
             }
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/SpeechOrbView.java b/v17/leanback/src/android/support/v17/leanback/widget/SpeechOrbView.java
index 67946d5..90df896 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/SpeechOrbView.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/SpeechOrbView.java
@@ -11,8 +11,8 @@
  */
 public class SpeechOrbView extends SearchOrbView {
     private final float mSoundLevelMaxZoom;
-    private final Colors mListeningOrbColors;
-    private final Colors mNotListeningOrbColors;
+    private Colors mListeningOrbColors;
+    private Colors mNotListeningOrbColors;
 
     private int mCurrentLevel = 0;
     private boolean mListening = false;
@@ -48,6 +48,24 @@
     }
 
     /**
+     * Sets default listening state orb color.
+     *
+     * @param colors SearchOrbView.Colors.
+     */
+    public void setListeningOrbColors(Colors colors) {
+        mListeningOrbColors = colors;
+    }
+
+    /**
+     * Sets default not-listening state orb color.
+     *
+     * @param colors SearchOrbView.Colors.
+     */
+    public void setNotListeningOrbColors(Colors colors) {
+        mNotListeningOrbColors = colors;
+    }
+
+    /**
      * Sets the view to display listening state.
      */
     public void showListening() {
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/StaggeredGrid.java b/v17/leanback/src/android/support/v17/leanback/widget/StaggeredGrid.java
index 2fef48e..1d731db 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/StaggeredGrid.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/StaggeredGrid.java
@@ -218,9 +218,9 @@
         }
         // Assuming the cachedIndex is next to item on the same row, so the
         // sum of offset of [cachedIndex + 1, itemIndex] should be size of the
-        // cached item plus margin.
-        int offset = isReversedFlow() ?  -getLocation(cachedIndex).size - mMargin:
-                getLocation(cachedIndex).size + mMargin;
+        // cached item plus spacing.
+        int offset = isReversedFlow() ?  -getLocation(cachedIndex).size - mSpacing:
+                getLocation(cachedIndex).size + mSpacing;
         for (int i = cachedIndex + 1; i <= getLastIndex(); i++) {
             offset -= getLocation(i).offset;
         }
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/StaggeredGridDefault.java b/v17/leanback/src/android/support/v17/leanback/widget/StaggeredGridDefault.java
index 975c43c..f4c0141 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/StaggeredGridDefault.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/StaggeredGridDefault.java
@@ -289,13 +289,13 @@
                     if (rowIndex == 0) {
                         location = mReversedFlow ? getRowMin(mNumRows - 1) : getRowMax(mNumRows - 1);
                         if (location != Integer.MAX_VALUE && location != Integer.MIN_VALUE) {
-                            location = location + (mReversedFlow ? -mMargin : mMargin);
+                            location = location + (mReversedFlow ? -mSpacing : mSpacing);
                         }
                     } else {
                         location = mReversedFlow ? getRowMax(rowIndex - 1) : getRowMin(rowIndex - 1);
                     }
                 } else {
-                    location = location + (mReversedFlow ? -mMargin : mMargin);
+                    location = location + (mReversedFlow ? -mSpacing : mSpacing);
                 }
                 int size = appendVisibleItemToRow(itemIndex++, rowIndex, location);
                 filledOne = true;
@@ -307,7 +307,7 @@
                         if (itemIndex == count || (!oneColumnMode && checkAppendOverLimit(toLimit))) {
                             return filledOne;
                         }
-                        location = location + (mReversedFlow ? - size - mMargin : size + mMargin);
+                        location = location + (mReversedFlow ? - size - mSpacing : size + mSpacing);
                         size = appendVisibleItemToRow(itemIndex++, rowIndex, location);
                     }
                 } else {
@@ -390,13 +390,13 @@
                     if (rowIndex == mNumRows - 1) {
                         location = mReversedFlow ? getRowMax(0) : getRowMin(0);
                         if (location != Integer.MAX_VALUE && location != Integer.MIN_VALUE) {
-                            location = location + (mReversedFlow ? mMargin : -mMargin);
+                            location = location + (mReversedFlow ? mSpacing : -mSpacing);
                         }
                     } else {
                         location = mReversedFlow ? getRowMin(rowIndex + 1) : getRowMax(rowIndex + 1);
                     }
                 } else {
-                    location = location + (mReversedFlow ? mMargin : -mMargin);
+                    location = location + (mReversedFlow ? mSpacing : -mSpacing);
                 }
                 int size = prependVisibleItemToRow(itemIndex--, rowIndex, location);
                 filledOne = true;
@@ -409,7 +409,7 @@
                         if (itemIndex < 0 || (!oneColumnMode && checkPrependOverLimit(toLimit))) {
                             return filledOne;
                         }
-                        location = location + (mReversedFlow ? size + mMargin : -size - mMargin);
+                        location = location + (mReversedFlow ? size + mSpacing : -size - mSpacing);
                         size = prependVisibleItemToRow(itemIndex--, rowIndex, location);
                     }
                 } else {
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/TitleHelper.java b/v17/leanback/src/android/support/v17/leanback/widget/TitleHelper.java
index c687e07..f12d8d0 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/TitleHelper.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/TitleHelper.java
@@ -45,8 +45,8 @@
             if (focused != mTitleView && direction == View.FOCUS_UP) {
                 return mTitleView;
             }
-            final boolean isRtl = ViewCompat.getLayoutDirection(focused) ==
-                    View.LAYOUT_DIRECTION_RTL;
+            final boolean isRtl = ViewCompat.getLayoutDirection(focused)
+                    == View.LAYOUT_DIRECTION_RTL;
             final int forward = isRtl ? View.FOCUS_LEFT : View.FOCUS_RIGHT;
             if (mTitleView.hasFocus() && (direction == View.FOCUS_DOWN || direction == forward)) {
                 return mSceneRoot;
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/WindowAlignment.java b/v17/leanback/src/android/support/v17/leanback/widget/WindowAlignment.java
index 0e8ce24..9a7d424 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/WindowAlignment.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/WindowAlignment.java
@@ -14,15 +14,12 @@
 
 package android.support.v17.leanback.widget;
 
-import static android.support.v17.leanback.widget.BaseGridView.WINDOW_ALIGN_LOW_EDGE;
-import static android.support.v17.leanback.widget.BaseGridView.WINDOW_ALIGN_HIGH_EDGE;
 import static android.support.v17.leanback.widget.BaseGridView.WINDOW_ALIGN_BOTH_EDGE;
+import static android.support.v17.leanback.widget.BaseGridView.WINDOW_ALIGN_HIGH_EDGE;
+import static android.support.v17.leanback.widget.BaseGridView.WINDOW_ALIGN_LOW_EDGE;
 import static android.support.v17.leanback.widget.BaseGridView.WINDOW_ALIGN_OFFSET_PERCENT_DISABLED;
-
 import static android.support.v7.widget.RecyclerView.HORIZONTAL;
 
-import android.view.View;
-
 /**
  * Maintains Window Alignment information of two axis.
  */
@@ -227,8 +224,8 @@
             int afterMiddlePosition = clientSize - middlePosition;
             boolean isMinUnknown = isMinUnknown();
             boolean isMaxUnknown = isMaxUnknown();
-            if (!isMinUnknown && !isMaxUnknown &&
-                    (mWindowAlignment & WINDOW_ALIGN_BOTH_EDGE) == WINDOW_ALIGN_BOTH_EDGE) {
+            if (!isMinUnknown && !isMaxUnknown
+                    && (mWindowAlignment & WINDOW_ALIGN_BOTH_EDGE) == WINDOW_ALIGN_BOTH_EDGE) {
                 if (mMaxEdge - mMinEdge <= clientSize) {
                     // total children size is less than view port and we want to align
                     // both edge:  align first child to start edge of view port
@@ -264,8 +261,7 @@
 
         @Override
         public String toString() {
-            return "center: " + mScrollCenter + " min:" + mMinEdge +
-                    " max:" + mMaxEdge;
+            return "center: " + mScrollCenter + " min:" + mMinEdge + " max:" + mMaxEdge;
         }
 
     }
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/picker/Picker.java b/v17/leanback/src/android/support/v17/leanback/widget/picker/Picker.java
index ca539a8..55ec6de 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/picker/Picker.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/picker/Picker.java
@@ -479,8 +479,9 @@
 
     private void updateColumnSize(VerticalGridView columnView) {
         ViewGroup.LayoutParams lp = columnView.getLayoutParams();
-        lp.height = (int) (getPickerItemHeightPixels() * (isActivated() ?
-                getActivatedVisibleItemCount() : getVisibleItemCount()));
+        float itemCount = isActivated() ? getActivatedVisibleItemCount() : getVisibleItemCount();
+        lp.height = (int) (getPickerItemHeightPixels() * itemCount
+                + columnView.getVerticalSpacing() * (itemCount - 1));
         columnView.setLayoutParams(lp);
     }
 
diff --git a/v17/leanback/tests/Android.mk b/v17/leanback/tests/Android.mk
index db64d88..6c1a709 100644
--- a/v17/leanback/tests/Android.mk
+++ b/v17/leanback/tests/Android.mk
@@ -36,7 +36,7 @@
         android-support-v7-recyclerview \
         android-support-v17-leanback \
         android-support-test \
-        mockito-target
+        mockito-target-minus-junit4
 
 LOCAL_PACKAGE_NAME := AndroidLeanbackTests
 
diff --git a/v17/leanback/tests/AndroidManifest.xml b/v17/leanback/tests/AndroidManifest.xml
index 5c421e3..2c6912e 100644
--- a/v17/leanback/tests/AndroidManifest.xml
+++ b/v17/leanback/tests/AndroidManifest.xml
@@ -42,10 +42,35 @@
                   android:theme="@style/Theme.Leanback.Browse"
                   android:exported="true" />
 
+        <activity android:name="android.support.v17.leanback.app.DetailsFragmentTestActivity"
+                  android:theme="@style/Theme.Leanback"
+                  android:exported="true" />
+
         <activity android:name="android.support.v17.leanback.app.BrowseSupportFragmentTestActivity"
                   android:theme="@style/Theme.Leanback.Browse"
                   android:exported="true" />
 
+        <activity android:name="android.support.v17.leanback.app.GuidedStepFragmentTestActivity"
+                  android:theme="@style/Theme.Leanback.GuidedStep"
+                  android:exported="true" />
+
+        <activity android:name="android.support.v17.leanback.app.GuidedStepSupportFragmentTestActivity"
+                  android:theme="@style/Theme.Leanback.GuidedStep"
+                  android:exported="true" />
+
+        <activity android:name="android.support.v17.leanback.app.PlaybackOverlayTestActivity"
+                  android:theme="@style/Theme.Leanback"
+                  android:exported="true" />
+        <activity
+            android:name="android.support.v17.leanback.app.VerticalGridFragmentTest$ImmediateRemoveFragmentActivity"
+            android:exported="true"
+            android:theme="@style/Theme.Leanback.VerticalGrid" />
+
+        <activity
+            android:name="android.support.v17.leanback.app.VerticalGridSupportFragmentTest$ImmediateRemoveFragmentActivity"
+            android:exported="true"
+            android:theme="@style/Theme.Leanback.VerticalGrid" />
+
     </application>
 
 </manifest>
diff --git a/v17/leanback/tests/generatev4.py b/v17/leanback/tests/generatev4.py
index 6d72c8b..da0ea53 100755
--- a/v17/leanback/tests/generatev4.py
+++ b/v17/leanback/tests/generatev4.py
@@ -19,10 +19,11 @@
 
 print "Generate v4 fragment related code for leanback"
 
-files = ['BrowseTest']
+files = ['BrowseTest', 'GuidedStepTest']
 
 cls = ['BrowseTest', 'Background', 'Base', 'BaseRow', 'Browse', 'Details', 'Error', 'Headers',
-      'PlaybackOverlay', 'Rows', 'Search', 'VerticalGrid', 'Branded']
+      'PlaybackOverlay', 'Rows', 'Search', 'VerticalGrid', 'Branded',
+      'GuidedStepTest', 'GuidedStep']
 
 for w in files:
     print "copy {}Fragment to {}SupportFragment".format(w, w)
@@ -37,11 +38,35 @@
             line = line.replace('{}Fragment'.format(w), '{}SupportFragment'.format(w))
         line = line.replace('android.app.Fragment', 'android.support.v4.app.Fragment')
         line = line.replace('android.app.Activity', 'android.support.v4.app.FragmentActivity')
+        line = line.replace('Activity getActivity()', 'FragmentActivity getActivity()')
         outfile.write(line)
     file.close()
     outfile.close()
 
-testcls = ['Browse']
+testcls = ['GuidedStep']
+
+for w in testcls:
+    print "copy {}FrgamentTestBase to {}SupportFragmentTestBase".format(w, w)
+
+    file = open('java/android/support/v17/leanback/app/{}FragmentTestBase.java'.format(w), 'r')
+    outfile = open('java/android/support/v17/leanback/app/{}SupportFragmentTestBase.java'.format(w), 'w')
+
+    outfile.write("/* This file is auto-generated from {}FrgamentTestBase.java.  DO NOT MODIFY. */\n\n".format(w))
+
+    for line in file:
+        for w in cls:
+            line = line.replace('{}Fragment'.format(w), '{}SupportFragment'.format(w))
+        for w in testcls:
+            line = line.replace('{}FragmentTestBase'.format(w), '{}SupportFragmentTestBase'.format(w))
+            line = line.replace('{}FragmentTestActivity'.format(w), '{}SupportFragmentTestActivity'.format(w))
+            line = line.replace('{}TestFragment'.format(w), '{}TestSupportFragment'.format(w))
+        line = line.replace('android.app.Fragment', 'android.support.v4.app.Fragment')
+        line = line.replace('android.app.Activity', 'android.support.v4.app.FragmentActivity')
+        outfile.write(line)
+    file.close()
+    outfile.close()
+
+testcls = ['Browse', 'GuidedStep', 'VerticalGrid']
 
 for w in testcls:
     print "copy {}FrgamentTest to {}SupportFragmentTest".format(w, w)
@@ -49,35 +74,79 @@
     file = open('java/android/support/v17/leanback/app/{}FragmentTest.java'.format(w), 'r')
     outfile = open('java/android/support/v17/leanback/app/{}SupportFragmentTest.java'.format(w), 'w')
 
-    outfile.write("/* This file is auto-generated from {}FrgamentTest.java.  DO NOT MODIFY. */\n\n".format(w))
+    outfile.write("/* This file is auto-generated from {}FragmentTest.java.  DO NOT MODIFY. */\n\n".format(w))
 
     for line in file:
         for w in cls:
             line = line.replace('{}Fragment'.format(w), '{}SupportFragment'.format(w))
         for w in testcls:
+            line = line.replace('{}FragmentTestBase'.format(w), '{}SupportFragmentTestBase'.format(w))
             line = line.replace('{}FragmentTest'.format(w), '{}SupportFragmentTest'.format(w))
             line = line.replace('{}FragmentTestActivity'.format(w), '{}SupportFragmentTestActivity'.format(w))
             line = line.replace('{}TestFragment'.format(w), '{}TestSupportFragment'.format(w))
+        line = line.replace('android.app.Fragment', 'android.support.v4.app.Fragment')
+        line = line.replace('android.app.Activity', 'android.support.v4.app.FragmentActivity')
+	line = line.replace('extends Activity', 'extends FragmentActivity')
+	line = line.replace('Activity.this.getFragmentManager', 'Activity.this.getSupportFragmentManager')
         outfile.write(line)
     file.close()
     outfile.close()
 
+testcls = ['Browse', 'GuidedStep']
 
-print "copy BrowseFragmentTestActivity to BrowseSupportFragmentTestActivity"
-file = open('java/android/support/v17/leanback/app/BrowseFragmentTestActivity.java', 'r')
-outfile = open('java/android/support/v17/leanback/app/BrowseSupportFragmentTestActivity.java', 'w')
-outfile.write("/* This file is auto-generated from BrowseFragmentTestActivity.java.  DO NOT MODIFY. */\n\n")
+for w in testcls:
+    print "copy {}FragmentTestActivity to {}SupportFragmentTestActivity".format(w, w)
+    file = open('java/android/support/v17/leanback/app/{}FragmentTestActivity.java'.format(w), 'r')
+    outfile = open('java/android/support/v17/leanback/app/{}SupportFragmentTestActivity.java'.format(w), 'w')
+    outfile.write("/* This file is auto-generated from {}FragmentTestActivity.java.  DO NOT MODIFY. */\n\n".format(w))
+    for line in file:
+        line = line.replace('{}TestFragment'.format(w), '{}TestSupportFragment'.format(w))
+        line = line.replace('{}FragmentTestActivity'.format(w), '{}SupportFragmentTestActivity'.format(w))
+        line = line.replace('android.app.Fragment', 'android.support.v4.app.Fragment')
+        line = line.replace('android.app.Activity', 'android.support.v4.app.FragmentActivity')
+        line = line.replace('extends Activity', 'extends FragmentActivity')
+        line = line.replace('getFragmentManager', 'getSupportFragmentManager')
+        outfile.write(line)
+    file.close()
+    outfile.close()
+
+print "copy ParallaxIntEffectTest to ParallaxFloatEffectTest"
+file = open('java/android/support/v17/leanback/widget/ParallaxIntEffectTest.java', 'r')
+outfile = open('java/android/support/v17/leanback/widget/ParallaxFloatEffectTest.java', 'w')
+outfile.write("/* This file is auto-generated from ParallaxIntEffectTest.java.  DO NOT MODIFY. */\n\n")
 for line in file:
-    line = line.replace('BrowseTestFragment', 'BrowseTestSupportFragment')
-    line = line.replace('BrowseFragmentTestActivity', 'BrowseSupportFragmentTestActivity')
-    line = line.replace('android.app.Fragment', 'android.support.v4.app.Fragment')
-    line = line.replace('android.app.Activity', 'android.support.v4.app.FragmentActivity')
-    line = line.replace('extends Activity', 'extends FragmentActivity')
-    line = line.replace('getFragmentManager', 'getSupportFragmentManager')
+    line = line.replace('IntEffect', 'FloatEffect')
+    line = line.replace('IntSource', 'FloatSource')
+    line = line.replace('IntProperty', 'FloatProperty')
+    line = line.replace('IntValue', 'FloatValue')
+    line = line.replace('intValue()', 'floatValue()')
+    line = line.replace('int getMaxParentVisibleSize', 'float getMaxParentVisibleSize')
+    line = line.replace('int screenMax', 'float screenMax')
+    line = line.replace('assertEquals((int)', 'assertFloatEquals((float)')
+    line = line.replace('(int)', '(float)')
     outfile.write(line)
 file.close()
 outfile.close()
 
+
+print "copy ParallaxIntSourceTest to ParallaxFloatSourceTest"
+file = open('java/android/support/v17/leanback/widget/ParallaxIntSourceTest.java', 'r')
+outfile = open('java/android/support/v17/leanback/widget/ParallaxFloatSourceTest.java', 'w')
+outfile.write("/* This file is auto-generated from ParallaxIntSourceTest.java.  DO NOT MODIFY. */\n\n")
+for line in file:
+    line = line.replace('IntSource', 'FloatSource')
+    line = line.replace('IntProperty', 'FloatProperty')
+    line = line.replace('IntValue', 'FloatValue')
+    line = line.replace('intValue()', 'floatValue()')
+    line = line.replace('int getMaxParentVisibleSize', 'float getMaxParentVisibleSize')
+    line = line.replace('int screenMax', 'float screenMax')
+    line = line.replace('assertEquals((int)', 'assertFloatEquals((float)')
+    line = line.replace('(int)', '(float)')
+    outfile.write(line)
+file.close()
+outfile.close()
+
+
 print "copy PlaybackControlGlueTest to PlaybackControlSupportGlueTest"
 file = open('java/android/support/v17/leanback/app/PlaybackControlGlueTest.java', 'r')
 outfile = open('java/android/support/v17/leanback/app/PlaybackControlSupportGlueTest.java', 'w')
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/app/BrowseFragmentTest.java b/v17/leanback/tests/java/android/support/v17/leanback/app/BrowseFragmentTest.java
index 4fd4168..dff8be6 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/app/BrowseFragmentTest.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/app/BrowseFragmentTest.java
@@ -15,31 +15,27 @@
  */
 package android.support.v17.leanback.app;
 
-import android.support.v17.leanback.test.R;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.view.KeyEvent;
-
-import android.support.v17.leanback.widget.Presenter;
-import android.support.v17.leanback.widget.ListRowPresenter;
-import android.content.Intent;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import android.support.test.InstrumentationRegistry;
-import android.support.test.runner.AndroidJUnit4;
-import android.support.test.rule.ActivityTestRule;
-import android.support.test.espresso.action.ViewActions;
-import org.mockito.Mockito;
-
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertNull;
 import static org.mockito.Matchers.any;
 import static org.mockito.Mockito.timeout;
 import static org.mockito.Mockito.verify;
 
+import android.content.Intent;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.v17.leanback.widget.ListRowPresenter;
+import android.support.v17.leanback.widget.Presenter;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.KeyEvent;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mockito;
+
 @MediumTest
 @RunWith(AndroidJUnit4.class)
 public class BrowseFragmentTest {
@@ -48,8 +44,8 @@
     static final long HORIZONTAL_SCROLL_WAIT = 2000;
 
     @Rule
-    public ActivityTestRule<BrowseFragmentTestActivity> activityTestRule
-            = new ActivityTestRule<>(BrowseFragmentTestActivity.class, false, false);
+    public ActivityTestRule<BrowseFragmentTestActivity> activityTestRule =
+            new ActivityTestRule<>(BrowseFragmentTestActivity.class, false, false);
     private BrowseFragmentTestActivity mActivity;
 
     @Test
@@ -62,6 +58,7 @@
 
         Thread.sleep(dataLoadingDelay + TRANSITION_LENGTH);
 
+        assertNotNull(mActivity.getBrowseTestFragment().getMainFragment());
         sendKeys(KeyEvent.KEYCODE_DPAD_RIGHT);
         Thread.sleep(TRANSITION_LENGTH);
         sendKeys(KeyEvent.KEYCODE_BACK, KeyEvent.KEYCODE_BACK);
@@ -77,6 +74,7 @@
 
         Thread.sleep(dataLoadingDelay + TRANSITION_LENGTH);
 
+        assertNotNull(mActivity.getBrowseTestFragment().getMainFragment());
         sendKeys(KeyEvent.KEYCODE_DPAD_RIGHT);
         Thread.sleep(TRANSITION_LENGTH);
         sendKeys(KeyEvent.KEYCODE_BACK, KeyEvent.KEYCODE_BACK);
@@ -90,6 +88,7 @@
         intent.putExtra(BrowseFragmentTestActivity.EXTRA_ADD_TO_BACKSTACK , false);
         mActivity = activityTestRule.launchActivity(intent);
 
+        assertNull(mActivity.getBrowseTestFragment().getMainFragment());
         sendKeys(KeyEvent.KEYCODE_DPAD_RIGHT);
     }
 
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/app/BrowseFragmentTestActivity.java b/v17/leanback/tests/java/android/support/v17/leanback/app/BrowseFragmentTestActivity.java
index 5e52a22..e01a168 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/app/BrowseFragmentTestActivity.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/app/BrowseFragmentTestActivity.java
@@ -36,25 +36,19 @@
         super.onCreate(savedInstanceState);
         Intent intent = getIntent();
 
-        BrowseTestFragment.NUM_ROWS = intent.getIntExtra(EXTRA_NUM_ROWS,
-                BrowseTestFragment.DEFAULT_NUM_ROWS);
-        BrowseTestFragment.REPEAT_PER_ROW = intent.getIntExtra(EXTRA_REPEAT_PER_ROW,
-                BrowseTestFragment.DEFAULT_REPEAT_PER_ROW);
-        BrowseTestFragment.LOAD_DATA_DELAY = intent.getLongExtra(EXTRA_LOAD_DATA_DELAY,
-                BrowseTestFragment.DEFAULT_LOAD_DATA_DELAY);
-        BrowseTestFragment.TEST_ENTRANCE_TRANSITION = intent.getBooleanExtra(
-                EXTRA_TEST_ENTRANCE_TRANSITION,
-                BrowseTestFragment.DEFAULT_TEST_ENTRANCE_TRANSITION);
-        BrowseTestFragment.SET_ADAPTER_AFTER_DATA_LOAD = intent.getBooleanExtra(
-                EXTRA_SET_ADAPTER_AFTER_DATA_LOAD,
-                BrowseTestFragment.DEFAULT_SET_ADAPTER_AFTER_DATA_LOAD);
         setContentView(R.layout.browse);
-        FragmentTransaction ft = getFragmentManager().beginTransaction();
-        ft.replace(R.id.main_frame, new BrowseTestFragment());
-        if (intent.getBooleanExtra(EXTRA_ADD_TO_BACKSTACK, false)) {
-            ft.addToBackStack(null);
+        if (savedInstanceState == null) {
+            Bundle arguments = new Bundle();
+            arguments.putAll(intent.getExtras());
+            BrowseTestFragment fragment = new BrowseTestFragment();
+            fragment.setArguments(arguments);
+            FragmentTransaction ft = getFragmentManager().beginTransaction();
+            ft.replace(R.id.main_frame, fragment);
+            if (intent.getBooleanExtra(EXTRA_ADD_TO_BACKSTACK, false)) {
+                ft.addToBackStack(null);
+            }
+            ft.commit();
         }
-        ft.commit();
     }
 
     public BrowseTestFragment getBrowseTestFragment() {
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/app/BrowseSupportFragmentTest.java b/v17/leanback/tests/java/android/support/v17/leanback/app/BrowseSupportFragmentTest.java
index abb2dc9..a03110e 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/app/BrowseSupportFragmentTest.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/app/BrowseSupportFragmentTest.java
@@ -1,4 +1,4 @@
-/* This file is auto-generated from BrowseFrgamentTest.java.  DO NOT MODIFY. */
+/* This file is auto-generated from BrowseFragmentTest.java.  DO NOT MODIFY. */
 
 /*
  * Copyright (C) 2015 The Android Open Source Project
@@ -17,31 +17,27 @@
  */
 package android.support.v17.leanback.app;
 
-import android.support.v17.leanback.test.R;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.view.KeyEvent;
-
-import android.support.v17.leanback.widget.Presenter;
-import android.support.v17.leanback.widget.ListRowPresenter;
-import android.content.Intent;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import android.support.test.InstrumentationRegistry;
-import android.support.test.runner.AndroidJUnit4;
-import android.support.test.rule.ActivityTestRule;
-import android.support.test.espresso.action.ViewActions;
-import org.mockito.Mockito;
-
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertNull;
 import static org.mockito.Matchers.any;
 import static org.mockito.Mockito.timeout;
 import static org.mockito.Mockito.verify;
 
+import android.content.Intent;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.v17.leanback.widget.ListRowPresenter;
+import android.support.v17.leanback.widget.Presenter;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.KeyEvent;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mockito;
+
 @MediumTest
 @RunWith(AndroidJUnit4.class)
 public class BrowseSupportFragmentTest {
@@ -50,8 +46,8 @@
     static final long HORIZONTAL_SCROLL_WAIT = 2000;
 
     @Rule
-    public ActivityTestRule<BrowseSupportFragmentTestActivity> activityTestRule
-            = new ActivityTestRule<>(BrowseSupportFragmentTestActivity.class, false, false);
+    public ActivityTestRule<BrowseSupportFragmentTestActivity> activityTestRule =
+            new ActivityTestRule<>(BrowseSupportFragmentTestActivity.class, false, false);
     private BrowseSupportFragmentTestActivity mActivity;
 
     @Test
@@ -64,6 +60,7 @@
 
         Thread.sleep(dataLoadingDelay + TRANSITION_LENGTH);
 
+        assertNotNull(mActivity.getBrowseTestSupportFragment().getMainFragment());
         sendKeys(KeyEvent.KEYCODE_DPAD_RIGHT);
         Thread.sleep(TRANSITION_LENGTH);
         sendKeys(KeyEvent.KEYCODE_BACK, KeyEvent.KEYCODE_BACK);
@@ -79,6 +76,7 @@
 
         Thread.sleep(dataLoadingDelay + TRANSITION_LENGTH);
 
+        assertNotNull(mActivity.getBrowseTestSupportFragment().getMainFragment());
         sendKeys(KeyEvent.KEYCODE_DPAD_RIGHT);
         Thread.sleep(TRANSITION_LENGTH);
         sendKeys(KeyEvent.KEYCODE_BACK, KeyEvent.KEYCODE_BACK);
@@ -92,6 +90,7 @@
         intent.putExtra(BrowseSupportFragmentTestActivity.EXTRA_ADD_TO_BACKSTACK , false);
         mActivity = activityTestRule.launchActivity(intent);
 
+        assertNull(mActivity.getBrowseTestSupportFragment().getMainFragment());
         sendKeys(KeyEvent.KEYCODE_DPAD_RIGHT);
     }
 
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/app/BrowseSupportFragmentTestActivity.java b/v17/leanback/tests/java/android/support/v17/leanback/app/BrowseSupportFragmentTestActivity.java
index d92b58d..14f72bc 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/app/BrowseSupportFragmentTestActivity.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/app/BrowseSupportFragmentTestActivity.java
@@ -38,25 +38,19 @@
         super.onCreate(savedInstanceState);
         Intent intent = getIntent();
 
-        BrowseTestSupportFragment.NUM_ROWS = intent.getIntExtra(EXTRA_NUM_ROWS,
-                BrowseTestSupportFragment.DEFAULT_NUM_ROWS);
-        BrowseTestSupportFragment.REPEAT_PER_ROW = intent.getIntExtra(EXTRA_REPEAT_PER_ROW,
-                BrowseTestSupportFragment.DEFAULT_REPEAT_PER_ROW);
-        BrowseTestSupportFragment.LOAD_DATA_DELAY = intent.getLongExtra(EXTRA_LOAD_DATA_DELAY,
-                BrowseTestSupportFragment.DEFAULT_LOAD_DATA_DELAY);
-        BrowseTestSupportFragment.TEST_ENTRANCE_TRANSITION = intent.getBooleanExtra(
-                EXTRA_TEST_ENTRANCE_TRANSITION,
-                BrowseTestSupportFragment.DEFAULT_TEST_ENTRANCE_TRANSITION);
-        BrowseTestSupportFragment.SET_ADAPTER_AFTER_DATA_LOAD = intent.getBooleanExtra(
-                EXTRA_SET_ADAPTER_AFTER_DATA_LOAD,
-                BrowseTestSupportFragment.DEFAULT_SET_ADAPTER_AFTER_DATA_LOAD);
         setContentView(R.layout.browse);
-        FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
-        ft.replace(R.id.main_frame, new BrowseTestSupportFragment());
-        if (intent.getBooleanExtra(EXTRA_ADD_TO_BACKSTACK, false)) {
-            ft.addToBackStack(null);
+        if (savedInstanceState == null) {
+            Bundle arguments = new Bundle();
+            arguments.putAll(intent.getExtras());
+            BrowseTestSupportFragment fragment = new BrowseTestSupportFragment();
+            fragment.setArguments(arguments);
+            FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
+            ft.replace(R.id.main_frame, fragment);
+            if (intent.getBooleanExtra(EXTRA_ADD_TO_BACKSTACK, false)) {
+                ft.addToBackStack(null);
+            }
+            ft.commit();
         }
-        ft.commit();
     }
 
     public BrowseTestSupportFragment getBrowseTestSupportFragment() {
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/app/BrowseTestFragment.java b/v17/leanback/tests/java/android/support/v17/leanback/app/BrowseTestFragment.java
index 62fa32e..c2a9ca0 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/app/BrowseTestFragment.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/app/BrowseTestFragment.java
@@ -13,6 +13,12 @@
  */
 package android.support.v17.leanback.app;
 
+import static android.support.v17.leanback.app.BrowseFragmentTestActivity.EXTRA_LOAD_DATA_DELAY;
+import static android.support.v17.leanback.app.BrowseFragmentTestActivity.EXTRA_NUM_ROWS;
+import static android.support.v17.leanback.app.BrowseFragmentTestActivity.EXTRA_REPEAT_PER_ROW;
+import static android.support.v17.leanback.app.BrowseFragmentTestActivity.EXTRA_SET_ADAPTER_AFTER_DATA_LOAD;
+import static android.support.v17.leanback.app.BrowseFragmentTestActivity.EXTRA_TEST_ENTRANCE_TRANSITION;
+
 import android.os.Bundle;
 import android.os.Handler;
 import android.support.v17.leanback.widget.ArrayObjectAdapter;
@@ -37,23 +43,33 @@
     final static boolean DEFAULT_TEST_ENTRANCE_TRANSITION = true;
     final static boolean DEFAULT_SET_ADAPTER_AFTER_DATA_LOAD = false;
 
-    static int NUM_ROWS = DEFAULT_NUM_ROWS;
-    static int REPEAT_PER_ROW = DEFAULT_REPEAT_PER_ROW;
-    static long LOAD_DATA_DELAY = DEFAULT_LOAD_DATA_DELAY;
-    static boolean TEST_ENTRANCE_TRANSITION = DEFAULT_TEST_ENTRANCE_TRANSITION;
-    static boolean SET_ADAPTER_AFTER_DATA_LOAD = DEFAULT_SET_ADAPTER_AFTER_DATA_LOAD;
-
     private ArrayObjectAdapter mRowsAdapter;
 
     // For good performance, it's important to use a single instance of
     // a card presenter for all rows using that presenter.
     final static StringPresenter sCardPresenter = new StringPresenter();
 
+    int NUM_ROWS;
+    int REPEAT_PER_ROW;
+
     @Override
     public void onCreate(Bundle savedInstanceState) {
         Log.i(TAG, "onCreate");
         super.onCreate(savedInstanceState);
 
+        Bundle arguments = getArguments();
+        NUM_ROWS = arguments.getInt(EXTRA_NUM_ROWS, BrowseTestFragment.DEFAULT_NUM_ROWS);
+        REPEAT_PER_ROW = arguments.getInt(EXTRA_REPEAT_PER_ROW,
+                DEFAULT_REPEAT_PER_ROW);
+        long LOAD_DATA_DELAY = arguments.getLong(EXTRA_LOAD_DATA_DELAY,
+                DEFAULT_LOAD_DATA_DELAY);
+        boolean TEST_ENTRANCE_TRANSITION = arguments.getBoolean(
+                EXTRA_TEST_ENTRANCE_TRANSITION,
+                DEFAULT_TEST_ENTRANCE_TRANSITION);
+        final boolean SET_ADAPTER_AFTER_DATA_LOAD = arguments.getBoolean(
+                EXTRA_SET_ADAPTER_AFTER_DATA_LOAD,
+                DEFAULT_SET_ADAPTER_AFTER_DATA_LOAD);
+
         if (!SET_ADAPTER_AFTER_DATA_LOAD) {
             setupRows();
         }
@@ -86,6 +102,9 @@
         new Handler().postDelayed(new Runnable() {
             @Override
             public void run() {
+                if (getActivity() == null || getActivity().isDestroyed()) {
+                    return;
+                }
                 if (SET_ADAPTER_AFTER_DATA_LOAD) {
                     setupRows();
                 }
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/app/BrowseTestSupportFragment.java b/v17/leanback/tests/java/android/support/v17/leanback/app/BrowseTestSupportFragment.java
index 6031dfa..b83b56d 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/app/BrowseTestSupportFragment.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/app/BrowseTestSupportFragment.java
@@ -15,6 +15,12 @@
  */
 package android.support.v17.leanback.app;
 
+import static android.support.v17.leanback.app.BrowseSupportFragmentTestActivity.EXTRA_LOAD_DATA_DELAY;
+import static android.support.v17.leanback.app.BrowseSupportFragmentTestActivity.EXTRA_NUM_ROWS;
+import static android.support.v17.leanback.app.BrowseSupportFragmentTestActivity.EXTRA_REPEAT_PER_ROW;
+import static android.support.v17.leanback.app.BrowseSupportFragmentTestActivity.EXTRA_SET_ADAPTER_AFTER_DATA_LOAD;
+import static android.support.v17.leanback.app.BrowseSupportFragmentTestActivity.EXTRA_TEST_ENTRANCE_TRANSITION;
+
 import android.os.Bundle;
 import android.os.Handler;
 import android.support.v17.leanback.widget.ArrayObjectAdapter;
@@ -39,23 +45,33 @@
     final static boolean DEFAULT_TEST_ENTRANCE_TRANSITION = true;
     final static boolean DEFAULT_SET_ADAPTER_AFTER_DATA_LOAD = false;
 
-    static int NUM_ROWS = DEFAULT_NUM_ROWS;
-    static int REPEAT_PER_ROW = DEFAULT_REPEAT_PER_ROW;
-    static long LOAD_DATA_DELAY = DEFAULT_LOAD_DATA_DELAY;
-    static boolean TEST_ENTRANCE_TRANSITION = DEFAULT_TEST_ENTRANCE_TRANSITION;
-    static boolean SET_ADAPTER_AFTER_DATA_LOAD = DEFAULT_SET_ADAPTER_AFTER_DATA_LOAD;
-
     private ArrayObjectAdapter mRowsAdapter;
 
     // For good performance, it's important to use a single instance of
     // a card presenter for all rows using that presenter.
     final static StringPresenter sCardPresenter = new StringPresenter();
 
+    int NUM_ROWS;
+    int REPEAT_PER_ROW;
+
     @Override
     public void onCreate(Bundle savedInstanceState) {
         Log.i(TAG, "onCreate");
         super.onCreate(savedInstanceState);
 
+        Bundle arguments = getArguments();
+        NUM_ROWS = arguments.getInt(EXTRA_NUM_ROWS, BrowseTestSupportFragment.DEFAULT_NUM_ROWS);
+        REPEAT_PER_ROW = arguments.getInt(EXTRA_REPEAT_PER_ROW,
+                DEFAULT_REPEAT_PER_ROW);
+        long LOAD_DATA_DELAY = arguments.getLong(EXTRA_LOAD_DATA_DELAY,
+                DEFAULT_LOAD_DATA_DELAY);
+        boolean TEST_ENTRANCE_TRANSITION = arguments.getBoolean(
+                EXTRA_TEST_ENTRANCE_TRANSITION,
+                DEFAULT_TEST_ENTRANCE_TRANSITION);
+        final boolean SET_ADAPTER_AFTER_DATA_LOAD = arguments.getBoolean(
+                EXTRA_SET_ADAPTER_AFTER_DATA_LOAD,
+                DEFAULT_SET_ADAPTER_AFTER_DATA_LOAD);
+
         if (!SET_ADAPTER_AFTER_DATA_LOAD) {
             setupRows();
         }
@@ -88,6 +104,9 @@
         new Handler().postDelayed(new Runnable() {
             @Override
             public void run() {
+                if (getActivity() == null || getActivity().isDestroyed()) {
+                    return;
+                }
                 if (SET_ADAPTER_AFTER_DATA_LOAD) {
                     setupRows();
                 }
@@ -116,7 +135,7 @@
                 listRowAdapter.add("Hello world");
                 listRowAdapter.add("Android TV");
                 listRowAdapter.add("Leanback");
-                listRowAdapter.add("GuidedStepFragment");
+                listRowAdapter.add("GuidedStepSupportFragment");
             }
             HeaderItem header = new HeaderItem(i, "Row " + i);
             mRowsAdapter.add(new ListRow(header, listRowAdapter));
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/app/DetailsFragmentTest.java b/v17/leanback/tests/java/android/support/v17/leanback/app/DetailsFragmentTest.java
new file mode 100644
index 0000000..baeb77f
--- /dev/null
+++ b/v17/leanback/tests/java/android/support/v17/leanback/app/DetailsFragmentTest.java
@@ -0,0 +1,104 @@
+/*
+ * 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 android.support.v17.leanback.app;
+
+import static org.junit.Assert.assertEquals;
+
+import android.content.Intent;
+import android.graphics.Rect;
+import android.graphics.drawable.ColorDrawable;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.rule.ActivityTestRule;
+import android.support.v17.leanback.R;
+import android.support.v17.leanback.graphics.CompositeDrawable;
+import android.support.v17.leanback.graphics.FitWidthBitmapDrawable;
+import android.support.v17.leanback.testutils.PollingCheck;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.View;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * Unit tests for {@link DetailsTestFragment}.
+ */
+@RunWith(JUnit4.class)
+@MediumTest
+public class DetailsFragmentTest {
+
+    @Rule
+    public ActivityTestRule<DetailsFragmentTestActivity> activityTestRule =
+            new ActivityTestRule<>(DetailsFragmentTestActivity.class, false, false);
+    private DetailsFragmentTestActivity mActivity;
+
+    @Test
+    public void parallaxTest() throws InterruptedException {
+        final int mDefaultVerticalOffset = -300;
+        Intent intent = new Intent();
+        intent.putExtra(DetailsTestFragment.VERTICAL_OFFSET, mDefaultVerticalOffset);
+        mActivity = activityTestRule.launchActivity(intent);
+
+        final DetailsTestFragment detailsFragment = mActivity.getDetailsFragment();
+        DetailsBackgroundParallaxHelper parallaxHelper = detailsFragment.getParallaxHelper();
+        final CompositeDrawable drawable = (CompositeDrawable) parallaxHelper.getDrawable();
+        final FitWidthBitmapDrawable bitmapDrawable = (FitWidthBitmapDrawable)
+                (drawable.getChildAt(0).getDrawable());
+
+        PollingCheck.waitFor(4000, new PollingCheck.PollingCheckCondition() {
+            @Override
+            public boolean canProceed() {
+                return mActivity.getDetailsFragment().getRowsFragment().getAdapter().size() > 1;
+            }
+        });
+
+        int windowHeight = mActivity.getWindow().getDecorView().getHeight();
+        int windowWidth = mActivity.getWindow().getDecorView().getWidth();
+
+        Rect bounds = drawable.getChildAt(0).getDrawable().getBounds();
+        assertEquals(windowWidth, bounds.width());
+        assertEquals(windowHeight / 2, bounds.height());
+        assertEquals(0, bitmapDrawable.getVerticalOffset());
+
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                detailsFragment.getRowsFragment().getVerticalGridView().scrollToPosition(1);
+            }
+        });
+
+        PollingCheck.waitFor(4000, new PollingCheck.PollingCheckCondition() {
+            @Override
+            public boolean canProceed() {
+                return bitmapDrawable.getVerticalOffset() == mDefaultVerticalOffset;
+            }
+        });
+
+        bounds = drawable.getChildAt(0).getDrawable().getBounds();
+        assertEquals(0, bounds.height());
+        assertEquals(windowWidth, bounds.width());
+
+        View detailsFrame = mActivity.findViewById(R.id.details_frame);
+        int [] loc = new int[2];
+        detailsFrame.getLocationOnScreen(loc);
+        ColorDrawable colorDrawable = (ColorDrawable) (drawable.getChildAt(1).getDrawable());
+
+        assertEquals(windowWidth, colorDrawable.getBounds().width());
+        assertEquals(windowHeight - (loc[1] + detailsFrame.getHeight()),
+                colorDrawable.getBounds().height());
+    }
+}
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/app/DetailsFragmentTestActivity.java b/v17/leanback/tests/java/android/support/v17/leanback/app/DetailsFragmentTestActivity.java
new file mode 100644
index 0000000..87050c1
--- /dev/null
+++ b/v17/leanback/tests/java/android/support/v17/leanback/app/DetailsFragmentTestActivity.java
@@ -0,0 +1,62 @@
+/*
+ * 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 android.support.v17.leanback.app;
+
+import android.app.Activity;
+import android.app.FragmentTransaction;
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.v17.leanback.test.R;
+
+/**
+ * Activity containing {@link DetailsFragmentTest} used for testing.
+ */
+public class DetailsFragmentTestActivity extends Activity {
+    private DetailsTestFragment mFragment;
+
+    /**
+     * Called when the activity is first created.
+     */
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.details);
+        mFragment = new DetailsTestFragment();
+
+        if (savedInstanceState == null) {
+            Intent intent = getIntent();
+            if (intent.getExtras() != null) {
+                Bundle arguments = new Bundle();
+                arguments.putAll(intent.getExtras());
+                mFragment.setArguments(arguments);
+            }
+            FragmentTransaction ft = getFragmentManager().beginTransaction();
+            ft.replace(R.id.fragment_root, mFragment);
+            ft.commit();
+        }
+    }
+
+    @Override
+    protected void onStart() {
+        super.onStart();
+        mFragment.setItem(new PhotoItem("Hello world", "Fake content goes here",
+                R.drawable.spiderman));
+    }
+
+    public DetailsTestFragment getDetailsFragment() {
+        return mFragment;
+    }
+}
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/app/DetailsParallaxManagerTest.java b/v17/leanback/tests/java/android/support/v17/leanback/app/DetailsParallaxManagerTest.java
new file mode 100644
index 0000000..1350b0b
--- /dev/null
+++ b/v17/leanback/tests/java/android/support/v17/leanback/app/DetailsParallaxManagerTest.java
@@ -0,0 +1,65 @@
+/*
+ * 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 android.support.v17.leanback.app;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import android.support.test.rule.ActivityTestRule;
+import android.support.v17.leanback.widget.ParallaxRecyclerViewSource;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * Unit tests for {@link DetailsParallaxManager}.
+ */
+@RunWith(JUnit4.class)
+@SmallTest
+public class DetailsParallaxManagerTest {
+
+    @Rule
+    public ActivityTestRule<DetailsFragmentTestActivity> activityTestRule =
+            new ActivityTestRule<>(DetailsFragmentTestActivity.class);
+    private DetailsFragmentTestActivity mActivity;
+
+    @Before
+    public void setUp() {
+        mActivity = activityTestRule.getActivity();
+    }
+
+    @Test
+    public void setupTest() {
+        double delta = 0.0002;
+        DetailsParallaxManager dpm = new DetailsParallaxManager(
+                mActivity.getDetailsFragment().getRowsFragment().getVerticalGridView());
+
+        assertNotNull(dpm.getParallax());
+
+        ParallaxRecyclerViewSource.ChildPositionProperty frameTop = dpm.getFrameTop();
+        assertEquals(0f, frameTop.getFraction(), delta);
+        assertEquals(0f, frameTop.getAdapterPosition(), delta);
+
+
+        ParallaxRecyclerViewSource.ChildPositionProperty frameBottom = dpm.getFrameBottom();
+        assertEquals(1f, frameBottom.getFraction(), delta);
+        assertEquals(0f, frameBottom.getAdapterPosition(), delta);
+    }
+}
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/app/DetailsTestFragment.java b/v17/leanback/tests/java/android/support/v17/leanback/app/DetailsTestFragment.java
new file mode 100644
index 0000000..0d8dede
--- /dev/null
+++ b/v17/leanback/tests/java/android/support/v17/leanback/app/DetailsTestFragment.java
@@ -0,0 +1,178 @@
+/*
+ * 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 android.support.v17.leanback.app;
+
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.os.Bundle;
+import android.os.Handler;
+import android.support.v17.leanback.test.R;
+import android.support.v17.leanback.widget.AbstractDetailsDescriptionPresenter;
+import android.support.v17.leanback.widget.Action;
+import android.support.v17.leanback.widget.ArrayObjectAdapter;
+import android.support.v17.leanback.widget.ClassPresenterSelector;
+import android.support.v17.leanback.widget.DetailsOverviewRow;
+import android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter;
+import android.support.v17.leanback.widget.FullWidthDetailsOverviewSharedElementHelper;
+import android.support.v17.leanback.widget.HeaderItem;
+import android.support.v17.leanback.widget.ImageCardView;
+import android.support.v17.leanback.widget.ListRow;
+import android.support.v17.leanback.widget.ListRowPresenter;
+import android.support.v17.leanback.widget.Presenter;
+import android.support.v17.leanback.widget.SparseArrayObjectAdapter;
+import android.view.ViewGroup;
+
+public class DetailsTestFragment extends android.support.v17.leanback.app.DetailsFragment {
+    private static final String ITEM = "item";
+    public static final String VERTICAL_OFFSET = "details_fragment";
+
+    private static final int NUM_ROWS = 3;
+    private ArrayObjectAdapter mRowsAdapter;
+    private PhotoItem mPhotoItem;
+    private final Presenter mCardPresenter = new Presenter() {
+        @Override
+        public ViewHolder onCreateViewHolder(ViewGroup parent) {
+            ImageCardView cardView = new ImageCardView(getActivity());
+            cardView.setFocusable(true);
+            cardView.setFocusableInTouchMode(true);
+            return new ViewHolder(cardView);
+        }
+
+        @Override
+        public void onBindViewHolder(ViewHolder viewHolder, Object item) {
+            ImageCardView imageCardView = (ImageCardView) viewHolder.view;
+            imageCardView.setTitleText("Android Tv");
+            imageCardView.setContentText("Android Tv Production Inc.");
+            imageCardView.setMainImageDimensions(313, 176);
+        }
+
+        @Override
+        public void onUnbindViewHolder(ViewHolder viewHolder) {
+        }
+    };
+
+    private static final int ACTION_PLAY = 1;
+    private static final int ACTION_RENT = 2;
+    private static final int ACTION_BUY = 3;
+
+    private static final long TIME_TO_LOAD_OVERVIEW_ROW_MS = 1000;
+    private static final long TIME_TO_LOAD_RELATED_ROWS_MS = 2000;
+
+    private Action mActionPlay;
+    private Action mActionRent;
+    private Action mActionBuy;
+
+    private FullWidthDetailsOverviewSharedElementHelper mHelper;
+    private DetailsBackgroundParallaxHelper mParallaxHelper;
+    private int mMinVerticalOffset;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setTitle("Leanback Sample App");
+
+        if (getArguments() != null) {
+            mMinVerticalOffset = getArguments().getInt(VERTICAL_OFFSET, -100);
+        }
+        mActionPlay = new Action(ACTION_PLAY, "Play");
+        mActionRent = new Action(ACTION_RENT, "Rent", "$3.99",
+                getResources().getDrawable(R.drawable.ic_action_a));
+        mActionBuy = new Action(ACTION_BUY, "Buy $9.99");
+
+        ClassPresenterSelector ps = new ClassPresenterSelector();
+        FullWidthDetailsOverviewRowPresenter dorPresenter =
+                new FullWidthDetailsOverviewRowPresenter(new AbstractDetailsDescriptionPresenter() {
+                    @Override
+                    protected void onBindDescription(
+                            AbstractDetailsDescriptionPresenter.ViewHolder vh, Object item) {
+                        vh.getTitle().setText("Funny Movie");
+                        vh.getSubtitle().setText("Android TV Production Inc.");
+                        vh.getBody().setText("What a great movie!");
+                    }
+                });
+
+        ps.addClassPresenter(DetailsOverviewRow.class, dorPresenter);
+        ps.addClassPresenter(ListRow.class, new ListRowPresenter());
+        mRowsAdapter = new ArrayObjectAdapter(ps);
+    }
+
+    @Override
+    public void onSaveInstanceState(Bundle outState) {
+        super.onSaveInstanceState(outState);
+        outState.putParcelable(ITEM, mPhotoItem);
+    }
+
+    public void setItem(PhotoItem photoItem) {
+        mPhotoItem = photoItem;
+        mRowsAdapter.clear();
+        new Handler().postDelayed(new Runnable() {
+            public void run() {
+                Resources res = getActivity().getResources();
+                DetailsOverviewRow dor = new DetailsOverviewRow(mPhotoItem.getTitle());
+                dor.setImageDrawable(res.getDrawable(mPhotoItem.getImageResourceId()));
+                SparseArrayObjectAdapter adapter = new SparseArrayObjectAdapter();
+                adapter.set(ACTION_RENT, mActionRent);
+                adapter.set(ACTION_BUY, mActionBuy);
+                dor.setActionsAdapter(adapter);
+                mRowsAdapter.add(0, dor);
+                setSelectedPosition(0, true);
+            }
+        }, TIME_TO_LOAD_OVERVIEW_ROW_MS);
+
+
+        new Handler().postDelayed(new Runnable() {
+            public void run() {
+                for (int i = 0; i < NUM_ROWS; ++i) {
+                    ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(mCardPresenter);
+                    listRowAdapter.add(new PhotoItem("Hello world", R.drawable.spiderman));
+                    listRowAdapter.add(new PhotoItem("This is a test", R.drawable.spiderman));
+                    listRowAdapter.add(new PhotoItem("Android TV", R.drawable.spiderman));
+                    listRowAdapter.add(new PhotoItem("Leanback", R.drawable.spiderman));
+                    HeaderItem header = new HeaderItem(i, "Row " + i);
+                    mRowsAdapter.add(new ListRow(header, listRowAdapter));
+                }
+            }
+        }, TIME_TO_LOAD_RELATED_ROWS_MS);
+
+        setAdapter(mRowsAdapter);
+    }
+
+    @Override
+    public void onStart() {
+        super.onStart();
+        mParallaxHelper = new DetailsBackgroundParallaxHelper.ParallaxBuilder(
+                getActivity(),
+                getParallaxManager())
+                .setBitmapMinVerticalOffset(mMinVerticalOffset)
+                .build();
+        BackgroundManager backgroundManager = BackgroundManager.getInstance(getActivity());
+        backgroundManager.attach(getActivity().getWindow());
+        backgroundManager.setDrawable(mParallaxHelper.getDrawable());
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+        Bitmap bitmap = BitmapFactory.decodeResource(getActivity().getResources(),
+                R.drawable.spiderman);
+        mParallaxHelper.setBitmap(bitmap);
+    }
+
+    DetailsBackgroundParallaxHelper getParallaxHelper() {
+        return mParallaxHelper;
+    }
+}
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/app/GuidedStepFragmentTest.java b/v17/leanback/tests/java/android/support/v17/leanback/app/GuidedStepFragmentTest.java
new file mode 100644
index 0000000..d105c5a
--- /dev/null
+++ b/v17/leanback/tests/java/android/support/v17/leanback/app/GuidedStepFragmentTest.java
@@ -0,0 +1,351 @@
+/*
+ * 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 android.support.v17.leanback.app;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.v17.leanback.testutils.PollingCheck;
+import android.view.ViewGroup;
+import android.view.View;
+import android.view.LayoutInflater;
+import android.view.KeyEvent;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+
+import android.support.v17.leanback.widget.GuidanceStylist.Guidance;
+import android.support.v17.leanback.widget.GuidedAction;
+
+import android.support.test.espresso.Espresso;
+import android.support.test.espresso.matcher.RootMatchers;
+import android.support.test.espresso.action.ViewActions;
+import android.support.test.InstrumentationRegistry;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.mockito.ArgumentCaptor;
+import org.mockito.stubbing.Answer;
+import org.mockito.invocation.InvocationOnMock;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.mockito.Mockito.*;
+import static org.junit.Assert.*;
+
+/**
+ * @hide from javadoc
+ */
+@RunWith(AndroidJUnit4.class)
+public class GuidedStepFragmentTest extends GuidedStepFragmentTestBase {
+
+    @Test
+    public void nextAndBack() throws Throwable {
+        GuidedStepTestFragment.Provider first = mockProvider("first");
+        doAnswer(new Answer<Void>() {
+            public Void answer(InvocationOnMock invocation) {
+                List actions = (List) invocation.getArguments()[0];
+                actions.add(new GuidedAction.Builder().id(1000).title("OK").build());
+                return null;
+            }
+        }).when(first).onCreateActions(any(List.class), any(Bundle.class));
+        doAnswer(new Answer<Void>() {
+            public Void answer(InvocationOnMock invocation) {
+                GuidedAction action = (GuidedAction) invocation.getArguments()[0];
+                GuidedStepTestFragment.Provider obj = (GuidedStepTestFragment.Provider)
+                        invocation.getMock();
+                if (action.getId() == 1000) {
+                    GuidedStepFragment.add(obj.getFragmentManager(),
+                            new GuidedStepTestFragment("second"));
+                }
+                return null;
+            }
+        }).when(first).onGuidedActionClicked(any(GuidedAction.class));
+
+        GuidedStepTestFragment.Provider second = mockProvider("second");
+
+        GuidedStepFragmentTestActivity activity = launchTestActivity("first");
+        verify(first, times(1)).onCreate(any(Bundle.class));
+        verify(first, times(1)).onCreateGuidance(any(Bundle.class));
+        verify(first, times(1)).onCreateActions(any(List.class), any(Bundle.class));
+        verify(first, times(1)).onCreateButtonActions(any(List.class), any(Bundle.class));
+        verify(first, times(1)).onCreateView(any(LayoutInflater.class), any(ViewGroup.class),
+                any(Bundle.class), any(View.class));
+        verify(first, times(1)).onViewStateRestored(any(Bundle.class));
+        verify(first, times(1)).onStart();
+        verify(first, times(1)).onResume();
+
+        sendKey(KeyEvent.KEYCODE_DPAD_CENTER);
+        verify(first, times(1)).onGuidedActionClicked(any(GuidedAction.class));
+
+        PollingCheck.waitFor(new EnterTransitionFinish(second));
+        verify(first, times(1)).onPause();
+        verify(first, times(1)).onStop();
+        verify(first, times(1)).onDestroyView();
+        verify(second, times(1)).onCreate(any(Bundle.class));
+        verify(second, times(1)).onCreateGuidance(any(Bundle.class));
+        verify(second, times(1)).onCreateActions(any(List.class), any(Bundle.class));
+        verify(second, times(1)).onCreateButtonActions(any(List.class), any(Bundle.class));
+        verify(second, times(1)).onCreateView(any(LayoutInflater.class), any(ViewGroup.class),
+                any(Bundle.class), any(View.class));
+        verify(second, times(1)).onViewStateRestored(any(Bundle.class));
+        verify(second, times(1)).onStart();
+        verify(second, times(1)).onResume();
+
+        sendKey(KeyEvent.KEYCODE_BACK);
+
+        PollingCheck.waitFor(new EnterTransitionFinish(first));
+        verify(second, times(1)).onPause();
+        verify(second, times(1)).onStop();
+        verify(second, times(1)).onDestroyView();
+        verify(second, times(1)).onDestroy();
+        verify(first, times(1)).onCreateActions(any(List.class), any(Bundle.class));
+        verify(first, times(2)).onCreateView(any(LayoutInflater.class), any(ViewGroup.class),
+                any(Bundle.class), any(View.class));
+        verify(first, times(2)).onViewStateRestored(any(Bundle.class));
+        verify(first, times(2)).onStart();
+        verify(first, times(2)).onResume();
+
+        sendKey(KeyEvent.KEYCODE_BACK);
+        PollingCheck.waitFor(new PollingCheck.ActivityDestroy(activity));
+        verify(first, times(1)).onDestroy();
+        assertTrue(activity.isDestroyed());
+    }
+
+    @Test
+    public void restoreFragments() throws Throwable {
+        GuidedStepTestFragment.Provider first = mockProvider("first");
+        doAnswer(new Answer<Void>() {
+            public Void answer(InvocationOnMock invocation) {
+                List actions = (List) invocation.getArguments()[0];
+                actions.add(new GuidedAction.Builder().id(1000).title("OK").build());
+                actions.add(new GuidedAction.Builder().id(1001).editable(true).title("text")
+                        .build());
+                actions.add(new GuidedAction.Builder().id(1002).editable(true).title("text")
+                        .autoSaveRestoreEnabled(false).build());
+                return null;
+            }
+        }).when(first).onCreateActions(any(List.class), any(Bundle.class));
+        doAnswer(new Answer<Void>() {
+            public Void answer(InvocationOnMock invocation) {
+                GuidedAction action = (GuidedAction) invocation.getArguments()[0];
+                GuidedStepTestFragment.Provider obj = (GuidedStepTestFragment.Provider)
+                        invocation.getMock();
+                if (action.getId() == 1000) {
+                    GuidedStepFragment.add(obj.getFragmentManager(),
+                            new GuidedStepTestFragment("second"));
+                }
+                return null;
+            }
+        }).when(first).onGuidedActionClicked(any(GuidedAction.class));
+
+        GuidedStepTestFragment.Provider second = mockProvider("second");
+
+        final GuidedStepFragmentTestActivity activity = launchTestActivity("first");
+        first.getFragment().findActionById(1001).setTitle("modified text");
+        first.getFragment().findActionById(1002).setTitle("modified text");
+        sendKey(KeyEvent.KEYCODE_DPAD_CENTER);
+        PollingCheck.waitFor(new EnterTransitionFinish(second));
+
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                activity.recreate();
+            }
+        });
+        PollingCheck.waitFor(new EnterTransitionFinish(second));
+        verify(first, times(2)).onCreate(any(Bundle.class));
+        verify(first, times(1)).onCreateView(any(LayoutInflater.class), any(ViewGroup.class),
+                any(Bundle.class), any(View.class));
+        verify(first, times(2)).onCreateActions(any(List.class), any(Bundle.class));
+        verify(first, times(1)).onDestroy();
+        verify(second, times(2)).onCreate(any(Bundle.class));
+        verify(second, times(2)).onCreateView(any(LayoutInflater.class), any(ViewGroup.class),
+                any(Bundle.class), any(View.class));
+        verify(second, times(1)).onDestroy();
+        assertEquals("modified text", first.getFragment().findActionById(1001).getTitle());
+        assertEquals("text", first.getFragment().findActionById(1002).getTitle());
+
+        sendKey(KeyEvent.KEYCODE_BACK);
+        PollingCheck.waitFor(new EnterTransitionFinish(first));
+        verify(second, times(2)).onPause();
+        verify(second, times(2)).onStop();
+        verify(second, times(2)).onDestroyView();
+        verify(second, times(2)).onDestroy();
+        verify(first, times(2)).onCreateView(any(LayoutInflater.class), any(ViewGroup.class),
+                any(Bundle.class), any(View.class));
+    }
+
+
+    @Test
+    public void finishGuidedStepFragment_finishes_activity() throws Throwable {
+        GuidedStepTestFragment.Provider first = mockProvider("first");
+        doAnswer(new Answer<Void>() {
+            public Void answer(InvocationOnMock invocation) {
+                List actions = (List) invocation.getArguments()[0];
+                actions.add(new GuidedAction.Builder().id(1001).title("Finish activity").build());
+                return null;
+            }
+        }).when(first).onCreateActions(any(List.class), any(Bundle.class));
+        doAnswer(new Answer<Void>() {
+            public Void answer(InvocationOnMock invocation) {
+                GuidedAction action = (GuidedAction) invocation.getArguments()[0];
+                GuidedStepTestFragment.Provider obj = (GuidedStepTestFragment.Provider)
+                        invocation.getMock();
+                if (action.getId() == 1001) {
+                    obj.getFragment().finishGuidedStepFragments();
+                }
+                return null;
+            }
+        }).when(first).onGuidedActionClicked(any(GuidedAction.class));
+
+        final GuidedStepFragmentTestActivity activity = launchTestActivity("first");
+
+        View viewFinish = first.getFragment().getActionItemView(0);
+        assertTrue(viewFinish.hasFocus());
+        sendKey(KeyEvent.KEYCODE_DPAD_CENTER);
+        PollingCheck.waitFor(new PollingCheck.ActivityDestroy(activity));
+        verify(first, times(1)).onDestroy();
+    }
+
+    @Test
+    public void finishGuidedStepFragment_finishes_fragments() throws Throwable {
+        GuidedStepTestFragment.Provider first = mockProvider("first");
+        doAnswer(new Answer<Void>() {
+            public Void answer(InvocationOnMock invocation) {
+                List actions = (List) invocation.getArguments()[0];
+                actions.add(new GuidedAction.Builder().id(1001).title("Finish fragments").build());
+                return null;
+            }
+        }).when(first).onCreateActions(any(List.class), any(Bundle.class));
+        doAnswer(new Answer<Void>() {
+            public Void answer(InvocationOnMock invocation) {
+                GuidedAction action = (GuidedAction) invocation.getArguments()[0];
+                GuidedStepTestFragment.Provider obj = (GuidedStepTestFragment.Provider)
+                        invocation.getMock();
+                if (action.getId() == 1001) {
+                    obj.getFragment().finishGuidedStepFragments();
+                }
+                return null;
+            }
+        }).when(first).onGuidedActionClicked(any(GuidedAction.class));
+
+        final GuidedStepFragmentTestActivity activity = launchTestActivity("first",
+                false /*asRoot*/);
+
+        View viewFinish = first.getFragment().getActionItemView(0);
+        assertTrue(viewFinish.hasFocus());
+        sendKey(KeyEvent.KEYCODE_DPAD_CENTER);
+
+        // fragment should be destroyed, activity should not destroyed
+        waitOnDestroy(first, 1);
+        assertFalse(activity.isDestroyed());
+    }
+
+    @Test
+    public void subActions() throws Throwable {
+        final boolean[] expandSubActionInOnCreateView = new boolean[] {false};
+        GuidedStepTestFragment.Provider first = mockProvider("first");
+        doAnswer(new Answer<Void>() {
+            public Void answer(InvocationOnMock invocation) {
+                GuidedStepTestFragment.Provider obj = (GuidedStepTestFragment.Provider)
+                        invocation.getMock();
+                if (expandSubActionInOnCreateView[0]) {
+                    obj.getFragment().expandAction(obj.getFragment().findActionById(1000), false);
+                }
+                return null;
+            }
+        }).when(first).onCreateView(any(LayoutInflater.class), any(ViewGroup.class),
+                any(Bundle.class), any(View.class));
+        doAnswer(new Answer<Void>() {
+            public Void answer(InvocationOnMock invocation) {
+                List actions = (List) invocation.getArguments()[0];
+                List<GuidedAction> subActions = new ArrayList<GuidedAction>();
+                subActions.add(new GuidedAction.Builder().id(2000).title("item1").build());
+                subActions.add(new GuidedAction.Builder().id(2001).title("item2").build());
+                actions.add(new GuidedAction.Builder().id(1000).subActions(subActions)
+                        .title("list").build());
+                return null;
+            }
+        }).when(first).onCreateActions(any(List.class), any(Bundle.class));
+        doAnswer(new Answer<Boolean>() {
+            public Boolean answer(InvocationOnMock invocation) {
+                GuidedStepTestFragment.Provider obj = (GuidedStepTestFragment.Provider)
+                        invocation.getMock();
+                GuidedAction action = (GuidedAction) invocation.getArguments()[0];
+                if (action.getId() == 2000) {
+                    return true;
+                } else if (action.getId() == 2001) {
+                    GuidedStepFragment.add(obj.getFragmentManager(),
+                            new GuidedStepTestFragment("second"));
+                    return false;
+                }
+                return false;
+            }
+        }).when(first).onSubGuidedActionClicked(any(GuidedAction.class));
+
+        GuidedStepTestFragment.Provider second = mockProvider("second");
+
+        final GuidedStepFragmentTestActivity activity = launchTestActivity("first");
+
+        // after clicked, it sub actions list should expand
+        View viewForList = first.getFragment().getActionItemView(0);
+        assertTrue(viewForList.hasFocus());
+        sendKey(KeyEvent.KEYCODE_DPAD_CENTER);
+        PollingCheck.waitFor(new ExpandTransitionFinish(first));
+        assertFalse(viewForList.hasFocus());
+
+        sendKey(KeyEvent.KEYCODE_DPAD_CENTER);
+        ArgumentCaptor<GuidedAction> actionCapture = ArgumentCaptor.forClass(GuidedAction.class);
+        verify(first, times(1)).onSubGuidedActionClicked(actionCapture.capture());
+        assertEquals(2000, actionCapture.getValue().getId());
+        // after clicked a sub action, it sub actions list should close
+        PollingCheck.waitFor(new ExpandTransitionFinish(first));
+        assertTrue(viewForList.hasFocus());
+
+        sendKey(KeyEvent.KEYCODE_DPAD_CENTER);
+        PollingCheck.waitFor(new ExpandTransitionFinish(first));
+
+        assertFalse(viewForList.hasFocus());
+        sendKey(KeyEvent.KEYCODE_DPAD_DOWN);
+        sendKey(KeyEvent.KEYCODE_DPAD_CENTER);
+        ArgumentCaptor<GuidedAction> actionCapture2 = ArgumentCaptor.forClass(GuidedAction.class);
+        verify(first, times(2)).onSubGuidedActionClicked(actionCapture2.capture());
+        assertEquals(2001, actionCapture2.getValue().getId());
+
+        PollingCheck.waitFor(new EnterTransitionFinish(second));
+        verify(second, times(1)).onCreateView(any(LayoutInflater.class), any(ViewGroup.class),
+                any(Bundle.class), any(View.class));
+
+        // test expand sub action when return to first fragment
+        expandSubActionInOnCreateView[0] = true;
+        sendKey(KeyEvent.KEYCODE_BACK);
+        PollingCheck.waitFor(new EnterTransitionFinish(first));
+        verify(first, times(2)).onCreateView(any(LayoutInflater.class), any(ViewGroup.class),
+                any(Bundle.class), any(View.class));
+        assertTrue(first.getFragment().isExpanded());
+
+        sendKey(KeyEvent.KEYCODE_BACK);
+        PollingCheck.waitFor(new ExpandTransitionFinish(first));
+        assertFalse(first.getFragment().isExpanded());
+
+        sendKey(KeyEvent.KEYCODE_BACK);
+        PollingCheck.waitFor(new PollingCheck.ActivityDestroy(activity));
+        verify(first, times(1)).onDestroy();
+    }
+}
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/app/GuidedStepFragmentTestActivity.java b/v17/leanback/tests/java/android/support/v17/leanback/app/GuidedStepFragmentTestActivity.java
new file mode 100644
index 0000000..06beab6
--- /dev/null
+++ b/v17/leanback/tests/java/android/support/v17/leanback/app/GuidedStepFragmentTestActivity.java
@@ -0,0 +1,54 @@
+/*
+ * 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 android.support.v17.leanback.app;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+
+/**
+ * @hide from javadoc
+ */
+public class GuidedStepFragmentTestActivity extends Activity {
+
+    /**
+     * Frst Test that will be included in this Activity
+     */
+    public static final String EXTRA_TEST_NAME = "testName";
+    /**
+     * True(default) to addAsRoot() for first Test, false to use add()
+     */
+    public static final String EXTRA_ADD_AS_ROOT = "addAsRoot";
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        Intent intent = getIntent();
+
+        if (savedInstanceState == null) {
+            String firstTestName = intent.getStringExtra(EXTRA_TEST_NAME);
+            if (firstTestName != null) {
+                GuidedStepTestFragment testFragment = new GuidedStepTestFragment(firstTestName);
+                if (intent.getBooleanExtra(EXTRA_ADD_AS_ROOT, true)) {
+                    GuidedStepTestFragment.addAsRoot(this, testFragment, android.R.id.content);
+                } else {
+                    GuidedStepTestFragment.add(getFragmentManager(), testFragment,
+                            android.R.id.content);
+                }
+            }
+        }
+    }
+}
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/app/GuidedStepFragmentTestBase.java b/v17/leanback/tests/java/android/support/v17/leanback/app/GuidedStepFragmentTestBase.java
new file mode 100644
index 0000000..2219f37
--- /dev/null
+++ b/v17/leanback/tests/java/android/support/v17/leanback/app/GuidedStepFragmentTestBase.java
@@ -0,0 +1,130 @@
+/*
+ * 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 android.support.v17.leanback.app;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Intent;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.rule.ActivityTestRule;
+import android.support.v17.leanback.R;
+import android.support.v17.leanback.testutils.PollingCheck;
+import android.view.View;
+
+import org.junit.Before;
+import org.junit.Rule;
+
+/**
+ * @hide from javadoc
+ */
+public class GuidedStepFragmentTestBase {
+
+    private static final long TIMEOUT = 5000;
+
+    @Rule
+    public ActivityTestRule<GuidedStepFragmentTestActivity> activityTestRule =
+            new ActivityTestRule<>(GuidedStepFragmentTestActivity.class, false, false);
+
+    @Before
+    public void clearTests() {
+        GuidedStepTestFragment.clearTests();
+    }
+
+    public static class ExpandTransitionFinish extends PollingCheck.PollingCheckCondition {
+        GuidedStepTestFragment.Provider mProvider;
+
+        public ExpandTransitionFinish(GuidedStepTestFragment.Provider provider) {
+            mProvider = provider;
+        }
+
+        @Override
+        public boolean canPreProceed() {
+            return false;
+        }
+
+        @Override
+        public boolean canProceed() {
+            GuidedStepTestFragment fragment = mProvider.getFragment();
+            if (fragment != null && fragment.getView() != null) {
+                if (!fragment.getGuidedActionsStylist().isInExpandTransition()) {
+                    // expand transition finishes
+                    return true;
+                }
+            }
+            return false;
+        }
+    }
+
+    public static void waitOnDestroy(GuidedStepTestFragment.Provider provider,
+            int times) {
+        verify(provider, timeout((int)TIMEOUT).times(times)).onDestroy();
+    }
+
+    public static class EnterTransitionFinish extends PollingCheck.PollingCheckCondition {
+        PollingCheck.ViewScreenPositionDetector mDector =
+                new PollingCheck.ViewScreenPositionDetector();
+
+        GuidedStepTestFragment.Provider mProvider;
+
+        public EnterTransitionFinish(GuidedStepTestFragment.Provider provider) {
+            mProvider = provider;
+        }
+        @Override
+        public boolean canProceed() {
+            GuidedStepTestFragment fragment = mProvider.getFragment();
+            if (fragment != null && fragment.getView() != null) {
+                View view = fragment.getView().findViewById(R.id.guidance_title);
+                if (view != null) {
+                    if (mDector.isViewStableOnScreen(view)) {
+                        return true;
+                    }
+                }
+            }
+            return false;
+        }
+    }
+
+    public static void sendKey(int keyCode) {
+        InstrumentationRegistry.getInstrumentation().sendKeyDownUpSync(keyCode);
+    }
+
+    public GuidedStepFragmentTestActivity launchTestActivity(String firstTestName) {
+        Intent intent = new Intent();
+        intent.putExtra(GuidedStepFragmentTestActivity.EXTRA_TEST_NAME, firstTestName);
+        return activityTestRule.launchActivity(intent);
+    }
+
+    public GuidedStepFragmentTestActivity launchTestActivity(String firstTestName,
+            boolean addAsRoot) {
+        Intent intent = new Intent();
+        intent.putExtra(GuidedStepFragmentTestActivity.EXTRA_TEST_NAME, firstTestName);
+        intent.putExtra(GuidedStepFragmentTestActivity.EXTRA_ADD_AS_ROOT, addAsRoot);
+        return activityTestRule.launchActivity(intent);
+    }
+
+    public static GuidedStepTestFragment.Provider mockProvider(String testName) {
+        GuidedStepTestFragment.Provider test = mock(GuidedStepTestFragment.Provider.class);
+        when(test.getActivity()).thenCallRealMethod();
+        when(test.getFragmentManager()).thenCallRealMethod();
+        when(test.getFragment()).thenCallRealMethod();
+        GuidedStepTestFragment.setupTest(testName, test);
+        return test;
+    }
+}
+
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/app/GuidedStepSupportFragmentTest.java b/v17/leanback/tests/java/android/support/v17/leanback/app/GuidedStepSupportFragmentTest.java
new file mode 100644
index 0000000..ef4dd65
--- /dev/null
+++ b/v17/leanback/tests/java/android/support/v17/leanback/app/GuidedStepSupportFragmentTest.java
@@ -0,0 +1,353 @@
+/* This file is auto-generated from GuidedStepFragmentTest.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 android.support.v17.leanback.app;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.v17.leanback.testutils.PollingCheck;
+import android.view.ViewGroup;
+import android.view.View;
+import android.view.LayoutInflater;
+import android.view.KeyEvent;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+
+import android.support.v17.leanback.widget.GuidanceStylist.Guidance;
+import android.support.v17.leanback.widget.GuidedAction;
+
+import android.support.test.espresso.Espresso;
+import android.support.test.espresso.matcher.RootMatchers;
+import android.support.test.espresso.action.ViewActions;
+import android.support.test.InstrumentationRegistry;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.mockito.ArgumentCaptor;
+import org.mockito.stubbing.Answer;
+import org.mockito.invocation.InvocationOnMock;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.mockito.Mockito.*;
+import static org.junit.Assert.*;
+
+/**
+ * @hide from javadoc
+ */
+@RunWith(AndroidJUnit4.class)
+public class GuidedStepSupportFragmentTest extends GuidedStepSupportFragmentTestBase {
+
+    @Test
+    public void nextAndBack() throws Throwable {
+        GuidedStepTestSupportFragment.Provider first = mockProvider("first");
+        doAnswer(new Answer<Void>() {
+            public Void answer(InvocationOnMock invocation) {
+                List actions = (List) invocation.getArguments()[0];
+                actions.add(new GuidedAction.Builder().id(1000).title("OK").build());
+                return null;
+            }
+        }).when(first).onCreateActions(any(List.class), any(Bundle.class));
+        doAnswer(new Answer<Void>() {
+            public Void answer(InvocationOnMock invocation) {
+                GuidedAction action = (GuidedAction) invocation.getArguments()[0];
+                GuidedStepTestSupportFragment.Provider obj = (GuidedStepTestSupportFragment.Provider)
+                        invocation.getMock();
+                if (action.getId() == 1000) {
+                    GuidedStepSupportFragment.add(obj.getFragmentManager(),
+                            new GuidedStepTestSupportFragment("second"));
+                }
+                return null;
+            }
+        }).when(first).onGuidedActionClicked(any(GuidedAction.class));
+
+        GuidedStepTestSupportFragment.Provider second = mockProvider("second");
+
+        GuidedStepSupportFragmentTestActivity activity = launchTestActivity("first");
+        verify(first, times(1)).onCreate(any(Bundle.class));
+        verify(first, times(1)).onCreateGuidance(any(Bundle.class));
+        verify(first, times(1)).onCreateActions(any(List.class), any(Bundle.class));
+        verify(first, times(1)).onCreateButtonActions(any(List.class), any(Bundle.class));
+        verify(first, times(1)).onCreateView(any(LayoutInflater.class), any(ViewGroup.class),
+                any(Bundle.class), any(View.class));
+        verify(first, times(1)).onViewStateRestored(any(Bundle.class));
+        verify(first, times(1)).onStart();
+        verify(first, times(1)).onResume();
+
+        sendKey(KeyEvent.KEYCODE_DPAD_CENTER);
+        verify(first, times(1)).onGuidedActionClicked(any(GuidedAction.class));
+
+        PollingCheck.waitFor(new EnterTransitionFinish(second));
+        verify(first, times(1)).onPause();
+        verify(first, times(1)).onStop();
+        verify(first, times(1)).onDestroyView();
+        verify(second, times(1)).onCreate(any(Bundle.class));
+        verify(second, times(1)).onCreateGuidance(any(Bundle.class));
+        verify(second, times(1)).onCreateActions(any(List.class), any(Bundle.class));
+        verify(second, times(1)).onCreateButtonActions(any(List.class), any(Bundle.class));
+        verify(second, times(1)).onCreateView(any(LayoutInflater.class), any(ViewGroup.class),
+                any(Bundle.class), any(View.class));
+        verify(second, times(1)).onViewStateRestored(any(Bundle.class));
+        verify(second, times(1)).onStart();
+        verify(second, times(1)).onResume();
+
+        sendKey(KeyEvent.KEYCODE_BACK);
+
+        PollingCheck.waitFor(new EnterTransitionFinish(first));
+        verify(second, times(1)).onPause();
+        verify(second, times(1)).onStop();
+        verify(second, times(1)).onDestroyView();
+        verify(second, times(1)).onDestroy();
+        verify(first, times(1)).onCreateActions(any(List.class), any(Bundle.class));
+        verify(first, times(2)).onCreateView(any(LayoutInflater.class), any(ViewGroup.class),
+                any(Bundle.class), any(View.class));
+        verify(first, times(2)).onViewStateRestored(any(Bundle.class));
+        verify(first, times(2)).onStart();
+        verify(first, times(2)).onResume();
+
+        sendKey(KeyEvent.KEYCODE_BACK);
+        PollingCheck.waitFor(new PollingCheck.ActivityDestroy(activity));
+        verify(first, times(1)).onDestroy();
+        assertTrue(activity.isDestroyed());
+    }
+
+    @Test
+    public void restoreFragments() throws Throwable {
+        GuidedStepTestSupportFragment.Provider first = mockProvider("first");
+        doAnswer(new Answer<Void>() {
+            public Void answer(InvocationOnMock invocation) {
+                List actions = (List) invocation.getArguments()[0];
+                actions.add(new GuidedAction.Builder().id(1000).title("OK").build());
+                actions.add(new GuidedAction.Builder().id(1001).editable(true).title("text")
+                        .build());
+                actions.add(new GuidedAction.Builder().id(1002).editable(true).title("text")
+                        .autoSaveRestoreEnabled(false).build());
+                return null;
+            }
+        }).when(first).onCreateActions(any(List.class), any(Bundle.class));
+        doAnswer(new Answer<Void>() {
+            public Void answer(InvocationOnMock invocation) {
+                GuidedAction action = (GuidedAction) invocation.getArguments()[0];
+                GuidedStepTestSupportFragment.Provider obj = (GuidedStepTestSupportFragment.Provider)
+                        invocation.getMock();
+                if (action.getId() == 1000) {
+                    GuidedStepSupportFragment.add(obj.getFragmentManager(),
+                            new GuidedStepTestSupportFragment("second"));
+                }
+                return null;
+            }
+        }).when(first).onGuidedActionClicked(any(GuidedAction.class));
+
+        GuidedStepTestSupportFragment.Provider second = mockProvider("second");
+
+        final GuidedStepSupportFragmentTestActivity activity = launchTestActivity("first");
+        first.getFragment().findActionById(1001).setTitle("modified text");
+        first.getFragment().findActionById(1002).setTitle("modified text");
+        sendKey(KeyEvent.KEYCODE_DPAD_CENTER);
+        PollingCheck.waitFor(new EnterTransitionFinish(second));
+
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                activity.recreate();
+            }
+        });
+        PollingCheck.waitFor(new EnterTransitionFinish(second));
+        verify(first, times(2)).onCreate(any(Bundle.class));
+        verify(first, times(1)).onCreateView(any(LayoutInflater.class), any(ViewGroup.class),
+                any(Bundle.class), any(View.class));
+        verify(first, times(2)).onCreateActions(any(List.class), any(Bundle.class));
+        verify(first, times(1)).onDestroy();
+        verify(second, times(2)).onCreate(any(Bundle.class));
+        verify(second, times(2)).onCreateView(any(LayoutInflater.class), any(ViewGroup.class),
+                any(Bundle.class), any(View.class));
+        verify(second, times(1)).onDestroy();
+        assertEquals("modified text", first.getFragment().findActionById(1001).getTitle());
+        assertEquals("text", first.getFragment().findActionById(1002).getTitle());
+
+        sendKey(KeyEvent.KEYCODE_BACK);
+        PollingCheck.waitFor(new EnterTransitionFinish(first));
+        verify(second, times(2)).onPause();
+        verify(second, times(2)).onStop();
+        verify(second, times(2)).onDestroyView();
+        verify(second, times(2)).onDestroy();
+        verify(first, times(2)).onCreateView(any(LayoutInflater.class), any(ViewGroup.class),
+                any(Bundle.class), any(View.class));
+    }
+
+
+    @Test
+    public void finishGuidedStepSupportFragment_finishes_activity() throws Throwable {
+        GuidedStepTestSupportFragment.Provider first = mockProvider("first");
+        doAnswer(new Answer<Void>() {
+            public Void answer(InvocationOnMock invocation) {
+                List actions = (List) invocation.getArguments()[0];
+                actions.add(new GuidedAction.Builder().id(1001).title("Finish activity").build());
+                return null;
+            }
+        }).when(first).onCreateActions(any(List.class), any(Bundle.class));
+        doAnswer(new Answer<Void>() {
+            public Void answer(InvocationOnMock invocation) {
+                GuidedAction action = (GuidedAction) invocation.getArguments()[0];
+                GuidedStepTestSupportFragment.Provider obj = (GuidedStepTestSupportFragment.Provider)
+                        invocation.getMock();
+                if (action.getId() == 1001) {
+                    obj.getFragment().finishGuidedStepSupportFragments();
+                }
+                return null;
+            }
+        }).when(first).onGuidedActionClicked(any(GuidedAction.class));
+
+        final GuidedStepSupportFragmentTestActivity activity = launchTestActivity("first");
+
+        View viewFinish = first.getFragment().getActionItemView(0);
+        assertTrue(viewFinish.hasFocus());
+        sendKey(KeyEvent.KEYCODE_DPAD_CENTER);
+        PollingCheck.waitFor(new PollingCheck.ActivityDestroy(activity));
+        verify(first, times(1)).onDestroy();
+    }
+
+    @Test
+    public void finishGuidedStepSupportFragment_finishes_fragments() throws Throwable {
+        GuidedStepTestSupportFragment.Provider first = mockProvider("first");
+        doAnswer(new Answer<Void>() {
+            public Void answer(InvocationOnMock invocation) {
+                List actions = (List) invocation.getArguments()[0];
+                actions.add(new GuidedAction.Builder().id(1001).title("Finish fragments").build());
+                return null;
+            }
+        }).when(first).onCreateActions(any(List.class), any(Bundle.class));
+        doAnswer(new Answer<Void>() {
+            public Void answer(InvocationOnMock invocation) {
+                GuidedAction action = (GuidedAction) invocation.getArguments()[0];
+                GuidedStepTestSupportFragment.Provider obj = (GuidedStepTestSupportFragment.Provider)
+                        invocation.getMock();
+                if (action.getId() == 1001) {
+                    obj.getFragment().finishGuidedStepSupportFragments();
+                }
+                return null;
+            }
+        }).when(first).onGuidedActionClicked(any(GuidedAction.class));
+
+        final GuidedStepSupportFragmentTestActivity activity = launchTestActivity("first",
+                false /*asRoot*/);
+
+        View viewFinish = first.getFragment().getActionItemView(0);
+        assertTrue(viewFinish.hasFocus());
+        sendKey(KeyEvent.KEYCODE_DPAD_CENTER);
+
+        // fragment should be destroyed, activity should not destroyed
+        waitOnDestroy(first, 1);
+        assertFalse(activity.isDestroyed());
+    }
+
+    @Test
+    public void subActions() throws Throwable {
+        final boolean[] expandSubActionInOnCreateView = new boolean[] {false};
+        GuidedStepTestSupportFragment.Provider first = mockProvider("first");
+        doAnswer(new Answer<Void>() {
+            public Void answer(InvocationOnMock invocation) {
+                GuidedStepTestSupportFragment.Provider obj = (GuidedStepTestSupportFragment.Provider)
+                        invocation.getMock();
+                if (expandSubActionInOnCreateView[0]) {
+                    obj.getFragment().expandAction(obj.getFragment().findActionById(1000), false);
+                }
+                return null;
+            }
+        }).when(first).onCreateView(any(LayoutInflater.class), any(ViewGroup.class),
+                any(Bundle.class), any(View.class));
+        doAnswer(new Answer<Void>() {
+            public Void answer(InvocationOnMock invocation) {
+                List actions = (List) invocation.getArguments()[0];
+                List<GuidedAction> subActions = new ArrayList<GuidedAction>();
+                subActions.add(new GuidedAction.Builder().id(2000).title("item1").build());
+                subActions.add(new GuidedAction.Builder().id(2001).title("item2").build());
+                actions.add(new GuidedAction.Builder().id(1000).subActions(subActions)
+                        .title("list").build());
+                return null;
+            }
+        }).when(first).onCreateActions(any(List.class), any(Bundle.class));
+        doAnswer(new Answer<Boolean>() {
+            public Boolean answer(InvocationOnMock invocation) {
+                GuidedStepTestSupportFragment.Provider obj = (GuidedStepTestSupportFragment.Provider)
+                        invocation.getMock();
+                GuidedAction action = (GuidedAction) invocation.getArguments()[0];
+                if (action.getId() == 2000) {
+                    return true;
+                } else if (action.getId() == 2001) {
+                    GuidedStepSupportFragment.add(obj.getFragmentManager(),
+                            new GuidedStepTestSupportFragment("second"));
+                    return false;
+                }
+                return false;
+            }
+        }).when(first).onSubGuidedActionClicked(any(GuidedAction.class));
+
+        GuidedStepTestSupportFragment.Provider second = mockProvider("second");
+
+        final GuidedStepSupportFragmentTestActivity activity = launchTestActivity("first");
+
+        // after clicked, it sub actions list should expand
+        View viewForList = first.getFragment().getActionItemView(0);
+        assertTrue(viewForList.hasFocus());
+        sendKey(KeyEvent.KEYCODE_DPAD_CENTER);
+        PollingCheck.waitFor(new ExpandTransitionFinish(first));
+        assertFalse(viewForList.hasFocus());
+
+        sendKey(KeyEvent.KEYCODE_DPAD_CENTER);
+        ArgumentCaptor<GuidedAction> actionCapture = ArgumentCaptor.forClass(GuidedAction.class);
+        verify(first, times(1)).onSubGuidedActionClicked(actionCapture.capture());
+        assertEquals(2000, actionCapture.getValue().getId());
+        // after clicked a sub action, it sub actions list should close
+        PollingCheck.waitFor(new ExpandTransitionFinish(first));
+        assertTrue(viewForList.hasFocus());
+
+        sendKey(KeyEvent.KEYCODE_DPAD_CENTER);
+        PollingCheck.waitFor(new ExpandTransitionFinish(first));
+
+        assertFalse(viewForList.hasFocus());
+        sendKey(KeyEvent.KEYCODE_DPAD_DOWN);
+        sendKey(KeyEvent.KEYCODE_DPAD_CENTER);
+        ArgumentCaptor<GuidedAction> actionCapture2 = ArgumentCaptor.forClass(GuidedAction.class);
+        verify(first, times(2)).onSubGuidedActionClicked(actionCapture2.capture());
+        assertEquals(2001, actionCapture2.getValue().getId());
+
+        PollingCheck.waitFor(new EnterTransitionFinish(second));
+        verify(second, times(1)).onCreateView(any(LayoutInflater.class), any(ViewGroup.class),
+                any(Bundle.class), any(View.class));
+
+        // test expand sub action when return to first fragment
+        expandSubActionInOnCreateView[0] = true;
+        sendKey(KeyEvent.KEYCODE_BACK);
+        PollingCheck.waitFor(new EnterTransitionFinish(first));
+        verify(first, times(2)).onCreateView(any(LayoutInflater.class), any(ViewGroup.class),
+                any(Bundle.class), any(View.class));
+        assertTrue(first.getFragment().isExpanded());
+
+        sendKey(KeyEvent.KEYCODE_BACK);
+        PollingCheck.waitFor(new ExpandTransitionFinish(first));
+        assertFalse(first.getFragment().isExpanded());
+
+        sendKey(KeyEvent.KEYCODE_BACK);
+        PollingCheck.waitFor(new PollingCheck.ActivityDestroy(activity));
+        verify(first, times(1)).onDestroy();
+    }
+}
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/app/GuidedStepSupportFragmentTestActivity.java b/v17/leanback/tests/java/android/support/v17/leanback/app/GuidedStepSupportFragmentTestActivity.java
new file mode 100644
index 0000000..0e4b367
--- /dev/null
+++ b/v17/leanback/tests/java/android/support/v17/leanback/app/GuidedStepSupportFragmentTestActivity.java
@@ -0,0 +1,56 @@
+/* This file is auto-generated from GuidedStepFragmentTestActivity.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 android.support.v17.leanback.app;
+
+import android.support.v4.app.FragmentActivity;
+import android.content.Intent;
+import android.os.Bundle;
+
+/**
+ * @hide from javadoc
+ */
+public class GuidedStepSupportFragmentTestActivity extends FragmentActivity {
+
+    /**
+     * Frst Test that will be included in this Activity
+     */
+    public static final String EXTRA_TEST_NAME = "testName";
+    /**
+     * True(default) to addAsRoot() for first Test, false to use add()
+     */
+    public static final String EXTRA_ADD_AS_ROOT = "addAsRoot";
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        Intent intent = getIntent();
+
+        if (savedInstanceState == null) {
+            String firstTestName = intent.getStringExtra(EXTRA_TEST_NAME);
+            if (firstTestName != null) {
+                GuidedStepTestSupportFragment testFragment = new GuidedStepTestSupportFragment(firstTestName);
+                if (intent.getBooleanExtra(EXTRA_ADD_AS_ROOT, true)) {
+                    GuidedStepTestSupportFragment.addAsRoot(this, testFragment, android.R.id.content);
+                } else {
+                    GuidedStepTestSupportFragment.add(getSupportFragmentManager(), testFragment,
+                            android.R.id.content);
+                }
+            }
+        }
+    }
+}
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/app/GuidedStepSupportFragmentTestBase.java b/v17/leanback/tests/java/android/support/v17/leanback/app/GuidedStepSupportFragmentTestBase.java
new file mode 100644
index 0000000..088b053
--- /dev/null
+++ b/v17/leanback/tests/java/android/support/v17/leanback/app/GuidedStepSupportFragmentTestBase.java
@@ -0,0 +1,132 @@
+/* This file is auto-generated from GuidedStepFrgamentTestBase.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 android.support.v17.leanback.app;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Intent;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.rule.ActivityTestRule;
+import android.support.v17.leanback.R;
+import android.support.v17.leanback.testutils.PollingCheck;
+import android.view.View;
+
+import org.junit.Before;
+import org.junit.Rule;
+
+/**
+ * @hide from javadoc
+ */
+public class GuidedStepSupportFragmentTestBase {
+
+    private static final long TIMEOUT = 5000;
+
+    @Rule
+    public ActivityTestRule<GuidedStepSupportFragmentTestActivity> activityTestRule =
+            new ActivityTestRule<>(GuidedStepSupportFragmentTestActivity.class, false, false);
+
+    @Before
+    public void clearTests() {
+        GuidedStepTestSupportFragment.clearTests();
+    }
+
+    public static class ExpandTransitionFinish extends PollingCheck.PollingCheckCondition {
+        GuidedStepTestSupportFragment.Provider mProvider;
+
+        public ExpandTransitionFinish(GuidedStepTestSupportFragment.Provider provider) {
+            mProvider = provider;
+        }
+
+        @Override
+        public boolean canPreProceed() {
+            return false;
+        }
+
+        @Override
+        public boolean canProceed() {
+            GuidedStepTestSupportFragment fragment = mProvider.getFragment();
+            if (fragment != null && fragment.getView() != null) {
+                if (!fragment.getGuidedActionsStylist().isInExpandTransition()) {
+                    // expand transition finishes
+                    return true;
+                }
+            }
+            return false;
+        }
+    }
+
+    public static void waitOnDestroy(GuidedStepTestSupportFragment.Provider provider,
+            int times) {
+        verify(provider, timeout((int)TIMEOUT).times(times)).onDestroy();
+    }
+
+    public static class EnterTransitionFinish extends PollingCheck.PollingCheckCondition {
+        PollingCheck.ViewScreenPositionDetector mDector =
+                new PollingCheck.ViewScreenPositionDetector();
+
+        GuidedStepTestSupportFragment.Provider mProvider;
+
+        public EnterTransitionFinish(GuidedStepTestSupportFragment.Provider provider) {
+            mProvider = provider;
+        }
+        @Override
+        public boolean canProceed() {
+            GuidedStepTestSupportFragment fragment = mProvider.getFragment();
+            if (fragment != null && fragment.getView() != null) {
+                View view = fragment.getView().findViewById(R.id.guidance_title);
+                if (view != null) {
+                    if (mDector.isViewStableOnScreen(view)) {
+                        return true;
+                    }
+                }
+            }
+            return false;
+        }
+    }
+
+    public static void sendKey(int keyCode) {
+        InstrumentationRegistry.getInstrumentation().sendKeyDownUpSync(keyCode);
+    }
+
+    public GuidedStepSupportFragmentTestActivity launchTestActivity(String firstTestName) {
+        Intent intent = new Intent();
+        intent.putExtra(GuidedStepSupportFragmentTestActivity.EXTRA_TEST_NAME, firstTestName);
+        return activityTestRule.launchActivity(intent);
+    }
+
+    public GuidedStepSupportFragmentTestActivity launchTestActivity(String firstTestName,
+            boolean addAsRoot) {
+        Intent intent = new Intent();
+        intent.putExtra(GuidedStepSupportFragmentTestActivity.EXTRA_TEST_NAME, firstTestName);
+        intent.putExtra(GuidedStepSupportFragmentTestActivity.EXTRA_ADD_AS_ROOT, addAsRoot);
+        return activityTestRule.launchActivity(intent);
+    }
+
+    public static GuidedStepTestSupportFragment.Provider mockProvider(String testName) {
+        GuidedStepTestSupportFragment.Provider test = mock(GuidedStepTestSupportFragment.Provider.class);
+        when(test.getActivity()).thenCallRealMethod();
+        when(test.getFragmentManager()).thenCallRealMethod();
+        when(test.getFragment()).thenCallRealMethod();
+        GuidedStepTestSupportFragment.setupTest(testName, test);
+        return test;
+    }
+}
+
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/app/GuidedStepTestFragment.java b/v17/leanback/tests/java/android/support/v17/leanback/app/GuidedStepTestFragment.java
new file mode 100644
index 0000000..c530925
--- /dev/null
+++ b/v17/leanback/tests/java/android/support/v17/leanback/app/GuidedStepTestFragment.java
@@ -0,0 +1,239 @@
+/*
+ * 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 android.support.v17.leanback.app;
+
+import android.app.Activity;
+import android.app.FragmentManager;
+import android.os.Bundle;
+import android.view.ViewGroup;
+import android.view.View;
+import android.view.LayoutInflater;
+
+
+import android.support.v17.leanback.widget.GuidanceStylist.Guidance;
+import android.support.v17.leanback.widget.GuidedAction;
+
+import java.util.List;
+import java.util.HashMap;
+
+/**
+ * @hide from javadoc
+ */
+public class GuidedStepTestFragment extends GuidedStepFragment {
+
+    private static final String KEY_TEST_NAME = "key_test_name";
+
+    private static final HashMap<String, Provider> sTestMap = new HashMap<String, Provider>();
+
+    public static class Provider {
+
+        GuidedStepTestFragment mFragment;
+
+        public void onCreate(Bundle savedInstanceState) {
+        }
+
+        public void onSaveInstanceState(Bundle outState) {
+        }
+
+        public Guidance onCreateGuidance(Bundle savedInstanceState) {
+            return new Guidance("", "", "", null);
+        }
+
+        public void onCreateActions(List<GuidedAction> actions, Bundle savedInstanceState) {
+        }
+
+        public void onCreateButtonActions(List<GuidedAction> actions, Bundle savedInstanceState) {
+        }
+
+        public void onGuidedActionClicked(GuidedAction action) {
+        }
+
+        public boolean onSubGuidedActionClicked(GuidedAction action) {
+            return true;
+        }
+
+        public void onCreateView(LayoutInflater inflater, ViewGroup container,
+                Bundle savedInstanceState, View result) {
+        }
+
+        public void onDestroyView() {
+        }
+
+        public void onDestroy() {
+        }
+
+        public void onStart() {
+        }
+
+        public void onStop() {
+        }
+
+        public void onResume() {
+        }
+
+        public void onPause() {
+        }
+
+        public void onViewStateRestored(Bundle bundle) {
+        }
+
+        public void onDetach() {
+        }
+
+        public GuidedStepTestFragment getFragment() {
+            return mFragment;
+        }
+
+        public Activity getActivity() {
+            return mFragment.getActivity();
+        }
+
+        public FragmentManager getFragmentManager() {
+            return mFragment.getFragmentManager();
+        }
+    }
+
+    public static void setupTest(String testName, Provider provider) {
+        sTestMap.put(testName, provider);
+    }
+
+    public static void clearTests() {
+        sTestMap.clear();
+    }
+
+    CharSequence mTestName;
+    Provider mProvider;
+
+    public GuidedStepTestFragment() {
+    }
+
+    public GuidedStepTestFragment(String testName) {
+        setTestName(testName);
+    }
+
+    public void setTestName(CharSequence testName) {
+        mTestName = testName;
+    }
+
+    public CharSequence getTestName() {
+        return mTestName;
+    }
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        if (savedInstanceState != null) {
+            mTestName = savedInstanceState.getCharSequence(KEY_TEST_NAME, null);
+        }
+        mProvider = sTestMap.get(mTestName);
+        if (mProvider == null) {
+            throw new IllegalArgumentException("you must setupTest()");
+        }
+        mProvider.mFragment = this;
+        super.onCreate(savedInstanceState);
+        mProvider.onCreate(savedInstanceState);
+    }
+
+    @Override
+    public void onSaveInstanceState(Bundle outState) {
+        super.onSaveInstanceState(outState);
+        outState.putCharSequence(KEY_TEST_NAME, mTestName);
+        mProvider.onSaveInstanceState(outState);
+    }
+
+    @Override
+    public Guidance onCreateGuidance(Bundle savedInstanceState) {
+        Guidance g = mProvider.onCreateGuidance(savedInstanceState);
+        if (g == null) {
+            g = new Guidance("", "", "", null);
+        }
+        return g;
+    }
+
+    @Override
+    public void onCreateActions(List<GuidedAction> actions, Bundle savedInstanceState) {
+        mProvider.onCreateActions(actions, savedInstanceState);
+    }
+
+    @Override
+    public void onCreateButtonActions(List<GuidedAction> actions, Bundle savedInstanceState) {
+        mProvider.onCreateButtonActions(actions, savedInstanceState);
+    }
+
+    @Override
+    public void onGuidedActionClicked(GuidedAction action) {
+        mProvider.onGuidedActionClicked(action);
+    }
+
+    @Override
+    public boolean onSubGuidedActionClicked(GuidedAction action) {
+        return mProvider.onSubGuidedActionClicked(action);
+    }
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle state) {
+        View view = super.onCreateView(inflater, container, state);
+        mProvider.onCreateView(inflater, container, state, view);
+        return view;
+    }
+
+    @Override
+    public void onDestroyView() {
+        mProvider.onDestroyView();
+        super.onDestroyView();
+    }
+
+    @Override
+    public void onDestroy() {
+        mProvider.onDestroy();
+        super.onDestroy();
+    }
+
+    @Override
+    public void onPause() {
+        mProvider.onPause();
+        super.onPause();
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+        mProvider.onResume();
+    }
+
+    @Override
+    public void onStart() {
+        super.onStart();
+        mProvider.onStart();
+    }
+
+    @Override
+    public void onStop() {
+        mProvider.onStop();
+        super.onStop();
+    }
+
+    @Override
+    public void onDetach() {
+        mProvider.onDetach();
+        super.onDetach();
+    }
+
+    @Override
+    public void onViewStateRestored(Bundle bundle) {
+        super.onViewStateRestored(bundle);
+        mProvider.onViewStateRestored(bundle);
+    }
+}
+
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/app/GuidedStepTestSupportFragment.java b/v17/leanback/tests/java/android/support/v17/leanback/app/GuidedStepTestSupportFragment.java
new file mode 100644
index 0000000..04aa6f0
--- /dev/null
+++ b/v17/leanback/tests/java/android/support/v17/leanback/app/GuidedStepTestSupportFragment.java
@@ -0,0 +1,241 @@
+/* This file is auto-generated from GuidedStepTestFragment.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 android.support.v17.leanback.app;
+
+import android.support.v4.app.FragmentActivity;
+import android.support.v4.app.FragmentManager;
+import android.os.Bundle;
+import android.view.ViewGroup;
+import android.view.View;
+import android.view.LayoutInflater;
+
+
+import android.support.v17.leanback.widget.GuidanceStylist.Guidance;
+import android.support.v17.leanback.widget.GuidedAction;
+
+import java.util.List;
+import java.util.HashMap;
+
+/**
+ * @hide from javadoc
+ */
+public class GuidedStepTestSupportFragment extends GuidedStepSupportFragment {
+
+    private static final String KEY_TEST_NAME = "key_test_name";
+
+    private static final HashMap<String, Provider> sTestMap = new HashMap<String, Provider>();
+
+    public static class Provider {
+
+        GuidedStepTestSupportFragment mFragment;
+
+        public void onCreate(Bundle savedInstanceState) {
+        }
+
+        public void onSaveInstanceState(Bundle outState) {
+        }
+
+        public Guidance onCreateGuidance(Bundle savedInstanceState) {
+            return new Guidance("", "", "", null);
+        }
+
+        public void onCreateActions(List<GuidedAction> actions, Bundle savedInstanceState) {
+        }
+
+        public void onCreateButtonActions(List<GuidedAction> actions, Bundle savedInstanceState) {
+        }
+
+        public void onGuidedActionClicked(GuidedAction action) {
+        }
+
+        public boolean onSubGuidedActionClicked(GuidedAction action) {
+            return true;
+        }
+
+        public void onCreateView(LayoutInflater inflater, ViewGroup container,
+                Bundle savedInstanceState, View result) {
+        }
+
+        public void onDestroyView() {
+        }
+
+        public void onDestroy() {
+        }
+
+        public void onStart() {
+        }
+
+        public void onStop() {
+        }
+
+        public void onResume() {
+        }
+
+        public void onPause() {
+        }
+
+        public void onViewStateRestored(Bundle bundle) {
+        }
+
+        public void onDetach() {
+        }
+
+        public GuidedStepTestSupportFragment getFragment() {
+            return mFragment;
+        }
+
+        public FragmentActivity getActivity() {
+            return mFragment.getActivity();
+        }
+
+        public FragmentManager getFragmentManager() {
+            return mFragment.getFragmentManager();
+        }
+    }
+
+    public static void setupTest(String testName, Provider provider) {
+        sTestMap.put(testName, provider);
+    }
+
+    public static void clearTests() {
+        sTestMap.clear();
+    }
+
+    CharSequence mTestName;
+    Provider mProvider;
+
+    public GuidedStepTestSupportFragment() {
+    }
+
+    public GuidedStepTestSupportFragment(String testName) {
+        setTestName(testName);
+    }
+
+    public void setTestName(CharSequence testName) {
+        mTestName = testName;
+    }
+
+    public CharSequence getTestName() {
+        return mTestName;
+    }
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        if (savedInstanceState != null) {
+            mTestName = savedInstanceState.getCharSequence(KEY_TEST_NAME, null);
+        }
+        mProvider = sTestMap.get(mTestName);
+        if (mProvider == null) {
+            throw new IllegalArgumentException("you must setupTest()");
+        }
+        mProvider.mFragment = this;
+        super.onCreate(savedInstanceState);
+        mProvider.onCreate(savedInstanceState);
+    }
+
+    @Override
+    public void onSaveInstanceState(Bundle outState) {
+        super.onSaveInstanceState(outState);
+        outState.putCharSequence(KEY_TEST_NAME, mTestName);
+        mProvider.onSaveInstanceState(outState);
+    }
+
+    @Override
+    public Guidance onCreateGuidance(Bundle savedInstanceState) {
+        Guidance g = mProvider.onCreateGuidance(savedInstanceState);
+        if (g == null) {
+            g = new Guidance("", "", "", null);
+        }
+        return g;
+    }
+
+    @Override
+    public void onCreateActions(List<GuidedAction> actions, Bundle savedInstanceState) {
+        mProvider.onCreateActions(actions, savedInstanceState);
+    }
+
+    @Override
+    public void onCreateButtonActions(List<GuidedAction> actions, Bundle savedInstanceState) {
+        mProvider.onCreateButtonActions(actions, savedInstanceState);
+    }
+
+    @Override
+    public void onGuidedActionClicked(GuidedAction action) {
+        mProvider.onGuidedActionClicked(action);
+    }
+
+    @Override
+    public boolean onSubGuidedActionClicked(GuidedAction action) {
+        return mProvider.onSubGuidedActionClicked(action);
+    }
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle state) {
+        View view = super.onCreateView(inflater, container, state);
+        mProvider.onCreateView(inflater, container, state, view);
+        return view;
+    }
+
+    @Override
+    public void onDestroyView() {
+        mProvider.onDestroyView();
+        super.onDestroyView();
+    }
+
+    @Override
+    public void onDestroy() {
+        mProvider.onDestroy();
+        super.onDestroy();
+    }
+
+    @Override
+    public void onPause() {
+        mProvider.onPause();
+        super.onPause();
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+        mProvider.onResume();
+    }
+
+    @Override
+    public void onStart() {
+        super.onStart();
+        mProvider.onStart();
+    }
+
+    @Override
+    public void onStop() {
+        mProvider.onStop();
+        super.onStop();
+    }
+
+    @Override
+    public void onDetach() {
+        mProvider.onDetach();
+        super.onDetach();
+    }
+
+    @Override
+    public void onViewStateRestored(Bundle bundle) {
+        super.onViewStateRestored(bundle);
+        mProvider.onViewStateRestored(bundle);
+    }
+}
+
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/app/PhotoItem.java b/v17/leanback/tests/java/android/support/v17/leanback/app/PhotoItem.java
new file mode 100644
index 0000000..3c2460a
--- /dev/null
+++ b/v17/leanback/tests/java/android/support/v17/leanback/app/PhotoItem.java
@@ -0,0 +1,81 @@
+/*
+ * 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 android.support.v17.leanback.app;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+public class PhotoItem implements Parcelable {
+    private String mTitle;
+    private String mContent;
+    private int mImageResourceId;
+
+    public PhotoItem(String title, int imageResourceId) {
+        this(title, null, imageResourceId);
+    }
+
+    public PhotoItem(String title, String content, int imageResourceId) {
+        mTitle = title;
+        mContent = content;
+        mImageResourceId = imageResourceId;
+    }
+
+    public int getImageResourceId() {
+        return mImageResourceId;
+    }
+
+    public String getTitle() {
+        return mTitle;
+    }
+
+    public String getContent() {
+        return mContent;
+    }
+
+    @Override
+    public String toString() {
+        return mTitle;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeString(mTitle);
+        dest.writeInt(mImageResourceId);
+    }
+
+    public static final Parcelable.Creator<PhotoItem> CREATOR =
+            new Parcelable.Creator<PhotoItem>() {
+        @Override
+        public PhotoItem createFromParcel(Parcel in) {
+            return new PhotoItem(in);
+        }
+
+        @Override
+        public PhotoItem[] newArray(int size) {
+            return new PhotoItem[size];
+        }
+    };
+
+    private PhotoItem(Parcel in) {
+        mTitle = in.readString();
+        mImageResourceId = in.readInt();
+    }
+}
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 5dbec44..fae07be 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
@@ -13,31 +13,26 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package android.support.v17.leanback.app;
 
-import org.junit.Assert;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.v17.leanback.widget.PlaybackControlsRow;
+import android.support.v17.leanback.widget.SparseArrayObjectAdapter;
+import android.view.KeyEvent;
 
+import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import android.content.Context;
-import android.graphics.drawable.Drawable;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 
-import android.support.v17.leanback.widget.PlaybackControlsRow;
-import android.support.v17.leanback.widget.SparseArrayObjectAdapter;
-
-import android.support.test.InstrumentationRegistry;
-import android.support.test.runner.AndroidJUnit4;
-import android.support.annotation.UiThread;
-
-import android.test.suitebuilder.annotation.SmallTest;
-import android.view.KeyEvent;
-
-@SmallTest
 @RunWith(AndroidJUnit4.class)
 public class PlaybackControlGlueTest {
 
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 69e61dc..b7518a9 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
@@ -15,31 +15,26 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package android.support.v17.leanback.app;
 
-import org.junit.Assert;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.v17.leanback.widget.PlaybackControlsRow;
+import android.support.v17.leanback.widget.SparseArrayObjectAdapter;
+import android.view.KeyEvent;
 
+import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import android.content.Context;
-import android.graphics.drawable.Drawable;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 
-import android.support.v17.leanback.widget.PlaybackControlsRow;
-import android.support.v17.leanback.widget.SparseArrayObjectAdapter;
-
-import android.support.test.InstrumentationRegistry;
-import android.support.test.runner.AndroidJUnit4;
-import android.support.annotation.UiThread;
-
-import android.test.suitebuilder.annotation.SmallTest;
-import android.view.KeyEvent;
-
-@SmallTest
 @RunWith(AndroidJUnit4.class)
 public class PlaybackControlSupportGlueTest {
 
@@ -350,4 +345,161 @@
             assertEquals(0, rewind.getIndex());
         }
     }
+
+    @Test
+    public void testMediaPauseButtonOnFF() {
+        PlaybackControlsRow row = new PlaybackControlsRow();
+        glue.setControlsRow(row);
+        SparseArrayObjectAdapter adapter = (SparseArrayObjectAdapter)
+                row.getPrimaryActionsAdapter();
+        PlaybackControlsRow.MultiAction playPause = (PlaybackControlsRow.MultiAction) adapter
+                .lookup(PlaybackControlSupportGlue.ACTION_PLAY_PAUSE);
+        PlaybackControlsRow.MultiAction fastForward = (PlaybackControlsRow.MultiAction) adapter
+                .lookup(PlaybackControlSupportGlue.ACTION_FAST_FORWARD);
+
+        glue.onActionClicked(playPause);
+        glue.onActionClicked(fastForward);
+        assertEquals(PlaybackControlSupportGlue.PLAYBACK_SPEED_FAST_L0, glue.getCurrentSpeedId());
+        glue.onKey(null, KeyEvent.KEYCODE_MEDIA_PAUSE, new KeyEvent(KeyEvent.ACTION_DOWN,
+                KeyEvent.KEYCODE_MEDIA_PAUSE));
+        assertEquals(PlaybackControlSupportGlue.PLAYBACK_SPEED_PAUSED, glue.getCurrentSpeedId());
+    }
+
+    @Test
+    public void testMediaPauseButtonOnPlay() {
+        PlaybackControlsRow row = new PlaybackControlsRow();
+        glue.setControlsRow(row);
+        SparseArrayObjectAdapter adapter = (SparseArrayObjectAdapter)
+                row.getPrimaryActionsAdapter();
+        PlaybackControlsRow.MultiAction playPause = (PlaybackControlsRow.MultiAction) adapter
+                .lookup(PlaybackControlSupportGlue.ACTION_PLAY_PAUSE);
+
+        glue.onActionClicked(playPause);
+        assertEquals(PlaybackControlSupportGlue.PLAYBACK_SPEED_NORMAL, glue.getCurrentSpeedId());
+        glue.onKey(null, KeyEvent.KEYCODE_MEDIA_PAUSE, new KeyEvent(KeyEvent.ACTION_DOWN,
+                KeyEvent.KEYCODE_MEDIA_PAUSE));
+        assertEquals(PlaybackControlSupportGlue.PLAYBACK_SPEED_PAUSED, glue.getCurrentSpeedId());
+    }
+
+    @Test
+    public void testMediaPauseButtonOnPause() {
+        PlaybackControlsRow row = new PlaybackControlsRow();
+        glue.setControlsRow(row);
+        SparseArrayObjectAdapter adapter = (SparseArrayObjectAdapter)
+                row.getPrimaryActionsAdapter();
+        PlaybackControlsRow.MultiAction playPause = (PlaybackControlsRow.MultiAction) adapter
+                .lookup(PlaybackControlSupportGlue.ACTION_PLAY_PAUSE);
+
+        glue.onActionClicked(playPause);
+        glue.onActionClicked(playPause);
+        assertEquals(PlaybackControlSupportGlue.PLAYBACK_SPEED_PAUSED, glue.getCurrentSpeedId());
+        glue.onKey(null, KeyEvent.KEYCODE_MEDIA_PAUSE, new KeyEvent(KeyEvent.ACTION_DOWN,
+                KeyEvent.KEYCODE_MEDIA_PAUSE));
+        assertEquals(PlaybackControlSupportGlue.PLAYBACK_SPEED_PAUSED, glue.getCurrentSpeedId());
+    }
+
+    @Test
+    public void testMediaPlayButtonOnFF() {
+        PlaybackControlsRow row = new PlaybackControlsRow();
+        glue.setControlsRow(row);
+        SparseArrayObjectAdapter adapter = (SparseArrayObjectAdapter)
+                row.getPrimaryActionsAdapter();
+        PlaybackControlsRow.MultiAction playPause = (PlaybackControlsRow.MultiAction) adapter
+                .lookup(PlaybackControlSupportGlue.ACTION_PLAY_PAUSE);
+        PlaybackControlsRow.MultiAction fastForward = (PlaybackControlsRow.MultiAction) adapter
+                .lookup(PlaybackControlSupportGlue.ACTION_FAST_FORWARD);
+
+        glue.onActionClicked(playPause);
+        glue.onActionClicked(fastForward);
+        assertEquals(PlaybackControlSupportGlue.PLAYBACK_SPEED_FAST_L0, glue.getCurrentSpeedId());
+        glue.onKey(null, KeyEvent.KEYCODE_MEDIA_PLAY, new KeyEvent(KeyEvent.ACTION_DOWN,
+                KeyEvent.KEYCODE_MEDIA_PLAY));
+        assertEquals(PlaybackControlSupportGlue.PLAYBACK_SPEED_NORMAL, glue.getCurrentSpeedId());
+    }
+
+    @Test
+    public void testMediaPlayButtonOnPlay() {
+        PlaybackControlsRow row = new PlaybackControlsRow();
+        glue.setControlsRow(row);
+        SparseArrayObjectAdapter adapter = (SparseArrayObjectAdapter)
+                row.getPrimaryActionsAdapter();
+        PlaybackControlsRow.MultiAction playPause = (PlaybackControlsRow.MultiAction) adapter
+                .lookup(PlaybackControlSupportGlue.ACTION_PLAY_PAUSE);
+
+        glue.onActionClicked(playPause);
+        assertEquals(PlaybackControlSupportGlue.PLAYBACK_SPEED_NORMAL, glue.getCurrentSpeedId());
+        glue.onKey(null, KeyEvent.KEYCODE_MEDIA_PLAY, new KeyEvent(KeyEvent.ACTION_DOWN,
+                KeyEvent.KEYCODE_MEDIA_PLAY));
+        assertEquals(PlaybackControlSupportGlue.PLAYBACK_SPEED_NORMAL, glue.getCurrentSpeedId());
+    }
+
+    @Test
+    public void testMediaPlayButtonOnPause() {
+        PlaybackControlsRow row = new PlaybackControlsRow();
+        glue.setControlsRow(row);
+        SparseArrayObjectAdapter adapter = (SparseArrayObjectAdapter)
+                row.getPrimaryActionsAdapter();
+        PlaybackControlsRow.MultiAction playPause = (PlaybackControlsRow.MultiAction) adapter
+                .lookup(PlaybackControlSupportGlue.ACTION_PLAY_PAUSE);
+
+        glue.onActionClicked(playPause);
+        glue.onActionClicked(playPause);
+        assertEquals(PlaybackControlSupportGlue.PLAYBACK_SPEED_PAUSED, glue.getCurrentSpeedId());
+        glue.onKey(null, KeyEvent.KEYCODE_MEDIA_PLAY, new KeyEvent(KeyEvent.ACTION_DOWN,
+                KeyEvent.KEYCODE_MEDIA_PLAY));
+        assertEquals(PlaybackControlSupportGlue.PLAYBACK_SPEED_NORMAL, glue.getCurrentSpeedId());
+    }
+
+    @Test
+    public void testMediaPlayPauseButtonOnFF() {
+        PlaybackControlsRow row = new PlaybackControlsRow();
+        glue.setControlsRow(row);
+        SparseArrayObjectAdapter adapter = (SparseArrayObjectAdapter)
+                row.getPrimaryActionsAdapter();
+        PlaybackControlsRow.MultiAction playPause = (PlaybackControlsRow.MultiAction) adapter
+                .lookup(PlaybackControlSupportGlue.ACTION_PLAY_PAUSE);
+        PlaybackControlsRow.MultiAction fastForward = (PlaybackControlsRow.MultiAction) adapter
+                .lookup(PlaybackControlSupportGlue.ACTION_FAST_FORWARD);
+
+        glue.onActionClicked(playPause);
+        glue.onActionClicked(fastForward);
+        assertEquals(PlaybackControlSupportGlue.PLAYBACK_SPEED_FAST_L0, glue.getCurrentSpeedId());
+        glue.onKey(null, KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE, new KeyEvent(KeyEvent.ACTION_DOWN,
+                KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE));
+        assertEquals(PlaybackControlSupportGlue.PLAYBACK_SPEED_NORMAL, glue.getCurrentSpeedId());
+    }
+
+    @Test
+    public void testMediaPlayPauseButtonOnPlay() {
+        PlaybackControlsRow row = new PlaybackControlsRow();
+        glue.setControlsRow(row);
+        SparseArrayObjectAdapter adapter = (SparseArrayObjectAdapter)
+                row.getPrimaryActionsAdapter();
+        PlaybackControlsRow.MultiAction playPause = (PlaybackControlsRow.MultiAction) adapter
+                .lookup(PlaybackControlSupportGlue.ACTION_PLAY_PAUSE);
+
+        glue.onActionClicked(playPause);
+        assertEquals(PlaybackControlSupportGlue.PLAYBACK_SPEED_NORMAL, glue.getCurrentSpeedId());
+        glue.onKey(null, KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE, new KeyEvent(KeyEvent.ACTION_DOWN,
+                KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE));
+        assertEquals(PlaybackControlSupportGlue.PLAYBACK_SPEED_PAUSED, glue.getCurrentSpeedId());
+    }
+
+    @Test
+    public void testMediaPlayPauseButtonOnPause() {
+        PlaybackControlsRow row = new PlaybackControlsRow();
+        glue.setControlsRow(row);
+        SparseArrayObjectAdapter adapter = (SparseArrayObjectAdapter)
+                row.getPrimaryActionsAdapter();
+        PlaybackControlsRow.MultiAction playPause = (PlaybackControlsRow.MultiAction) adapter
+                .lookup(PlaybackControlSupportGlue.ACTION_PLAY_PAUSE);
+
+        glue.onActionClicked(playPause);
+        glue.onActionClicked(playPause);
+        assertEquals(PlaybackControlSupportGlue.PLAYBACK_SPEED_PAUSED, glue.getCurrentSpeedId());
+        glue.onKey(null, KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE, new KeyEvent(KeyEvent.ACTION_DOWN,
+                KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE));
+        assertEquals(PlaybackControlSupportGlue.PLAYBACK_SPEED_NORMAL, glue.getCurrentSpeedId());
+    }
+
 }
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/app/PlaybackOverlayFragmentTest.java b/v17/leanback/tests/java/android/support/v17/leanback/app/PlaybackOverlayFragmentTest.java
new file mode 100644
index 0000000..51907c5
--- /dev/null
+++ b/v17/leanback/tests/java/android/support/v17/leanback/app/PlaybackOverlayFragmentTest.java
@@ -0,0 +1,49 @@
+/*
+ * 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 android.support.v17.leanback.app;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.content.Intent;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.v17.leanback.test.R;
+import android.test.suitebuilder.annotation.MediumTest;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class PlaybackOverlayFragmentTest {
+
+    @Rule
+    public ActivityTestRule<PlaybackOverlayTestActivity> activityTestRule =
+            new ActivityTestRule<>(PlaybackOverlayTestActivity.class, false, false);
+    private PlaybackOverlayTestActivity mActivity;
+
+    @Test
+    public void workaroundVideoViewStealFocus() {
+        Intent intent = new Intent();
+        mActivity = activityTestRule.launchActivity(intent);
+
+        assertFalse(mActivity.findViewById(R.id.videoView).hasFocus());
+        assertTrue(mActivity.getPlaybackFragment().getView().hasFocus());
+    }
+
+}
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/app/PlaybackOverlayTestActivity.java b/v17/leanback/tests/java/android/support/v17/leanback/app/PlaybackOverlayTestActivity.java
new file mode 100644
index 0000000..ea2aa38
--- /dev/null
+++ b/v17/leanback/tests/java/android/support/v17/leanback/app/PlaybackOverlayTestActivity.java
@@ -0,0 +1,57 @@
+/*
+ * 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 android.support.v17.leanback.app;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.support.v17.leanback.test.R;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class PlaybackOverlayTestActivity extends Activity {
+    private List<PictureInPictureListener> mListeners = new ArrayList<>();
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.playback_controls_with_video);
+    }
+
+    @Override
+    public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode) {
+        for (PictureInPictureListener listener : mListeners) {
+            listener.onPictureInPictureModeChanged(isInPictureInPictureMode);
+        }
+    }
+
+    public void registerPictureInPictureListener(PictureInPictureListener listener) {
+        mListeners.add(listener);
+    }
+
+    public void unregisterPictureInPictureListener(PictureInPictureListener listener) {
+        mListeners.remove(listener);
+    }
+
+    public interface PictureInPictureListener {
+        void onPictureInPictureModeChanged(boolean isInPictureInPictureMode);
+    }
+
+    public PlaybackOverlayTestFragment getPlaybackFragment() {
+        return (PlaybackOverlayTestFragment) getFragmentManager().findFragmentById(
+                R.id.playback_controls_fragment);
+    }
+}
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/app/PlaybackOverlayTestFragment.java b/v17/leanback/tests/java/android/support/v17/leanback/app/PlaybackOverlayTestFragment.java
new file mode 100644
index 0000000..6814b3a
--- /dev/null
+++ b/v17/leanback/tests/java/android/support/v17/leanback/app/PlaybackOverlayTestFragment.java
@@ -0,0 +1,445 @@
+/*
+ * 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 android.support.v17.leanback.app;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.os.Handler;
+import android.support.v17.leanback.test.R;
+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.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;
+import android.view.KeyEvent;
+import android.view.View;
+import android.widget.Toast;
+
+public class PlaybackOverlayTestFragment
+        extends PlaybackOverlayFragment
+        implements PlaybackOverlayTestActivity.PictureInPictureListener {
+    private static final String TAG = "leanback.PlaybackControlsFragment";
+
+    /**
+     * Change this to choose a different overlay background.
+     */
+    private static final int BACKGROUND_TYPE = PlaybackOverlayFragment.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 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();
+    }
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        Log.i(TAG, "onCreate");
+        super.onCreate(savedInstanceState);
+
+        setBackgroundType(BACKGROUND_TYPE);
+        setOnItemViewSelectedListener(mOnItemViewSelectedListener);
+
+        createComponents(getActivity());
+    }
+
+    private void createComponents(Context context) {
+        mGlue = new PlaybackControlHelper(context, this) {
+            @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
+            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();
+                    return;
+                }
+                super.onActionClicked(action);
+            }
+        };
+
+        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 mPlaybackControlsRowPresenter;
+                } 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();
+        mGlue.setFadingEnabled(true);
+        mGlue.enableProgressUpdating(mGlue.hasValidMedia() && mGlue.isMediaPlaying());
+        ((PlaybackOverlayTestActivity) getActivity()).registerPictureInPictureListener(this);
+    }
+
+    @Override
+    public void onStop() {
+        mGlue.enableProgressUpdating(false);
+        ((PlaybackOverlayTestActivity) 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());
+        }
+    }
+
+    abstract static class PlaybackControlHelper extends 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());
+            }
+        };
+
+        PlaybackControlHelper(Context context, PlaybackOverlayFragment 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(PlaybackControlGlue.ACTION_CUSTOM_LEFT_FIRST, mThumbsUpAction);
+                adapter.set(PlaybackControlGlue.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 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) {
+                        pausePlayback();
+                    } else {
+                        startPlayback(PlaybackControlGlue.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 == PlaybackControlGlue.PLAYBACK_SPEED_PAUSED) {
+                return;
+            }
+            mStartPosition = getCurrentPosition();
+            mSpeed = PlaybackControlGlue.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/v17/leanback/tests/java/android/support/v17/leanback/app/VerticalGridFragmentTest.java b/v17/leanback/tests/java/android/support/v17/leanback/app/VerticalGridFragmentTest.java
new file mode 100644
index 0000000..3091bc4
--- /dev/null
+++ b/v17/leanback/tests/java/android/support/v17/leanback/app/VerticalGridFragmentTest.java
@@ -0,0 +1,76 @@
+/*
+ * 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 android.support.v17.leanback.app;
+
+import android.app.Activity;
+import android.app.Fragment;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Handler;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.v17.leanback.widget.ArrayObjectAdapter;
+import android.support.v17.leanback.widget.VerticalGridPresenter;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class VerticalGridFragmentTest {
+
+    public static class GridFragment extends VerticalGridFragment {
+        @Override
+        public void onCreate(Bundle savedInstanceState) {
+            super.onCreate(savedInstanceState);
+            if (savedInstanceState == null) {
+                prepareEntranceTransition();
+            }
+            VerticalGridPresenter gridPresenter = new VerticalGridPresenter();
+            gridPresenter.setNumberOfColumns(3);
+            setGridPresenter(gridPresenter);
+            setAdapter(new ArrayObjectAdapter());
+        }
+    }
+
+    public static class ImmediateRemoveFragmentActivity extends Activity {
+        @Override
+        public void onCreate(Bundle savedInstanceState) {
+            super.onCreate(savedInstanceState);
+            new Handler().postDelayed(new Runnable(){
+                public void run() {
+                    GridFragment f = new GridFragment();
+                    ImmediateRemoveFragmentActivity.this.getFragmentManager().beginTransaction()
+                            .replace(android.R.id.content, f, null).commit();
+                    f.startEntranceTransition();
+                    ImmediateRemoveFragmentActivity.this.getFragmentManager().beginTransaction()
+                            .replace(android.R.id.content, new Fragment(), null).commit();
+                }
+            }, 500);
+        }
+    }
+
+    @Test
+    public void immediateRemoveFragment() throws Throwable {
+        Intent intent = new Intent();
+        ActivityTestRule<ImmediateRemoveFragmentActivity> activityTestRule =
+                new ActivityTestRule<>(ImmediateRemoveFragmentActivity.class, false, false);
+        ImmediateRemoveFragmentActivity activity = activityTestRule.launchActivity(intent);
+
+        Thread.sleep(1000);
+    }
+
+}
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/app/VerticalGridSupportFragmentTest.java b/v17/leanback/tests/java/android/support/v17/leanback/app/VerticalGridSupportFragmentTest.java
new file mode 100644
index 0000000..c17cf66
--- /dev/null
+++ b/v17/leanback/tests/java/android/support/v17/leanback/app/VerticalGridSupportFragmentTest.java
@@ -0,0 +1,78 @@
+/* This file is auto-generated from VerticalGridFragmentTest.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 android.support.v17.leanback.app;
+
+import android.support.v4.app.FragmentActivity;
+import android.support.v4.app.Fragment;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Handler;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.v17.leanback.widget.ArrayObjectAdapter;
+import android.support.v17.leanback.widget.VerticalGridPresenter;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class VerticalGridSupportFragmentTest {
+
+    public static class GridFragment extends VerticalGridSupportFragment {
+        @Override
+        public void onCreate(Bundle savedInstanceState) {
+            super.onCreate(savedInstanceState);
+            if (savedInstanceState == null) {
+                prepareEntranceTransition();
+            }
+            VerticalGridPresenter gridPresenter = new VerticalGridPresenter();
+            gridPresenter.setNumberOfColumns(3);
+            setGridPresenter(gridPresenter);
+            setAdapter(new ArrayObjectAdapter());
+        }
+    }
+
+    public static class ImmediateRemoveFragmentActivity extends FragmentActivity {
+        @Override
+        public void onCreate(Bundle savedInstanceState) {
+            super.onCreate(savedInstanceState);
+            new Handler().postDelayed(new Runnable(){
+                public void run() {
+                    GridFragment f = new GridFragment();
+                    ImmediateRemoveFragmentActivity.this.getSupportFragmentManager().beginTransaction()
+                            .replace(android.R.id.content, f, null).commit();
+                    f.startEntranceTransition();
+                    ImmediateRemoveFragmentActivity.this.getSupportFragmentManager().beginTransaction()
+                            .replace(android.R.id.content, new Fragment(), null).commit();
+                }
+            }, 500);
+        }
+    }
+
+    @Test
+    public void immediateRemoveFragment() throws Throwable {
+        Intent intent = new Intent();
+        ActivityTestRule<ImmediateRemoveFragmentActivity> activityTestRule =
+                new ActivityTestRule<>(ImmediateRemoveFragmentActivity.class, false, false);
+        ImmediateRemoveFragmentActivity activity = activityTestRule.launchActivity(intent);
+
+        Thread.sleep(1000);
+    }
+
+}
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/app/wizard/GuidedDatePickerTest.java b/v17/leanback/tests/java/android/support/v17/leanback/app/wizard/GuidedDatePickerTest.java
index 9cab5a1..e54bfc9 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/app/wizard/GuidedDatePickerTest.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/app/wizard/GuidedDatePickerTest.java
@@ -14,9 +14,14 @@
 
 package android.support.v17.leanback.app.wizard;
 
-import android.app.Instrumentation;
+import static org.junit.Assert.assertTrue;
+
+import android.content.Context;
 import android.content.Intent;
 import android.content.res.Resources;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
 import android.support.v17.leanback.app.GuidedStepFragment;
 import android.support.v17.leanback.test.R;
 import android.support.v17.leanback.widget.GuidanceStylist;
@@ -24,14 +29,16 @@
 import android.support.v17.leanback.widget.GuidedDatePickerAction;
 import android.support.v17.leanback.widget.VerticalGridView;
 import android.support.v17.leanback.widget.picker.DatePicker;
-import android.test.ActivityInstrumentationTestCase2;
 import android.test.suitebuilder.annotation.MediumTest;
 import android.util.Log;
 import android.view.KeyEvent;
-import android.view.View;
-import android.view.ViewGroup;
 import android.widget.LinearLayout;
 
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
 import java.util.Calendar;
@@ -39,43 +46,48 @@
 import java.util.List;
 
 @MediumTest
-public class GuidedDatePickerTest extends
-        ActivityInstrumentationTestCase2<GuidedStepAttributesTestActivity> {
+@RunWith(AndroidJUnit4.class)
+public class GuidedDatePickerTest {
 
     static final long TRANSITION_LENGTH = 1000;
     static long VERTICAL_SCROLL_WAIT = 500;
     static long HORIZONTAL_SCROLL_WAIT = 500;
-    static final long FINAL_WAIT = 3000;
+    static final long FINAL_WAIT = 1000;
 
     static final String TAG = "GuidedDatePickerTest";
 
     private static final int DAY_INDEX = 0;
     private static final int MONTH_INDEX = 1;
     private static final int YEAR_INDEX = 2;
-    Instrumentation mInstrumentation;
+
+    @Rule
+    public ActivityTestRule<GuidedStepAttributesTestActivity> activityTestRule =
+            new ActivityTestRule<>(GuidedStepAttributesTestActivity.class, false, false);
+
     GuidedStepAttributesTestActivity mActivity;
 
-    public GuidedDatePickerTest() {
-        super(GuidedStepAttributesTestActivity.class);
-    }
 
     private void initActivity(Intent intent) {
-
-        setActivityIntent(intent);
-        mActivity = getActivity();
+        mActivity = activityTestRule.launchActivity(intent);
         try {
             Thread.sleep(2000);
         } catch(InterruptedException e) {
             e.printStackTrace();
         }
+
     }
 
-    private void scrollOnField(int field, int[] columnIndices, DatePicker mPickerView,
-                               int SCROLL_DIR) throws Throwable {
+    Context mContext;
+    @Before
+    public void setUp() {
+        mContext = InstrumentationRegistry.getInstrumentation().getTargetContext();;
+    }
 
-        final GuidedStepFragment mFragment = (GuidedStepFragment)
-                mActivity.getGuidedStepTestFragment();
+    public static void sendKey(int keyCode) {
+        InstrumentationRegistry.getInstrumentation().sendKeyDownUpSync(keyCode);
+    }
 
+    private int getColumnIndexForDateField(int field, int[] columnIndices) {
         int mColDayIndex = columnIndices[0];
         int mColMonthIndex = columnIndices[1];
         int mColYearIndex = columnIndices[2];
@@ -90,13 +102,18 @@
             case Calendar.YEAR:
                 columnIndex = mColYearIndex;
         }
+        return columnIndex;
+    }
 
+    private void horizontalScrollToDateField(int field, int[] columnIndices,
+                                             DatePicker pickerView) throws Throwable{
+        int columnIndex = getColumnIndexForDateField(field, columnIndices);
 
-        LinearLayout columnsLayout = (LinearLayout) mPickerView.getChildAt(0);
+        LinearLayout columnsLayout = (LinearLayout) pickerView.getChildAt(0);
 
         int focusedFieldPos = columnsLayout.indexOfChild(columnsLayout.getFocusedChild());
         if (focusedFieldPos == -1) {
-            sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
+            sendKey(KeyEvent.KEYCODE_DPAD_CENTER);
             Thread.sleep(TRANSITION_LENGTH);
         }
         focusedFieldPos = columnsLayout.indexOfChild(columnsLayout.getFocusedChild());
@@ -124,45 +141,67 @@
             horizontalScrollDir = KeyEvent.KEYCODE_DPAD_LEFT;
         }
         for(int i = 0; i < horizontalScrollOffset; i++) {
-            sendKeys(horizontalScrollDir);
+            sendKey(horizontalScrollDir);
             Thread.sleep(HORIZONTAL_SCROLL_WAIT);
         }
 
+    }
+
+    /**
+     * Scrolls vertically all the way up or down (depending on the provided scrollDir parameter)
+     * to fieldValue if it's not equal to -1; otherwise, the scrolling goes all the way to the end.
+     * @param field The date field over which the scrolling is performed
+     * @param fieldValue The field value to scroll to or -1 if the scrolling should go all the way.
+     * @param columnIndices The date field indices corresponding to day, month, and the year
+     * @param pickerView The DatePicker view.
+     * @param scrollDir The direction of scrolling to reach the desired field value.
+     * @throws Throwable
+     */
+    private void verticalScrollToFieldValue(int field, int fieldValue, int[] columnIndices,
+                                                 DatePicker pickerView, int scrollDir)
+            throws Throwable {
+
+        int columnIndex = getColumnIndexForDateField(field, columnIndices);
+        int colDayIndex = columnIndices[0];
+        int colMonthIndex = columnIndices[1];
+        int colYearIndex = columnIndices[2];
+
+        horizontalScrollToDateField(field, columnIndices, pickerView);
 
         Calendar currentActionCal = Calendar.getInstance();
-        currentActionCal.setTimeInMillis(mPickerView.getDate());
+        currentActionCal.setTimeInMillis(pickerView.getDate());
 
         Calendar minCal = Calendar.getInstance();
-        minCal.setTimeInMillis(mPickerView.getMinDate());
+        minCal.setTimeInMillis(pickerView.getMinDate());
 
         Calendar maxCal = Calendar.getInstance();
-        maxCal.setTimeInMillis(mPickerView.getMaxDate());
+        maxCal.setTimeInMillis(pickerView.getMaxDate());
 
 
         int prevColumnVal = -1;
-        int currentColumnVal = mPickerView.getColumnAt(columnIndex).getCurrentValue();
-        while( currentColumnVal != prevColumnVal ){
-            assertTrue(getActivity().getString(R.string.datepicker_test_wrong_day_value),
-                    mPickerView.getColumnAt(mColDayIndex).getCurrentValue() ==
-                            currentActionCal.get(Calendar.DAY_OF_MONTH)
+        int currentColumnVal = pickerView.getColumnAt(columnIndex).getCurrentValue();
+        while( currentColumnVal != prevColumnVal && currentColumnVal != fieldValue){
+            assertTrue(mContext.getString(R.string.datepicker_test_wrong_day_value),
+                    pickerView.getColumnAt(colDayIndex).getCurrentValue()
+                            == currentActionCal.get(Calendar.DAY_OF_MONTH)
             );
-            assertTrue(getActivity().getString(R.string.datepicker_test_wrong_month_value),
-                    mPickerView.getColumnAt(mColMonthIndex).getCurrentValue() ==
-                            currentActionCal.get(Calendar.MONTH)
+            assertTrue(mContext.getString(R.string.datepicker_test_wrong_month_value),
+                    pickerView.getColumnAt(colMonthIndex).getCurrentValue()
+                            == currentActionCal.get(Calendar.MONTH)
             );
-            assertTrue(getActivity().getString(R.string.datepicker_test_wrong_year_value),
-                    mPickerView.getColumnAt(mColYearIndex).getCurrentValue() ==
-                            currentActionCal.get(Calendar.YEAR)
+            assertTrue(mContext.getString(R.string.datepicker_test_wrong_year_value),
+                    pickerView.getColumnAt(colYearIndex).getCurrentValue()
+                            == currentActionCal.get(Calendar.YEAR)
             );
 
-            int offset = SCROLL_DIR == KeyEvent.KEYCODE_DPAD_DOWN ? 1 : -1;
+            int offset = scrollDir == KeyEvent.KEYCODE_DPAD_DOWN ? 1 : -1;
             addDate(currentActionCal, field, offset, minCal, maxCal);
 
-            sendKeys(SCROLL_DIR);
+            sendKey(scrollDir);
             Thread.sleep(VERTICAL_SCROLL_WAIT);
 
             prevColumnVal = currentColumnVal;
-            currentColumnVal = mPickerView.getColumnAt(columnIndex).getCurrentValue();
+            currentColumnVal = pickerView.getColumnAt(columnIndex).getCurrentValue();
         }
     }
 
@@ -196,18 +235,14 @@
         }
     }
 
-    public void testDifferentMonthLengths() throws Throwable {
-
-        mInstrumentation = getInstrumentation();
-        Intent intent = new Intent(mInstrumentation.getContext(),
-                GuidedStepAttributesTestActivity.class);
-        Resources res = mInstrumentation.getContext().getResources();
-
-        final int NUM_DATE_ACTIONS = 1;
+    @Test
+    public void testJanuaryToFebruaryTransitionForLeapYear() throws Throwable {
+        long startTime = System.currentTimeMillis();
+        Intent intent = new Intent();
 
         String title = "Date Picker Transition Test";
         String breadcrumb = "Month Transition Test Demo";
-        String description = "Testing the transition between longer to shorter months";
+        String description = "Testing the transition from Jan to Feb (leap year)";
         GuidanceStylist.Guidance guidance = new GuidanceStylist.Guidance(title, description,
                 breadcrumb, null);
 
@@ -215,13 +250,13 @@
 
         Calendar cal = Calendar.getInstance();
 
-        cal.set(Calendar.YEAR, 2016);
+        cal.set(Calendar.YEAR, 2016);   // 2016 is a leap year
         cal.set(Calendar.MONTH, Calendar.JANUARY);
-        cal.set(Calendar.DAY_OF_MONTH, 30);
+        cal.set(Calendar.DAY_OF_MONTH, cal.getActualMaximum(Calendar.DAY_OF_MONTH));
         Date initialDate = cal.getTime();
 
         GuidedDatePickerAction action = new GuidedDatePickerAction.Builder(
-                mInstrumentation.getContext())
+                mContext)
                 .id(0)
                 .title("Date")
                 .date(initialDate.getTime())
@@ -239,14 +274,337 @@
         DatePicker mPickerView = (DatePicker) mActivity.findViewById(
                 R.id.guidedactions_activator_item);
 
-        final GuidedStepFragment mFragment = (GuidedStepFragment) mActivity.
-                getGuidedStepTestFragment();
-        traverseMonths(mPickerView, (GuidedDatePickerAction) actionList.get(0));
+        verticalScrollToFieldValue(Calendar.MONTH, Calendar.FEBRUARY, new int[] {0, 1, 2},
+                mPickerView, KeyEvent.KEYCODE_DPAD_DOWN);
+        long executionTime = System.currentTimeMillis() - startTime;
+        Log.d(TAG, "testJanuaryToFebruaryTransitionForLeapYear() Execution time: " + executionTime);
+        Thread.sleep(FINAL_WAIT);
+    }
+
+    @Test
+    public void testFebruaryToMarchTransitionForLeapYear() throws Throwable {
+        long startTime = System.currentTimeMillis();
+        Intent intent = new Intent();
+
+        String title = "Date Picker Transition Test";
+        String breadcrumb = "Month Transition Test Demo";
+        String description = "Testing the transition from Feb to Mar (leap year)";
+        GuidanceStylist.Guidance guidance = new GuidanceStylist.Guidance(title, description,
+                breadcrumb, null);
+
+        List<GuidedAction> actionList = new ArrayList<>();
+
+        Calendar cal = Calendar.getInstance();
+
+        cal.set(Calendar.YEAR, 2016);
+        cal.set(Calendar.MONTH, Calendar.FEBRUARY);
+        cal.set(Calendar.DAY_OF_MONTH, cal.getActualMaximum(Calendar.DAY_OF_MONTH));
+        Date initialDate = cal.getTime();
+
+        GuidedDatePickerAction action = new GuidedDatePickerAction.Builder(
+                mContext)
+                .id(0)
+                .title("Date")
+                .date(initialDate.getTime())
+                .datePickerFormat("DMY")
+                .build();
+
+        actionList.add(action);
+
+        GuidedStepAttributesTestFragment.clear();
+        GuidedStepAttributesTestFragment.GUIDANCE = guidance;
+        GuidedStepAttributesTestFragment.ACTION_LIST = actionList;
+
+        initActivity(intent);
+
+        DatePicker mPickerView = (DatePicker) mActivity.findViewById(
+                R.id.guidedactions_activator_item);
+
+        verticalScrollToFieldValue(Calendar.MONTH, Calendar.MARCH, new int[] {0, 1, 2},
+                mPickerView, KeyEvent.KEYCODE_DPAD_DOWN);
+        long executionTime = System.currentTimeMillis() - startTime;
+        Log.d(TAG, "testFebruaryToMarchTransition() Execution time: " + executionTime);
+        Thread.sleep(FINAL_WAIT);
+    }
+
+    @Test
+    public void testJanuaryToFebruaryTransitionForNonLeapYear() throws Throwable {
+        long startTime = System.currentTimeMillis();
+        Intent intent = new Intent();
+
+        String title = "Date Picker Transition Test";
+        String breadcrumb = "Month Transition Test Demo";
+        String description = "Testing the transition from Jan to Feb (nonleap year)";
+        GuidanceStylist.Guidance guidance = new GuidanceStylist.Guidance(title, description,
+                breadcrumb, null);
+
+        List<GuidedAction> actionList = new ArrayList<>();
+
+        Calendar cal = Calendar.getInstance();
+
+        cal.set(Calendar.YEAR, 2017);   // 2017 is a leap year
+        cal.set(Calendar.MONTH, Calendar.JANUARY);
+        cal.set(Calendar.DAY_OF_MONTH, cal.getActualMaximum(Calendar.DAY_OF_MONTH));
+        Date initialDate = cal.getTime();
+
+        GuidedDatePickerAction action = new GuidedDatePickerAction.Builder(
+                mContext)
+                .id(0)
+                .title("Date")
+                .date(initialDate.getTime())
+                .datePickerFormat("DMY")
+                .build();
+
+        actionList.add(action);
+
+        GuidedStepAttributesTestFragment.clear();
+        GuidedStepAttributesTestFragment.GUIDANCE = guidance;
+        GuidedStepAttributesTestFragment.ACTION_LIST = actionList;
+
+        initActivity(intent);
+
+        DatePicker mPickerView = (DatePicker) mActivity.findViewById(
+                R.id.guidedactions_activator_item);
+
+        verticalScrollToFieldValue(Calendar.MONTH, Calendar.FEBRUARY, new int[] {0, 1, 2},
+                mPickerView, KeyEvent.KEYCODE_DPAD_DOWN);
+        long executionTime = System.currentTimeMillis() - startTime;
+        Log.d(TAG, "testJanuaryToFebruaryTransition() Execution time: " + executionTime);
+        Thread.sleep(FINAL_WAIT);
+    }
+
+    @Test
+    public void testFebruaryToMarchTransitionForNonLeapYear() throws Throwable {
+        long startTime = System.currentTimeMillis();
+        Intent intent = new Intent();
+
+        String title = "Date Picker Transition Test";
+        String breadcrumb = "Month Transition Test Demo";
+        String description = "Testing the transition from Feb to Mar (nonleap year)";
+        GuidanceStylist.Guidance guidance = new GuidanceStylist.Guidance(title, description,
+                breadcrumb, null);
+
+        List<GuidedAction> actionList = new ArrayList<>();
+
+        Calendar cal = Calendar.getInstance();
+
+        cal.set(Calendar.YEAR, 2017);
+        cal.set(Calendar.MONTH, Calendar.FEBRUARY);
+        cal.set(Calendar.DAY_OF_MONTH, cal.getActualMaximum(Calendar.DAY_OF_MONTH));
+        Date initialDate = cal.getTime();
+
+        GuidedDatePickerAction action = new GuidedDatePickerAction.Builder(
+                mContext)
+                .id(0)
+                .title("Date")
+                .date(initialDate.getTime())
+                .datePickerFormat("DMY")
+                .build();
+
+        actionList.add(action);
+
+        GuidedStepAttributesTestFragment.clear();
+        GuidedStepAttributesTestFragment.GUIDANCE = guidance;
+        GuidedStepAttributesTestFragment.ACTION_LIST = actionList;
+
+        initActivity(intent);
+
+        DatePicker mPickerView = (DatePicker) mActivity.findViewById(
+                R.id.guidedactions_activator_item);
+
+        verticalScrollToFieldValue(Calendar.MONTH, Calendar.MARCH, new int[] {0, 1, 2},
+                mPickerView, KeyEvent.KEYCODE_DPAD_DOWN);
+        long executionTime = System.currentTimeMillis() - startTime;
+        Log.d(TAG, "testFebruaryToMarchTransition() Execution time: " + executionTime);
+        Thread.sleep(FINAL_WAIT);
+    }
+
+    @Test
+    public void testDecemberToNovemberTransition() throws Throwable {
+        long startTime = System.currentTimeMillis();
+        Intent intent = new Intent();
+
+        String title = "Date Picker Transition Test";
+        String breadcrumb = "Month Transition Test Demo";
+        String description = "Testing the transition from Dec to Nov";
+        GuidanceStylist.Guidance guidance = new GuidanceStylist.Guidance(title, description,
+                breadcrumb, null);
+
+        List<GuidedAction> actionList = new ArrayList<>();
+
+        Calendar cal = Calendar.getInstance();
+
+        cal.set(Calendar.YEAR, 2016);
+        cal.set(Calendar.MONTH, Calendar.DECEMBER);
+        cal.set(Calendar.DAY_OF_MONTH, cal.getActualMaximum(Calendar.DAY_OF_MONTH));
+        Date initialDate = cal.getTime();
+
+        GuidedDatePickerAction action = new GuidedDatePickerAction.Builder(
+                mContext)
+                .id(0)
+                .title("Date")
+                .date(initialDate.getTime())
+                .datePickerFormat("DMY")
+                .build();
+
+        actionList.add(action);
+
+        GuidedStepAttributesTestFragment.clear();
+        GuidedStepAttributesTestFragment.GUIDANCE = guidance;
+        GuidedStepAttributesTestFragment.ACTION_LIST = actionList;
+
+        initActivity(intent);
+
+        DatePicker mPickerView = (DatePicker) mActivity.findViewById(
+                R.id.guidedactions_activator_item);
+
+        verticalScrollToFieldValue(Calendar.MONTH, Calendar.NOVEMBER, new int[] {0, 1, 2},
+                mPickerView, KeyEvent.KEYCODE_DPAD_UP);
+        long executionTime = System.currentTimeMillis() - startTime;
+        Log.d(TAG, "testDecemberToNovember() Execution time: " + executionTime);
+        Thread.sleep(FINAL_WAIT);
+    }
+
+    @Test
+    public void testNovemberToOctoberTransition() throws Throwable {
+        long startTime = System.currentTimeMillis();
+        Intent intent = new Intent();
+
+        String title = "Date Picker Transition Test";
+        String breadcrumb = "Month Transition Test Demo";
+        String description = "Testing the transition from Nov to Oct";
+        GuidanceStylist.Guidance guidance = new GuidanceStylist.Guidance(title, description,
+                breadcrumb, null);
+
+        List<GuidedAction> actionList = new ArrayList<>();
+
+        Calendar cal = Calendar.getInstance();
+
+        cal.set(Calendar.YEAR, 2016);
+        cal.set(Calendar.MONTH, Calendar.NOVEMBER);
+        cal.set(Calendar.DAY_OF_MONTH, cal.getActualMaximum(Calendar.DAY_OF_MONTH));
+        Date initialDate = cal.getTime();
+
+        GuidedDatePickerAction action = new GuidedDatePickerAction.Builder(
+                mContext)
+                .id(0)
+                .title("Date")
+                .date(initialDate.getTime())
+                .datePickerFormat("DMY")
+                .build();
+
+        actionList.add(action);
+
+        GuidedStepAttributesTestFragment.clear();
+        GuidedStepAttributesTestFragment.GUIDANCE = guidance;
+        GuidedStepAttributesTestFragment.ACTION_LIST = actionList;
+
+        initActivity(intent);
+
+        DatePicker mPickerView = (DatePicker) mActivity.findViewById(
+                R.id.guidedactions_activator_item);
+
+        verticalScrollToFieldValue(Calendar.MONTH, Calendar.OCTOBER, new int[] {0, 1, 2},
+                mPickerView, KeyEvent.KEYCODE_DPAD_UP);
+        long executionTime = System.currentTimeMillis() - startTime;
+        Log.d(TAG, "testNovemberToOctober() Execution time: " + executionTime);
+        Thread.sleep(FINAL_WAIT);
+    }
+
+    @Test
+    public void testLeapToNonLeapYearTransition() throws Throwable {
+        long startTime = System.currentTimeMillis();
+        Intent intent = new Intent();
+
+        String title = "Date Picker Transition Test";
+        String breadcrumb = "Leap Year Transition Test Demo";
+        String description = "Testing Feb transition from leap to nonlneap year";
+        GuidanceStylist.Guidance guidance = new GuidanceStylist.Guidance(title, description,
+                breadcrumb, null);
+
+        List<GuidedAction> actionList = new ArrayList<>();
+
+        Calendar cal = Calendar.getInstance();
+
+        cal.set(Calendar.YEAR, 2016);   // 2016 is a leap year
+        cal.set(Calendar.MONTH, Calendar.FEBRUARY);
+        cal.set(Calendar.DAY_OF_MONTH, cal.getActualMaximum(Calendar.DAY_OF_MONTH));
+        Date initialDate = cal.getTime();
+
+        GuidedDatePickerAction action = new GuidedDatePickerAction.Builder(
+                mContext)
+                .id(0)
+                .title("Date")
+                .date(initialDate.getTime())
+                .datePickerFormat("DMY")
+                .build();
+
+        actionList.add(action);
+
+        GuidedStepAttributesTestFragment.clear();
+        GuidedStepAttributesTestFragment.GUIDANCE = guidance;
+        GuidedStepAttributesTestFragment.ACTION_LIST = actionList;
+
+        initActivity(intent);
+
+        DatePicker mPickerView = (DatePicker) mActivity.findViewById(
+                R.id.guidedactions_activator_item);
+
+        verticalScrollToFieldValue(Calendar.YEAR, 2017, new int[] {0, 1, 2},
+                mPickerView, KeyEvent.KEYCODE_DPAD_DOWN);
+        long executionTime = System.currentTimeMillis() - startTime;
+        Log.d(TAG, "testLeapToNonLeapYearTransition() Execution time: " + executionTime);
+        Thread.sleep(FINAL_WAIT);
+    }
+
+    @Test
+    public void testNonLeapToLeapYearTransition() throws Throwable {
+        long startTime = System.currentTimeMillis();
+        Intent intent = new Intent();
+
+        String title = "Date Picker Transition Test";
+        String breadcrumb = "Leap Year Transition Test Demo";
+        String description = "Testing Feb transition from nonleap to leap year";
+        GuidanceStylist.Guidance guidance = new GuidanceStylist.Guidance(title, description,
+                breadcrumb, null);
+
+        List<GuidedAction> actionList = new ArrayList<>();
+
+        Calendar cal = Calendar.getInstance();
+
+        cal.set(Calendar.YEAR, 2017);   // 2017 is a non-leap year
+        cal.set(Calendar.MONTH, Calendar.FEBRUARY);
+        cal.set(Calendar.DAY_OF_MONTH, cal.getActualMaximum(Calendar.DAY_OF_MONTH));
+        Date initialDate = cal.getTime();
+
+        GuidedDatePickerAction action = new GuidedDatePickerAction.Builder(
+                mContext)
+                .id(0)
+                .title("Date")
+                .date(initialDate.getTime())
+                .datePickerFormat("DMY")
+                .build();
+
+        actionList.add(action);
+
+        GuidedStepAttributesTestFragment.clear();
+        GuidedStepAttributesTestFragment.GUIDANCE = guidance;
+        GuidedStepAttributesTestFragment.ACTION_LIST = actionList;
+
+        initActivity(intent);
+
+        DatePicker mPickerView = (DatePicker) mActivity.findViewById(
+                R.id.guidedactions_activator_item);
+
+        verticalScrollToFieldValue(Calendar.YEAR, 2016, new int[] {0, 1, 2},
+                mPickerView, KeyEvent.KEYCODE_DPAD_UP);
+        long executionTime = System.currentTimeMillis() - startTime;
+        Log.d(TAG, "testNonLeapToLeapYearTransition() Execution time: " + executionTime);
         Thread.sleep(FINAL_WAIT);
     }
 
     private void traverseMonths(DatePicker mPickerView, GuidedDatePickerAction dateAction)
-            throws Throwable{
+            throws Throwable {
 
         final GuidedStepFragment mFragment = (GuidedStepFragment)
                 mActivity.getGuidedStepTestFragment();
@@ -254,7 +612,7 @@
         Calendar currentActionCal = Calendar.getInstance();
         currentActionCal.setTimeInMillis(dateAction.getDate());
 
-        sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
+        sendKey(KeyEvent.KEYCODE_DPAD_CENTER);
         Thread.sleep(TRANSITION_LENGTH);
 
         int prevMonth = -1;
@@ -264,7 +622,7 @@
             int currentDayOfMonth = mPickerView.getColumnAt(DAY_INDEX).getCurrentValue();
             // scroll down the days till reaching the last day of month
             while (currentDayOfMonth != prevDayOfMonth) {
-                sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+                sendKey(KeyEvent.KEYCODE_DPAD_DOWN);
                 Thread.sleep(VERTICAL_SCROLL_WAIT);
                 prevDayOfMonth = currentDayOfMonth;
                 currentDayOfMonth = mPickerView.getColumnAt(DAY_INDEX).getCurrentValue();
@@ -272,10 +630,10 @@
             int oldDayValue = mPickerView.getColumnAt(DAY_INDEX).getCurrentValue();
             int oldMonthValue = mPickerView.getColumnAt(MONTH_INDEX).getCurrentValue();
             // increment the month
-            sendKeys(KeyEvent.KEYCODE_DPAD_RIGHT);
+            sendKey(KeyEvent.KEYCODE_DPAD_RIGHT);
             Thread.sleep(VERTICAL_SCROLL_WAIT);
 
-            sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+            sendKey(KeyEvent.KEYCODE_DPAD_DOWN);
             Thread.sleep(TRANSITION_LENGTH);
 
             int newDayValue = mPickerView.getColumnAt(DAY_INDEX).getCurrentValue();
@@ -283,7 +641,7 @@
             verifyMonthTransition(currentActionCal,
                     oldDayValue, oldMonthValue, newDayValue, newMonthValue);
 
-            sendKeys(KeyEvent.KEYCODE_DPAD_LEFT);
+            sendKey(KeyEvent.KEYCODE_DPAD_LEFT);
             Thread.sleep(TRANSITION_LENGTH);
             prevMonth = currentMonth;
             currentMonth = newMonthValue;
@@ -291,6 +649,7 @@
 
     }
 
+
     private void verifyMonthTransition(Calendar currentCal, int oldDayValue, int oldMonthValue,
                                        int newDayValue, int newMonthValue) {
 
@@ -302,25 +661,86 @@
         int expectedOldDayValue = currentCal.getActualMaximum(Calendar.DAY_OF_MONTH);
         currentCal.set(Calendar.MONTH, newMonthValue);
         int numDaysInNewMonth = currentCal.getActualMaximum(Calendar.DAY_OF_MONTH);
-        int expectedNewDayValue = (expectedOldDayValue <= numDaysInNewMonth) ?
-                expectedOldDayValue : numDaysInNewMonth;
+        int expectedNewDayValue = (expectedOldDayValue <= numDaysInNewMonth)
+                ? expectedOldDayValue : numDaysInNewMonth;
 
-        assertTrue(getActivity().getString(
+        assertTrue(mContext.getString(
                 R.string.datepicker_test_transition_error1, oldMonthValue),
                 oldDayValue == expectedOldDayValue
         );
-        assertTrue(getActivity().getString(
+        assertTrue(mContext.getString(
                 R.string.datepicker_test_transition_error2, newDayValue, newMonthValue),
                 newDayValue == expectedNewDayValue
         );
     }
 
-    public void testDateRanges() throws Throwable {
+    @Test
+    public void testDateRangesMDYFormat() throws Throwable {
 
-        mInstrumentation = getInstrumentation();
-        Intent intent = new Intent(mInstrumentation.getContext(),
-                GuidedStepAttributesTestActivity.class);
-        Resources res = mInstrumentation.getContext().getResources();
+        long startTime = System.currentTimeMillis();
+
+        GuidedDatePickerAction[] datePickerActions = setupDateActionsForMinAndMaxRangeTests();
+
+        scrollToMinAndMaxDates(new int[] {1, 0, 2}, datePickerActions[0]);
+        long executionTime = System.currentTimeMillis() - startTime;
+        Log.d(TAG, "testDateRangesMDYFormat() Execution time: " + executionTime);
+        Thread.sleep(FINAL_WAIT);
+    }
+
+    public void testDateRangesDMYFormat() throws Throwable {
+
+        long startTime = System.currentTimeMillis();
+
+        GuidedDatePickerAction[] datePickerActions = setupDateActionsForMinAndMaxRangeTests();
+        Log.d(TAG, "setup dateactions complete!");
+        scrollToMinAndMaxDates(new int[] {0, 1, 2}, datePickerActions[1]);
+        long executionTime = System.currentTimeMillis() - startTime;
+        Log.d(TAG, "testDateRangesDMYFormat() Execution time: " + executionTime);
+        Thread.sleep(FINAL_WAIT);
+    }
+
+    @Test
+    public void testDateRangesWithYearEqual() throws Throwable {
+
+        long startTime = System.currentTimeMillis();
+
+        GuidedDatePickerAction[] datePickerActions = setupDateActionsForMinAndMaxRangeTests();
+
+        scrollToMinAndMaxDates(new int[] {0, 1, 2}, datePickerActions[2]);
+        long executionTime = System.currentTimeMillis() - startTime;
+        Log.d(TAG, "testDateRangesWithYearEqual() Execution time: " + executionTime);
+        Thread.sleep(FINAL_WAIT);
+    }
+
+    @Test
+    public void testDateRangesWithMonthAndYearEqual() throws Throwable {
+
+        long startTime = System.currentTimeMillis();
+
+        GuidedDatePickerAction[] datePickerActions = setupDateActionsForMinAndMaxRangeTests();
+
+        scrollToMinAndMaxDates(new int[] {0, 1, 2}, datePickerActions[3]);
+        long executionTime = System.currentTimeMillis() - startTime;
+        Log.d(TAG, "testDateRangesWithMonthAndYearEqual() Execution time: " + executionTime);
+        Thread.sleep(FINAL_WAIT);
+    }
+
+    @Test
+    public void testDateRangesWithAllFieldsEqual() throws Throwable {
+
+        long startTime = System.currentTimeMillis();
+
+        GuidedDatePickerAction[] datePickerActions = setupDateActionsForMinAndMaxRangeTests();
+
+        scrollToMinAndMaxDates(new int[] {0, 1, 2}, datePickerActions[4]);
+        long executionTime = System.currentTimeMillis() - startTime;
+        Log.d(TAG, "testDateRangesWithAllFieldsEqual() Execution time: " + executionTime);
+        Thread.sleep(FINAL_WAIT);
+    }
+
+    private GuidedDatePickerAction[] setupDateActionsForMinAndMaxRangeTests() {
+        Intent intent = new Intent();
+        Resources res = mContext.getResources();
 
         SimpleDateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy");
 
@@ -349,7 +769,7 @@
 
         // testing different date formats and the correctness of range changes as we scroll
         GuidedDatePickerAction dateAction1 = new GuidedDatePickerAction.Builder(
-                mInstrumentation.getContext())
+                mContext)
                 .id(0)
                 .title(res.getString(R.string.datepicker_with_range_title,
                         dateFormat.format(minCal.getTime()),
@@ -362,7 +782,7 @@
                 .build();
 
         GuidedDatePickerAction dateAction2 = new GuidedDatePickerAction.Builder(
-                mInstrumentation.getContext())
+                mContext)
                 .id(1)
                 .title(res.getString(R.string.datepicker_with_range_title,
                         dateFormat.format(minCal.getTimeInMillis()),
@@ -382,7 +802,7 @@
         maxCal.set(Calendar.MONTH, maxMonth);
 
         GuidedDatePickerAction dateAction3 = new GuidedDatePickerAction.Builder(
-                mInstrumentation.getContext())
+                mContext)
                 .id(2)
                 .title(res.getString(R.string.datepicker_with_range_title,
                         dateFormat.format(minCal.getTimeInMillis()),
@@ -403,7 +823,7 @@
         maxCal.set(Calendar.DAY_OF_MONTH, maxDay);
 
         GuidedDatePickerAction dateAction4 = new GuidedDatePickerAction.Builder(
-                mInstrumentation.getContext())
+                mContext)
                 .id(3)
                 .title(res.getString(R.string.datepicker_with_range_title,
                         dateFormat.format(minCal.getTimeInMillis()),
@@ -420,7 +840,7 @@
         minCal.set(Calendar.DAY_OF_MONTH, maxCal.get(Calendar.DAY_OF_MONTH));
 
         GuidedDatePickerAction dateAction5 = new GuidedDatePickerAction.Builder(
-                mInstrumentation.getContext())
+                mContext)
                 .id(4)
                 .title(res.getString(R.string.datepicker_with_range_title,
                         dateFormat.format(minCal.getTimeInMillis()),
@@ -443,17 +863,8 @@
         GuidedStepAttributesTestFragment.ACTION_LIST = actionList;
 
         initActivity(intent);
-
-        final GuidedStepFragment mFragment = (GuidedStepFragment) mActivity.
-                getGuidedStepTestFragment();
-
-        scrollToMinAndMaxDates(new int[] {1, 0, 2}, dateAction1);
-        scrollToMinAndMaxDates(new int[] {0, 1, 2}, dateAction2);
-        scrollToMinAndMaxDates(new int[] {0, 1, 2}, dateAction3);
-        scrollToMinAndMaxDates(new int[] {0, 1, 2}, dateAction4);
-        scrollToMinAndMaxDates(new int[] {0, 1, 2}, dateAction5);
-
-        Thread.sleep(FINAL_WAIT);
+        return new GuidedDatePickerAction[] {dateAction1, dateAction2, dateAction3, dateAction4,
+                dateAction5};
     }
 
     private void scrollToMinAndMaxDates(int[] columnIndices, GuidedDatePickerAction dateAction)
@@ -475,12 +886,12 @@
             verticalScrollDir = KeyEvent.KEYCODE_DPAD_UP;
         }
         for(int i = 0; i < verticalScrollOffset; i++) {
-            sendKeys(verticalScrollDir);
+            sendKey(verticalScrollDir);
             Thread.sleep(TRANSITION_LENGTH);
         }
 
-        assertTrue("The wrong action was selected!", mFragment.getSelectedActionPosition() ==
-                dateAction.getId());
+        assertTrue("The wrong action was selected!", mFragment.getSelectedActionPosition()
+                == dateAction.getId());
         DatePicker mPickerView = (DatePicker) mFragment.getActionItemView((int) dateAction.getId())
                 .findViewById(R.id.guidedactions_activator_item);
 
@@ -490,29 +901,35 @@
 
         // scrolling to the minimum date
 
-        scrollOnField(Calendar.YEAR, columnIndices, mPickerView, KeyEvent.KEYCODE_DPAD_UP);
+        verticalScrollToFieldValue(Calendar.YEAR, -1, columnIndices, mPickerView,
+                KeyEvent.KEYCODE_DPAD_UP);
         dateAction.setDate(mPickerView.getDate());
 
-        scrollOnField(Calendar.MONTH, columnIndices, mPickerView, KeyEvent.KEYCODE_DPAD_UP);
+        verticalScrollToFieldValue(Calendar.MONTH, -1, columnIndices, mPickerView,
+                KeyEvent.KEYCODE_DPAD_UP);
         dateAction.setDate(mPickerView.getDate());
 
-        scrollOnField(Calendar.DAY_OF_MONTH, columnIndices, mPickerView, KeyEvent.KEYCODE_DPAD_UP);
+        verticalScrollToFieldValue(Calendar.DAY_OF_MONTH, -1, columnIndices, mPickerView,
+                KeyEvent.KEYCODE_DPAD_UP);
         dateAction.setDate(mPickerView.getDate());
 
         Thread.sleep(VERTICAL_SCROLL_WAIT);
 
         // now scrolling to the maximum date
 
-        scrollOnField(Calendar.YEAR, columnIndices, mPickerView, KeyEvent.KEYCODE_DPAD_DOWN);
+        verticalScrollToFieldValue(Calendar.YEAR, -1, columnIndices, mPickerView,
+                KeyEvent.KEYCODE_DPAD_DOWN);
         dateAction.setDate(mPickerView.getDate());
 
-        scrollOnField(Calendar.MONTH, columnIndices, mPickerView, KeyEvent.KEYCODE_DPAD_DOWN);
+        verticalScrollToFieldValue(Calendar.MONTH, -1, columnIndices, mPickerView,
+                KeyEvent.KEYCODE_DPAD_DOWN);
         dateAction.setDate(mPickerView.getDate());
 
-        scrollOnField(Calendar.DAY_OF_MONTH, columnIndices, mPickerView, KeyEvent.KEYCODE_DPAD_DOWN);
+        verticalScrollToFieldValue(Calendar.DAY_OF_MONTH, -1, columnIndices, mPickerView,
+                KeyEvent.KEYCODE_DPAD_DOWN);
         dateAction.setDate(mPickerView.getDate());
 
-        sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
+        sendKey(KeyEvent.KEYCODE_DPAD_CENTER);
         Thread.sleep(TRANSITION_LENGTH);
     }
 
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/app/wizard/GuidedStepAttributesTest.java b/v17/leanback/tests/java/android/support/v17/leanback/app/wizard/GuidedStepAttributesTest.java
index 8387dbd..5af0202 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/app/wizard/GuidedStepAttributesTest.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/app/wizard/GuidedStepAttributesTest.java
@@ -14,41 +14,46 @@
 
 package android.support.v17.leanback.app.wizard;
 
-import android.app.Instrumentation;
+import static org.junit.Assert.assertTrue;
+
+import android.content.Context;
 import android.content.Intent;
 import android.content.res.Resources;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
 import android.support.v17.leanback.app.GuidedStepFragment;
 import android.support.v17.leanback.test.R;
 import android.support.v17.leanback.widget.GuidanceStylist;
 import android.support.v17.leanback.widget.GuidedAction;
-import android.test.ActivityInstrumentationTestCase2;
 import android.test.suitebuilder.annotation.MediumTest;
-import android.util.Log;
 import android.view.KeyEvent;
 
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 
 @MediumTest
-public class GuidedStepAttributesTest extends
-        ActivityInstrumentationTestCase2<GuidedStepAttributesTestActivity> {
+@RunWith(AndroidJUnit4.class)
+public class GuidedStepAttributesTest {
     static final long TRANSITION_LENGTH = 1000;
 
     static final String TAG = "GuidedStepAttributesTest";
 
-    Instrumentation mInstrumentation;
+    @Rule
+    public ActivityTestRule<GuidedStepAttributesTestActivity> activityTestRule =
+            new ActivityTestRule<>(GuidedStepAttributesTestActivity.class, false, false);
+
     GuidedStepAttributesTestActivity mActivity;
 
-    public GuidedStepAttributesTest() {
-        super(GuidedStepAttributesTestActivity.class);
-    }
-
     private void initActivity(Intent intent) {
-
-        setActivityIntent(intent);
-        mActivity = getActivity();
+        mActivity = activityTestRule.launchActivity(intent);
         try {
             Thread.sleep(2000);
         } catch(InterruptedException e) {
@@ -56,12 +61,21 @@
         }
     }
 
+    Context mContext;
+    @Before
+    public void setUp() {
+        mContext = InstrumentationRegistry.getInstrumentation().getTargetContext();;
+    }
+
+    public static void sendKey(int keyCode) {
+        InstrumentationRegistry.getInstrumentation().sendKeyDownUpSync(keyCode);
+    }
+
+    @Test
     public void testFocusDisabledOnActions() throws Throwable {
 
-        mInstrumentation = getInstrumentation();
-        Intent intent = new Intent(mInstrumentation.getContext(),
-                GuidedStepAttributesTestActivity.class);
-        Resources res = mInstrumentation.getContext().getResources();
+        Intent intent = new Intent();
+        Resources res = mContext.getResources();
 
         final int NUM_SEARCH_ACTIONS = 10;
         final List<Integer> ACTIONS_WITH_DISABLED_FOCUS = new ArrayList<>(
@@ -87,7 +101,7 @@
 
         List<GuidedAction> actionList = new ArrayList<>();
         for (int i = 0; i < NUM_SEARCH_ACTIONS; i++ ) {
-            actionList.add(new GuidedAction.Builder(mInstrumentation.getContext())
+            actionList.add(new GuidedAction.Builder(mContext)
                     .id(ACTION_ID_SEARCH)
                     .title(res.getString(R.string.search) + "" + i)
                     .description(res.getString(R.string.search_description) + i)
@@ -113,7 +127,7 @@
                     actionList.get(lastSelectedActionId).getTitle()),
                     lastSelectedActionId == EXPECTED_ACTIONS_ID_AFTER_EACH_SELECT.get(selectIndex));
             selectIndex++;
-            sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+            sendKey(KeyEvent.KEYCODE_DPAD_DOWN);
             prevSelectedActionPosition = nextSelectedActionPosition;
             nextSelectedActionPosition = mFragment.getSelectedActionPosition();
             Thread.sleep(TRANSITION_LENGTH);
@@ -126,7 +140,7 @@
                     actionList.get(lastSelectedActionId).getTitle()),
                     lastSelectedActionId == EXPECTED_ACTIONS_ID_AFTER_EACH_SELECT.get(selectIndex));
             selectIndex++;
-            sendKeys(KeyEvent.KEYCODE_DPAD_UP);
+            sendKey(KeyEvent.KEYCODE_DPAD_UP);
             prevSelectedActionPosition = nextSelectedActionPosition;
             nextSelectedActionPosition = mFragment.getSelectedActionPosition();
             Thread.sleep(TRANSITION_LENGTH);
@@ -148,12 +162,16 @@
         }
     };
 
+    /**
+     * Creates a number of enabled and disable actions and tests whether the flag is correctly set
+     * by clicking on each individual action and checking whether the click event is triggered.
+     * @throws Throwable
+     */
+    @Test
     public void testDisabledActions() throws Throwable {
 
-        mInstrumentation = getInstrumentation();
-        Intent intent = new Intent(mInstrumentation.getContext(),
-                GuidedStepAttributesTestActivity.class);
-        Resources res = mInstrumentation.getContext().getResources();
+        Intent intent = new Intent();
+        Resources res = mContext.getResources();
 
         final int NUM_SEARCH_ACTIONS = 10;
         final List<Integer> DISABLED_ACTIONS = new ArrayList<>(
@@ -193,7 +211,7 @@
                 breadcrumb, null);
 
         List<GuidedAction> actionList = new ArrayList<>();
-        actionList.add(new GuidedAction.Builder(mInstrumentation.getContext())
+        actionList.add(new GuidedAction.Builder(mContext)
                 .id(ACTION_ID_REVERT_BUTTON)
                 .title(res.getString(R.string.invert_title))
                 .description(res.getString(R.string.revert_description))
@@ -201,7 +219,7 @@
         );
 
         for (int i = 0; i < NUM_SEARCH_ACTIONS; i++ ) {
-            actionList.add(new GuidedAction.Builder(mInstrumentation.getContext())
+            actionList.add(new GuidedAction.Builder(mContext)
                     .id(ACTION_ID_SEARCH_END++)
                     .title(res.getString(R.string.search) + "" + i)
                     .description(res.getString(R.string.search_description) + i)
@@ -223,32 +241,102 @@
 
         initActivity(intent);
 
+        examineEnabledAndDisabledActions(actionList, CLICK_SEQUENCE, EXPECTED_FOCUSED_SEQUENCE,
+                EXPECTED_CLICKED_SEQUENCE);
+    }
+
+    /**
+     * Toggles Enabled flags in oll the actions of the prior test, and tests whether they are
+     * correctly reverted.
+     */
+    @Test
+    public void testToggleEnabledFlags() throws Throwable {
+
+        Intent intent = new Intent();
+        Resources res = mContext.getResources();
+
+        final int NUM_SEARCH_ACTIONS = 10;
+        final List<Integer> DISABLED_ACTIONS = new ArrayList<>(
+                Arrays.asList(1, 3, 5, 7));
+        final int ACTION_ID_REVERT_BUTTON = 0;
+        final int ACTION_ID_SEARCH_BEGIN = ACTION_ID_REVERT_BUTTON + 1;
+        int ACTION_ID_SEARCH_END = ACTION_ID_SEARCH_BEGIN;
+
+        // sequence of clicked actions simulated in the test
+        List<Integer> CLICK_SEQUENCE = new ArrayList<>();
+
+        // Expected Clicked sequence can be different from focused ones since some of the actions
+        // are disabled hence not clickable
+        List<Integer> EXPECTED_FOCUSED_SEQUENCE = new ArrayList<>();
+        List<Integer> EXPECTED_CLICKED_SEQUENCE = new ArrayList<>();
+        // Expected actions state according to list of DISABLED_ACTIONS: false for disabled actions
+        List<Boolean> EXPECTED_ACTIONS_STATE = new ArrayList<>(
+                Arrays.asList(new Boolean[NUM_SEARCH_ACTIONS])
+        );
+        Collections.fill(EXPECTED_ACTIONS_STATE, Boolean.FALSE);
+
+        for(int i = 0; i < NUM_SEARCH_ACTIONS; i++) {
+            CLICK_SEQUENCE.add(i + 1);
+        }
+        for(int clickedActionId : CLICK_SEQUENCE) {
+            EXPECTED_FOCUSED_SEQUENCE.add(clickedActionId);
+            if (DISABLED_ACTIONS.contains(clickedActionId - 1))
+                EXPECTED_CLICKED_SEQUENCE.add(clickedActionId);
+            else
+                EXPECTED_CLICKED_SEQUENCE.add(-1);
+        }
+
+        String title = "Guided Actions Enabled Test";
+        String breadcrumb = "Toggle Enabled Flag Test Demo";
+        String description = "";
+        GuidanceStylist.Guidance guidance = new GuidanceStylist.Guidance(title, description,
+                breadcrumb, null);
+
+        List<GuidedAction> actionList = new ArrayList<>();
+        actionList.add(new GuidedAction.Builder(mContext)
+                .id(ACTION_ID_REVERT_BUTTON)
+                .title(res.getString(R.string.invert_title))
+                .description(res.getString(R.string.revert_description))
+                .build()
+        );
+
+        for (int i = 0; i < NUM_SEARCH_ACTIONS; i++ ) {
+            actionList.add(new GuidedAction.Builder(mContext)
+                    .id(ACTION_ID_SEARCH_END++)
+                    .title(res.getString(R.string.search) + "" + i)
+                    .description(res.getString(R.string.search_description) + i)
+                    .build()
+            );
+        }
+        for(int action_id : DISABLED_ACTIONS ) {
+            if ( action_id >= 0 && action_id < NUM_SEARCH_ACTIONS ) {
+                actionList.get(action_id + 1).setEnabled(false);
+                EXPECTED_ACTIONS_STATE.set(action_id, Boolean.TRUE);
+            }
+        }
+
+        GuidedStepAttributesTestFragment.clear();
+        GuidedStepAttributesTestFragment.GUIDANCE = guidance;
+        GuidedStepAttributesTestFragment.ACTION_LIST = actionList;
+        GuidedStepAttributesTestFragment.setActionClickCallback(ACTION_ID_REVERT_BUTTON,
+                sRevertCallback);
+
+        initActivity(intent);
+
         final GuidedStepFragment mFragment = (GuidedStepFragment)
                 mActivity.getGuidedStepTestFragment();
 
-        examineEnabledAndDisabledActions(actionList, CLICK_SEQUENCE, EXPECTED_FOCUSED_SEQUENCE,
-                EXPECTED_CLICKED_SEQUENCE);
-        // now toggling all enabled/disabled actions to disabled/enabled and running the test again
-        Log.d(TAG, "Toggling actions...");
-        runTestOnUiThread(new Runnable() {
+        mActivity.runOnUiThread(new Runnable() {
             @Override
             public void run() {
                 mFragment.setSelectedActionPosition(0);
             }
         });
         Thread.sleep(TRANSITION_LENGTH);
-        sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
+        sendKey(KeyEvent.KEYCODE_DPAD_CENTER);
         Thread.sleep(TRANSITION_LENGTH);
-        for(int i = 0; i < EXPECTED_CLICKED_SEQUENCE.size(); i++) {
-            if (EXPECTED_CLICKED_SEQUENCE.get(i) == -1)
-                EXPECTED_CLICKED_SEQUENCE.set(i, CLICK_SEQUENCE.get(i));
-            else
-                EXPECTED_CLICKED_SEQUENCE.set(i, -1);
-        }
-
         examineEnabledAndDisabledActions(actionList, CLICK_SEQUENCE, EXPECTED_FOCUSED_SEQUENCE,
                 EXPECTED_CLICKED_SEQUENCE);
-
     }
 
     private void examineEnabledAndDisabledActions(
@@ -264,7 +352,7 @@
             GuidedStepAttributesTestFragment.LAST_SELECTED_ACTION_ID =
                     GuidedStepAttributesTestFragment.LAST_CLICKED_ACTION_ID = -1;
             final int id = CLICK_SEQUENCE.get(i);
-            runTestOnUiThread(new Runnable() {
+            mActivity.runOnUiThread(new Runnable() {
                 @Override
                 public void run() {
                     mFragment.setSelectedActionPosition(id);
@@ -272,34 +360,33 @@
             });
             Thread.sleep(TRANSITION_LENGTH);
 
-            sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
+            sendKey(KeyEvent.KEYCODE_DPAD_CENTER);
             Thread.sleep(TRANSITION_LENGTH);
 
-            assertTrue(mInstrumentation.getContext().getResources().getString(
+            assertTrue(mContext.getResources().getString(
                     R.string.enabled_test_wrong_focus_error_message),
-                    GuidedStepAttributesTestFragment.LAST_SELECTED_ACTION_ID ==
-                            EXPECTED_FOCUSED_SEQUENCE.get(i)
+                    GuidedStepAttributesTestFragment.LAST_SELECTED_ACTION_ID
+                            == EXPECTED_FOCUSED_SEQUENCE.get(i)
             );
-            assertTrue(mInstrumentation.getContext().getResources().getString(
+            assertTrue(mContext.getResources().getString(
                     R.string.enabled_test_wrong_click_error_message),
-                    GuidedStepAttributesTestFragment.LAST_CLICKED_ACTION_ID ==
-                            EXPECTED_CLICKED_SEQUENCE.get(i)
+                    GuidedStepAttributesTestFragment.LAST_CLICKED_ACTION_ID
+                            == EXPECTED_CLICKED_SEQUENCE.get(i)
             );
-            assertTrue(mInstrumentation.getContext().getResources().getString(
+            assertTrue(mContext.getResources().getString(
                     R.string.enabled_test_wrong_flag_error_message),
-                    (GuidedStepAttributesTestFragment.LAST_CLICKED_ACTION_ID == -1) ?
-                            !actionList.get(id).isEnabled() :
-                            actionList.get(id).isEnabled()
+                    (GuidedStepAttributesTestFragment.LAST_CLICKED_ACTION_ID == -1)
+                            ? !actionList.get(id).isEnabled()
+                            : actionList.get(id).isEnabled()
             );
         }
     }
 
+    @Test
     public void testCheckedActions() throws Throwable {
 
-        mInstrumentation = getInstrumentation();
-        Intent intent = new Intent(mInstrumentation.getContext(),
-                GuidedStepAttributesTestActivity.class);
-        Resources res = mInstrumentation.getContext().getResources();
+        Intent intent = new Intent();
+        Resources res = mContext.getResources();
 
         final int NUM_RADIO_ACTIONS = 3;
         final int NUM_CHECK_BOX_ACTIONS = 3;
@@ -331,7 +418,7 @@
                 breadcrumb, null);
 
         List<GuidedAction> actionList = new ArrayList<>();
-        actionList.add(new GuidedAction.Builder(mInstrumentation.getContext())
+        actionList.add(new GuidedAction.Builder(mContext)
                 .title(res.getString(R.string.radio_actions_info_title))
                 .description(res.getString(R.string.radio_actions_info_desc))
                 .infoOnly(true)
@@ -342,7 +429,7 @@
 
         int firstRadioActionIndex = actionList.size();
         for(int i = 0; i < NUM_RADIO_ACTIONS; i++) {
-            actionList.add(new GuidedAction.Builder(mInstrumentation.getContext())
+            actionList.add(new GuidedAction.Builder(mContext)
                     .title(res.getString(R.string.checkbox_title) + i)
                     .description(res.getString(R.string.checkbox_desc) + i)
                     .checkSetId(GuidedAction.DEFAULT_CHECK_SET_ID)
@@ -352,7 +439,7 @@
                 actionList.get(firstRadioActionIndex + i).setChecked(true);
         }
 
-        actionList.add(new GuidedAction.Builder(mInstrumentation.getContext())
+        actionList.add(new GuidedAction.Builder(mContext)
                 .title(res.getString(R.string.checkbox_actions_info_title))
                 .description(res.getString(R.string.checkbox_actions_info_desc))
                 .infoOnly(true)
@@ -362,7 +449,7 @@
         );
         int firstCheckBoxActionIndex = actionList.size();
         for(int i = 0; i < NUM_CHECK_BOX_ACTIONS; i++) {
-            actionList.add(new GuidedAction.Builder(mInstrumentation.getContext())
+            actionList.add(new GuidedAction.Builder(mContext)
                     .title(res.getString(R.string.checkbox_title) + i)
                     .description(res.getString(R.string.checkbox_desc) + i)
                     .checkSetId(GuidedAction.CHECKBOX_CHECK_SET_ID)
@@ -404,11 +491,9 @@
         for(GuidedAction checkAction : actionList) {
             if (checkAction.infoOnly())
                 continue;
-            assertTrue("Action " + actionIndex + " is " +
-                            (!checkAction.isChecked() ? "un-" : "") +
-                    "checked while it shouldn't be!",
-                    checkAction.isChecked() ==
-                            EXPECTED_ACTIONS_STATE_AFTER_EACH_CLICK.get(actionIndex));
+            assertTrue("Action " + actionIndex + " is " + (!checkAction.isChecked() ? "un-" : "")
+                    + "checked while it shouldn't be!", checkAction.isChecked()
+                            == EXPECTED_ACTIONS_STATE_AFTER_EACH_CLICK.get(actionIndex));
             actionIndex++;
         }
     }
@@ -424,7 +509,7 @@
         final int firstCheckBoxActionIndex = firstRadioActionIndex + NUM_RADIO_ACTIONS + 1;
         for(int actionId = 0; actionId < NUM_RADIO_ACTIONS; actionId++) {
             final int id = actionId;
-            runTestOnUiThread(new Runnable() {
+            mActivity.runOnUiThread(new Runnable() {
                 @Override
                 public void run() {
                     guidedStepCheckedFragment
@@ -433,7 +518,7 @@
             });
             Thread.sleep(TRANSITION_LENGTH);
 
-            sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
+            sendKey(KeyEvent.KEYCODE_DPAD_CENTER);
             Thread.sleep(TRANSITION_LENGTH);
             updateExpectedActionsStateAfterClick(EXPECTED_ACTIONS_STATE_AFTER_EACH_CLICK,
                     NUM_RADIO_ACTIONS, NUM_CHECK_BOX_ACTIONS, actionId);
@@ -442,7 +527,7 @@
 
         for(int actionId = 0; actionId < NUM_CHECK_BOX_ACTIONS; actionId++) {
             final int id = actionId;
-            runTestOnUiThread(new Runnable() {
+            mActivity.runOnUiThread(new Runnable() {
                 @Override
                 public void run() {
                     guidedStepCheckedFragment
@@ -451,7 +536,7 @@
             });
             Thread.sleep(TRANSITION_LENGTH);
 
-            sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
+            sendKey(KeyEvent.KEYCODE_DPAD_CENTER);
             Thread.sleep(TRANSITION_LENGTH);
             updateExpectedActionsStateAfterClick(EXPECTED_ACTIONS_STATE_AFTER_EACH_CLICK,
                     NUM_RADIO_ACTIONS, NUM_CHECK_BOX_ACTIONS, NUM_RADIO_ACTIONS + actionId);
@@ -459,20 +544,185 @@
         }
     }
 
-    public void testSubActions() throws Throwable {
+    @Test
+    public void testActionWithTwoSubActions() throws Throwable {
+        ExpectedSubActionResult result = setUpActionsForSubActionsTest();
 
-        mInstrumentation = getInstrumentation();
-        Intent intent = new Intent(mInstrumentation.getContext(),
-                GuidedStepAttributesTestActivity.class);
-        Resources res = mInstrumentation.getContext().getResources();
+        final int actionPos = 0;
+        final GuidedAction selectedAction = result.actionList.get(actionPos);
+        List<Integer> expectedFocusedSeq = result.expectedFocusedSeq.get(actionPos);
+        List<Integer> expectedClickedSeq = result.expectedClickedSeq.get(actionPos);
 
-        String TAG = "testSubActions";
+        traverseSubActionsAndVerifyFocusAndClickEvents(selectedAction, actionPos, expectedFocusedSeq,
+                expectedClickedSeq);
+    }
+
+    @Test
+    public void testActionWithOneSubAction() throws Throwable {
+        ExpectedSubActionResult result = setUpActionsForSubActionsTest();
+
+        final int actionPos = 1;
+        final GuidedAction selectedAction = result.actionList.get(actionPos);
+        List<Integer> expectedFocusedSeq = result.expectedFocusedSeq.get(actionPos);
+        List<Integer> expectedClickedSeq = result.expectedClickedSeq.get(actionPos);
+
+        traverseSubActionsAndVerifyFocusAndClickEvents(selectedAction, actionPos, expectedFocusedSeq,
+                expectedClickedSeq);
+    }
+
+    @Test
+    public void testActionWithZeroSubActions() throws Throwable {
+        ExpectedSubActionResult result = setUpActionsForSubActionsTest();
+
+        final int actionPos = 2;
+        final GuidedAction selectedAction = result.actionList.get(actionPos);
+        List<Integer> expectedFocusedSeq = result.expectedFocusedSeq.get(actionPos);
+        List<Integer> expectedClickedSeq = result.expectedClickedSeq.get(actionPos);
+
+        traverseSubActionsAndVerifyFocusAndClickEvents(selectedAction, actionPos, expectedFocusedSeq,
+                expectedClickedSeq);
+    }
+
+    @Test
+    public void testActionWithThreeSubActions() throws Throwable {
+        ExpectedSubActionResult result = setUpActionsForSubActionsTest();
+
+        final int actionPos = 3;
+        final GuidedAction selectedAction = result.actionList.get(actionPos);
+        List<Integer> expectedFocusedSeq = result.expectedFocusedSeq.get(actionPos);
+        List<Integer> expectedClickedSeq = result.expectedClickedSeq.get(actionPos);
+
+        traverseSubActionsAndVerifyFocusAndClickEvents(selectedAction, actionPos, expectedFocusedSeq,
+                expectedClickedSeq);
+    }
+
+    /**
+     * Traverses the list of sub actions of a gudied action. It also verifies the correct action
+     * or sub action is focused or clicked as the traversal is performed.
+     * @param selectedAction The action of interest
+     * @param actionPos The position of selectedAction within the array of guidedactions
+     * @param expectedFocusedSeq The actual actions IDs used as a reference to verify focused actions
+     * @param expectedClickedSeq The actual action IDs used as a reference to verify clicked actions
+     * @throws Throwable
+     */
+    private void traverseSubActionsAndVerifyFocusAndClickEvents(GuidedAction selectedAction,
+                                                                int actionPos,
+                                                                List<Integer> expectedFocusedSeq,
+                                                                List<Integer> expectedClickedSeq)
+            throws Throwable{
+
+        final GuidedStepFragment mFragment =
+                (GuidedStepFragment) mActivity.getGuidedStepTestFragment();
+        int focusStep = 0, clickStep = 0;
+        GuidedStepAttributesTestFragment.LAST_SELECTED_ACTION_ID =
+                GuidedStepAttributesTestFragment.LAST_CLICKED_ACTION_ID = -1;
+
+
+        final int pos = actionPos;
+        mActivity.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mFragment.setSelectedActionPosition(pos);
+            }
+        });
+        Thread.sleep(TRANSITION_LENGTH);
+
+        if (mFragment.getSelectedActionPosition() != actionPos) {
+            assertTrue(mContext.getResources().getString(
+                    R.string.subaction_test_wrong_focus_error_message),
+                    GuidedStepAttributesTestFragment.LAST_SELECTED_ACTION_ID
+                            == expectedFocusedSeq.get(focusStep++)
+            );
+        } else {
+            // If the currently focused position is the same as the position of the action of interest,
+            // then GuidedStepFragment won't received onGuidedActionFocused callback. Since the first
+            // element in the expectedFocusSeq is always the id of this action, we need to move focusStep
+            // one step forward.
+            focusStep++;
+        }
+        if (selectedAction.hasSubActions()) {
+            // Following for loop clicks on a specific action and scrolls & clicks through
+            // all its subactions
+            for (int j = 0; j < selectedAction.getSubActions().size(); j++) {
+                sendKey(KeyEvent.KEYCODE_DPAD_CENTER);
+                Thread.sleep(TRANSITION_LENGTH);
+                assertTrue(mContext.getResources().getString(
+                        R.string.subaction_test_wrong_focus_error_message),
+                        GuidedStepAttributesTestFragment.LAST_SELECTED_ACTION_ID
+                                == expectedFocusedSeq.get(focusStep++)
+                );
+                assertTrue(mContext.getResources().getString(
+                        R.string.subaction_test_wrong_click_error_message),
+                        GuidedStepAttributesTestFragment.LAST_CLICKED_ACTION_ID
+                                == expectedClickedSeq.get(clickStep++)
+                );
+
+                for (int k = 0; k < j; k++) {
+                    sendKey(KeyEvent.KEYCODE_DPAD_DOWN);
+                    Thread.sleep(TRANSITION_LENGTH);
+                    assertTrue(mContext.getResources().getString(
+                            R.string.subaction_test_wrong_focus_error_message),
+                            GuidedStepAttributesTestFragment.LAST_SELECTED_ACTION_ID
+                                    == expectedFocusedSeq.get(focusStep++)
+                    );
+                }
+                sendKey(KeyEvent.KEYCODE_DPAD_CENTER);
+                Thread.sleep(TRANSITION_LENGTH);
+
+                assertTrue(mContext.getResources().getString(
+                        R.string.subaction_test_wrong_focus_error_message),
+                        GuidedStepAttributesTestFragment.LAST_SELECTED_ACTION_ID
+                                == expectedFocusedSeq.get(focusStep++)
+                );
+                assertTrue(mContext.getResources().getString(
+                        R.string.subaction_test_wrong_click_error_message),
+                        GuidedStepAttributesTestFragment.LAST_CLICKED_ACTION_ID
+                                == expectedClickedSeq.get(clickStep++)
+                );
+            }
+        } else {
+            sendKey(KeyEvent.KEYCODE_DPAD_CENTER);
+            Thread.sleep(TRANSITION_LENGTH);
+            assertTrue(mContext.getResources().getString(
+                    R.string.subaction_test_wrong_focus_error_message),
+                    GuidedStepAttributesTestFragment.LAST_SELECTED_ACTION_ID
+                            == expectedFocusedSeq.get(focusStep++)
+            );
+            assertTrue(mContext.getResources().getString(
+                    R.string.subaction_test_wrong_click_error_message),
+                    GuidedStepAttributesTestFragment.LAST_CLICKED_ACTION_ID
+                            == expectedClickedSeq.get(clickStep++)
+            );
+        }
+    }
+
+    static class ExpectedSubActionResult {
+        List<List<Integer>> expectedFocusedSeq; // Expected sequence of action (or subaction) ids to receive focus events;
+        // Each entry corresponds to an action item in the guidedactions pane
+        List<List<Integer>> expectedClickedSeq; // Expected sequence of action (or subaction) ids to receive click events;
+        // Each entry corresponds to an action item in the guidedactions pane
+        List<GuidedAction> actionList;          // List of GuidedActions in the guidedactions pane
+    }
+
+    /**
+     * Populates a sample list of actions and subactions in the guidedactions pane.
+     * @return  An object holding the expected sequence of action and subactions IDs that receive
+     * focus and click events as well as the list of GuidedActions.
+     */
+    private ExpectedSubActionResult setUpActionsForSubActionsTest() {
+        Intent intent = new Intent();
+        Resources res = mContext.getResources();
+
+        ExpectedSubActionResult result = new ExpectedSubActionResult();
+        result.expectedFocusedSeq = new ArrayList<>();
+        result.expectedClickedSeq = new ArrayList<>();
+
         final int NUM_REGULAR_ACTIONS = 4;
         final int[] NUM_SUBACTIONS_PER_ACTION = {2, 1, 0, 3};
         final int[] REGULAR_ACTIONS_INDEX =  new int[NUM_REGULAR_ACTIONS];
         final int[] BEGIN_SUBACTION_INDEX_PER_ACTION = new int[NUM_REGULAR_ACTIONS];
         final int[] END_SUBACTION_INDEX_PER_ACTION = new int[NUM_REGULAR_ACTIONS];
-        // Actions and Subactions are assigned unique sequential IDs
+        // Actions and SubActions are assigned unique sequential IDs
         int lastIndex = 0;
         for(int i = 0; i < NUM_REGULAR_ACTIONS; i++) {
             REGULAR_ACTIONS_INDEX[i] = lastIndex;
@@ -481,29 +731,27 @@
             END_SUBACTION_INDEX_PER_ACTION[i] = (lastIndex += NUM_SUBACTIONS_PER_ACTION[i]);
         }
 
-        // Sample click sequence for the main action list (not subactions)
-        List<Integer> ACTION_CLICK_SEQUENCE = new ArrayList<>(Arrays.asList(
-                3, 2, 1, 0
-        ));
-        List<Integer> EXPECTED_FOCUSED_SEQUENCE = new ArrayList<>();
-        List<Integer> EXPECTED_CLICKED_SEQUENCE = new ArrayList<>();
+        for (int i = 0; i < NUM_REGULAR_ACTIONS; i++) {
+            List<Integer> expectedFocusSeqForEachAction = new ArrayList<>();
+            List<Integer> expectedClickedSeqForEachAction = new ArrayList<>();
+            expectedFocusSeqForEachAction.add(REGULAR_ACTIONS_INDEX[i]);
 
-        for(int clickedActionId : ACTION_CLICK_SEQUENCE) {
-            EXPECTED_FOCUSED_SEQUENCE.add(REGULAR_ACTIONS_INDEX[clickedActionId]);
-            if (NUM_SUBACTIONS_PER_ACTION[clickedActionId] > 0) {
-                for (int i = BEGIN_SUBACTION_INDEX_PER_ACTION[clickedActionId]; i <
-                        END_SUBACTION_INDEX_PER_ACTION[clickedActionId]; i++) {
-                    EXPECTED_CLICKED_SEQUENCE.add(REGULAR_ACTIONS_INDEX[clickedActionId]);
-                    for (int j = BEGIN_SUBACTION_INDEX_PER_ACTION[clickedActionId]; j <= i; j++) {
-                        EXPECTED_FOCUSED_SEQUENCE.add(j);
+            if (NUM_SUBACTIONS_PER_ACTION[i] > 0) {
+                for (int j = BEGIN_SUBACTION_INDEX_PER_ACTION[i];
+                        j < END_SUBACTION_INDEX_PER_ACTION[i]; j++) {
+                    expectedClickedSeqForEachAction.add(REGULAR_ACTIONS_INDEX[i]);
+                    for (int k = BEGIN_SUBACTION_INDEX_PER_ACTION[i]; k <= j; k++) {
+                        expectedFocusSeqForEachAction.add(k);
                     }
-                    EXPECTED_CLICKED_SEQUENCE.add(i);
-                    EXPECTED_FOCUSED_SEQUENCE.add(REGULAR_ACTIONS_INDEX[clickedActionId]);
+                    expectedClickedSeqForEachAction.add(j);
+                    expectedFocusSeqForEachAction.add(REGULAR_ACTIONS_INDEX[i]);
                 }
             } else {
-                EXPECTED_CLICKED_SEQUENCE.add(REGULAR_ACTIONS_INDEX[clickedActionId]);
-                EXPECTED_FOCUSED_SEQUENCE.add(REGULAR_ACTIONS_INDEX[clickedActionId]);
+                expectedClickedSeqForEachAction.add(REGULAR_ACTIONS_INDEX[i]);
+                expectedFocusSeqForEachAction.add(REGULAR_ACTIONS_INDEX[i]);
             }
+            result.expectedFocusedSeq.add(expectedFocusSeqForEachAction);
+            result.expectedClickedSeq.add(expectedClickedSeqForEachAction);
         }
 
         String title = "Guided SubActions Test";
@@ -516,7 +764,7 @@
 
         lastIndex = 0;
         for (int i = 0; i < NUM_REGULAR_ACTIONS; i++ ) {
-            GuidedAction action = new GuidedAction.Builder(mInstrumentation.getContext())
+            GuidedAction action = new GuidedAction.Builder(mContext)
                     .id(lastIndex++)
                     .title(res.getString(R.string.dropdown_action_title, i))
                     .description(res.getString(R.string.dropdown_action_desc, i))
@@ -525,7 +773,7 @@
                 List<GuidedAction> subActions = new ArrayList<>();
                 action.setSubActions(subActions);
                 for(int j = 0; j < NUM_SUBACTIONS_PER_ACTION[i]; j++) {
-                    subActions.add(new GuidedAction.Builder(mInstrumentation.getContext())
+                    subActions.add(new GuidedAction.Builder(mContext)
                             .id(lastIndex++)
                             .title(res.getString(R.string.subaction_title, j))
                             .description("")
@@ -535,90 +783,13 @@
             }
             actionList.add(action);
         }
+        result.actionList = actionList;
 
         GuidedStepAttributesTestFragment.clear();
         GuidedStepAttributesTestFragment.GUIDANCE = guidance;
         GuidedStepAttributesTestFragment.ACTION_LIST = actionList;
 
         initActivity(intent);
-
-        final GuidedStepFragment mFragment = (GuidedStepFragment) mActivity.
-                getGuidedStepTestFragment();
-
-        int focusStep = 0, clickStep = 0;
-        for(int i = 0; i < ACTION_CLICK_SEQUENCE.size(); i++) {
-            GuidedStepAttributesTestFragment.LAST_SELECTED_ACTION_ID =
-                    GuidedStepAttributesTestFragment.LAST_CLICKED_ACTION_ID = -1;
-            final int id = ACTION_CLICK_SEQUENCE.get(i);
-            final GuidedAction selectedAction = actionList.get(id);
-            runTestOnUiThread(new Runnable() {
-                @Override
-                public void run() {
-                    mFragment.setSelectedActionPosition(id);
-                }
-            });
-            Thread.sleep(TRANSITION_LENGTH);
-
-            assertTrue(mInstrumentation.getContext().getResources().getString(
-                    R.string.subaction_test_wrong_focus_error_message),
-                    GuidedStepAttributesTestFragment.LAST_SELECTED_ACTION_ID ==
-                            EXPECTED_FOCUSED_SEQUENCE.get(focusStep++)
-            );
-
-            if (selectedAction.hasSubActions()) {
-                // Following for loop clicks on a specific action and scrolls & clicks through
-                // all its subactions
-                for (int j = 0; j < selectedAction.getSubActions().size(); j++) {
-                    sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
-                    Thread.sleep(TRANSITION_LENGTH);
-                    assertTrue(mInstrumentation.getContext().getResources().getString(
-                            R.string.subaction_test_wrong_focus_error_message),
-                            GuidedStepAttributesTestFragment.LAST_SELECTED_ACTION_ID ==
-                                    EXPECTED_FOCUSED_SEQUENCE.get(focusStep++)
-                    );
-                    assertTrue(mInstrumentation.getContext().getResources().getString(
-                            R.string.subaction_test_wrong_click_error_message),
-                            GuidedStepAttributesTestFragment.LAST_CLICKED_ACTION_ID ==
-                                    EXPECTED_CLICKED_SEQUENCE.get(clickStep++)
-                    );
-                    for (int k = 0; k < j; k++) {
-                        sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
-                        Thread.sleep(TRANSITION_LENGTH);
-                        assertTrue(mInstrumentation.getContext().getResources().getString(
-                                R.string.subaction_test_wrong_focus_error_message),
-                                GuidedStepAttributesTestFragment.LAST_SELECTED_ACTION_ID ==
-                                        EXPECTED_FOCUSED_SEQUENCE.get(focusStep++)
-                        );
-                    }
-                    sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
-                    Thread.sleep(TRANSITION_LENGTH);
-
-                    assertTrue(mInstrumentation.getContext().getResources().getString(
-                            R.string.subaction_test_wrong_focus_error_message),
-                            GuidedStepAttributesTestFragment.LAST_SELECTED_ACTION_ID ==
-                                    EXPECTED_FOCUSED_SEQUENCE.get(focusStep++)
-                    );
-                    assertTrue(mInstrumentation.getContext().getResources().getString(
-                            R.string.subaction_test_wrong_click_error_message),
-                            GuidedStepAttributesTestFragment.LAST_CLICKED_ACTION_ID ==
-                                    EXPECTED_CLICKED_SEQUENCE.get(clickStep++)
-                    );
-                }
-            } else {
-                sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
-                Thread.sleep(TRANSITION_LENGTH);
-                assertTrue(mInstrumentation.getContext().getResources().getString(
-                        R.string.subaction_test_wrong_focus_error_message),
-                        GuidedStepAttributesTestFragment.LAST_SELECTED_ACTION_ID ==
-                                EXPECTED_FOCUSED_SEQUENCE.get(focusStep++)
-                );
-                assertTrue(mInstrumentation.getContext().getResources().getString(
-                        R.string.subaction_test_wrong_click_error_message),
-                        GuidedStepAttributesTestFragment.LAST_CLICKED_ACTION_ID ==
-                                EXPECTED_CLICKED_SEQUENCE.get(clickStep++)
-                );
-            }
-        }
-
+        return result;
     }
 }
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/app/wizard/GuidedStepAttributesTestActivity.java b/v17/leanback/tests/java/android/support/v17/leanback/app/wizard/GuidedStepAttributesTestActivity.java
index a0433cc..57a7e51 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/app/wizard/GuidedStepAttributesTestActivity.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/app/wizard/GuidedStepAttributesTestActivity.java
@@ -16,7 +16,6 @@
 
 import android.app.Activity;
 import android.app.Fragment;
-import android.content.Intent;
 import android.os.Bundle;
 import android.support.v17.leanback.app.GuidedStepFragment;
 
@@ -31,8 +30,6 @@
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
-        Intent intent = getIntent();
-
         mGuidedStepAttributesTestFragment = new GuidedStepAttributesTestFragment();
         GuidedStepFragment.addAsRoot(this, mGuidedStepAttributesTestFragment, android.R.id.content);
     }
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/graphics/ChildDrawableTest.java b/v17/leanback/tests/java/android/support/v17/leanback/graphics/ChildDrawableTest.java
new file mode 100644
index 0000000..b07c3bb
--- /dev/null
+++ b/v17/leanback/tests/java/android/support/v17/leanback/graphics/ChildDrawableTest.java
@@ -0,0 +1,171 @@
+/*
+ * 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 android.support.v17.leanback.graphics;
+
+import static org.junit.Assert.assertEquals;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Rect;
+import android.graphics.drawable.BitmapDrawable;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Unit test for {@link ChildDrawable}
+ */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class ChildDrawableTest {
+
+    private static final int HEIGHT = 800;
+    private static final int WIDTH = 600;
+    Bitmap bitmap = Bitmap.createBitmap(WIDTH, HEIGHT, Bitmap.Config.ARGB_8888);
+
+    @Test
+    public void updateBounds_noBoundsRule() {
+        CompositeDrawable parentDrawable = new CompositeDrawable();
+        FitWidthBitmapDrawable drawable = new FitWidthBitmapDrawable();
+        drawable.setBitmap(bitmap);
+        Rect bounds = new Rect(0, 0, WIDTH, HEIGHT);
+        parentDrawable.addChildDrawable(drawable);
+        parentDrawable.updateBounds(bounds);
+
+        Rect adjustedBounds = drawable.getBounds();
+        assertEquals(bounds, adjustedBounds);
+    }
+
+    @Test
+    public void updateBounds_withBoundsRule() {
+        CompositeDrawable parentDrawable = new CompositeDrawable();
+        float fraction = 0.5f;
+        FitWidthBitmapDrawable drawable = new FitWidthBitmapDrawable();
+        drawable.setBitmap(bitmap);
+        Rect bounds = new Rect(0, 0, WIDTH, HEIGHT);
+        assertEquals(HEIGHT, bounds.height());
+        assertEquals(WIDTH, bounds.width());
+
+        // inherit from parent
+        parentDrawable.addChildDrawable(drawable);
+        parentDrawable.getChildAt(0).getBoundsRule().mBottom = BoundsRule.inheritFromParent(fraction);
+        parentDrawable.updateBounds(bounds);
+
+        Rect adjustedBounds = drawable.getBounds();
+        Rect expectedBounds = new Rect(bounds);
+        expectedBounds.bottom = bounds.top + (int) (HEIGHT * fraction);
+        assertEquals(expectedBounds, adjustedBounds);
+
+        // absolute value
+        drawable.setBounds(bounds);
+        parentDrawable.getChildAt(0).getBoundsRule().mBottom = BoundsRule.absoluteValue(200);
+        parentDrawable.updateBounds(bounds);
+
+        adjustedBounds = drawable.getBounds();
+        expectedBounds = new Rect(bounds);
+        expectedBounds.bottom = 200;
+        assertEquals(expectedBounds, adjustedBounds);
+
+        // inherit with offset
+        parentDrawable.getChildAt(0).getBoundsRule().mBottom = BoundsRule.inheritFromParentWithOffset(fraction, 100);
+        parentDrawable.updateBounds(bounds);
+
+        adjustedBounds = drawable.getBounds();
+        expectedBounds = new Rect(bounds);
+        expectedBounds.bottom = bounds.top + (int) (HEIGHT * fraction + 100);
+        assertEquals(expectedBounds, adjustedBounds);
+
+        // inherit from parent 2
+        bounds = new Rect(100, 200, WIDTH, HEIGHT);
+        parentDrawable.getChildAt(0).getBoundsRule().mBottom = BoundsRule.inheritFromParent(fraction);
+        parentDrawable.updateBounds(bounds);
+
+        adjustedBounds = drawable.getBounds();
+        expectedBounds = new Rect(bounds);
+        expectedBounds.bottom = bounds.top + (int) ((HEIGHT-200) * fraction);
+        assertEquals(expectedBounds, adjustedBounds);
+    }
+
+    @Test
+    public void updateBounds_withOverride() {
+        CompositeDrawable parentDrawable = new CompositeDrawable();
+        float fraction = 0.5f;
+        FitWidthBitmapDrawable drawable = new FitWidthBitmapDrawable();
+        drawable.setBitmap(bitmap);
+        Rect bounds = new Rect(0, 0, WIDTH, HEIGHT);
+        drawable.setBounds(bounds);
+        assertEquals(HEIGHT, drawable.getBounds().height());
+        assertEquals(WIDTH, drawable.getBounds().width());
+
+        parentDrawable.addChildDrawable(drawable);
+
+        // inherit from parent
+        BoundsRule boundsRule = parentDrawable.getChildAt(0).getBoundsRule();
+        boundsRule.mTop = BoundsRule.absoluteValue(-200);
+        boundsRule.mBottom = BoundsRule.inheritFromParent(fraction);
+        parentDrawable.getChildAt(0).getBoundsRule().mTop.setAbsoluteValue(-100);
+
+        parentDrawable.updateBounds(bounds);
+
+        Rect adjustedBounds = drawable.getBounds();
+        Rect expectedBounds = new Rect(bounds);
+        expectedBounds.top = -100;
+        expectedBounds.bottom = bounds.top + (int) (HEIGHT * fraction);
+        assertEquals(expectedBounds, adjustedBounds);
+
+        // inherit from parent with offset
+        boundsRule.mBottom = BoundsRule.absoluteValue(HEIGHT);
+
+        parentDrawable.updateBounds(bounds);
+
+        adjustedBounds = drawable.getBounds();
+        expectedBounds = new Rect(bounds);
+        expectedBounds.top = -100;
+        expectedBounds.bottom = HEIGHT;
+        assertEquals(expectedBounds, adjustedBounds);
+    }
+
+    @Test
+    public void constantState() {
+        Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
+        CompositeDrawable parentDrawable = new CompositeDrawable();
+        BitmapDrawable childDrawable = new BitmapDrawable(context.getResources(), bitmap);
+        parentDrawable.addChildDrawable(childDrawable);
+
+        // getConstantState().newDrawable() will create a new CompositeDrawable with shared states:
+        CompositeDrawable parentDrawble2 = (CompositeDrawable)
+                parentDrawable.getConstantState().newDrawable();
+        BitmapDrawable childDrawable2 = (BitmapDrawable) parentDrawble2.getChildAt(0).getDrawable();
+        parentDrawable.setAlpha(128);
+        assertEquals(128, parentDrawble2.getAlpha());
+        assertEquals(128, childDrawable2.getAlpha());
+
+        // after mutate(), parentDrawble2 will have its own state
+        parentDrawble2.mutate();
+        childDrawable2 = (BitmapDrawable) parentDrawble2.getChildAt(0).getDrawable();
+        parentDrawable.setAlpha(64);
+        assertEquals(64, parentDrawable.getAlpha());
+        assertEquals(64, childDrawable.getAlpha());
+        assertEquals(128, parentDrawble2.getAlpha());
+        assertEquals(128, childDrawable2.getAlpha());
+        childDrawable.setAlpha(100);
+        assertEquals(128, parentDrawble2.getAlpha());
+        assertEquals(128, childDrawable2.getAlpha());
+    }
+}
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/graphics/FitWidthBitmapDrawableTest.java b/v17/leanback/tests/java/android/support/v17/leanback/graphics/FitWidthBitmapDrawableTest.java
new file mode 100644
index 0000000..0b893c4
--- /dev/null
+++ b/v17/leanback/tests/java/android/support/v17/leanback/graphics/FitWidthBitmapDrawableTest.java
@@ -0,0 +1,85 @@
+/*
+ * 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 android.support.v17.leanback.graphics;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.verify;
+
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mockito;
+
+/**
+ * Unit test for {@link FitWidthBitmapDrawable}
+ */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class FitWidthBitmapDrawableTest {
+    private final static int SCREEN_WIDTH = 1600;
+    private final static int SCREEN_HEIGHT = 1080;
+    private final static int WIDTH = 300;
+    private final static int HEIGHT = 600;
+    private Bitmap bitmap = Bitmap.createBitmap(WIDTH, HEIGHT, Bitmap.Config.ARGB_8888);
+
+    @Test
+    public void draw_withOffset() {
+        int offset = 600;
+        FitWidthBitmapDrawable drawable = new FitWidthBitmapDrawable();
+        drawable.setBitmap(bitmap);
+        drawable.setVerticalOffset(offset);
+        Rect bounds = new Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
+        drawable.setBounds(bounds);
+
+        Canvas canvas = Mockito.mock(Canvas.class);
+        drawable.draw(canvas);
+
+        Rect expectedBounds = bounds;
+        verify(canvas).clipRect(expectedBounds);
+
+        Rect bitmapBounds = new Rect(0, 0, WIDTH, HEIGHT);
+        int nH = (int) (((float)SCREEN_WIDTH/WIDTH * HEIGHT) + offset);
+        Rect expectedDest = new Rect(0, offset, SCREEN_WIDTH, nH);
+        verify(canvas).drawBitmap(eq(bitmap), eq(bitmapBounds), eq(expectedDest), any(Paint.class));
+    }
+
+    @Test
+    public void constantState() {
+        FitWidthBitmapDrawable drawable = new FitWidthBitmapDrawable();
+        drawable.setBitmap(bitmap);
+        drawable.setVerticalOffset(600);
+
+        // getConstantState().newDrawable() will create a new drawable with shared states:
+        FitWidthBitmapDrawable drawable2 = (FitWidthBitmapDrawable)
+                drawable.getConstantState().newDrawable();
+        drawable.setAlpha(128);
+        assertEquals(128, drawable2.getAlpha());
+
+        // after mutate(), drawable2 will have its own state
+        drawable2.mutate();
+        drawable.setAlpha(64);
+        assertEquals(64, drawable.getAlpha());
+        assertEquals(128, drawable2.getAlpha());
+    }
+}
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/testutils/PollingCheck.java b/v17/leanback/tests/java/android/support/v17/leanback/testutils/PollingCheck.java
new file mode 100644
index 0000000..2f2fc5d
--- /dev/null
+++ b/v17/leanback/tests/java/android/support/v17/leanback/testutils/PollingCheck.java
@@ -0,0 +1,158 @@
+/*
+ * 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 android.support.v17.leanback.testutils;
+
+import android.app.Activity;
+import android.view.View;
+
+import java.util.concurrent.Callable;
+
+import junit.framework.Assert;
+
+public abstract class PollingCheck {
+
+    private static final long TIME_SLICE = 250;
+    private long mTimeout = 5000;
+
+    public abstract static class PollingCheckCondition {
+        public abstract boolean canProceed();
+
+        public boolean canPreProceed() {
+            return canProceed();
+        }
+    }
+
+    public PollingCheck() {
+    }
+
+    public PollingCheck(long timeout) {
+        mTimeout = timeout;
+    }
+
+    protected abstract boolean check();
+
+    protected boolean preCheck() {
+        return check();
+    }
+
+    public void run() {
+        if (preCheck()) {
+            return;
+        }
+
+        long timeout = mTimeout;
+        while (timeout > 0) {
+            try {
+                Thread.sleep(TIME_SLICE);
+            } catch (InterruptedException e) {
+                Assert.fail("unexpected InterruptedException");
+            }
+
+            if (check()) {
+                return;
+            }
+
+            timeout -= TIME_SLICE;
+        }
+
+        Assert.fail("unexpected timeout");
+    }
+
+    public static void waitFor(final PollingCheckCondition condition) {
+        new PollingCheck() {
+            @Override
+            protected boolean check() {
+                return condition.canProceed();
+            }
+
+            @Override
+            protected boolean preCheck() {
+                return condition.canPreProceed();
+            }
+        }.run();
+    }
+
+    public static void waitFor(long timeout, final PollingCheckCondition condition) {
+        new PollingCheck(timeout) {
+            @Override
+            protected boolean check() {
+                return condition.canProceed();
+            }
+        }.run();
+    }
+
+    public static class ViewScreenPositionDetector {
+
+        int[] lastLocation = null;
+        int[] newLocation = new int[2];
+
+        public boolean isViewStableOnScreen(View view) {
+            if (lastLocation == null) {
+                // get initial location
+                lastLocation = new int[2];
+                view.getLocationInWindow(lastLocation);
+            } else {
+                // get new location and compare to old location
+                view.getLocationInWindow(newLocation);
+                if (newLocation[0] == lastLocation[0]
+                        && newLocation[1] == lastLocation[1]) {
+                    // location stable,  animation finished
+                    return true;
+                }
+                lastLocation[0] = newLocation[0];
+                lastLocation[1] = newLocation[1];
+            }
+            return false;
+        }
+    }
+
+    public static class ViewStableOnScreen extends PollingCheckCondition {
+
+        View mView;
+        ViewScreenPositionDetector mDector = new ViewScreenPositionDetector();
+
+        public ViewStableOnScreen(View view) {
+            mView = view;
+        }
+
+        @Override
+        public boolean canPreProceed() {
+            return false;
+        }
+
+        @Override
+        public boolean canProceed() {
+            return mDector.isViewStableOnScreen(mView);
+        }
+
+    }
+
+    public static class ActivityDestroy extends PollingCheckCondition {
+
+        Activity mActivity;
+
+        public ActivityDestroy(Activity activity) {
+            mActivity = activity;
+        }
+
+        @Override
+        public boolean canProceed() {
+            return mActivity.isDestroyed();
+        }
+
+    }
+
+}
\ No newline at end of file
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/widget/BaseCardViewTest.java b/v17/leanback/tests/java/android/support/v17/leanback/widget/BaseCardViewTest.java
new file mode 100644
index 0000000..78c4405
--- /dev/null
+++ b/v17/leanback/tests/java/android/support/v17/leanback/widget/BaseCardViewTest.java
@@ -0,0 +1,303 @@
+/*
+ * 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 android.support.v17.leanback.widget;
+
+import static android.support.v17.leanback.widget.BaseCardView.LayoutParams.MATCH_PARENT;
+import static android.support.v17.leanback.widget.BaseCardView.LayoutParams.VIEW_TYPE_INFO;
+import static android.support.v17.leanback.widget.BaseCardView.LayoutParams.VIEW_TYPE_MAIN;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.support.test.InstrumentationRegistry;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.view.View;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.mockito.Mockito;
+
+@SmallTest
+@RunWith(JUnit4.class)
+public class BaseCardViewTest {
+
+    BaseCardView.LayoutParams createLayoutParams(int viewType, int width, int height) {
+        BaseCardView.LayoutParams lp = new BaseCardView.LayoutParams(width, height);
+        lp.viewType = viewType;
+        return lp;
+    }
+
+    void mockInfoHeightAnimation(BaseCardView view, int width, int startHeight, int endHeight) {
+        ((BaseCardView.InfoHeightAnimation) view.getAnimation()).mockStart();
+        measureAndLayout(view, width, startHeight);
+        ((BaseCardView.InfoHeightAnimation) view.getAnimation()).mockEnd();
+        assertNull(view.getAnimation());
+        measureAndLayout(view, width, endHeight);
+    }
+
+    void mockInfoAlphaAnimation(BaseCardView view, View infoView,
+            float startAlpha, float endAlpha) {
+        ((BaseCardView.InfoAlphaAnimation) view.getAnimation()).mockStart();
+        assertEquals(startAlpha, infoView.getAlpha(), 0.01f);
+        assertEquals(View.VISIBLE, infoView.getVisibility());
+        ((BaseCardView.InfoAlphaAnimation) view.getAnimation()).mockEnd();
+        assertNull(view.getAnimation());
+        assertEquals(endAlpha, infoView.getAlpha(), 0.01f);
+        assertEquals(endAlpha == 0f? View.GONE: View.VISIBLE, infoView.getVisibility());
+    }
+
+    void measureAndLayout(View view, int expectedWidth, int expectedHeight) {
+        view.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
+        assertEquals(expectedWidth, view.getMeasuredWidth());
+        assertEquals(expectedHeight, view.getMeasuredHeight());
+        view.layout(0, 0, expectedWidth, expectedHeight);
+    }
+
+    void verifyLayoutTimes(View.OnLayoutChangeListener listener, int timesCalled) {
+        verify(listener, times(timesCalled)).onLayoutChange(any(View.class),
+                any(Integer.class), any(Integer.class), any(Integer.class), any(Integer.class),
+                any(Integer.class), any(Integer.class), any(Integer.class), any(Integer.class));
+    }
+
+    @Test
+    public void infoOver_InfoVisibleAlways() {
+        BaseCardView cardView = new BaseCardView(InstrumentationRegistry.getContext());
+        View main = new View(cardView.getContext());
+        main.setLayoutParams(createLayoutParams(VIEW_TYPE_MAIN, 500, 500));
+        cardView.addView(main);
+        View info = new View(cardView.getContext());
+        View.OnLayoutChangeListener onLayout = Mockito.mock(View.OnLayoutChangeListener.class);
+        info.addOnLayoutChangeListener(onLayout);
+        info.setLayoutParams(createLayoutParams(VIEW_TYPE_INFO, MATCH_PARENT, 200));
+        cardView.addView(info);
+        cardView.setCardType(BaseCardView.CARD_TYPE_INFO_OVER);
+        cardView.setInfoVisibility(BaseCardView.CARD_REGION_VISIBLE_ALWAYS);
+
+        measureAndLayout(cardView, 500, 500);
+        verifyLayoutTimes(onLayout, 1);
+        assertEquals(1f, info.getAlpha(), 0.01f);
+
+        cardView.setActivated(true);
+        assertFalse(cardView.isLayoutRequested());
+        assertNull(cardView.getAnimation());
+        measureAndLayout(cardView, 500, 500);
+        verifyLayoutTimes(onLayout, 1);
+        assertEquals(1f, info.getAlpha(), 0.01f);
+
+        cardView.setActivated(false);
+        assertFalse(cardView.isLayoutRequested());
+        assertNull(cardView.getAnimation());
+        measureAndLayout(cardView, 500, 500);
+        verifyLayoutTimes(onLayout, 1);
+        assertEquals(1f, info.getAlpha(), 0.01f);
+
+        cardView.setSelected(true);
+        assertFalse(cardView.isLayoutRequested());
+        assertNull(cardView.getAnimation());
+        measureAndLayout(cardView, 500, 500);
+        verifyLayoutTimes(onLayout, 1);
+        assertEquals(1f, info.getAlpha(), 0.01f);
+
+        cardView.setSelected(false);
+        assertFalse(cardView.isLayoutRequested());
+        assertNull(cardView.getAnimation());
+        measureAndLayout(cardView, 500, 500);
+        verifyLayoutTimes(onLayout, 1);
+        assertEquals(1f, info.getAlpha(), 0.01f);
+    }
+
+    @Test
+    public void infoUnder_InfoVisibleAlways() {
+        BaseCardView cardView = new BaseCardView(InstrumentationRegistry.getContext());
+        View main = new View(cardView.getContext());
+        main.setLayoutParams(createLayoutParams(VIEW_TYPE_MAIN, 500, 500));
+        cardView.addView(main);
+        View info = new View(cardView.getContext());
+        View.OnLayoutChangeListener onLayout = Mockito.mock(View.OnLayoutChangeListener.class);
+        info.addOnLayoutChangeListener(onLayout);
+        info.setLayoutParams(createLayoutParams(VIEW_TYPE_INFO, MATCH_PARENT, 200));
+        cardView.addView(info);
+        cardView.setCardType(BaseCardView.CARD_TYPE_INFO_UNDER);
+        cardView.setInfoVisibility(BaseCardView.CARD_REGION_VISIBLE_ALWAYS);
+
+        measureAndLayout(cardView, 500, 700);
+        verifyLayoutTimes(onLayout, 1);
+        assertEquals(1f, info.getAlpha(), 0.01f);
+
+        cardView.setActivated(true);
+        assertFalse(cardView.isLayoutRequested());
+        assertNull(cardView.getAnimation());
+        measureAndLayout(cardView, 500, 700);
+        verifyLayoutTimes(onLayout, 1);
+        assertEquals(1f, info.getAlpha(), 0.01f);
+
+        cardView.setActivated(false);
+        assertFalse(cardView.isLayoutRequested());
+        assertNull(cardView.getAnimation());
+        measureAndLayout(cardView, 500, 700);
+        verifyLayoutTimes(onLayout, 1);
+        assertEquals(1f, info.getAlpha(), 0.01f);
+
+        cardView.setSelected(true);
+        assertFalse(cardView.isLayoutRequested());
+        assertNull(cardView.getAnimation());
+        measureAndLayout(cardView, 500, 700);
+        verifyLayoutTimes(onLayout, 1);
+        assertEquals(1f, info.getAlpha(), 0.01f);
+
+        cardView.setSelected(false);
+        assertFalse(cardView.isLayoutRequested());
+        assertNull(cardView.getAnimation());
+        measureAndLayout(cardView, 500, 700);
+        verifyLayoutTimes(onLayout, 1);
+        assertEquals(1f, info.getAlpha(), 0.01f);
+    }
+
+    @Test
+    public void infoUnder_InfoVisibleActivated() {
+        BaseCardView cardView = new BaseCardView(InstrumentationRegistry.getContext());
+        View main = new View(cardView.getContext());
+        main.setLayoutParams(createLayoutParams(VIEW_TYPE_MAIN, 500, 500));
+        cardView.addView(main);
+        View info = new View(cardView.getContext());
+        View.OnLayoutChangeListener onLayout = Mockito.mock(View.OnLayoutChangeListener.class);
+        info.addOnLayoutChangeListener(onLayout);
+        info.setLayoutParams(createLayoutParams(VIEW_TYPE_INFO, MATCH_PARENT, 200));
+        cardView.addView(info);
+        cardView.setCardType(BaseCardView.CARD_TYPE_INFO_UNDER);
+        cardView.setInfoVisibility(BaseCardView.CARD_REGION_VISIBLE_ACTIVATED);
+
+        measureAndLayout(cardView, 500, 500);
+        verifyLayoutTimes(onLayout, 0);
+        assertEquals(1f, info.getAlpha(), 0.01f);
+
+        cardView.setActivated(true);
+        assertTrue(cardView.isLayoutRequested());
+        measureAndLayout(cardView, 500, 700);
+        verifyLayoutTimes(onLayout, 1);
+        assertEquals(1f, info.getAlpha(), 0.01f);
+
+        cardView.setActivated(false);
+        assertTrue(cardView.isLayoutRequested());
+        measureAndLayout(cardView, 500, 500);
+        verifyLayoutTimes(onLayout, 1);
+        assertEquals(1f, info.getAlpha(), 0.01f);
+
+        // changing selected does not affect size
+        cardView.setSelected(true);
+        assertFalse(cardView.isLayoutRequested());
+        measureAndLayout(cardView, 500, 500);
+        verifyLayoutTimes(onLayout, 1);
+        assertEquals(1f, info.getAlpha(), 0.01f);
+
+        // changing selected does not affect size
+        cardView.setSelected(false);
+        assertFalse(cardView.isLayoutRequested());
+        measureAndLayout(cardView, 500, 500);
+        verifyLayoutTimes(onLayout, 1);
+        assertEquals(1f, info.getAlpha(), 0.01f);
+    }
+
+    @Test
+    public void infoUnder_InfoVisibleSelected() {
+        final BaseCardView cardView = new BaseCardView(InstrumentationRegistry.getContext());
+        View main = new View(cardView.getContext());
+        main.setLayoutParams(createLayoutParams(VIEW_TYPE_MAIN, 500, 500));
+        cardView.addView(main);
+        View info = new View(cardView.getContext());
+        View.OnLayoutChangeListener onLayout = Mockito.mock(View.OnLayoutChangeListener.class);
+        info.addOnLayoutChangeListener(onLayout);
+        info.setLayoutParams(createLayoutParams(VIEW_TYPE_INFO, MATCH_PARENT, 200));
+        cardView.addView(info);
+        cardView.setCardType(BaseCardView.CARD_TYPE_INFO_UNDER);
+        cardView.setInfoVisibility(BaseCardView.CARD_REGION_VISIBLE_SELECTED);
+
+        measureAndLayout(cardView, 500, 500);
+        verifyLayoutTimes(onLayout, 0);
+        assertEquals(1f, info.getAlpha(), 0.01f);
+
+        // changing activated does not affect size
+        cardView.setActivated(true);
+        measureAndLayout(cardView, 500, 500);
+        assertNull(cardView.getAnimation());
+        assertEquals(1f, info.getAlpha(), 0.01f);
+
+        // start info height animation 500 -> 700
+        cardView.setSelected(true);
+        assertEquals(1f, info.getAlpha(), 0.01f);
+        mockInfoHeightAnimation(cardView, 500 /*width*/, 500 /*startHeight*/, 700 /*endHeight*/);
+
+        // changing activated does not affect size
+        cardView.setActivated(false);
+        assertEquals(1f, info.getAlpha(), 0.01f);
+        measureAndLayout(cardView, 500, 700);
+        assertNull(cardView.getAnimation());
+
+        // start info height animation 700 -> 500
+        cardView.setSelected(false);
+        assertEquals(1f, info.getAlpha(), 0.01f);
+        mockInfoHeightAnimation(cardView, 500 /*width*/, 700 /*startHeight*/, 500 /*endHeight*/);
+    }
+
+    @Test
+    public void infoOver_InfoVisibleSelected() {
+        final BaseCardView cardView = new BaseCardView(InstrumentationRegistry.getContext());
+        View main = new View(cardView.getContext());
+        main.setLayoutParams(createLayoutParams(VIEW_TYPE_MAIN, 500, 500));
+        cardView.addView(main);
+        View info = new View(cardView.getContext());
+        View.OnLayoutChangeListener onLayout = Mockito.mock(View.OnLayoutChangeListener.class);
+        info.addOnLayoutChangeListener(onLayout);
+        info.setLayoutParams(createLayoutParams(VIEW_TYPE_INFO, MATCH_PARENT, 200));
+        cardView.addView(info);
+        cardView.setCardType(BaseCardView.CARD_TYPE_INFO_OVER);
+        cardView.setInfoVisibility(BaseCardView.CARD_REGION_VISIBLE_SELECTED);
+
+        measureAndLayout(cardView, 500, 500);
+        verifyLayoutTimes(onLayout, 0);
+        assertFalse(cardView.isSelected());
+        assertFalse(cardView.isActivated());
+        assertEquals(0f, info.getAlpha(), 0.01f);
+
+        cardView.setActivated(true);
+        assertFalse(cardView.isLayoutRequested());
+        assertNull(cardView.getAnimation());
+
+        assertEquals(info.getVisibility(), View.GONE);
+        assertEquals(0f, info.getAlpha(), 0.01f);
+        // start info animation alpha 0f -> 1f
+        cardView.setSelected(true);
+        // change visibility when start animation causing layout requested
+        assertTrue(cardView.isLayoutRequested());
+        measureAndLayout(cardView, 500, 500);
+        mockInfoAlphaAnimation(cardView, info, 0f, 1f);
+        assertEquals(1f, info.getAlpha(), 0.01f);
+
+        // start info animation alpha 1f -> 0f
+        cardView.setSelected(false);
+        assertFalse(cardView.isLayoutRequested());
+        mockInfoAlphaAnimation(cardView, info, 1f, 0f);
+        assertEquals(0f, info.getAlpha(), 0.01f);
+    }
+
+}
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/widget/GridActivity.java b/v17/leanback/tests/java/android/support/v17/leanback/widget/GridActivity.java
index d4c2e89..6678101 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/widget/GridActivity.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/widget/GridActivity.java
@@ -16,21 +16,16 @@
 
 package android.support.v17.leanback.widget;
 
-import android.support.v17.leanback.test.R;
-import android.support.v7.widget.RecyclerView;
-import android.support.v17.leanback.widget.BaseGridView;
-import android.support.v17.leanback.widget.OnChildSelectedListener;
 import android.app.Activity;
 import android.content.Intent;
 import android.graphics.Color;
 import android.os.Bundle;
+import android.support.v17.leanback.test.R;
+import android.support.v7.widget.RecyclerView;
 import android.util.Log;
-import android.util.SparseArray;
 import android.view.View;
-import android.view.View.OnClickListener;
 import android.view.View.OnFocusChangeListener;
 import android.view.ViewGroup;
-import android.widget.ImageView;
 import android.widget.TextView;
 
 import java.util.ArrayList;
@@ -310,8 +305,8 @@
 
         @Override
         public FacetProvider getFacetProvider(int viewType) {
-            final Object alignmentFacet = mAlignmentViewTypeProvider != null?
-                mAlignmentViewTypeProvider.getItemAlignmentFacet(viewType) : null;
+            final Object alignmentFacet = mAlignmentViewTypeProvider != null
+                    ? mAlignmentViewTypeProvider.getItemAlignmentFacet(viewType) : null;
             if (alignmentFacet != null) {
                 return new FacetProvider() {
                     @Override
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/widget/GridTest.java b/v17/leanback/tests/java/android/support/v17/leanback/widget/GridTest.java
index 4577963..6f5529e 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/widget/GridTest.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/widget/GridTest.java
@@ -15,8 +15,6 @@
  */
 package android.support.v17.leanback.widget;
 
-import android.test.AndroidTestCase;
-
 import java.io.PrintWriter;
 import java.io.StringWriter;
 
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/widget/GridWidgetTest.java b/v17/leanback/tests/java/android/support/v17/leanback/widget/GridWidgetTest.java
index 4061c66..b72675e 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/widget/GridWidgetTest.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/widget/GridWidgetTest.java
@@ -15,19 +15,26 @@
  */
 package android.support.v17.leanback.widget;
 
-import android.app.Instrumentation;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+
 import android.content.Intent;
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.Rect;
 import android.graphics.drawable.ColorDrawable;
 import android.os.Parcelable;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
 import android.support.v17.leanback.test.R;
 import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
 import android.support.v7.widget.RecyclerView;
 import android.support.v7.widget.RecyclerViewAccessibilityDelegate;
-import android.test.ActivityInstrumentationTestCase2;
-import android.test.suitebuilder.annotation.MediumTest;
 import android.text.Selection;
 import android.text.Spannable;
 import android.util.SparseArray;
@@ -37,19 +44,23 @@
 import android.view.ViewGroup;
 import android.widget.TextView;
 
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TestName;
+import org.junit.runner.RunWith;
+
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Comparator;
 import java.util.HashMap;
 
-@MediumTest
-public class GridWidgetTest extends ActivityInstrumentationTestCase2<GridActivity> {
+@RunWith(AndroidJUnit4.class)
+public class GridWidgetTest {
 
     private static final boolean HUMAN_DELAY = false;
     private static final long WAIT_FOR_SCROLL_IDLE_TIMEOUT_MS = 60000;
 
     protected GridActivity mActivity;
-    protected Instrumentation mInstrumentation;
     protected BaseGridView mGridView;
     protected GridLayoutManager mLayoutManager;
     protected int mOrientation;
@@ -75,8 +86,16 @@
         }
     };
 
-    public GridWidgetTest() {
-        super("android.support.v17.leanback.test", GridActivity.class);
+    @Rule public TestName testName = new TestName();
+
+    public static void sendKey(int keyCode) {
+        InstrumentationRegistry.getInstrumentation().sendKeyDownUpSync(keyCode);
+    }
+
+    public static void sendRepeatedKeys(int repeats, int keyCode) {
+        for (int i = 0; i < repeats; i++) {
+            InstrumentationRegistry.getInstrumentation().sendKeyDownUpSync(keyCode);
+        }
     }
 
     private void humanDelay(int delay) throws InterruptedException {
@@ -86,7 +105,7 @@
      * Change size of the Adapter and notifyDataSetChanged.
      */
     private void changeArraySize(final int size) throws Throwable {
-        runTestOnUiThread(new Runnable() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             public void run() {
                 mActivity.changeArraySize(size);
             }
@@ -98,7 +117,7 @@
      * Change selected position.
      */
     private void setSelectedPosition(final int position, final int scrollExtra) throws Throwable {
-        runTestOnUiThread(new Runnable() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             public void run() {
                 mGridView.setSelectedPosition(position, scrollExtra);
             }
@@ -129,8 +148,8 @@
     protected void waitForScrollIdle(Runnable verify) throws Throwable {
         Thread.sleep(100);
         int total = 0;
-        while (mGridView.getLayoutManager().isSmoothScrolling() ||
-                mGridView.getScrollState() != BaseGridView.SCROLL_STATE_IDLE) {
+        while (mGridView.getLayoutManager().isSmoothScrolling()
+                || mGridView.getScrollState() != BaseGridView.SCROLL_STATE_IDLE) {
             if ((total += 100) >= WAIT_FOR_SCROLL_IDLE_TIMEOUT_MS) {
                 throw new RuntimeException("waitForScrollIdle Timeout");
             }
@@ -140,7 +159,7 @@
                 break;
             }
             if (verify != null) {
-                runTestOnUiThread(verify);
+                InstrumentationRegistry.getInstrumentation().runOnMainSync(verify);
             }
         }
     }
@@ -156,7 +175,7 @@
                 break;
             }
             if (verify != null) {
-                runTestOnUiThread(verify);
+                InstrumentationRegistry.getInstrumentation().runOnMainSync(verify);
             }
         } while (mGridView.hasTransientState());
     }
@@ -174,7 +193,7 @@
     protected void scroll(int key, Runnable verify) throws Throwable {
         do {
             if (verify != null) {
-                runTestOnUiThread(verify);
+                InstrumentationRegistry.getInstrumentation().runOnMainSync(verify);
             }
             sendRepeatedKeys(10, key);
             try {
@@ -182,8 +201,8 @@
             } catch (InterruptedException ex) {
                 break;
             }
-        } while (mGridView.getLayoutManager().isSmoothScrolling() ||
-                mGridView.getScrollState() != BaseGridView.SCROLL_STATE_IDLE);
+        } while (mGridView.getLayoutManager().isSmoothScrolling()
+                || mGridView.getScrollState() != BaseGridView.SCROLL_STATE_IDLE);
     }
 
     protected void scrollToBegin(Runnable verify) throws Throwable {
@@ -226,8 +245,8 @@
             if (mOrientation == BaseGridView.HORIZONTAL) {
                 rowLocation = v.getTop();
             } else {
-                rowLocation = mGridView.getLayoutDirection() == ViewGroup.LAYOUT_DIRECTION_RTL ?
-                    v.getRight() : v.getLeft();
+                rowLocation = mGridView.getLayoutDirection() == ViewGroup.LAYOUT_DIRECTION_RTL
+                        ? v.getRight() : v.getLeft();
             }
             ArrayList<View> views = rows.get(rowLocation);
             if (views == null) {
@@ -351,13 +370,13 @@
     }
 
     private void initActivity(Intent intent) {
-        setActivityIntent(intent);
-        mActivity = getActivity();
-        final String testName = getName();
+        ActivityTestRule<GridActivity> activityTestRule =
+                new ActivityTestRule<GridActivity>(GridActivity.class, false, false);
+        mActivity = activityTestRule.launchActivity(intent);
         try {
-            runTestOnUiThread(new Runnable() {
+            InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
                 public void run() {
-                    mActivity.setTitle(testName);
+                    mActivity.setTitle(testName.getMethodName());
                 }
             });
             Thread.sleep(1000);
@@ -367,9 +386,9 @@
         mGridView = mActivity.mGridView;
     }
 
+    @Test
     public void testThreeRowHorizontalBasic() throws Throwable {
-        mInstrumentation = getInstrumentation();
-        Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class);
+        Intent intent = new Intent();
         intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.horizontal_grid);
         intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 100);
         initActivity(intent);
@@ -430,6 +449,7 @@
         }
     }
 
+    @Test
     public void testItemDecorationAndMargins() throws Throwable {
 
         final int leftMargin = 3;
@@ -438,8 +458,7 @@
         final int bottomMargin = 8;
         final int itemHeight = 100;
 
-        mInstrumentation = getInstrumentation();
-        Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class);
+        Intent intent = new Intent();
         intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.vertical_linear);
         intent.putExtra(GridActivity.EXTRA_ITEMS, new int[]{itemHeight, itemHeight, itemHeight});
         intent.putExtra(GridActivity.EXTRA_LAYOUT_MARGINS,
@@ -456,7 +475,7 @@
         final int decorationRight = 19;
         final int decorationBottom = 2;
 
-        runTestOnUiThread(new Runnable() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             public void run() {
                 mGridView.addItemDecoration(new DividerDecoration(decorationLeft, decorationTop,
                         decorationRight, decorationBottom));
@@ -483,6 +502,7 @@
 
     }
 
+    @Test
     public void testItemDecorationAndMarginsAndOpticalBounds() throws Throwable {
         final int leftMargin = 3;
         final int topMargin = 4;
@@ -491,8 +511,7 @@
         final int itemHeight = 100;
         final int ninePatchDrawableResourceId = R.drawable.lb_card_shadow_focused;
 
-        mInstrumentation = getInstrumentation();
-        Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class);
+        Intent intent = new Intent();
         intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.vertical_linear);
         intent.putExtra(GridActivity.EXTRA_ITEMS, new int[]{itemHeight, itemHeight, itemHeight});
         intent.putExtra(GridActivity.EXTRA_CHILD_LAYOUT_ID, R.layout.relative_layout);
@@ -522,7 +541,7 @@
         assertTrue(opticalInsetsRight > 0);
         assertTrue(opticalInsetsBottom > 0);
 
-        runTestOnUiThread(new Runnable() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             public void run() {
                 mGridView.addItemDecoration(new DividerDecoration(decorationLeft, decorationTop,
                         decorationRight, decorationBottom));
@@ -553,10 +572,10 @@
 
     }
 
+    @Test
     public void testThreeColumnVerticalBasic() throws Throwable {
 
-        mInstrumentation = getInstrumentation();
-        Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class);
+        Intent intent = new Intent();
         intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.vertical_grid);
         intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 200);
         initActivity(intent);
@@ -571,9 +590,9 @@
         verifyBeginAligned();
     }
 
+    @Test
     public void testRedundantAppendRemove() throws Throwable {
-        mInstrumentation = getInstrumentation();
-        Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class);
+        Intent intent = new Intent();
         intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
                 R.layout.vertical_grid_testredundantappendremove);
         intent.putExtra(GridActivity.EXTRA_ITEMS, new int[]{
@@ -600,9 +619,9 @@
         verifyBeginAligned();
     }
 
+    @Test
     public void testRedundantAppendRemove2() throws Throwable {
-        mInstrumentation = getInstrumentation();
-        Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class);
+        Intent intent = new Intent();
         intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
                 R.layout.horizontal_grid_testredundantappendremove2);
         intent.putExtra(GridActivity.EXTRA_ITEMS, new int[]{
@@ -642,10 +661,9 @@
         verifyEdgesSame(endEdges, endEdges2);
     }
 
+    @Test
     public void testItemMovedHorizontal() throws Throwable {
-
-        mInstrumentation = getInstrumentation();
-        Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class);
+        Intent intent = new Intent();
         intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
                 R.layout.horizontal_grid);
         intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 200);
@@ -658,17 +676,17 @@
         mActivity.swap(150, 152);
         waitForTransientStateGone(null);
 
-        runTestOnUiThread(mVerifyLayout);
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(mVerifyLayout);
 
         scrollToBegin(mVerifyLayout);
 
         verifyBeginAligned();
     }
 
+    @Test
     public void testItemMovedVertical() throws Throwable {
 
-        mInstrumentation = getInstrumentation();
-        Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class);
+        Intent intent = new Intent();
         intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
                 R.layout.vertical_grid);
         intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 200);
@@ -681,7 +699,7 @@
         mActivity.swap(150, 152);
         waitForTransientStateGone(null);
 
-        runTestOnUiThread(mVerifyLayout);
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(mVerifyLayout);
 
         scrollToEnd(mVerifyLayout);
         scrollToBegin(mVerifyLayout);
@@ -689,10 +707,10 @@
         verifyBeginAligned();
     }
 
+    @Test
     public void testItemAddRemoveHorizontal() throws Throwable {
 
-        mInstrumentation = getInstrumentation();
-        Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class);
+        Intent intent = new Intent();
         intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
                 R.layout.horizontal_grid);
         intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 200);
@@ -724,10 +742,10 @@
         verifyBeginAligned();
     }
 
+    @Test
     public void testSetSelectedPositionDetached() throws Throwable {
 
-        mInstrumentation = getInstrumentation();
-        Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class);
+        Intent intent = new Intent();
         intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
                 R.layout.horizontal_linear);
         intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 50);
@@ -737,17 +755,17 @@
 
         final int focusToIndex = 49;
         final ViewGroup parent = (ViewGroup) mGridView.getParent();
-        runTestOnUiThread(new Runnable() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             public void run() {
                 parent.removeView(mGridView);
             }
         });
-        runTestOnUiThread(new Runnable() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             public void run() {
                 mGridView.setSelectedPositionSmooth(focusToIndex);
             }
         });
-        runTestOnUiThread(new Runnable() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             public void run() {
                 parent.addView(mGridView);
                 mGridView.requestFocus();
@@ -759,17 +777,17 @@
         assertTrue(mGridView.getLayoutManager().findViewByPosition(focusToIndex).hasFocus());
 
         final int focusToIndex2 = 0;
-        runTestOnUiThread(new Runnable() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             public void run() {
                 parent.removeView(mGridView);
             }
         });
-        runTestOnUiThread(new Runnable() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             public void run() {
                 mGridView.setSelectedPosition(focusToIndex2);
             }
         });
-        runTestOnUiThread(new Runnable() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             public void run() {
                 parent.addView(mGridView);
                 mGridView.requestFocus();
@@ -781,10 +799,10 @@
         assertTrue(mGridView.getLayoutManager().findViewByPosition(focusToIndex2).hasFocus());
     }
 
+    @Test
     public void testBug22209986() throws Throwable {
 
-        mInstrumentation = getInstrumentation();
-        Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class);
+        Intent intent = new Intent();
         intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
                 R.layout.horizontal_linear);
         intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 50);
@@ -793,7 +811,7 @@
         mNumRows = 1;
 
         final int focusToIndex = mGridView.getChildCount() - 1;
-        runTestOnUiThread(new Runnable() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             public void run() {
                 mGridView.setSelectedPositionSmooth(focusToIndex);
             }
@@ -801,14 +819,14 @@
 
         waitForTransientStateGone(null);
         waitForScrollIdle();
-        runTestOnUiThread(new Runnable() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             public void run() {
                 mGridView.setSelectedPositionSmooth(focusToIndex + 1);
             }
         });
         // let the scroll running for a while and requestLayout during scroll
         Thread.sleep(80);
-        runTestOnUiThread(new Runnable() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             public void run() {
                 assertEquals(mGridView.getScrollState(), BaseGridView.SCROLL_STATE_SETTLING);
                 mGridView.requestLayout();
@@ -819,7 +837,7 @@
 
         int leftEdge = mGridView.getLayoutManager().findViewByPosition(focusToIndex).getLeft();
 
-        runTestOnUiThread(new Runnable() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             public void run() {
                 mGridView.requestLayout();
             }
@@ -830,10 +848,10 @@
                 mGridView.getLayoutManager().findViewByPosition(focusToIndex).getLeft());
     }
 
+    @Test
     public void testScrollAndRemove() throws Throwable {
 
-        mInstrumentation = getInstrumentation();
-        Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class);
+        Intent intent = new Intent();
         intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
                 R.layout.horizontal_linear);
         intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 50);
@@ -842,13 +860,13 @@
         mNumRows = 1;
 
         final int focusToIndex = mGridView.getChildCount() - 1;
-        runTestOnUiThread(new Runnable() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             public void run() {
                 mGridView.setSelectedPositionSmooth(focusToIndex);
             }
         });
 
-        runTestOnUiThread(new Runnable() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             public void run() {
                 mActivity.removeItems(focusToIndex, 1);
             }
@@ -858,7 +876,7 @@
         waitForScrollIdle();
         int leftEdge = mGridView.getLayoutManager().findViewByPosition(focusToIndex).getLeft();
 
-        runTestOnUiThread(new Runnable() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             public void run() {
                 mGridView.requestLayout();
             }
@@ -869,10 +887,10 @@
                 mGridView.getLayoutManager().findViewByPosition(focusToIndex).getLeft());
     }
 
+    @Test
     public void testScrollAndInsert() throws Throwable {
 
-        mInstrumentation = getInstrumentation();
-        Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class);
+        Intent intent = new Intent();
         intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
                 R.layout.vertical_grid);
         int[] items = new int[1000];
@@ -886,7 +904,7 @@
 
         initActivity(intent);
 
-        runTestOnUiThread(new Runnable() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             public void run() {
                 mGridView.setSelectedPositionSmooth(150);
             }
@@ -895,13 +913,13 @@
 
         View view =  mGridView.getChildAt(mGridView.getChildCount() - 1);
         final int focusToIndex = mGridView.getChildAdapterPosition(view);
-        runTestOnUiThread(new Runnable() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             public void run() {
                 mGridView.setSelectedPositionSmooth(focusToIndex);
             }
         });
 
-        runTestOnUiThread(new Runnable() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             public void run() {
                 int[] newItems = new int[]{300, 300, 300};
                 mActivity.addItems(0, newItems);
@@ -912,10 +930,10 @@
         waitForScrollIdle();
     }
 
+    @Test
     public void testScrollAndInsertBeforeVisibleItem() throws Throwable {
 
-        mInstrumentation = getInstrumentation();
-        Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class);
+        Intent intent = new Intent();
         intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
                 R.layout.vertical_grid);
         int[] items = new int[1000];
@@ -929,7 +947,7 @@
 
         initActivity(intent);
 
-        runTestOnUiThread(new Runnable() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             public void run() {
                 mGridView.setSelectedPositionSmooth(150);
             }
@@ -938,13 +956,13 @@
 
         View view =  mGridView.getChildAt(mGridView.getChildCount() - 1);
         final int focusToIndex = mGridView.getChildAdapterPosition(view);
-        runTestOnUiThread(new Runnable() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             public void run() {
                 mGridView.setSelectedPositionSmooth(focusToIndex);
             }
         });
 
-        runTestOnUiThread(new Runnable() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             public void run() {
                 int[] newItems = new int[]{300, 300, 300};
                 mActivity.addItems(focusToIndex, newItems);
@@ -955,10 +973,10 @@
         waitForScrollIdle();
     }
 
+    @Test
     public void testSmoothScrollAndRemove() throws Throwable {
 
-        mInstrumentation = getInstrumentation();
-        Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class);
+        Intent intent = new Intent();
         intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
                 R.layout.horizontal_linear);
         intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 50);
@@ -967,13 +985,13 @@
         mNumRows = 1;
 
         final int focusToIndex = 40;
-        runTestOnUiThread(new Runnable() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             public void run() {
                 mGridView.setSelectedPositionSmooth(focusToIndex);
             }
         });
 
-        runTestOnUiThread(new Runnable() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             public void run() {
                 mActivity.removeItems(focusToIndex, 1);
             }
@@ -986,7 +1004,7 @@
         waitForScrollIdle();
         int leftEdge = mGridView.getLayoutManager().findViewByPosition(focusToIndex).getLeft();
 
-        runTestOnUiThread(new Runnable() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             public void run() {
                 mGridView.requestLayout();
             }
@@ -997,10 +1015,10 @@
                 mGridView.getLayoutManager().findViewByPosition(focusToIndex).getLeft());
     }
 
+    @Test
     public void testSmoothScrollAndRemove2() throws Throwable {
 
-        mInstrumentation = getInstrumentation();
-        Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class);
+        Intent intent = new Intent();
         intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
                 R.layout.horizontal_linear);
         intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 50);
@@ -1009,14 +1027,14 @@
         mNumRows = 1;
 
         final int focusToIndex = 40;
-        runTestOnUiThread(new Runnable() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             public void run() {
                 mGridView.setSelectedPositionSmooth(focusToIndex);
             }
         });
 
         final int removeIndex = mGridView.getChildCount() - 1;
-        runTestOnUiThread(new Runnable() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             public void run() {
                 mActivity.removeItems(removeIndex, 1);
             }
@@ -1029,7 +1047,7 @@
         waitForScrollIdle();
         int leftEdge = mGridView.getLayoutManager().findViewByPosition(focusToIndex).getLeft();
 
-        runTestOnUiThread(new Runnable() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             public void run() {
                 mGridView.requestLayout();
             }
@@ -1040,9 +1058,9 @@
                 mGridView.getLayoutManager().findViewByPosition(focusToIndex).getLeft());
     }
 
+    @Test
     public void testPendingSmoothScrollAndRemove() throws Throwable {
-        mInstrumentation = getInstrumentation();
-        Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class);
+        Intent intent = new Intent();
         intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
                 R.layout.vertical_linear);
         intent.putExtra(GridActivity.EXTRA_REQUEST_FOCUS_ONLAYOUT, true);
@@ -1063,13 +1081,13 @@
 
         // Pressing lots of key to make sure smooth scroller is running
         for (int i = 0; i < 20; i++) {
-            sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+            sendKey(KeyEvent.KEYCODE_DPAD_DOWN);
         }
         Thread.sleep(100);
 
         assertTrue(mGridView.getLayoutManager().isSmoothScrolling());
         final int removeIndex = mGridView.getChildCount() - 1;
-        runTestOnUiThread(new Runnable() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             public void run() {
                 mActivity.removeItems(removeIndex, 1);
             }
@@ -1084,7 +1102,7 @@
         int focusIndex = mGridView.getSelectedPosition();
         int leftEdge = mGridView.getLayoutManager().findViewByPosition(focusIndex).getLeft();
 
-        runTestOnUiThread(new Runnable() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             public void run() {
                 mGridView.requestLayout();
             }
@@ -1095,10 +1113,10 @@
                 mGridView.getLayoutManager().findViewByPosition(focusIndex).getLeft());
     }
 
+    @Test
     public void testFocusToFirstItem() throws Throwable {
 
-        mInstrumentation = getInstrumentation();
-        Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class);
+        Intent intent = new Intent();
         intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
                 R.layout.horizontal_grid);
         intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 200);
@@ -1122,6 +1140,7 @@
         assertTrue(mGridView.getLayoutManager().findViewByPosition(0).hasFocus());
     }
 
+    @Test
     public void testNonFocusableHorizontal() throws Throwable {
         final int numItems = 200;
         final int startPos = 45;
@@ -1129,8 +1148,7 @@
         final int numColumns = 3;
         final int endPos = startPos + numColumns * (skips + 1);
 
-        mInstrumentation = getInstrumentation();
-        Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class);
+        Intent intent = new Intent();
         intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
                 R.layout.horizontal_grid);
         intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, numItems);
@@ -1151,27 +1169,27 @@
         waitForScrollIdle(mVerifyLayout);
 
         if (mGridView.getLayoutDirection() == ViewGroup.LAYOUT_DIRECTION_RTL) {
-            sendKeys(KeyEvent.KEYCODE_DPAD_LEFT);
+            sendKey(KeyEvent.KEYCODE_DPAD_LEFT);
         } else {
-            sendKeys(KeyEvent.KEYCODE_DPAD_RIGHT);
+            sendKey(KeyEvent.KEYCODE_DPAD_RIGHT);
         }
         waitForScrollIdle(mVerifyLayout);
         assertEquals(endPos, mGridView.getSelectedPosition());
 
         if (mGridView.getLayoutDirection() == ViewGroup.LAYOUT_DIRECTION_RTL) {
-            sendKeys(KeyEvent.KEYCODE_DPAD_RIGHT);
+            sendKey(KeyEvent.KEYCODE_DPAD_RIGHT);
         } else {
-            sendKeys(KeyEvent.KEYCODE_DPAD_LEFT);
+            sendKey(KeyEvent.KEYCODE_DPAD_LEFT);
         }
         waitForScrollIdle(mVerifyLayout);
         assertEquals(startPos, mGridView.getSelectedPosition());
 
     }
 
+    @Test
     public void testNoInitialFocusable() throws Throwable {
 
-        mInstrumentation = getInstrumentation();
-        Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class);
+        Intent intent = new Intent();
         intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
                 R.layout.horizontal_linear);
         final int numItems = 100;
@@ -1192,19 +1210,19 @@
         assertTrue(mGridView.isFocused());
 
         if (mGridView.getLayoutDirection() == ViewGroup.LAYOUT_DIRECTION_RTL) {
-            sendKeys(KeyEvent.KEYCODE_DPAD_LEFT);
+            sendKey(KeyEvent.KEYCODE_DPAD_LEFT);
         } else {
-            sendKeys(KeyEvent.KEYCODE_DPAD_RIGHT);
+            sendKey(KeyEvent.KEYCODE_DPAD_RIGHT);
         }
         waitForScrollIdle(mVerifyLayout);
         assertEquals(firstFocusableIndex, mGridView.getSelectedPosition());
         assertTrue(mGridView.getLayoutManager().findViewByPosition(firstFocusableIndex).hasFocus());
     }
 
+    @Test
     public void testFocusOutOfEmptyListView() throws Throwable {
 
-        mInstrumentation = getInstrumentation();
-        Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class);
+        Intent intent = new Intent();
         intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
                 R.layout.horizontal_linear);
         final int numItems = 100;
@@ -1215,7 +1233,7 @@
         initActivity(intent);
 
         final View horizontalGridView = new HorizontalGridViewEx(mGridView.getContext());
-        runTestOnUiThread(new Runnable() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             @Override
             public void run() {
                 horizontalGridView.setFocusable(true);
@@ -1228,15 +1246,15 @@
 
         assertTrue(horizontalGridView.isFocused());
 
-        sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+        sendKey(KeyEvent.KEYCODE_DPAD_DOWN);
 
         assertTrue(mGridView.hasFocus());
     }
 
+    @Test
     public void testTransferFocusToChildWhenGainFocus() throws Throwable {
 
-        mInstrumentation = getInstrumentation();
-        Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class);
+        Intent intent = new Intent();
         intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
                 R.layout.horizontal_linear);
         final int numItems = 100;
@@ -1259,10 +1277,10 @@
         assertTrue(mGridView.getLayoutManager().findViewByPosition(firstFocusableIndex).hasFocus());
     }
 
+    @Test
     public void testFocusFromSecondChild() throws Throwable {
 
-        mInstrumentation = getInstrumentation();
-        Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class);
+        Intent intent = new Intent();
         intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
                 R.layout.horizontal_linear);
         final int numItems = 100;
@@ -1278,7 +1296,7 @@
         initActivity(intent);
 
         // switching Adapter to cause a full rebind,  test if it will focus to second item.
-        runTestOnUiThread(new Runnable() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             @Override
             public void run() {
                 mActivity.mNumItems = numItems;
@@ -1288,6 +1306,7 @@
         });
     }
 
+    @Test
     public void testNonFocusableVertical() throws Throwable {
         final int numItems = 200;
         final int startPos = 44;
@@ -1295,8 +1314,7 @@
         final int numColumns = 3;
         final int endPos = startPos + numColumns * (skips + 1);
 
-        mInstrumentation = getInstrumentation();
-        Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class);
+        Intent intent = new Intent();
         intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
                 R.layout.vertical_grid);
         intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, numItems);
@@ -1316,21 +1334,21 @@
         mGridView.setSelectedPositionSmooth(startPos);
         waitForScrollIdle(mVerifyLayout);
 
-        sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+        sendKey(KeyEvent.KEYCODE_DPAD_DOWN);
         waitForScrollIdle(mVerifyLayout);
         assertEquals(endPos, mGridView.getSelectedPosition());
 
-        sendKeys(KeyEvent.KEYCODE_DPAD_UP);
+        sendKey(KeyEvent.KEYCODE_DPAD_UP);
         waitForScrollIdle(mVerifyLayout);
         assertEquals(startPos, mGridView.getSelectedPosition());
 
     }
 
+    @Test
     public void testLtrFocusOutStartDisabled() throws Throwable {
         final int numItems = 200;
 
-        mInstrumentation = getInstrumentation();
-        Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class);
+        Intent intent = new Intent();
         intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.vertical_grid_ltr);
         intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, numItems);
         intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
@@ -1338,7 +1356,7 @@
         mNumRows = 1;
         initActivity(intent);
 
-        runTestOnUiThread(new Runnable() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             @Override
             public void run() {
                 mGridView.requestFocus();
@@ -1347,16 +1365,16 @@
         });
         waitForScrollIdle(mVerifyLayout);
 
-        sendKeys(KeyEvent.KEYCODE_DPAD_LEFT);
+        sendKey(KeyEvent.KEYCODE_DPAD_LEFT);
         waitForScrollIdle(mVerifyLayout);
         assertTrue(mGridView.hasFocus());
     }
 
+    @Test
     public void testRtlFocusOutStartDisabled() throws Throwable {
         final int numItems = 200;
 
-        mInstrumentation = getInstrumentation();
-        Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class);
+        Intent intent = new Intent();
         intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.vertical_grid_rtl);
         intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, numItems);
         intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
@@ -1364,7 +1382,7 @@
         mNumRows = 1;
         initActivity(intent);
 
-        runTestOnUiThread(new Runnable() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             @Override
             public void run() {
                 mGridView.requestFocus();
@@ -1373,18 +1391,18 @@
         });
         waitForScrollIdle(mVerifyLayout);
 
-        sendKeys(KeyEvent.KEYCODE_DPAD_RIGHT);
+        sendKey(KeyEvent.KEYCODE_DPAD_RIGHT);
         waitForScrollIdle(mVerifyLayout);
         assertTrue(mGridView.hasFocus());
     }
 
+    @Test
     public void testTransferFocusable() throws Throwable {
         final int numItems = 200;
         final int numColumns = 3;
         final int startPos = 1;
 
-        mInstrumentation = getInstrumentation();
-        Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class);
+        Intent intent = new Intent();
         intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
                 R.layout.horizontal_grid);
         intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, numItems);
@@ -1408,13 +1426,13 @@
         assertTrue(mGridView.getLayoutManager().findViewByPosition(startPos).hasFocus());
     }
 
+    @Test
     public void testTransferFocusable2() throws Throwable {
         final int numItems = 200;
         final int numColumns = 3;
         final int startPos = 10;
 
-        mInstrumentation = getInstrumentation();
-        Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class);
+        Intent intent = new Intent();
         intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
                 R.layout.horizontal_grid);
         intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, numItems);
@@ -1438,9 +1456,9 @@
         assertTrue(mGridView.getLayoutManager().findViewByPosition(startPos).hasFocus());
     }
 
+    @Test
     public void testNonFocusableLoseInFastLayout() throws Throwable {
-        mInstrumentation = getInstrumentation();
-        Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class);
+        Intent intent = new Intent();
         intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
                 R.layout.vertical_linear);
         int[] items = new int[300];
@@ -1460,16 +1478,16 @@
         waitForScrollIdleAndItemAnimation(mVerifyLayout);
 
         for (int i = 0; i < pressDown; i++) {
-            sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+            sendKey(KeyEvent.KEYCODE_DPAD_DOWN);
         }
         waitForScrollIdleAndItemAnimation(mVerifyLayout);
         assertFalse(mGridView.isFocused());
 
     }
 
+    @Test
     public void testFocusableViewAvailable() throws Throwable {
-        mInstrumentation = getInstrumentation();
-        Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class);
+        Intent intent = new Intent();
         intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
                 R.layout.vertical_linear);
         intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 0);
@@ -1481,7 +1499,7 @@
 
         initActivity(intent);
 
-        runTestOnUiThread(new Runnable() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             @Override
             public void run() {
                 // RecyclerView does not respect focusable and focusableInTouchMode flag, so
@@ -1505,13 +1523,13 @@
         waitForScrollIdleAndItemAnimation(mVerifyLayout);
 
         assertFalse("GridView should not be scrolled", scrolled[0]);
-        assertTrue(mGridView.getChildAt(1).hasFocus());
+        assertTrue(mGridView.getLayoutManager().findViewByPosition(2).hasFocus());
 
     }
 
+    @Test
     public void testSetSelectionWithDelta() throws Throwable {
-        mInstrumentation = getInstrumentation();
-        Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class);
+        Intent intent = new Intent();
         intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
                 R.layout.vertical_linear);
         intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 300);
@@ -1521,7 +1539,7 @@
 
         initActivity(intent);
 
-        runTestOnUiThread(new Runnable() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             public void run() {
                 mGridView.setSelectedPositionSmooth(3);
             }
@@ -1561,7 +1579,7 @@
         assertEquals(top1 - 100, top6);
 
         // scroll to invisible item that is far away.
-        runTestOnUiThread(new Runnable() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             public void run() {
                 mGridView.setSelectedPositionSmooth(100);
             }
@@ -1576,9 +1594,9 @@
         assertEquals(top1 - 50, top8);
     }
 
+    @Test
     public void testSetSelectionWithDeltaInGrid() throws Throwable {
-        mInstrumentation = getInstrumentation();
-        Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class);
+        Intent intent = new Intent();
         intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
                 R.layout.vertical_grid);
         intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 500);
@@ -1588,7 +1606,7 @@
 
         initActivity(intent);
 
-        runTestOnUiThread(new Runnable() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             public void run() {
                 mGridView.setSelectedPositionSmooth(10);
             }
@@ -1629,7 +1647,7 @@
         assertEquals(top1 - 100, top6);
 
         // scroll to invisible item that is far away.
-        runTestOnUiThread(new Runnable() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             public void run() {
                 mGridView.setSelectedPositionSmooth(200);
             }
@@ -1646,9 +1664,9 @@
     }
 
 
+    @Test
     public void testSetSelectionWithDeltaInGrid1() throws Throwable {
-        mInstrumentation = getInstrumentation();
-        Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class);
+        Intent intent = new Intent();
         intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
                 R.layout.vertical_grid);
         intent.putExtra(GridActivity.EXTRA_ITEMS, new int[]{
@@ -1691,7 +1709,7 @@
 
         initActivity(intent);
 
-        runTestOnUiThread(new Runnable() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             public void run() {
                 mGridView.setSelectedPositionSmooth(10);
             }
@@ -1732,7 +1750,7 @@
         assertEquals(top1 - 100, top6);
 
         // scroll to invisible item that is far away.
-        runTestOnUiThread(new Runnable() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             public void run() {
                 mGridView.setSelectedPositionSmooth(200);
             }
@@ -1748,9 +1766,9 @@
         assertEquals(top1 - 50, top8);
     }
 
+    @Test
     public void testSmoothScrollSelectionEvents() throws Throwable {
-        mInstrumentation = getInstrumentation();
-        Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class);
+        Intent intent = new Intent();
         intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
                 R.layout.vertical_grid);
         intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 500);
@@ -1759,7 +1777,7 @@
         mNumRows = 3;
         initActivity(intent);
 
-        runTestOnUiThread(new Runnable() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             public void run() {
                 mGridView.setSelectedPositionSmooth(30);
             }
@@ -1787,9 +1805,9 @@
 
     }
 
+    @Test
     public void testSmoothScrollSelectionEventsLinear() throws Throwable {
-        mInstrumentation = getInstrumentation();
-        Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class);
+        Intent intent = new Intent();
         intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
                 R.layout.vertical_linear);
         intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 500);
@@ -1798,7 +1816,7 @@
         mNumRows = 1;
         initActivity(intent);
 
-        runTestOnUiThread(new Runnable() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             public void run() {
                 mGridView.setSelectedPositionSmooth(10);
             }
@@ -1826,9 +1844,9 @@
 
     }
 
+    @Test
     public void testScrollToNoneExisting() throws Throwable {
-        mInstrumentation = getInstrumentation();
-        Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class);
+        Intent intent = new Intent();
         intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
                 R.layout.vertical_grid);
         intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 100);
@@ -1837,7 +1855,7 @@
         mNumRows = 3;
         initActivity(intent);
 
-        runTestOnUiThread(new Runnable() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             public void run() {
                 mGridView.setSelectedPositionSmooth(99);
             }
@@ -1846,13 +1864,13 @@
         humanDelay(500);
 
 
-        runTestOnUiThread(new Runnable() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             public void run() {
                 mGridView.setSelectedPositionSmooth(50);
             }
         });
         Thread.sleep(100);
-        runTestOnUiThread(new Runnable() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             public void run() {
                 mGridView.requestLayout();
                 mGridView.setSelectedPositionSmooth(0);
@@ -1863,9 +1881,9 @@
 
     }
 
+    @Test
     public void testSmoothscrollerInterrupted() throws Throwable {
-        mInstrumentation = getInstrumentation();
-        Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class);
+        Intent intent = new Intent();
         intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
                 R.layout.vertical_linear);
         intent.putExtra(GridActivity.EXTRA_REQUEST_FOCUS_ONLAYOUT, true);
@@ -1886,19 +1904,19 @@
 
         // Pressing lots of key to make sure smooth scroller is running
         for (int i = 0; i < 20; i++) {
-            sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+            sendKey(KeyEvent.KEYCODE_DPAD_DOWN);
         }
         Thread.sleep(100);
         int total = 0;
-        while (mGridView.getLayoutManager().isSmoothScrolling() ||
-                mGridView.getScrollState() != BaseGridView.SCROLL_STATE_IDLE) {
+        while (mGridView.getLayoutManager().isSmoothScrolling()
+                || mGridView.getScrollState() != BaseGridView.SCROLL_STATE_IDLE) {
             if ((total += 10) >= WAIT_FOR_SCROLL_IDLE_TIMEOUT_MS) {
                 throw new RuntimeException("waitForScrollIdle Timeout");
             }
             try {
                 // Repeatedly pressing to make sure pending keys does not drop to zero.
                 Thread.sleep(10);
-                sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+                sendKey(KeyEvent.KEYCODE_DPAD_DOWN);
             } catch (InterruptedException ex) {
                 break;
             }
@@ -1908,9 +1926,9 @@
                 ((VerticalGridViewEx) mGridView).mSmoothScrollByCalled < 10);
     }
 
+    @Test
     public void testSmoothscrollerCancelled() throws Throwable {
-        mInstrumentation = getInstrumentation();
-        Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class);
+        Intent intent = new Intent();
         intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
                 R.layout.vertical_linear);
         intent.putExtra(GridActivity.EXTRA_REQUEST_FOCUS_ONLAYOUT, true);
@@ -1931,7 +1949,7 @@
 
         int targetPosition = items.length - 1;
         mGridView.setSelectedPositionSmooth(targetPosition);
-        runTestOnUiThread(new Runnable() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             public void run() {
                 mGridView.stopScroll();
             }
@@ -1942,9 +1960,9 @@
                 mGridView.findFocus());
     }
 
+    @Test
     public void testSetNumRowsAndAddItem() throws Throwable {
-        mInstrumentation = getInstrumentation();
-        Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class);
+        Intent intent = new Intent();
         intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
                 R.layout.vertical_linear);
         intent.putExtra(GridActivity.EXTRA_REQUEST_FOCUS_ONLAYOUT, true);
@@ -1964,7 +1982,7 @@
 
         mActivity.addItems(items.length, new int[]{300});
 
-        runTestOnUiThread(new Runnable() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             public void run() {
                 ((VerticalGridView) mGridView).setNumColumns(2);
             }
@@ -1974,9 +1992,9 @@
     }
 
 
+    @Test
     public void testRequestLayoutBugInLayout() throws Throwable {
-        mInstrumentation = getInstrumentation();
-        Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class);
+        Intent intent = new Intent();
         intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
                 R.layout.vertical_linear);
         intent.putExtra(GridActivity.EXTRA_CHILD_LAYOUT_ID, R.layout.relative_layout);
@@ -1992,23 +2010,23 @@
 
         initActivity(intent);
 
-        runTestOnUiThread(new Runnable() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             public void run() {
                 mGridView.setSelectedPositionSmooth(1);
             }
         });
         waitForScrollIdle(mVerifyLayout);
 
-        sendKeys(KeyEvent.KEYCODE_DPAD_UP);
+        sendKey(KeyEvent.KEYCODE_DPAD_UP);
         waitForScrollIdle(mVerifyLayout);
 
         assertEquals("Line 2", ((TextView) mGridView.findFocus()).getText().toString());
     }
 
 
+    @Test
     public void testChangeLayoutInChild() throws Throwable {
-        mInstrumentation = getInstrumentation();
-        Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class);
+        Intent intent = new Intent();
         intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
                 R.layout.vertical_linear_wrap_content);
         intent.putExtra(GridActivity.EXTRA_REQUEST_LAYOUT_ONFOCUS, true);
@@ -2023,7 +2041,7 @@
 
         initActivity(intent);
 
-        runTestOnUiThread(new Runnable() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             public void run() {
                 mGridView.setSelectedPositionSmooth(0);
             }
@@ -2031,7 +2049,7 @@
         waitForScrollIdleAndItemAnimation(mVerifyLayout);
         verifyMargin();
 
-        runTestOnUiThread(new Runnable() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             public void run() {
                 mGridView.setSelectedPositionSmooth(1);
             }
@@ -2040,9 +2058,9 @@
         verifyMargin();
     }
 
+    @Test
     public void testWrapContent() throws Throwable {
-        mInstrumentation = getInstrumentation();
-        Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class);
+        Intent intent = new Intent();
         intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
                 R.layout.horizontal_grid_wrap);
         int[] items = new int[200];
@@ -2055,7 +2073,7 @@
 
         initActivity(intent);
 
-        runTestOnUiThread(new Runnable() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             public void run() {
                 mActivity.attachToNewAdapter(new int[0]);
             }
@@ -2064,9 +2082,9 @@
     }
 
 
+    @Test
     public void testZeroFixedSecondarySize() throws Throwable {
-        mInstrumentation = getInstrumentation();
-        Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class);
+        Intent intent = new Intent();
         intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
                 R.layout.vertical_linear_measured_with_zero);
         intent.putExtra(GridActivity.EXTRA_SECONDARY_SIZE_ZERO, true);
@@ -2083,9 +2101,9 @@
 
     }
 
+    @Test
     public void testChildStates() throws Throwable {
-        mInstrumentation = getInstrumentation();
-        Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class);
+        Intent intent = new Intent();
         intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.vertical_linear);
         int[] items = new int[100];
         for (int i = 0; i < items.length; i++) {
@@ -2104,7 +2122,7 @@
         final SparseArray<Parcelable> container = new SparseArray<Parcelable>();
 
         // 1 Save view states
-        runTestOnUiThread(new Runnable() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             public void run() {
                 Selection.setSelection((Spannable)(((TextView) mGridView.getChildAt(0))
                         .getText()), 0, 1);
@@ -2115,7 +2133,7 @@
         });
 
         // 2 Change view states
-        runTestOnUiThread(new Runnable() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             public void run() {
                 Selection.setSelection((Spannable)(((TextView) mGridView.getChildAt(0))
                         .getText()), 1, 2);
@@ -2125,7 +2143,7 @@
         });
 
         // 3 Detached and re-attached,  should still maintain state of (2)
-        runTestOnUiThread(new Runnable() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             public void run() {
                 mGridView.setSelectedPositionSmooth(1);
             }
@@ -2137,13 +2155,13 @@
         assertEquals(((TextView) mGridView.getChildAt(1)).getSelectionEnd(), 2);
 
         // 4 Recycled and rebound, should load state from (2)
-        runTestOnUiThread(new Runnable() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             public void run() {
                 mGridView.setSelectedPositionSmooth(20);
             }
         });
         waitForScrollIdle(mVerifyLayout);
-        runTestOnUiThread(new Runnable() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             public void run() {
                 mGridView.setSelectedPositionSmooth(0);
             }
@@ -2156,9 +2174,9 @@
     }
 
 
+    @Test
     public void testNoDispatchSaveChildState() throws Throwable {
-        mInstrumentation = getInstrumentation();
-        Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class);
+        Intent intent = new Intent();
         intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.vertical_linear);
         int[] items = new int[100];
         for (int i = 0; i < items.length; i++) {
@@ -2176,7 +2194,7 @@
         final SparseArray<Parcelable> container = new SparseArray<Parcelable>();
 
         // 1. Set text selection, save view states should do nothing on child
-        runTestOnUiThread(new Runnable() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             public void run() {
                 for (int i = 0; i < mGridView.getChildCount(); i++) {
                     Selection.setSelection((Spannable)(((TextView) mGridView.getChildAt(i))
@@ -2187,7 +2205,7 @@
         });
 
         // 2. clear the text selection
-        runTestOnUiThread(new Runnable() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             public void run() {
                 for (int i = 0; i < mGridView.getChildCount(); i++) {
                     Selection.removeSelection((Spannable)(((TextView) mGridView.getChildAt(i))
@@ -2197,7 +2215,7 @@
         });
 
         // 3. Restore view states should be a no-op for child
-        runTestOnUiThread(new Runnable() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             public void run() {
                 mGridView.restoreHierarchyState(container);
                 for (int i = 0; i < mGridView.getChildCount(); i++) {
@@ -2271,9 +2289,9 @@
         }
     }
 
+    @Test
     public void testMultipleScrollPosition1() throws Throwable {
-        mInstrumentation = getInstrumentation();
-        Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class);
+        Intent intent = new Intent();
         intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
                 R.layout.vertical_linear);
         intent.putExtra(GridActivity.EXTRA_CHILD_LAYOUT_ID, R.layout.relative_layout);
@@ -2300,7 +2318,7 @@
         assertEquals("First view is aligned with padding top",
                 mGridView.getPaddingTop(), mGridView.getChildAt(0).getTop());
 
-        sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+        sendKey(KeyEvent.KEYCODE_DPAD_DOWN);
         waitForScrollIdle(mVerifyLayout);
 
         final View v = mGridView.getChildAt(0);
@@ -2340,9 +2358,9 @@
         }
     }
 
+    @Test
     public void testMultipleScrollPosition2() throws Throwable {
-        mInstrumentation = getInstrumentation();
-        Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class);
+        Intent intent = new Intent();
         intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.vertical_linear);
         intent.putExtra(GridActivity.EXTRA_CHILD_LAYOUT_ID, R.layout.relative_layout);
         intent.putExtra(GridActivity.EXTRA_REQUEST_FOCUS_ONLAYOUT, true);
@@ -2364,7 +2382,7 @@
         assertEquals("First view is aligned with padding top", mGridView.getPaddingTop(),
                 mGridView.getChildAt(0).getTop());
 
-        sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+        sendKey(KeyEvent.KEYCODE_DPAD_DOWN);
         waitForScrollIdle(mVerifyLayout);
 
         final View v = mGridView.getChildAt(0);
@@ -2403,9 +2421,9 @@
         }
     }
 
+    @Test
     public void testMultipleScrollPosition3() throws Throwable {
-        mInstrumentation = getInstrumentation();
-        Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class);
+        Intent intent = new Intent();
         intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.vertical_linear);
         intent.putExtra(GridActivity.EXTRA_CHILD_LAYOUT_ID, R.layout.relative_layout);
         intent.putExtra(GridActivity.EXTRA_REQUEST_FOCUS_ONLAYOUT, true);
@@ -2427,7 +2445,7 @@
         assertEquals("First view is aligned with padding top", mGridView.getPaddingTop(),
                 mGridView.getChildAt(0).getTop());
 
-        sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+        sendKey(KeyEvent.KEYCODE_DPAD_DOWN);
         waitForScrollIdle(mVerifyLayout);
 
         final View v = mGridView.getChildAt(0);
@@ -2439,9 +2457,9 @@
                 mGridView.getPaddingTop() - (t2align - t1align), v.getTop());
     }
 
+    @Test
     public void testSelectionAndAddItemInOneCycle() throws Throwable {
-        mInstrumentation = getInstrumentation();
-        Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class);
+        Intent intent = new Intent();
         intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
                 R.layout.vertical_linear);
         intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 0);
@@ -2449,7 +2467,7 @@
         mOrientation = BaseGridView.HORIZONTAL;
         mNumRows = 1;
 
-        runTestOnUiThread(new Runnable() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             public void run() {
                 mActivity.addItems(0, new int[]{300, 300});
                 mGridView.setSelectedPosition(0);
@@ -2459,17 +2477,18 @@
         assertEquals(0, mGridView.getSelectedPosition());
     }
 
+    @Test
     public void testSelectViewTaskSmoothWithAdapterChange() throws Throwable {
         testSelectViewTaskWithAdapterChange(true /*smooth*/);
     }
 
+    @Test
     public void testSelectViewTaskWithAdapterChange() throws Throwable {
         testSelectViewTaskWithAdapterChange(false /*smooth*/);
     }
 
     private void testSelectViewTaskWithAdapterChange(final boolean smooth) throws Throwable {
-        mInstrumentation = getInstrumentation();
-        Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class);
+        Intent intent = new Intent();
         intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
                 R.layout.vertical_linear);
         intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 2);
@@ -2484,7 +2503,7 @@
                 selectedViewByTask[0] = viewHolder.itemView;
             }
         };
-        runTestOnUiThread(new Runnable() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             public void run() {
                 mActivity.removeItems(0, 1);
                 if (smooth) {
@@ -2501,9 +2520,9 @@
         assertSame(mGridView.getLayoutManager().findViewByPosition(0), selectedViewByTask[0]);
     }
 
+    @Test
     public void testNotifyItemTypeChangedSelectionEvent() throws Throwable {
-        mInstrumentation = getInstrumentation();
-        Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class);
+        Intent intent = new Intent();
         intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
                 R.layout.vertical_linear);
         intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 10);
@@ -2521,7 +2540,7 @@
             }
         });
 
-        runTestOnUiThread(new Runnable() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             public void run() {
                 ChangeableViewTypesProvider.setViewType(0, 1);
                 mGridView.getAdapter().notifyItemChanged(0, 1);
@@ -2533,9 +2552,9 @@
         assertEquals((int) selectedLog.get(0), 0);
     }
 
+    @Test
     public void testSelectionSmoothAndAddItemInOneCycle() throws Throwable {
-        mInstrumentation = getInstrumentation();
-        Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class);
+        Intent intent = new Intent();
         intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
                 R.layout.vertical_linear);
         intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 0);
@@ -2543,7 +2562,7 @@
         mOrientation = BaseGridView.HORIZONTAL;
         mNumRows = 1;
 
-        runTestOnUiThread(new Runnable() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             public void run() {
                 mActivity.addItems(0, new int[]{300, 300});
                 mGridView.setSelectedPositionSmooth(0);
@@ -2553,9 +2572,9 @@
         assertEquals(0, mGridView.getSelectedPosition());
     }
 
+    @Test
     public void testExtraLayoutSpace() throws Throwable {
-        mInstrumentation = getInstrumentation();
-        Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class);
+        Intent intent = new Intent();
         intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
                 R.layout.vertical_linear);
         intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 1000);
@@ -2569,7 +2588,7 @@
         mNumRows = 1;
 
         // add extra layout space
-        runTestOnUiThread(new Runnable() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             public void run() {
                 mGridView.setExtraLayoutSpace(extraLayoutSize);
             }
@@ -2578,8 +2597,7 @@
         View v;
         v = mGridView.getChildAt(mGridView.getChildCount() - 1);
         assertTrue(v.getTop() < windowSize + extraLayoutSize);
-        assertTrue(v.getBottom() >= windowSize + extraLayoutSize -
-                mGridView.getVerticalMargin());
+        assertTrue(v.getBottom() >= windowSize + extraLayoutSize - mGridView.getVerticalMargin());
 
         mGridView.setSelectedPositionSmooth(150);
         waitForScrollIdle(mVerifyLayout);
@@ -2588,7 +2606,7 @@
         assertTrue(v.getTop() <= -extraLayoutSize + mGridView.getVerticalMargin());
 
         // clear extra layout space
-        runTestOnUiThread(new Runnable() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             public void run() {
                 mGridView.setExtraLayoutSpace(0);
                 verifyMargin();
@@ -2600,9 +2618,9 @@
         assertTrue(v.getBottom() >= windowSize - mGridView.getVerticalMargin());
     }
 
+    @Test
     public void testFocusFinder() throws Throwable {
-        mInstrumentation = getInstrumentation();
-        Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class);
+        Intent intent = new Intent();
         intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
                 R.layout.vertical_linear_with_button);
         intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 3);
@@ -2614,13 +2632,13 @@
         // test focus from button to vertical grid view
         final View button = mActivity.findViewById(R.id.button);
         assertTrue(button.isFocused());
-        sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+        sendKey(KeyEvent.KEYCODE_DPAD_DOWN);
         assertFalse(mGridView.isFocused());
         assertTrue(mGridView.hasFocus());
 
         // FocusFinder should find last focused(2nd) item on DPAD_DOWN
         final View secondChild = mGridView.getChildAt(1);
-        runTestOnUiThread(new Runnable() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             @Override
             public void run() {
                 secondChild.requestFocus();
@@ -2628,12 +2646,12 @@
             }
         });
         assertTrue(button.isFocused());
-        sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+        sendKey(KeyEvent.KEYCODE_DPAD_DOWN);
         assertTrue(secondChild.isFocused());
 
         // Bug 26918143 Even VerticalGridView is not focusable, FocusFinder should find last focused
         // (2nd) item on DPAD_DOWN.
-        runTestOnUiThread(new Runnable() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             @Override
             public void run() {
                 button.requestFocus();
@@ -2642,13 +2660,13 @@
         mGridView.setFocusable(false);
         mGridView.setFocusableInTouchMode(false);
         assertTrue(button.isFocused());
-        sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+        sendKey(KeyEvent.KEYCODE_DPAD_DOWN);
         assertTrue(secondChild.isFocused());
     }
 
+    @Test
     public void testRestoreIndexAndAddItems() throws Throwable {
-        mInstrumentation = getInstrumentation();
-        Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class);
+        Intent intent = new Intent();
         intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
                 R.layout.vertical_linear);
         intent.putExtra(GridActivity.EXTRA_CHILD_LAYOUT_ID, R.layout.horizontal_item);
@@ -2659,7 +2677,7 @@
 
         assertEquals(mGridView.getSelectedPosition(), 0);
         final SparseArray states = new SparseArray();
-        runTestOnUiThread(new Runnable() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             @Override
             public void run() {
                 mGridView.saveHierarchyState(states);
@@ -2667,7 +2685,7 @@
             }
 
         });
-        runTestOnUiThread(new Runnable() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             @Override
             public void run() {
                 mGridView.restoreHierarchyState(states);
@@ -2680,9 +2698,9 @@
         assertEquals(mGridView.getSelectedPosition(), 0);
     }
 
+    @Test
     public void test27766012() throws Throwable {
-        mInstrumentation = getInstrumentation();
-        Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class);
+        Intent intent = new Intent();
         intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
                 R.layout.vertical_linear_with_button_onleft);
         intent.putExtra(GridActivity.EXTRA_CHILD_LAYOUT_ID, R.layout.horizontal_item);
@@ -2696,14 +2714,14 @@
         // set remove animator two seconds
         mGridView.getItemAnimator().setRemoveDuration(2000);
         final View view = mGridView.getChildAt(1);
-        runTestOnUiThread(new Runnable() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             @Override
             public void run() {
                 view.requestFocus();
             }
         });
         assertTrue(view.hasFocus());
-        runTestOnUiThread(new Runnable() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             @Override
             public void run() {
                 mActivity.removeItems(0, 2);
@@ -2713,7 +2731,7 @@
         // wait one second, removing second view is still attached to parent
         Thread.sleep(1000);
         assertSame(view.getParent(), mGridView);
-        runTestOnUiThread(new Runnable() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             @Override
             public void run() {
                 // refocus to the removed item and do a focus search.
@@ -2724,9 +2742,9 @@
         });
     }
 
+    @Test
     public void testBug27258366() throws Throwable {
-        mInstrumentation = getInstrumentation();
-        Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class);
+        Intent intent = new Intent();
         intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
                 R.layout.vertical_linear_with_button_onleft);
         intent.putExtra(GridActivity.EXTRA_CHILD_LAYOUT_ID, R.layout.horizontal_item);
@@ -2749,7 +2767,7 @@
                 }
             }
         };
-        runTestOnUiThread(new Runnable() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             @Override
             public void run() {
                 mGridView.getAdapter().notifyDataSetChanged();
@@ -2758,21 +2776,21 @@
         Thread.sleep(100);
 
         final ViewGroup secondChild = (ViewGroup) mGridView.getChildAt(1);
-        runTestOnUiThread(new Runnable() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             @Override
             public void run() {
                 secondChild.requestFocus();
             }
         });
-        sendKeys(KeyEvent.KEYCODE_DPAD_LEFT);
+        sendKey(KeyEvent.KEYCODE_DPAD_LEFT);
         Thread.sleep(100);
         final View button = mActivity.findViewById(R.id.button);
         assertTrue(button.isFocused());
     }
 
+    @Test
     public void testAccessibility() throws Throwable {
-        mInstrumentation = getInstrumentation();
-        Intent intent = new Intent(mInstrumentation.getContext(), GridActivity.class);
+        Intent intent = new Intent();
         intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
                 R.layout.vertical_linear);
         intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 1000);
@@ -2786,14 +2804,14 @@
         final RecyclerViewAccessibilityDelegate delegateCompat = mGridView
                 .getCompatAccessibilityDelegate();
         final AccessibilityNodeInfoCompat info = AccessibilityNodeInfoCompat.obtain();
-        runTestOnUiThread(new Runnable() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             @Override
             public void run() {
                 delegateCompat.onInitializeAccessibilityNodeInfo(mGridView, info);
             }
         });
         assertTrue("test sanity", info.isScrollable());
-        runTestOnUiThread(new Runnable() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             @Override
             public void run() {
                 delegateCompat.performAccessibilityAction(mGridView,
@@ -2804,14 +2822,14 @@
         int selectedPosition1 = mGridView.getSelectedPosition();
         assertTrue(0 < selectedPosition1);
 
-        runTestOnUiThread(new Runnable() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             @Override
             public void run() {
                 delegateCompat.onInitializeAccessibilityNodeInfo(mGridView, info);
             }
         });
         assertTrue("test sanity", info.isScrollable());
-        runTestOnUiThread(new Runnable() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             @Override
             public void run() {
                 delegateCompat.performAccessibilityAction(mGridView,
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/widget/MediaNowPlayingViewTest.java b/v17/leanback/tests/java/android/support/v17/leanback/widget/MediaNowPlayingViewTest.java
new file mode 100644
index 0000000..dc6354c
--- /dev/null
+++ b/v17/leanback/tests/java/android/support/v17/leanback/widget/MediaNowPlayingViewTest.java
@@ -0,0 +1,45 @@
+/*
+ * 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 android.support.v17.leanback.widget;
+
+
+import android.content.Context;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+/**
+ * Testing MediaNowPlayingView widget
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+
+public class MediaNowPlayingViewTest {
+    private Context mContext;
+
+    @Before
+    public void setup() throws Exception {
+        mContext = InstrumentationRegistry.getTargetContext();
+    }
+
+    @Test
+    public void testViewCreation() {
+        new MediaNowPlayingView(mContext, null);
+    }
+}
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/widget/PagingIndicatorTest.java b/v17/leanback/tests/java/android/support/v17/leanback/widget/PagingIndicatorTest.java
index abc396b..12edb62 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/widget/PagingIndicatorTest.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/widget/PagingIndicatorTest.java
@@ -15,19 +15,30 @@
  */
 package android.support.v17.leanback.widget;
 
-import android.test.AndroidTestCase;
+import static org.junit.Assert.assertEquals;
+
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
 import android.test.suitebuilder.annotation.SmallTest;
 
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests for {@link PagingIndicator}.
+ */
 @SmallTest
-public class PagingIndicatorTest extends AndroidTestCase {
+@RunWith(AndroidJUnit4.class)
+public class PagingIndicatorTest {
     private PagingIndicator mIndicator;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mIndicator = new PagingIndicator(getContext());
+    @Before
+    public void setup() throws Exception {
+        mIndicator = new PagingIndicator(InstrumentationRegistry.getTargetContext());
     }
 
+    @Test
     public void testDotPosition() {
         mIndicator.setPageCount(3);
         assertDotPosition();
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/widget/ParallaxFloatEffectTest.java b/v17/leanback/tests/java/android/support/v17/leanback/widget/ParallaxFloatEffectTest.java
new file mode 100644
index 0000000..beb598e
--- /dev/null
+++ b/v17/leanback/tests/java/android/support/v17/leanback/widget/ParallaxFloatEffectTest.java
@@ -0,0 +1,253 @@
+/* This file is auto-generated from ParallaxIntEffectTest.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 android.support.v17.leanback.widget;
+
+import android.support.test.runner.AndroidJUnitRunner;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+import android.support.test.runner.AndroidJUnit4;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class ParallaxFloatEffectTest {
+
+    ParallaxSource.FloatSource source;
+    float screenMax;
+    ParallaxEffect.FloatEffect effect;
+    @Mock ParallaxTarget target;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+        source = new ParallaxSource.FloatSource<ParallaxSource.FloatProperty>() {
+
+            public void setListener(ParallaxSource.Listener listener) {
+            }
+
+            public float getMaxParentVisibleSize() {
+                return screenMax;
+            }
+
+            @Override
+            public FloatProperty createProperty(String name, int index) {
+                return new FloatProperty(name, index);
+            }
+        };
+        effect = new ParallaxEffect.FloatEffect();
+    }
+
+    @Test
+    public void testOneVariable() {
+        screenMax = 1080;
+        ParallaxSource.FloatProperty var1 = source.addProperty("var1");
+
+        effect.setPropertyRanges(var1.atAbsolute(540), var1.atAbsolute(0));
+        effect.target(target);
+
+        // start
+        var1.setFloatValue(source, 540);
+        effect.performMapping(source);
+        verify(target, times(1)).update(0f);
+        Mockito.reset(target);
+
+        // 25% complete
+        var1.setFloatValue(source, 405);
+        effect.performMapping(source);
+        verify(target, times(1)).update(0.25f);
+        Mockito.reset(target);
+
+        // middle
+        var1.setFloatValue(source, 270);
+        effect.performMapping(source);
+        verify(target, times(1)).update(.5f);
+        Mockito.reset(target);
+
+        // 75% complete
+        var1.setFloatValue(source, 135);
+        effect.performMapping(source);
+        verify(target, times(1)).update(0.75f);
+        Mockito.reset(target);
+
+        // end
+        var1.setFloatValue(source, 0);
+        effect.performMapping(source);
+        verify(target, times(1)).update(1f);
+        Mockito.reset(target);
+
+        // after end
+        var1.setFloatValue(source, -1000);
+        effect.performMapping(source);
+        verify(target, times(1)).update(1f);
+        Mockito.reset(target);
+
+        // before start
+        var1.setFloatValue(source, 1000);
+        effect.performMapping(source);
+        verify(target, times(1)).update(0f);
+        Mockito.reset(target);
+
+        // unknown_before
+        var1.setFloatValue(source, ParallaxSource.FloatProperty.UNKNOWN_BEFORE);
+        effect.performMapping(source);
+        verify(target, times(1)).update(1f);
+        Mockito.reset(target);
+
+        // unknown_after
+        var1.setFloatValue(source, ParallaxSource.FloatProperty.UNKNOWN_AFTER);
+        effect.performMapping(source);
+        verify(target, times(1)).update(0f);
+        Mockito.reset(target);
+    }
+
+    @Test(expected=IllegalStateException.class)
+    public void testVerifyKeyValueOfSameVariableInDesendantOrder() {
+        screenMax = 1080;
+        ParallaxSource.FloatProperty var1 = source.addProperty("var1");
+
+        effect.setPropertyRanges(var1.atAbsolute(540), var1.atAbsolute(550));
+        effect.target(target);
+        var1.setFloatValue(source, 0);
+        effect.performMapping(source);
+    }
+
+    @Test
+    public void testTwoVariable() {
+        screenMax = 1080;
+        ParallaxSource.FloatProperty var1 = source.addProperty("var1");
+        ParallaxSource.FloatProperty var2 = source.addProperty("var2");
+
+        effect.setPropertyRanges(var1.atAbsolute(540), var2.atAbsolute(540));
+        effect.target(target);
+
+        // start
+        var1.setFloatValue(source, 540);
+        var2.setFloatValue(source, 840);
+        effect.performMapping(source);
+        verify(target, times(1)).update(0f);
+        Mockito.reset(target);
+
+        // middle
+        var1.setFloatValue(source, 390);
+        var2.setFloatValue(source, 690);
+        effect.performMapping(source);
+        verify(target, times(1)).update(.5f);
+        Mockito.reset(target);
+
+        // end
+        var1.setFloatValue(source, 240);
+        var2.setFloatValue(source, 540);
+        effect.performMapping(source);
+        verify(target, times(1)).update(1f);
+        Mockito.reset(target);
+
+        // after end
+        var1.setFloatValue(source, 200);
+        var2.setFloatValue(source, 500);
+        effect.performMapping(source);
+        verify(target, times(1)).update(1f);
+        Mockito.reset(target);
+
+        // before start
+        var1.setFloatValue(source, 1000);
+        var2.setFloatValue(source, 1300);
+        effect.performMapping(source);
+        verify(target, times(1)).update(0f);
+        Mockito.reset(target);
+
+        // unknown_before
+        var1.setFloatValue(source, ParallaxSource.FloatProperty.UNKNOWN_BEFORE);
+        var2.setFloatValue(source, ParallaxSource.FloatProperty.UNKNOWN_BEFORE);
+        effect.performMapping(source);
+        verify(target, times(1)).update(1f);
+        Mockito.reset(target);
+
+        // unknown_before
+        var1.setFloatValue(source, ParallaxSource.FloatProperty.UNKNOWN_BEFORE);
+        var2.setFloatValue(source, -1000);
+        effect.performMapping(source);
+        verify(target, times(1)).update(1f);
+        Mockito.reset(target);
+
+        // unknown_after
+        var1.setFloatValue(source, ParallaxSource.FloatProperty.UNKNOWN_AFTER);
+        var2.setFloatValue(source, ParallaxSource.FloatProperty.UNKNOWN_AFTER);
+        effect.performMapping(source);
+        verify(target, times(1)).update(0f);
+        Mockito.reset(target);
+
+        // unknown_after
+        var1.setFloatValue(source, 1000);
+        var2.setFloatValue(source, ParallaxSource.FloatProperty.UNKNOWN_AFTER);
+        effect.performMapping(source);
+        verify(target, times(1)).update(0f);
+        Mockito.reset(target);
+
+        // unknown_before and less
+        var1.setFloatValue(source, ParallaxSource.FloatProperty.UNKNOWN_BEFORE);
+        var2.setFloatValue(source, 500);
+        effect.performMapping(source);
+        verify(target, times(1)).update(1f);
+        Mockito.reset(target);
+
+        // unknown_before and hit second
+        var1.setFloatValue(source, ParallaxSource.FloatProperty.UNKNOWN_BEFORE);
+        var2.setFloatValue(source, 540);
+        effect.performMapping(source);
+        verify(target, times(1)).update(1f);
+        Mockito.reset(target);
+
+        // unknown_before with estimation
+        var1.setFloatValue(source, ParallaxSource.FloatProperty.UNKNOWN_BEFORE);
+        var2.setFloatValue(source, 1080);
+        effect.performMapping(source);
+        verify(target, times(1)).update(0.5f);
+        Mockito.reset(target);
+
+        // unknown_after with estimation
+        var1.setFloatValue(source, 0);
+        var2.setFloatValue(source, ParallaxSource.FloatProperty.UNKNOWN_AFTER);
+        effect.performMapping(source);
+        verify(target, times(1)).update(0.5f);
+        Mockito.reset(target);
+    }
+
+}
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/widget/ParallaxFloatSourceTest.java b/v17/leanback/tests/java/android/support/v17/leanback/widget/ParallaxFloatSourceTest.java
new file mode 100644
index 0000000..49e0999
--- /dev/null
+++ b/v17/leanback/tests/java/android/support/v17/leanback/widget/ParallaxFloatSourceTest.java
@@ -0,0 +1,165 @@
+/* This file is auto-generated from ParallaxIntSourceTest.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 android.support.v17.leanback.widget;
+
+import android.support.test.runner.AndroidJUnitRunner;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertSame;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+import android.support.test.runner.AndroidJUnit4;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class ParallaxFloatSourceTest {
+
+    ParallaxSource.FloatSource source;
+    float screenMax;
+
+    static void assertFloatEquals(float expected, float actual) {
+        org.junit.Assert.assertEquals((double)expected, (double)actual, 0.0001d);
+    }
+
+    @Before
+    public void setUp() throws Exception {
+        source = new ParallaxSource.FloatSource<ParallaxSource.FloatProperty>() {
+
+            public void setListener(ParallaxSource.Listener listener) {
+            }
+
+            public float getMaxParentVisibleSize() {
+                return screenMax;
+            }
+
+            @Override
+            public FloatProperty createProperty(String name, int index) {
+                return new FloatProperty(name, index);
+            }
+        };
+    }
+
+    @Test
+    public void testVariable() {
+        screenMax = 1080;
+        ParallaxSource.FloatProperty var1 = source.addProperty("var1");
+        var1.setFloatValue(source, 54);
+        assertFloatEquals((float)54, var1.getFloatValue(source));
+        assertEquals(var1.getName(), "var1");
+        var1.set(source, (float)2000);
+        assertFloatEquals((float)2000, var1.get(source).floatValue());
+    }
+
+    @Test
+    public void testFixedKeyValue() {
+        screenMax = 1080;
+        ParallaxSource.FloatProperty var1 = source.addProperty("var1");
+
+        ParallaxSource.FloatPropertyKeyValue keyValue = var1.atAbsolute(1000);
+        assertSame(keyValue.getProperty(), var1);
+        assertFloatEquals((float)1000, keyValue.getKeyValue(source));
+    }
+
+    @Test
+    public void testFractionOfKeyValue() {
+        screenMax = 1080;
+        ParallaxSource.FloatProperty var1 = source.addProperty("var1");
+
+        ParallaxSource.FloatPropertyKeyValue keyValue = var1.at(0, 0.5f);
+        assertSame(keyValue.getProperty(), var1);
+        assertFloatEquals((float)540, keyValue.getKeyValue(source));
+    }
+
+    @Test
+    public void testFixedKeyValueWithFraction() {
+        screenMax = 1080;
+        ParallaxSource.FloatProperty var1 = source.addProperty("var1");
+
+        ParallaxSource.FloatPropertyKeyValue keyValue = var1.at(-100, 0.5f);
+        assertSame(keyValue.getProperty(), var1);
+        assertFloatEquals((float)440, keyValue.getKeyValue(source));
+
+        ParallaxSource.FloatPropertyKeyValue keyValue2 = var1.at(100, 0.5f);
+        assertSame(keyValue2.getProperty(), var1);
+        assertFloatEquals((float)640, keyValue2.getKeyValue(source));
+    }
+
+    @Test(expected=IllegalStateException.class)
+    public void testVerifyFloatPropertys_wrongOrder() {
+        ParallaxSource.FloatProperty var1 = source.addProperty("var1");
+        ParallaxSource.FloatProperty var2 = source.addProperty("var2");;
+
+        var1.setFloatValue(source, (float)500);
+        var2.setFloatValue(source, (float)499);
+
+        source.verifyProperties();
+    }
+
+    @Test(expected=IllegalStateException.class)
+    public void testVerifyFloatPropertysWrong_combination() {
+        ParallaxSource.FloatProperty var1 = source.addProperty("var1");
+        ParallaxSource.FloatProperty var2 = source.addProperty("var2");
+
+        var1.setFloatValue(source, ParallaxSource.FloatProperty.UNKNOWN_BEFORE);
+        var2.setFloatValue(source, ParallaxSource.FloatProperty.UNKNOWN_AFTER);
+
+        source.verifyProperties();
+    }
+
+    @Test
+    public void testVerifyFloatPropertys_success() {
+        ParallaxSource.FloatProperty var1 = source.addProperty("var1");
+        ParallaxSource.FloatProperty var2 = source.addProperty("var2");
+
+        var1.setFloatValue(source, (float)499);
+        var2.setFloatValue(source, (float)500);
+
+        source.verifyProperties();
+
+        var1.setFloatValue(source, ParallaxSource.FloatProperty.UNKNOWN_BEFORE);
+        var2.setFloatValue(source, (float)500);
+
+        source.verifyProperties();
+
+        var1.setFloatValue(source, (float)499);
+        var2.setFloatValue(source, ParallaxSource.FloatProperty.UNKNOWN_AFTER);
+
+        source.verifyProperties();
+    }
+}
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/widget/ParallaxIntEffectTest.java b/v17/leanback/tests/java/android/support/v17/leanback/widget/ParallaxIntEffectTest.java
new file mode 100644
index 0000000..e4a74c0
--- /dev/null
+++ b/v17/leanback/tests/java/android/support/v17/leanback/widget/ParallaxIntEffectTest.java
@@ -0,0 +1,251 @@
+/*
+ * 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 android.support.v17.leanback.widget;
+
+import android.support.test.runner.AndroidJUnitRunner;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+import android.support.test.runner.AndroidJUnit4;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class ParallaxIntEffectTest {
+
+    ParallaxSource.IntSource source;
+    int screenMax;
+    ParallaxEffect.IntEffect effect;
+    @Mock ParallaxTarget target;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+        source = new ParallaxSource.IntSource<ParallaxSource.IntProperty>() {
+
+            public void setListener(ParallaxSource.Listener listener) {
+            }
+
+            public int getMaxParentVisibleSize() {
+                return screenMax;
+            }
+
+            @Override
+            public IntProperty createProperty(String name, int index) {
+                return new IntProperty(name, index);
+            }
+        };
+        effect = new ParallaxEffect.IntEffect();
+    }
+
+    @Test
+    public void testOneVariable() {
+        screenMax = 1080;
+        ParallaxSource.IntProperty var1 = source.addProperty("var1");
+
+        effect.setPropertyRanges(var1.atAbsolute(540), var1.atAbsolute(0));
+        effect.target(target);
+
+        // start
+        var1.setIntValue(source, 540);
+        effect.performMapping(source);
+        verify(target, times(1)).update(0f);
+        Mockito.reset(target);
+
+        // 25% complete
+        var1.setIntValue(source, 405);
+        effect.performMapping(source);
+        verify(target, times(1)).update(0.25f);
+        Mockito.reset(target);
+
+        // middle
+        var1.setIntValue(source, 270);
+        effect.performMapping(source);
+        verify(target, times(1)).update(.5f);
+        Mockito.reset(target);
+
+        // 75% complete
+        var1.setIntValue(source, 135);
+        effect.performMapping(source);
+        verify(target, times(1)).update(0.75f);
+        Mockito.reset(target);
+
+        // end
+        var1.setIntValue(source, 0);
+        effect.performMapping(source);
+        verify(target, times(1)).update(1f);
+        Mockito.reset(target);
+
+        // after end
+        var1.setIntValue(source, -1000);
+        effect.performMapping(source);
+        verify(target, times(1)).update(1f);
+        Mockito.reset(target);
+
+        // before start
+        var1.setIntValue(source, 1000);
+        effect.performMapping(source);
+        verify(target, times(1)).update(0f);
+        Mockito.reset(target);
+
+        // unknown_before
+        var1.setIntValue(source, ParallaxSource.IntProperty.UNKNOWN_BEFORE);
+        effect.performMapping(source);
+        verify(target, times(1)).update(1f);
+        Mockito.reset(target);
+
+        // unknown_after
+        var1.setIntValue(source, ParallaxSource.IntProperty.UNKNOWN_AFTER);
+        effect.performMapping(source);
+        verify(target, times(1)).update(0f);
+        Mockito.reset(target);
+    }
+
+    @Test(expected=IllegalStateException.class)
+    public void testVerifyKeyValueOfSameVariableInDesendantOrder() {
+        screenMax = 1080;
+        ParallaxSource.IntProperty var1 = source.addProperty("var1");
+
+        effect.setPropertyRanges(var1.atAbsolute(540), var1.atAbsolute(550));
+        effect.target(target);
+        var1.setIntValue(source, 0);
+        effect.performMapping(source);
+    }
+
+    @Test
+    public void testTwoVariable() {
+        screenMax = 1080;
+        ParallaxSource.IntProperty var1 = source.addProperty("var1");
+        ParallaxSource.IntProperty var2 = source.addProperty("var2");
+
+        effect.setPropertyRanges(var1.atAbsolute(540), var2.atAbsolute(540));
+        effect.target(target);
+
+        // start
+        var1.setIntValue(source, 540);
+        var2.setIntValue(source, 840);
+        effect.performMapping(source);
+        verify(target, times(1)).update(0f);
+        Mockito.reset(target);
+
+        // middle
+        var1.setIntValue(source, 390);
+        var2.setIntValue(source, 690);
+        effect.performMapping(source);
+        verify(target, times(1)).update(.5f);
+        Mockito.reset(target);
+
+        // end
+        var1.setIntValue(source, 240);
+        var2.setIntValue(source, 540);
+        effect.performMapping(source);
+        verify(target, times(1)).update(1f);
+        Mockito.reset(target);
+
+        // after end
+        var1.setIntValue(source, 200);
+        var2.setIntValue(source, 500);
+        effect.performMapping(source);
+        verify(target, times(1)).update(1f);
+        Mockito.reset(target);
+
+        // before start
+        var1.setIntValue(source, 1000);
+        var2.setIntValue(source, 1300);
+        effect.performMapping(source);
+        verify(target, times(1)).update(0f);
+        Mockito.reset(target);
+
+        // unknown_before
+        var1.setIntValue(source, ParallaxSource.IntProperty.UNKNOWN_BEFORE);
+        var2.setIntValue(source, ParallaxSource.IntProperty.UNKNOWN_BEFORE);
+        effect.performMapping(source);
+        verify(target, times(1)).update(1f);
+        Mockito.reset(target);
+
+        // unknown_before
+        var1.setIntValue(source, ParallaxSource.IntProperty.UNKNOWN_BEFORE);
+        var2.setIntValue(source, -1000);
+        effect.performMapping(source);
+        verify(target, times(1)).update(1f);
+        Mockito.reset(target);
+
+        // unknown_after
+        var1.setIntValue(source, ParallaxSource.IntProperty.UNKNOWN_AFTER);
+        var2.setIntValue(source, ParallaxSource.IntProperty.UNKNOWN_AFTER);
+        effect.performMapping(source);
+        verify(target, times(1)).update(0f);
+        Mockito.reset(target);
+
+        // unknown_after
+        var1.setIntValue(source, 1000);
+        var2.setIntValue(source, ParallaxSource.IntProperty.UNKNOWN_AFTER);
+        effect.performMapping(source);
+        verify(target, times(1)).update(0f);
+        Mockito.reset(target);
+
+        // unknown_before and less
+        var1.setIntValue(source, ParallaxSource.IntProperty.UNKNOWN_BEFORE);
+        var2.setIntValue(source, 500);
+        effect.performMapping(source);
+        verify(target, times(1)).update(1f);
+        Mockito.reset(target);
+
+        // unknown_before and hit second
+        var1.setIntValue(source, ParallaxSource.IntProperty.UNKNOWN_BEFORE);
+        var2.setIntValue(source, 540);
+        effect.performMapping(source);
+        verify(target, times(1)).update(1f);
+        Mockito.reset(target);
+
+        // unknown_before with estimation
+        var1.setIntValue(source, ParallaxSource.IntProperty.UNKNOWN_BEFORE);
+        var2.setIntValue(source, 1080);
+        effect.performMapping(source);
+        verify(target, times(1)).update(0.5f);
+        Mockito.reset(target);
+
+        // unknown_after with estimation
+        var1.setIntValue(source, 0);
+        var2.setIntValue(source, ParallaxSource.IntProperty.UNKNOWN_AFTER);
+        effect.performMapping(source);
+        verify(target, times(1)).update(0.5f);
+        Mockito.reset(target);
+    }
+
+}
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/widget/ParallaxIntSourceTest.java b/v17/leanback/tests/java/android/support/v17/leanback/widget/ParallaxIntSourceTest.java
new file mode 100644
index 0000000..4cad674
--- /dev/null
+++ b/v17/leanback/tests/java/android/support/v17/leanback/widget/ParallaxIntSourceTest.java
@@ -0,0 +1,163 @@
+/*
+ * 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 android.support.v17.leanback.widget;
+
+import android.support.test.runner.AndroidJUnitRunner;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertSame;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+import android.support.test.runner.AndroidJUnit4;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class ParallaxIntSourceTest {
+
+    ParallaxSource.IntSource source;
+    int screenMax;
+
+    static void assertFloatEquals(float expected, float actual) {
+        org.junit.Assert.assertEquals((double)expected, (double)actual, 0.0001d);
+    }
+
+    @Before
+    public void setUp() throws Exception {
+        source = new ParallaxSource.IntSource<ParallaxSource.IntProperty>() {
+
+            public void setListener(ParallaxSource.Listener listener) {
+            }
+
+            public int getMaxParentVisibleSize() {
+                return screenMax;
+            }
+
+            @Override
+            public IntProperty createProperty(String name, int index) {
+                return new IntProperty(name, index);
+            }
+        };
+    }
+
+    @Test
+    public void testVariable() {
+        screenMax = 1080;
+        ParallaxSource.IntProperty var1 = source.addProperty("var1");
+        var1.setIntValue(source, 54);
+        assertEquals((int)54, var1.getIntValue(source));
+        assertEquals(var1.getName(), "var1");
+        var1.set(source, (int)2000);
+        assertEquals((int)2000, var1.get(source).intValue());
+    }
+
+    @Test
+    public void testFixedKeyValue() {
+        screenMax = 1080;
+        ParallaxSource.IntProperty var1 = source.addProperty("var1");
+
+        ParallaxSource.IntPropertyKeyValue keyValue = var1.atAbsolute(1000);
+        assertSame(keyValue.getProperty(), var1);
+        assertEquals((int)1000, keyValue.getKeyValue(source));
+    }
+
+    @Test
+    public void testFractionOfKeyValue() {
+        screenMax = 1080;
+        ParallaxSource.IntProperty var1 = source.addProperty("var1");
+
+        ParallaxSource.IntPropertyKeyValue keyValue = var1.at(0, 0.5f);
+        assertSame(keyValue.getProperty(), var1);
+        assertEquals((int)540, keyValue.getKeyValue(source));
+    }
+
+    @Test
+    public void testFixedKeyValueWithFraction() {
+        screenMax = 1080;
+        ParallaxSource.IntProperty var1 = source.addProperty("var1");
+
+        ParallaxSource.IntPropertyKeyValue keyValue = var1.at(-100, 0.5f);
+        assertSame(keyValue.getProperty(), var1);
+        assertEquals((int)440, keyValue.getKeyValue(source));
+
+        ParallaxSource.IntPropertyKeyValue keyValue2 = var1.at(100, 0.5f);
+        assertSame(keyValue2.getProperty(), var1);
+        assertEquals((int)640, keyValue2.getKeyValue(source));
+    }
+
+    @Test(expected=IllegalStateException.class)
+    public void testVerifyIntPropertys_wrongOrder() {
+        ParallaxSource.IntProperty var1 = source.addProperty("var1");
+        ParallaxSource.IntProperty var2 = source.addProperty("var2");;
+
+        var1.setIntValue(source, (int)500);
+        var2.setIntValue(source, (int)499);
+
+        source.verifyProperties();
+    }
+
+    @Test(expected=IllegalStateException.class)
+    public void testVerifyIntPropertysWrong_combination() {
+        ParallaxSource.IntProperty var1 = source.addProperty("var1");
+        ParallaxSource.IntProperty var2 = source.addProperty("var2");
+
+        var1.setIntValue(source, ParallaxSource.IntProperty.UNKNOWN_BEFORE);
+        var2.setIntValue(source, ParallaxSource.IntProperty.UNKNOWN_AFTER);
+
+        source.verifyProperties();
+    }
+
+    @Test
+    public void testVerifyIntPropertys_success() {
+        ParallaxSource.IntProperty var1 = source.addProperty("var1");
+        ParallaxSource.IntProperty var2 = source.addProperty("var2");
+
+        var1.setIntValue(source, (int)499);
+        var2.setIntValue(source, (int)500);
+
+        source.verifyProperties();
+
+        var1.setIntValue(source, ParallaxSource.IntProperty.UNKNOWN_BEFORE);
+        var2.setIntValue(source, (int)500);
+
+        source.verifyProperties();
+
+        var1.setIntValue(source, (int)499);
+        var2.setIntValue(source, ParallaxSource.IntProperty.UNKNOWN_AFTER);
+
+        source.verifyProperties();
+    }
+}
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/widget/PresenterTest.java b/v17/leanback/tests/java/android/support/v17/leanback/widget/PresenterTest.java
index b9a230a..f05fcb7 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/widget/PresenterTest.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/widget/PresenterTest.java
@@ -15,23 +15,38 @@
  */
 package android.support.v17.leanback.widget;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import android.content.Context;
 import android.graphics.Bitmap;
-import android.support.v17.leanback.app.HeadersFragment;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
 import android.support.v17.leanback.R;
-import android.test.AndroidTestCase;
+import android.support.v17.leanback.app.HeadersFragment;
 import android.test.suitebuilder.annotation.MediumTest;
 import android.view.ContextThemeWrapper;
-import android.widget.FrameLayout;
 import android.view.View;
 import android.view.ViewGroup.LayoutParams;
-import android.support.v17.leanback.widget.DividerRow;
-import android.support.v17.leanback.widget.Row;
-import android.support.v17.leanback.widget.DividerPresenter;
-import android.view.ContextThemeWrapper;
+import android.widget.FrameLayout;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
 @MediumTest
-public class PresenterTest extends AndroidTestCase {
+@RunWith(AndroidJUnit4.class)
+public class PresenterTest {
+    private Context mContext;
 
+    @Before
+    public void setup() throws Exception {
+        mContext = InstrumentationRegistry.getTargetContext();
+    }
+
+    @Test
     public void testZoomFactors() throws Throwable {
         new ListRowPresenter(FocusHighlight.ZOOM_FACTOR_SMALL);
         new ListRowPresenter(FocusHighlight.ZOOM_FACTOR_MEDIUM);
@@ -46,7 +61,7 @@
 
     private void testHeaderPresenter(RowHeaderPresenter p) {
         int expectedVisibility;
-        Presenter.ViewHolder vh = p.onCreateViewHolder(new FrameLayout(getContext()));
+        Presenter.ViewHolder vh = p.onCreateViewHolder(new FrameLayout(mContext));
         p.onBindViewHolder(vh, null);
         expectedVisibility = p.isNullItemVisibilityGone() ? View.GONE : View.VISIBLE;
         assertTrue("Header visibility",
@@ -59,6 +74,7 @@
                 vh.view.getVisibility() == View.VISIBLE);
     }
 
+    @Test
     public void testHeaderPresenter() throws Throwable {
         HeadersFragment hf = new HeadersFragment();
         PresenterSelector ps = hf.getPresenterSelector();
@@ -90,8 +106,9 @@
         testHeaderPresenter(rhp);
     }
 
+    @Test
     public void testPlaybackControlsRowPresenter() {
-        setContext(new ContextThemeWrapper(getContext(), R.style.Theme_Leanback));
+        Context context = new ContextThemeWrapper(mContext, R.style.Theme_Leanback);
         Presenter detailsPresenter = new AbstractDetailsDescriptionPresenter() {
             @Override
             protected void onBindDescription(ViewHolder vh, Object item) {
@@ -102,7 +119,7 @@
         PlaybackControlsRowPresenter controlsRowPresenter = new PlaybackControlsRowPresenter(
                 detailsPresenter);
         PlaybackControlsRowPresenter.ViewHolder vh = (PlaybackControlsRowPresenter.ViewHolder)
-                controlsRowPresenter.onCreateViewHolder(new FrameLayout(getContext()));
+                controlsRowPresenter.onCreateViewHolder(new FrameLayout(context));
 
         Object item = new Object();
         PlaybackControlsRow controlsRow = new PlaybackControlsRow(item);
@@ -117,7 +134,7 @@
         controlsRowPresenter.onUnbindRowViewHolder(vh);
 
         controlsRow.setImageBitmap(
-                getContext(), Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888));
+                context, Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888));
         controlsRowPresenter.onBindRowViewHolder(vh, controlsRow);
         AssertHelper.assertGreaterThan("Controls card right panel layout height",
                 vh.view.findViewById(R.id.controls_card_right_panel).getLayoutParams().height, 0);
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/widget/ShadowOverlayContainerTest.java b/v17/leanback/tests/java/android/support/v17/leanback/widget/ShadowOverlayContainerTest.java
index 3b99486..f50ba59 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/widget/ShadowOverlayContainerTest.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/widget/ShadowOverlayContainerTest.java
@@ -15,23 +15,40 @@
  */
 package android.support.v17.leanback.widget;
 
-import android.test.AndroidTestCase;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.content.Context;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
 import android.test.suitebuilder.annotation.MediumTest;
 import android.view.View.MeasureSpec;
 import android.view.ViewGroup.LayoutParams;
 import android.widget.FrameLayout;
 import android.widget.TextView;
 
-@MediumTest
-public class ShadowOverlayContainerTest extends AndroidTestCase {
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class ShadowOverlayContainerTest {
+    private Context mContext;
+
+    @Before
+    public void setup() throws Exception {
+        mContext = InstrumentationRegistry.getTargetContext();
+    }
+
+    @Test
     public void testWrapContent() {
-        FrameLayout frameLayout = new FrameLayout(getContext());
-        TextView textView = new TextView(getContext());
+        FrameLayout frameLayout = new FrameLayout(mContext);
+        TextView textView = new TextView(mContext);
         textView.setLayoutParams(new FrameLayout.LayoutParams(LayoutParams.WRAP_CONTENT,
                 LayoutParams.WRAP_CONTENT));
         textView.setText("abc");
-        ShadowOverlayContainer container = new ShadowOverlayContainer(getContext());
+        ShadowOverlayContainer container = new ShadowOverlayContainer(mContext);
         container.initialize(true, true, true);
         container.wrap(textView);
         frameLayout.addView(container);
@@ -56,12 +73,13 @@
         assertEquals(container.getHeight(), textView.getHeight());
     }
 
+    @Test
     public void testFixedSize() {
-        FrameLayout frameLayout = new FrameLayout(getContext());
-        TextView textView = new TextView(getContext());
+        FrameLayout frameLayout = new FrameLayout(mContext);
+        TextView textView = new TextView(mContext);
         textView.setLayoutParams(new FrameLayout.LayoutParams(200, LayoutParams.WRAP_CONTENT));
         textView.setText("abc");
-        ShadowOverlayContainer container = new ShadowOverlayContainer(getContext());
+        ShadowOverlayContainer container = new ShadowOverlayContainer(mContext);
         container.initialize(true, true, true);
         container.wrap(textView);
         frameLayout.addView(container);
@@ -85,13 +103,14 @@
         assertEquals(container.getHeight(), textView.getHeight());
     }
 
+    @Test
     public void testMatchParent() {
-        FrameLayout frameLayout = new FrameLayout(getContext());
-        TextView textView = new TextView(getContext());
+        FrameLayout frameLayout = new FrameLayout(mContext);
+        TextView textView = new TextView(mContext);
         textView.setLayoutParams(new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT,
                 LayoutParams.WRAP_CONTENT));
         textView.setText("abc");
-        ShadowOverlayContainer container = new ShadowOverlayContainer(getContext());
+        ShadowOverlayContainer container = new ShadowOverlayContainer(mContext);
         container.initialize(true, true, true);
         container.wrap(textView);
         frameLayout.addView(container);
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/widget/SingleRowTest.java b/v17/leanback/tests/java/android/support/v17/leanback/widget/SingleRowTest.java
index 0cb34fb..fea0d64 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/widget/SingleRowTest.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/widget/SingleRowTest.java
@@ -40,7 +40,7 @@
         mProvider = new Provider(new int[]{80, 80, 30, 100, 40, 10});
 
         mSingleRow = new SingleRow();
-        mSingleRow.setMargin(20);
+        mSingleRow.setSpacing(20);
         mSingleRow.setProvider(mProvider);
         mSingleRow.appendVisibleItems(200);
         assertEquals(dump(mSingleRow) + " Should filled 2 items", 1, mSingleRow.mLastVisibleIndex);
@@ -84,7 +84,7 @@
         mProvider = new Provider(new int[]{80, 80, 30, 100, 40, 10});
 
         mSingleRow = new SingleRow();
-        mSingleRow.setMargin(20);
+        mSingleRow.setSpacing(20);
         mSingleRow.setProvider(mProvider);
         mSingleRow.setReversedFlow(true);
         mSingleRow.appendVisibleItems(-200);
@@ -126,7 +126,7 @@
         mProvider = new Provider(new int[]{80, 80, 30, 100, 40, 10});
 
         mSingleRow = new SingleRow();
-        mSingleRow.setMargin(20);
+        mSingleRow.setSpacing(20);
         mSingleRow.setProvider(mProvider);
         mSingleRow.appendVisibleItems(200);
         assertEquals(dump(mSingleRow) + " Should filled 2 items", 1, mSingleRow.mLastVisibleIndex);
@@ -148,7 +148,7 @@
         mProvider = new Provider(new int[]{80, 80, 30, 100, 40, 10});
 
         mSingleRow = new SingleRow();
-        mSingleRow.setMargin(20);
+        mSingleRow.setSpacing(20);
         mSingleRow.setProvider(mProvider);
         mSingleRow.setReversedFlow(true);
         mSingleRow.appendVisibleItems(-200);
diff --git a/v17/leanback/tests/java/android/support/v17/leanback/widget/StaggeredGridDefaultTest.java b/v17/leanback/tests/java/android/support/v17/leanback/widget/StaggeredGridDefaultTest.java
index 9d933bc..2ad3e7c 100644
--- a/v17/leanback/tests/java/android/support/v17/leanback/widget/StaggeredGridDefaultTest.java
+++ b/v17/leanback/tests/java/android/support/v17/leanback/widget/StaggeredGridDefaultTest.java
@@ -43,7 +43,7 @@
         // layout first 8 items then all items
         mStaggeredGrid = new StaggeredGridDefault();
         mStaggeredGrid.setNumRows(3);
-        mStaggeredGrid.setMargin(20);
+        mStaggeredGrid.setSpacing(20);
         mStaggeredGrid.setProvider(mProvider);
         mStaggeredGrid.appendVisibleItems(210);
         assertEquals(dump(mStaggeredGrid) + " Should fill 8 items",
@@ -59,7 +59,7 @@
         // layout all items together
         mStaggeredGrid = new StaggeredGridDefault();
         mStaggeredGrid.setNumRows(3);
-        mStaggeredGrid.setMargin(20);
+        mStaggeredGrid.setSpacing(20);
         mStaggeredGrid.setProvider(mProvider);
         mStaggeredGrid.appendVisibleItems(100000);
         assertEquals(dump(mStaggeredGrid) + " should fill 9 items",
diff --git a/v17/leanback/tests/res/drawable/ic_action_a.png b/v17/leanback/tests/res/drawable/ic_action_a.png
new file mode 100644
index 0000000..3d555ef
--- /dev/null
+++ b/v17/leanback/tests/res/drawable/ic_action_a.png
Binary files differ
diff --git a/v17/leanback/tests/res/drawable/spiderman.jpg b/v17/leanback/tests/res/drawable/spiderman.jpg
new file mode 100644
index 0000000..b68384c
--- /dev/null
+++ b/v17/leanback/tests/res/drawable/spiderman.jpg
Binary files differ
diff --git a/v17/leanback/tests/res/layout/details.xml b/v17/leanback/tests/res/layout/details.xml
new file mode 100644
index 0000000..88617ea
--- /dev/null
+++ b/v17/leanback/tests/res/layout/details.xml
@@ -0,0 +1,21 @@
+<?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:id="@+id/fragment_root"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent" />
diff --git a/v17/leanback/tests/res/layout/horizontal_grid.xml b/v17/leanback/tests/res/layout/horizontal_grid.xml
index 6c4eaf1..0fbb52f 100644
--- a/v17/leanback/tests/res/layout/horizontal_grid.xml
+++ b/v17/leanback/tests/res/layout/horizontal_grid.xml
@@ -12,8 +12,8 @@
       android:focusable="true"
       android:focusableInTouchMode="true"
       android:background="#00ffff"
-      lb:horizontalMargin="12dip"
-      lb:verticalMargin="24dip"
+      android:horizontalSpacing="12dip"
+      android:verticalSpacing="24dip"
       lb:numberOfRows="3"
       lb:rowHeight="150dip"
       android:paddingBottom="12dip"
diff --git a/v17/leanback/tests/res/layout/horizontal_grid_testredundantappendremove2.xml b/v17/leanback/tests/res/layout/horizontal_grid_testredundantappendremove2.xml
index fdfc0ea..746a458 100644
--- a/v17/leanback/tests/res/layout/horizontal_grid_testredundantappendremove2.xml
+++ b/v17/leanback/tests/res/layout/horizontal_grid_testredundantappendremove2.xml
@@ -12,8 +12,8 @@
       android:focusable="true"
       android:focusableInTouchMode="true"
       android:background="#00ffff"
-      lb:horizontalMargin="12dip"
-      lb:verticalMargin="24dip"
+      android:horizontalSpacing="12dip"
+      android:verticalSpacing="24dip"
       lb:numberOfRows="3"
       lb:rowHeight="150dip"
       android:paddingBottom="12dip"
diff --git a/v17/leanback/tests/res/layout/horizontal_linear.xml b/v17/leanback/tests/res/layout/horizontal_linear.xml
index 5e9da64..cca5781 100644
--- a/v17/leanback/tests/res/layout/horizontal_linear.xml
+++ b/v17/leanback/tests/res/layout/horizontal_linear.xml
@@ -13,8 +13,8 @@
       android:focusable="true"
       android:focusableInTouchMode="true"
       android:background="#00ffff"
-      lb:horizontalMargin="12dip"
-      lb:verticalMargin="24dip"
+      android:horizontalSpacing="12dip"
+      android:verticalSpacing="24dip"
       lb:numberOfColumns="1"
       lb:columnWidth="150dip"
       android:paddingBottom="12dip"
diff --git a/v17/leanback/tests/res/layout/playback_controls_with_video.xml b/v17/leanback/tests/res/layout/playback_controls_with_video.xml
new file mode 100644
index 0000000..cbf2a91
--- /dev/null
+++ b/v17/leanback/tests/res/layout/playback_controls_with_video.xml
@@ -0,0 +1,34 @@
+<?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" >
+
+    <VideoView
+        android:id="@+id/videoView"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_gravity="center" />
+
+    <fragment
+        android:id="@+id/playback_controls_fragment"
+        android:name="android.support.v17.leanback.app.PlaybackOverlayTestFragment"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent" />
+
+</FrameLayout>
\ No newline at end of file
diff --git a/v17/leanback/tests/res/layout/vertical_grid.xml b/v17/leanback/tests/res/layout/vertical_grid.xml
index f4c0065..5aa5697 100644
--- a/v17/leanback/tests/res/layout/vertical_grid.xml
+++ b/v17/leanback/tests/res/layout/vertical_grid.xml
@@ -12,8 +12,8 @@
       android:focusable="true"
       android:focusableInTouchMode="true"
       android:background="#00ffff"
-      lb:horizontalMargin="12dip"
-      lb:verticalMargin="24dip"
+      android:horizontalSpacing="12dip"
+      android:verticalSpacing="24dip"
       lb:numberOfColumns="3"
       lb:columnWidth="150dip"
       android:paddingBottom="12dip"
diff --git a/v17/leanback/tests/res/layout/vertical_grid_ltr.xml b/v17/leanback/tests/res/layout/vertical_grid_ltr.xml
index 6a390a3..762c5f7 100644
--- a/v17/leanback/tests/res/layout/vertical_grid_ltr.xml
+++ b/v17/leanback/tests/res/layout/vertical_grid_ltr.xml
@@ -20,8 +20,8 @@
       android:focusable="true"
       android:focusableInTouchMode="true"
       android:background="#00ffff"
-      lb:horizontalMargin="12dip"
-      lb:verticalMargin="24dip"
+      android:horizontalSpacing="12dip"
+      android:verticalSpacing="24dip"
       lb:numberOfColumns="1"
       lb:columnWidth="150dip"
       lb:focusOutSideStart="false"
diff --git a/v17/leanback/tests/res/layout/vertical_grid_rtl.xml b/v17/leanback/tests/res/layout/vertical_grid_rtl.xml
index 87b2054..b9a53e8 100644
--- a/v17/leanback/tests/res/layout/vertical_grid_rtl.xml
+++ b/v17/leanback/tests/res/layout/vertical_grid_rtl.xml
@@ -20,8 +20,8 @@
       android:focusable="true"
       android:focusableInTouchMode="true"
       android:background="#00ffff"
-      lb:horizontalMargin="12dip"
-      lb:verticalMargin="24dip"
+      android:horizontalSpacing="12dip"
+      android:verticalSpacing="24dip"
       lb:numberOfColumns="1"
       lb:columnWidth="150dip"
       lb:focusOutSideStart="false"
diff --git a/v17/leanback/tests/res/layout/vertical_grid_testredundantappendremove.xml b/v17/leanback/tests/res/layout/vertical_grid_testredundantappendremove.xml
index bf056f8..d0fdeca 100644
--- a/v17/leanback/tests/res/layout/vertical_grid_testredundantappendremove.xml
+++ b/v17/leanback/tests/res/layout/vertical_grid_testredundantappendremove.xml
@@ -12,8 +12,8 @@
       android:focusable="true"
       android:focusableInTouchMode="true"
       android:background="#00ffff"
-      lb:horizontalMargin="12dip"
-      lb:verticalMargin="24dip"
+      android:horizontalSpacing="12dip"
+      android:verticalSpacing="24dip"
       lb:numberOfColumns="3"
       lb:columnWidth="150dip"
       android:paddingBottom="12dip"
diff --git a/v17/leanback/tests/res/layout/vertical_linear.xml b/v17/leanback/tests/res/layout/vertical_linear.xml
index 0a1d00c..c76b26a 100644
--- a/v17/leanback/tests/res/layout/vertical_linear.xml
+++ b/v17/leanback/tests/res/layout/vertical_linear.xml
@@ -12,8 +12,8 @@
       android:focusable="true"
       android:focusableInTouchMode="true"
       android:background="#00ffff"
-      lb:horizontalMargin="12dip"
-      lb:verticalMargin="24dip"
+      android:horizontalSpacing="12dip"
+      android:verticalSpacing="24dip"
       lb:numberOfColumns="1"
       lb:columnWidth="150dip"
       android:paddingBottom="12dip"
diff --git a/v17/leanback/tests/res/layout/vertical_linear_measured_with_zero.xml b/v17/leanback/tests/res/layout/vertical_linear_measured_with_zero.xml
index 012829d..ef82c19 100644
--- a/v17/leanback/tests/res/layout/vertical_linear_measured_with_zero.xml
+++ b/v17/leanback/tests/res/layout/vertical_linear_measured_with_zero.xml
@@ -16,8 +16,8 @@
       android:focusable="true"
       android:focusableInTouchMode="true"
       android:background="#00ffff"
-      lb:horizontalMargin="12dip"
-      lb:verticalMargin="24dip"
+      android:horizontalSpacing="12dip"
+      android:verticalSpacing="24dip"
       lb:numberOfColumns="1" />
     </FrameLayout>
 
diff --git a/v17/leanback/tests/res/layout/vertical_linear_with_button.xml b/v17/leanback/tests/res/layout/vertical_linear_with_button.xml
index f37bdc3..067310d 100644
--- a/v17/leanback/tests/res/layout/vertical_linear_with_button.xml
+++ b/v17/leanback/tests/res/layout/vertical_linear_with_button.xml
@@ -20,8 +20,8 @@
       android:focusable="true"
       android:focusableInTouchMode="true"
       android:background="#00ffff"
-      lb:horizontalMargin="12dip"
-      lb:verticalMargin="24dip"
+      android:horizontalSpacing="12dip"
+      android:verticalSpacing="24dip"
       lb:numberOfColumns="1"
       lb:columnWidth="150dip"
       android:paddingBottom="12dip"
diff --git a/v17/leanback/tests/res/layout/vertical_linear_with_button_onleft.xml b/v17/leanback/tests/res/layout/vertical_linear_with_button_onleft.xml
index 6305de6..02b027c 100644
--- a/v17/leanback/tests/res/layout/vertical_linear_with_button_onleft.xml
+++ b/v17/leanback/tests/res/layout/vertical_linear_with_button_onleft.xml
@@ -20,8 +20,8 @@
       android:focusable="true"
       android:focusableInTouchMode="true"
       android:background="#00ffff"
-      lb:horizontalMargin="12dip"
-      lb:verticalMargin="4dip"
+      android_horizontalSpacing="12dip"
+      android:verticalSpacing="4dip"
       lb:numberOfColumns="1"
       android:paddingBottom="12dip"
       android:paddingLeft="12dip"
diff --git a/v17/leanback/tests/res/layout/vertical_linear_wrap_content.xml b/v17/leanback/tests/res/layout/vertical_linear_wrap_content.xml
index 6770983..7803901 100644
--- a/v17/leanback/tests/res/layout/vertical_linear_wrap_content.xml
+++ b/v17/leanback/tests/res/layout/vertical_linear_wrap_content.xml
@@ -12,8 +12,8 @@
       android:focusable="true"
       android:focusableInTouchMode="true"
       android:background="#00ffff"
-      lb:horizontalMargin="12dip"
-      lb:verticalMargin="24dip"
+      android:horizontalSpacing="12dip"
+      android:verticalSpacing="24dip"
       lb:numberOfColumns="1"
       lb:columnWidth="wrap_content"
       android:paddingBottom="12dip"
diff --git a/v17/preference-leanback/src/android/support/v17/preference/LeanbackPreferenceFragment.java b/v17/preference-leanback/src/android/support/v17/preference/LeanbackPreferenceFragment.java
index 4d5df85..dbff1c8 100644
--- a/v17/preference-leanback/src/android/support/v17/preference/LeanbackPreferenceFragment.java
+++ b/v17/preference-leanback/src/android/support/v17/preference/LeanbackPreferenceFragment.java
@@ -61,7 +61,19 @@
     @Override
     public void onViewCreated(View view, Bundle savedInstanceState) {
         super.onViewCreated(view, savedInstanceState);
-        final TextView decorTitle = (TextView) view.findViewById(R.id.decor_title);
-        decorTitle.setText(getPreferenceScreen().getTitle());
+        setTitle(getPreferenceScreen().getTitle());
+    }
+
+    /**
+     * Set the title to be shown above the preference list
+     * @param title Title text to be shown
+     */
+    public void setTitle(CharSequence title) {
+        final View view = getView();
+        final TextView decorTitle = view == null
+                ? null : (TextView) view.findViewById(R.id.decor_title);
+        if (decorTitle != null) {
+            decorTitle.setText(title);
+        }
     }
 }
diff --git a/v7/appcompat/res-public/values/public_styles.xml b/v7/appcompat/res-public/values/public_styles.xml
index 9e6df30..38efc46 100644
--- a/v7/appcompat/res-public/values/public_styles.xml
+++ b/v7/appcompat/res-public/values/public_styles.xml
@@ -54,6 +54,8 @@
     <public type="style" name="TextAppearance.AppCompat.Widget.ActionMode.Title"/>
     <public type="style" name="TextAppearance.AppCompat.Widget.ActionMode.Title.Inverse"/>
     <public type="style" name="TextAppearance.AppCompat.Widget.Button"/>
+    <public type="style" name="TextAppearance.AppCompat.Widget.Button.Borderless.Colored"/>
+    <public type="style" name="TextAppearance.AppCompat.Widget.Button.Colored"/>
     <public type="style" name="TextAppearance.AppCompat.Widget.Button.Inverse"/>
     <public type="style" name="TextAppearance.AppCompat.Widget.DropDownItem"/>
     <public type="style" name="TextAppearance.AppCompat.Widget.PopupMenu.Header"/>
diff --git a/v7/appcompat/res/color-v23/abc_btn_colored_text_material.xml b/v7/appcompat/res/color-v23/abc_btn_colored_text_material.xml
new file mode 100644
index 0000000..74170d6
--- /dev/null
+++ b/v7/appcompat/res/color-v23/abc_btn_colored_text_material.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<!-- Used for the text of a bordered colored button. -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_enabled="false"
+          android:alpha="?android:attr/disabledAlpha"
+          android:color="?android:attr/textColorPrimary" />
+    <item android:color="?android:attr/textColorPrimaryInverse" />
+</selector>
\ No newline at end of file
diff --git a/v7/appcompat/res/color/abc_btn_colored_text_material.xml b/v7/appcompat/res/color/abc_btn_colored_text_material.xml
new file mode 100644
index 0000000..897a3f7
--- /dev/null
+++ b/v7/appcompat/res/color/abc_btn_colored_text_material.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<!-- Used for the text of a bordered colored button. -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+          xmlns:app="http://schemas.android.com/apk/res-auto">
+    <item android:state_enabled="false"
+          app:alpha="?android:attr/disabledAlpha"
+          android:color="?android:attr/textColorPrimary" />
+    <item android:color="?android:attr/textColorPrimaryInverse" />
+</selector>
\ No newline at end of file
diff --git a/v7/appcompat/res/values-my-rMM/strings.xml b/v7/appcompat/res/values-my-rMM/strings.xml
index 93f779d..0248c15 100644
--- a/v7/appcompat/res/values-my-rMM/strings.xml
+++ b/v7/appcompat/res/values-my-rMM/strings.xml
@@ -27,7 +27,7 @@
     <string name="abc_search_hint" msgid="7723749260725869598">"ရှာဖွေပါ..."</string>
     <string name="abc_searchview_description_query" msgid="2550479030709304392">"ရှာစရာ အချက်အလက်နေရာ"</string>
     <string name="abc_searchview_description_clear" msgid="3691816814315814921">"ရှာစရာ အချက်အလက်များ ဖယ်ရှားရန်"</string>
-    <string name="abc_searchview_description_submit" msgid="8928215447528550784">"ရှာဖွေစရာ အချက်အလက်ကို အတည်ပြုရန်"</string>
+    <string name="abc_searchview_description_submit" msgid="8928215447528550784">"ရှာဖွေစရာ အချက်အလက်ကို ပေးပို့ရန်"</string>
     <string name="abc_searchview_description_voice" msgid="893419373245838918">"အသံဖြင့် ရှာဖွေခြင်း"</string>
     <string name="abc_activitychooserview_choose_application" msgid="2031811694353399454">"အက်ပ်တစ်ခုခုကို ရွေးချယ်ပါ"</string>
     <string name="abc_activity_chooser_view_see_all" msgid="7468859129482906941">"အားလုံးကို ကြည့်ရန်"</string>
diff --git a/v7/appcompat/res/values-v24/styles_base_text.xml b/v7/appcompat/res/values-v24/styles_base_text.xml
new file mode 100644
index 0000000..2e6182d
--- /dev/null
+++ b/v7/appcompat/res/values-v24/styles_base_text.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     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.
+-->
+<resources>
+
+    <style name="Base.TextAppearance.AppCompat.Widget.Button.Colored" parent="android:TextAppearance.Material.Widget.Button.Colored" />
+
+    <style name="Base.TextAppearance.AppCompat.Widget.Button.Borderless.Colored" parent="android:TextAppearance.Material.Widget.Button.Borderless.Colored" />
+
+</resources>
\ No newline at end of file
diff --git a/v7/appcompat/res/values/styles.xml b/v7/appcompat/res/values/styles.xml
index ec8bbe1..7595d74 100644
--- a/v7/appcompat/res/values/styles.xml
+++ b/v7/appcompat/res/values/styles.xml
@@ -298,6 +298,10 @@
 
     <style name="TextAppearance.AppCompat.Widget.TextView.SpinnerItem" parent="Base.TextAppearance.AppCompat.Widget.TextView.SpinnerItem" />
 
+    <style name="TextAppearance.AppCompat.Widget.Button.Colored" parent="Base.TextAppearance.AppCompat.Widget.Button.Colored" />
+
+    <style name="TextAppearance.AppCompat.Widget.Button.Borderless.Colored" parent="Base.TextAppearance.AppCompat.Widget.Button.Borderless.Colored" />
+
     <!--
          The following themes are deprecated.
     -->
diff --git a/v7/appcompat/res/values/styles_base.xml b/v7/appcompat/res/values/styles_base.xml
index b1d6c95..b8c1f29 100644
--- a/v7/appcompat/res/values/styles_base.xml
+++ b/v7/appcompat/res/values/styles_base.xml
@@ -453,7 +453,7 @@
     <!-- Colored bordered ink button -->
     <style name="Base.Widget.AppCompat.Button.Colored">
         <item name="android:background">@drawable/abc_btn_colored_material</item>
-        <item name="android:textAppearance">@style/TextAppearance.AppCompat.Widget.Button.Inverse</item>
+        <item name="android:textAppearance">@style/TextAppearance.AppCompat.Widget.Button.Colored</item>
     </style>
 
     <!-- Borderless ink button -->
@@ -463,7 +463,7 @@
 
     <!-- Colored borderless ink button -->
     <style name="Base.Widget.AppCompat.Button.Borderless.Colored">
-        <item name="android:textColor">@color/abc_btn_colored_borderless_text_material</item>
+        <item name="android:textAppearance">@style/TextAppearance.AppCompat.Widget.Button.Borderless.Colored</item>
     </style>
 
     <style name="Base.Widget.AppCompat.Button.ButtonBar.AlertDialog" parent="Widget.AppCompat.Button.Borderless.Colored">
diff --git a/v7/appcompat/res/values/styles_base_text.xml b/v7/appcompat/res/values/styles_base_text.xml
index 8597179..6a43144 100644
--- a/v7/appcompat/res/values/styles_base_text.xml
+++ b/v7/appcompat/res/values/styles_base_text.xml
@@ -139,4 +139,12 @@
         <item name="android:textColorHint">?android:attr/textColorHintInverse</item>
     </style>
 
+    <style name="Base.TextAppearance.AppCompat.Widget.Button.Colored">
+        <item name="android:textColor">@color/abc_btn_colored_text_material</item>
+    </style>
+
+    <style name="Base.TextAppearance.AppCompat.Widget.Button.Borderless.Colored" parent="Base.TextAppearance.AppCompat.Widget.Button">
+        <item name="android:textColor">@color/abc_btn_colored_borderless_text_material</item>
+    </style>
+
 </resources>
\ No newline at end of file
diff --git a/v7/appcompat/src/android/support/v7/view/ContextThemeWrapper.java b/v7/appcompat/src/android/support/v7/view/ContextThemeWrapper.java
index 8841d12..1fd0e61 100644
--- a/v7/appcompat/src/android/support/v7/view/ContextThemeWrapper.java
+++ b/v7/appcompat/src/android/support/v7/view/ContextThemeWrapper.java
@@ -18,6 +18,7 @@
 
 import android.content.Context;
 import android.content.ContextWrapper;
+import android.content.res.AssetManager;
 import android.content.res.Resources;
 import android.support.annotation.RestrictTo;
 import android.support.annotation.StyleRes;
@@ -111,5 +112,11 @@
         }
         onApplyThemeResource(mTheme, mThemeResource, first);
     }
+
+    @Override
+    public AssetManager getAssets() {
+        // Ensure we're returning assets with the correct configuration.
+        return getResources().getAssets();
+    }
 }
 
diff --git a/v7/appcompat/src/android/support/v7/widget/TintContextWrapper.java b/v7/appcompat/src/android/support/v7/widget/TintContextWrapper.java
index 5040bba..8202d45 100644
--- a/v7/appcompat/src/android/support/v7/widget/TintContextWrapper.java
+++ b/v7/appcompat/src/android/support/v7/widget/TintContextWrapper.java
@@ -18,6 +18,7 @@
 
 import android.content.Context;
 import android.content.ContextWrapper;
+import android.content.res.AssetManager;
 import android.content.res.Resources;
 import android.os.Build;
 import android.support.annotation.NonNull;
@@ -119,4 +120,10 @@
     public Resources getResources() {
         return mResources;
     }
+
+    @Override
+    public AssetManager getAssets() {
+        // Ensure we're returning assets with the correct configuration.
+        return mResources.getAssets();
+    }
 }
\ No newline at end of file
diff --git a/v7/appcompat/src/android/support/v7/widget/Toolbar.java b/v7/appcompat/src/android/support/v7/widget/Toolbar.java
index c69f147..01b28a8 100644
--- a/v7/appcompat/src/android/support/v7/widget/Toolbar.java
+++ b/v7/appcompat/src/android/support/v7/widget/Toolbar.java
@@ -2194,7 +2194,7 @@
      * <p>Toolbar.LayoutParams extends ActionBar.LayoutParams for compatibility with existing
      * ActionBar API. See
      * {@link android.support.v7.app.AppCompatActivity#setSupportActionBar(Toolbar)
-     * ActionBarActivity.setActionBar}
+     * AppCompatActivity.setSupportActionBar}
      * for more info on how to use a Toolbar as your Activity's ActionBar.</p>
      */
     public static class LayoutParams extends ActionBar.LayoutParams {
diff --git a/v7/appcompat/tests/AndroidManifest.xml b/v7/appcompat/tests/AndroidManifest.xml
index 7288eb3..adb158f 100644
--- a/v7/appcompat/tests/AndroidManifest.xml
+++ b/v7/appcompat/tests/AndroidManifest.xml
@@ -34,9 +34,9 @@
                 android:name="android.support.v7.app.AppCompatActivity"/>
 
         <activity
-                android:name="android.support.v7.app.WindowDecorActionBarActivity"/>
+                android:name="android.support.v7.app.WindowDecorAppCompatActivity"/>
         <activity
-                android:name="android.support.v7.app.ToolbarActionBarActivity"
+                android:name="android.support.v7.app.ToolbarAppCompatActivity"
                 android:theme="@style/Theme.AppCompat.NoActionBar"/>
 
         <activity
diff --git a/v7/appcompat/tests/src/android/support/v7/app/BasicsTestCaseWithToolbar.java b/v7/appcompat/tests/src/android/support/v7/app/BasicsTestCaseWithToolbar.java
index f104f02..62954be 100644
--- a/v7/appcompat/tests/src/android/support/v7/app/BasicsTestCaseWithToolbar.java
+++ b/v7/appcompat/tests/src/android/support/v7/app/BasicsTestCaseWithToolbar.java
@@ -21,9 +21,9 @@
 
 import org.junit.Test;
 
-public class BasicsTestCaseWithToolbar extends BaseBasicsTestCase<ToolbarActionBarActivity> {
+public class BasicsTestCaseWithToolbar extends BaseBasicsTestCase<ToolbarAppCompatActivity> {
     public BasicsTestCaseWithToolbar() {
-        super(ToolbarActionBarActivity.class);
+        super(ToolbarAppCompatActivity.class);
     }
 
     @Test
diff --git a/v7/appcompat/tests/src/android/support/v7/app/BasicsTestCaseWithWindowDecor.java b/v7/appcompat/tests/src/android/support/v7/app/BasicsTestCaseWithWindowDecor.java
index 27b5039..6cff38f 100644
--- a/v7/appcompat/tests/src/android/support/v7/app/BasicsTestCaseWithWindowDecor.java
+++ b/v7/appcompat/tests/src/android/support/v7/app/BasicsTestCaseWithWindowDecor.java
@@ -21,9 +21,9 @@
 
 import org.junit.Test;
 
-public class BasicsTestCaseWithWindowDecor extends BaseBasicsTestCase<WindowDecorActionBarActivity> {
+public class BasicsTestCaseWithWindowDecor extends BaseBasicsTestCase<WindowDecorAppCompatActivity> {
     public BasicsTestCaseWithWindowDecor() {
-        super(WindowDecorActionBarActivity.class);
+        super(WindowDecorAppCompatActivity.class);
     }
 
     @Test
diff --git a/v7/appcompat/tests/src/android/support/v7/app/DialogTestCase.java b/v7/appcompat/tests/src/android/support/v7/app/DialogTestCase.java
index a165d53..120d429 100644
--- a/v7/appcompat/tests/src/android/support/v7/app/DialogTestCase.java
+++ b/v7/appcompat/tests/src/android/support/v7/app/DialogTestCase.java
@@ -26,10 +26,10 @@
 import static org.junit.Assert.assertTrue;
 
 @MediumTest
-public class DialogTestCase extends BaseInstrumentationTestCase<WindowDecorActionBarActivity> {
+public class DialogTestCase extends BaseInstrumentationTestCase<WindowDecorAppCompatActivity> {
 
     public DialogTestCase() {
-        super(WindowDecorActionBarActivity.class);
+        super(WindowDecorAppCompatActivity.class);
     }
 
     @Test
diff --git a/v7/appcompat/tests/src/android/support/v7/app/KeyEventsTestCaseWithToolbar.java b/v7/appcompat/tests/src/android/support/v7/app/KeyEventsTestCaseWithToolbar.java
index 9caf551..cdaecc0 100644
--- a/v7/appcompat/tests/src/android/support/v7/app/KeyEventsTestCaseWithToolbar.java
+++ b/v7/appcompat/tests/src/android/support/v7/app/KeyEventsTestCaseWithToolbar.java
@@ -16,8 +16,8 @@
 
 package android.support.v7.app;
 
-public class KeyEventsTestCaseWithToolbar extends BaseKeyEventsTestCase<ToolbarActionBarActivity> {
+public class KeyEventsTestCaseWithToolbar extends BaseKeyEventsTestCase<ToolbarAppCompatActivity> {
     public KeyEventsTestCaseWithToolbar() {
-        super(ToolbarActionBarActivity.class);
+        super(ToolbarAppCompatActivity.class);
     }
 }
diff --git a/v7/appcompat/tests/src/android/support/v7/app/KeyEventsTestCaseWithWindowDecor.java b/v7/appcompat/tests/src/android/support/v7/app/KeyEventsTestCaseWithWindowDecor.java
index 9707a4c..02296fe 100644
--- a/v7/appcompat/tests/src/android/support/v7/app/KeyEventsTestCaseWithWindowDecor.java
+++ b/v7/appcompat/tests/src/android/support/v7/app/KeyEventsTestCaseWithWindowDecor.java
@@ -16,8 +16,8 @@
 
 package android.support.v7.app;
 
-public class KeyEventsTestCaseWithWindowDecor extends BaseKeyEventsTestCase<WindowDecorActionBarActivity> {
+public class KeyEventsTestCaseWithWindowDecor extends BaseKeyEventsTestCase<WindowDecorAppCompatActivity> {
     public KeyEventsTestCaseWithWindowDecor() {
-        super(WindowDecorActionBarActivity.class);
+        super(WindowDecorAppCompatActivity.class);
     }
 }
diff --git a/v7/appcompat/tests/src/android/support/v7/app/KeyboardShortcutsTestCaseWithToolbar.java b/v7/appcompat/tests/src/android/support/v7/app/KeyboardShortcutsTestCaseWithToolbar.java
index a27b20b..79c8596 100644
--- a/v7/appcompat/tests/src/android/support/v7/app/KeyboardShortcutsTestCaseWithToolbar.java
+++ b/v7/appcompat/tests/src/android/support/v7/app/KeyboardShortcutsTestCaseWithToolbar.java
@@ -29,9 +29,9 @@
 import org.junit.Test;
 
 public class KeyboardShortcutsTestCaseWithToolbar
-        extends BaseKeyboardShortcutsTestCase<ToolbarActionBarActivity> {
+        extends BaseKeyboardShortcutsTestCase<ToolbarAppCompatActivity> {
     public KeyboardShortcutsTestCaseWithToolbar() {
-        super(ToolbarActionBarActivity.class);
+        super(ToolbarAppCompatActivity.class);
     }
 
     @Test
diff --git a/v7/appcompat/tests/src/android/support/v7/app/KeyboardShortcutsTestCaseWithWindowDecor.java b/v7/appcompat/tests/src/android/support/v7/app/KeyboardShortcutsTestCaseWithWindowDecor.java
index 4289143..eac1881 100644
--- a/v7/appcompat/tests/src/android/support/v7/app/KeyboardShortcutsTestCaseWithWindowDecor.java
+++ b/v7/appcompat/tests/src/android/support/v7/app/KeyboardShortcutsTestCaseWithWindowDecor.java
@@ -17,8 +17,8 @@
 package android.support.v7.app;
 
 public class KeyboardShortcutsTestCaseWithWindowDecor
-        extends BaseKeyboardShortcutsTestCase<WindowDecorActionBarActivity> {
+        extends BaseKeyboardShortcutsTestCase<WindowDecorAppCompatActivity> {
     public KeyboardShortcutsTestCaseWithWindowDecor() {
-        super(WindowDecorActionBarActivity.class);
+        super(WindowDecorAppCompatActivity.class);
     }
 }
diff --git a/v7/appcompat/tests/src/android/support/v7/app/NightModeTestCase.java b/v7/appcompat/tests/src/android/support/v7/app/NightModeTestCase.java
index a3d91d2..772bb74 100644
--- a/v7/appcompat/tests/src/android/support/v7/app/NightModeTestCase.java
+++ b/v7/appcompat/tests/src/android/support/v7/app/NightModeTestCase.java
@@ -27,6 +27,7 @@
 import static org.junit.Assert.assertFalse;
 
 import android.support.test.filters.SdkSuppress;
+import android.support.test.filters.Suppress;
 import android.support.v7.appcompat.test.R;
 import android.test.suitebuilder.annotation.MediumTest;
 
@@ -63,6 +64,7 @@
         onView(withId(R.id.text_night_mode)).check(matches(withText(STRING_NIGHT)));
     }
 
+    @Suppress // Disabled b/31515380
     @Test
     public void testColorConvertedDrawableChangesWithNightMode() {
         final NightModeActivity activity = getActivity();
diff --git a/v7/appcompat/tests/src/android/support/v7/app/ToolbarActionBarActivity.java b/v7/appcompat/tests/src/android/support/v7/app/ToolbarAppCompatActivity.java
similarity index 94%
rename from v7/appcompat/tests/src/android/support/v7/app/ToolbarActionBarActivity.java
rename to v7/appcompat/tests/src/android/support/v7/app/ToolbarAppCompatActivity.java
index 4b07a2e..9042363 100644
--- a/v7/appcompat/tests/src/android/support/v7/app/ToolbarActionBarActivity.java
+++ b/v7/appcompat/tests/src/android/support/v7/app/ToolbarAppCompatActivity.java
@@ -20,7 +20,7 @@
 import android.support.v7.testutils.BaseTestActivity;
 import android.support.v7.widget.Toolbar;
 
-public class ToolbarActionBarActivity extends BaseTestActivity {
+public class ToolbarAppCompatActivity extends BaseTestActivity {
 
     private Toolbar mToolbar;
 
diff --git a/v7/appcompat/tests/src/android/support/v7/app/WindowDecorActionBarActivity.java b/v7/appcompat/tests/src/android/support/v7/app/WindowDecorAppCompatActivity.java
similarity index 92%
rename from v7/appcompat/tests/src/android/support/v7/app/WindowDecorActionBarActivity.java
rename to v7/appcompat/tests/src/android/support/v7/app/WindowDecorAppCompatActivity.java
index 90366aa..6454b11 100644
--- a/v7/appcompat/tests/src/android/support/v7/app/WindowDecorActionBarActivity.java
+++ b/v7/appcompat/tests/src/android/support/v7/app/WindowDecorAppCompatActivity.java
@@ -19,7 +19,7 @@
 import android.support.v7.appcompat.test.R;
 import android.support.v7.testutils.BaseTestActivity;
 
-public class WindowDecorActionBarActivity extends BaseTestActivity {
+public class WindowDecorAppCompatActivity extends BaseTestActivity {
 
     @Override
     protected int getContentViewLayoutResId() {
diff --git a/v7/mediarouter/Android.mk b/v7/mediarouter/Android.mk
index 0c00f76..83dedec 100644
--- a/v7/mediarouter/Android.mk
+++ b/v7/mediarouter/Android.mk
@@ -57,7 +57,7 @@
 # A helper sub-library that makes direct use of V24 APIs.
 include $(CLEAR_VARS)
 LOCAL_MODULE := android-support-v7-mediarouter-api24
-LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
+LOCAL_SDK_VERSION := 24
 LOCAL_SRC_FILES := $(call all-java-files-under, api24)
 LOCAL_STATIC_JAVA_LIBRARIES := android-support-v7-mediarouter-jellybean-mr2
 LOCAL_JAVA_LANGUAGE_VERSION := 1.7
@@ -76,7 +76,7 @@
 include $(CLEAR_VARS)
 LOCAL_USE_AAPT2 := true
 LOCAL_MODULE := android-support-v7-mediarouter
-LOCAL_SDK_VERSION := 9
+LOCAL_SDK_VERSION := current
 LOCAL_SDK_RES_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
 LOCAL_SRC_FILES := $(call all-java-files-under,src)
 LOCAL_STATIC_JAVA_LIBRARIES := android-support-v7-mediarouter-api24
diff --git a/v7/mediarouter/res/layout/mr_chooser_dialog.xml b/v7/mediarouter/res/layout/mr_chooser_dialog.xml
index bda99f5..ea0f7d5 100644
--- a/v7/mediarouter/res/layout/mr_chooser_dialog.xml
+++ b/v7/mediarouter/res/layout/mr_chooser_dialog.xml
@@ -14,16 +14,25 @@
      limitations under the License.
 -->
 
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="fill_parent"
-             android:layout_height="wrap_content" >
-
+             android:layout_height="wrap_content"
+             android:orientation="vertical">
+    <TextView android:id="@+id/mr_chooser_title"
+              android:layout_width="fill_parent"
+              android:layout_height="wrap_content"
+              android:paddingLeft="24dp"
+              android:paddingRight="24dp"
+              android:paddingTop="24dp"
+              android:text="@string/mr_chooser_title"
+              android:singleLine="true"
+              android:ellipsize="end"
+              android:textAppearance="@style/TextAppearance.MediaRouter.Title" />
     <ListView android:id="@+id/mr_chooser_list"
               android:layout_width="fill_parent"
               android:layout_height="wrap_content"
               android:divider="@android:color/transparent"
               android:dividerHeight="0dp" />
-
     <LinearLayout android:id="@android:id/empty"
               android:layout_width="fill_parent"
               android:layout_height="240dp"
@@ -35,11 +44,12 @@
         <TextView android:layout_width="wrap_content"
                   android:layout_height="wrap_content"
                   android:layout_gravity="center"
-                  android:text="@string/mr_chooser_searching" />
+                  android:text="@string/mr_chooser_searching"
+                  android:textAppearance="@style/TextAppearance.MediaRouter.SecondaryText" />
         <ProgressBar android:layout_width="150dp"
                      android:layout_height="wrap_content"
                      android:layout_gravity="center"
                      android:indeterminate="true"
                      style="?android:attr/progressBarStyleHorizontal" />
     </LinearLayout>
-</FrameLayout>
+</LinearLayout>
diff --git a/v7/mediarouter/res/layout/mr_chooser_list_item.xml b/v7/mediarouter/res/layout/mr_chooser_list_item.xml
index d578560..f51b3a6 100644
--- a/v7/mediarouter/res/layout/mr_chooser_list_item.xml
+++ b/v7/mediarouter/res/layout/mr_chooser_list_item.xml
@@ -38,14 +38,14 @@
                   android:layout_height="32dp"
                   android:singleLine="true"
                   android:ellipsize="marquee"
-                  android:textAppearance="?attr/mediaRouteChooserPrimaryTextStyle" />
+                  android:textAppearance="@style/TextAppearance.MediaRouter.PrimaryText" />
 
         <TextView android:id="@+id/mr_chooser_route_desc"
                   android:layout_width="fill_parent"
                   android:layout_height="24dp"
                   android:singleLine="true"
                   android:ellipsize="marquee"
-                  android:textAppearance="?attr/mediaRouteChooserSecondaryTextStyle" />
+                  android:textAppearance="@style/TextAppearance.MediaRouter.SecondaryText" />
     </LinearLayout>
 
 </LinearLayout>
diff --git a/v7/mediarouter/res/layout/mr_controller_material_dialog_b.xml b/v7/mediarouter/res/layout/mr_controller_material_dialog_b.xml
index 0cfcd6c..c8aa79f 100644
--- a/v7/mediarouter/res/layout/mr_controller_material_dialog_b.xml
+++ b/v7/mediarouter/res/layout/mr_controller_material_dialog_b.xml
@@ -16,15 +16,14 @@
 
 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
           android:id="@+id/mr_expandable_area"
-          android:background="@android:color/transparent"
           android:layout_width="fill_parent"
           android:layout_height="fill_parent">
     <LinearLayout android:id="@+id/mr_dialog_area"
                   android:layout_width="fill_parent"
                   android:layout_height="wrap_content"
-                  android:background="?attr/MediaRouteControllerWindowBackground"
                   android:layout_gravity="center"
-                  android:orientation="vertical">
+                  android:orientation="vertical"
+                  android:background="?attr/colorBackgroundFloating">
         <LinearLayout android:id="@+id/mr_title_bar"
                       android:layout_width="fill_parent"
                       android:layout_height="wrap_content"
@@ -38,7 +37,7 @@
                       android:gravity="center_vertical"
                       android:singleLine="true"
                       android:ellipsize="end"
-                      android:textAppearance="?attr/mediaRouteControllerTitleTextStyle" />
+                      android:textAppearance="@style/TextAppearance.MediaRouter.Title" />
             <ImageButton android:id="@+id/mr_close"
                          android:layout_width="48dp"
                          android:layout_height="48dp"
@@ -74,7 +73,8 @@
                               android:orientation="vertical"
                               android:paddingTop="16dp"
                               android:paddingBottom="16dp"
-                              android:layout_gravity="bottom">
+                              android:layout_gravity="bottom"
+                              android:theme="?attr/mediaRouteControlPanelThemeOverlay">
                     <include android:id="@+id/mr_playback_control"
                              layout="@layout/mr_playback_control" />
                     <View android:id="@+id/mr_control_divider"
@@ -92,7 +92,8 @@
                         android:scrollbarStyle="outsideOverlay"
                         android:clipToPadding="false"
                         android:visibility="gone"
-                        android:splitMotionEvents="false" />
+                        android:splitMotionEvents="false"
+                        android:theme="?attr/mediaRouteControlPanelThemeOverlay" />
             </LinearLayout>
         </FrameLayout>
         <include layout="@layout/abc_alert_dialog_button_bar_material" />
diff --git a/v7/mediarouter/res/layout/mr_controller_volume_item.xml b/v7/mediarouter/res/layout/mr_controller_volume_item.xml
index 985646d..d2d1572 100644
--- a/v7/mediarouter/res/layout/mr_controller_volume_item.xml
+++ b/v7/mediarouter/res/layout/mr_controller_volume_item.xml
@@ -27,7 +27,7 @@
         <TextView android:id="@+id/mr_name"
                   android:layout_width="wrap_content"
                   android:layout_height="wrap_content"
-                  android:textAppearance="?attr/mediaRouteControllerSecondaryTextStyle"
+                  android:textAppearance="@style/TextAppearance.MediaRouter.SecondaryText"
                   android:singleLine="true" />
         <LinearLayout android:layout_width="fill_parent"
                       android:layout_height="wrap_content"
diff --git a/v7/mediarouter/res/layout/mr_playback_control.xml b/v7/mediarouter/res/layout/mr_playback_control.xml
index 9ee2191..b441254 100644
--- a/v7/mediarouter/res/layout/mr_playback_control.xml
+++ b/v7/mediarouter/res/layout/mr_playback_control.xml
@@ -39,12 +39,12 @@
         <TextView android:id="@+id/mr_control_title"
                   android:layout_width="wrap_content"
                   android:layout_height="wrap_content"
-                  android:textAppearance="?attr/mediaRouteControllerPrimaryTextStyle"
+                  android:textAppearance="@style/TextAppearance.MediaRouter.PrimaryText"
                   android:singleLine="true" />
         <TextView android:id="@+id/mr_control_subtitle"
                   android:layout_width="wrap_content"
                   android:layout_height="wrap_content"
-                  android:textAppearance="?attr/mediaRouteControllerSecondaryTextStyle"
+                  android:textAppearance="@style/TextAppearance.MediaRouter.SecondaryText"
                   android:singleLine="true" />
     </LinearLayout>
 </RelativeLayout>
diff --git a/v7/mediarouter/res/values-af/strings.xml b/v7/mediarouter/res/values-af/strings.xml
index 9811194..444ffc2 100644
--- a/v7/mediarouter/res/values-af/strings.xml
+++ b/v7/mediarouter/res/values-af/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"Stelsel"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Toestelle"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Cast-knoppie"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Uitsaai-knoppie. Ontkoppel"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Uitsaai-knoppie. Koppel tans"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Uitsaai-knoppie. Gekoppel"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Saai uit na"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Vind tans toestelle"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Ontkoppel"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Vou uit"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Vou in"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Albumkunswerk"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Volumeglyer"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Geen media is gekies nie"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Geen inligting beskikbaar nie"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Saai tans skerm uit"</string>
diff --git a/v7/mediarouter/res/values-am/strings.xml b/v7/mediarouter/res/values-am/strings.xml
index 6f7931d..96a2c09 100644
--- a/v7/mediarouter/res/values-am/strings.xml
+++ b/v7/mediarouter/res/values-am/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"ስርዓት"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"መሣሪያዎች"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"የCast አዝራር"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Cast አዝራር። ግንኙነት ተቋርጧል"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Cast አዝራር በማገናኘት ላይ"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Cast አዝራር። ተገናኝቷል"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Cast አድርግ ወደ"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"መሣሪያዎችን በማግኘት ላይ"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"ግንኙነት አቋርጥ"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"አስፋ"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"ሰብስብ"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"የአልበም ስነ-ጥበብ"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"ተንሸራታች የድምፅ መቆጣጠሪያ"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"ምንም ማህደረመረጃ አልተመረጠም"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"ምንም መረጃ አይገኝም"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"ማያ ገጽን በመውሰድ ላይ"</string>
diff --git a/v7/mediarouter/res/values-ar/strings.xml b/v7/mediarouter/res/values-ar/strings.xml
index 29cab47..3caf4b6 100644
--- a/v7/mediarouter/res/values-ar/strings.xml
+++ b/v7/mediarouter/res/values-ar/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"النظام"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"الأجهزة"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"زر الإرسال"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"زر الإرسال. تم قطع الاتصال"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"زر الإرسال. جارٍ الاتصال"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"زر الإرسال. تم الاتصال"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"إرسال إلى"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"جارٍ البحث عن أجهزة"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"قطع الاتصال"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"توسيع"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"تصغير"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"صورة الألبوم"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"شريط تمرير مستوى الصوت"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"لم يتم اختيار أية وسائط"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"لا تتوفر أية معلومات"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"جارٍ إرسال الشاشة"</string>
diff --git a/v7/mediarouter/res/values-az-rAZ/strings.xml b/v7/mediarouter/res/values-az-rAZ/strings.xml
index 765520e..31574c3 100644
--- a/v7/mediarouter/res/values-az-rAZ/strings.xml
+++ b/v7/mediarouter/res/values-az-rAZ/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"Sistem"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Cihazlar"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Yayım düyməsi"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Yayım düyməsi. Bağlantı kəsildi"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Yayım düyməsi. Qoşulur"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Yayım düyməsi. Qoşuldu"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Bura yayımlayın"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Cihazlar axtarılır"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Bağlantını kəsin"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Genişləndirin"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Yığcamlaşdırın"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Albom incəsənəti"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Səs hərmi diyircəyi"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Heç bir media seçilməyib"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Əlçatan məlumat yoxdur"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Ekran yayımlanır"</string>
diff --git a/v7/mediarouter/res/values-b+sr+Latn/strings.xml b/v7/mediarouter/res/values-b+sr+Latn/strings.xml
index 6c32754..8075d2e 100644
--- a/v7/mediarouter/res/values-b+sr+Latn/strings.xml
+++ b/v7/mediarouter/res/values-b+sr+Latn/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"Sistem"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Uređaji"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Dugme Prebaci"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Dugme Prebaci. Veza je prekinuta"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Dugme Prebaci. Povezuje se"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Dugme Prebaci. Povezan je"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Prebacujte na"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Pronalaženje uređaja"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Prekini vezu"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Proširi"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Skupi"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Omot albuma"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Klizač za jačinu zvuka"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Nema izabranih medija"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Nisu dostupne nikakve informacije"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Prebacuje se ekran"</string>
diff --git a/v7/mediarouter/res/values-be-rBY/strings.xml b/v7/mediarouter/res/values-be-rBY/strings.xml
index de52c06..75c24d5 100644
--- a/v7/mediarouter/res/values-be-rBY/strings.xml
+++ b/v7/mediarouter/res/values-be-rBY/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"Сістэма"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Прылады"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Кнопка трансляцыі"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Кнопка трансляцыі. Адключана"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Кнопка трансляцыі. Ідзе падключэнне"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Кнопка трансляцыі. Падключана"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Трансляваць на"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Пошук прылад"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Адлучыць"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Разгарнуць"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Згарнуць"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Вокладка альбома"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Паўзунок гучнасці"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Медыяфайл не выбраны"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Інфармацыя адсутнічае"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Экран трансляцыі"</string>
diff --git a/v7/mediarouter/res/values-bg/strings.xml b/v7/mediarouter/res/values-bg/strings.xml
index 036b31f..d756d6c 100644
--- a/v7/mediarouter/res/values-bg/strings.xml
+++ b/v7/mediarouter/res/values-bg/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"Система"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Устройства"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Бутон за предаване"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Бутон за предаване. Връзката е прекратена"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Бутон за предаване. Свързва се"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Бутон за предаване. Установена е връзка"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Предаване към"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Търсят се устройства"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Прекратяване на връзката"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Разгъване"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Свиване"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Обложка на албума"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Плъзгач за силата на звука"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Няма избрана мултимедия"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Няма налична информация"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Екранът се предава"</string>
diff --git a/v7/mediarouter/res/values-bn-rBD/strings.xml b/v7/mediarouter/res/values-bn-rBD/strings.xml
index 0e3e491..b94b9af 100644
--- a/v7/mediarouter/res/values-bn-rBD/strings.xml
+++ b/v7/mediarouter/res/values-bn-rBD/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"সিস্টেম"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"ডিভাইসগুলি"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"কাস্ট করার বোতাম"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"কাস্ট করার বোতাম৷ সংযোগ বিচ্ছিন্ন হয়েছে"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"কাস্ট করার বোতাম৷ সংযোগ করা হচ্ছে"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"কাস্ট করার বোতাম৷ সংযুক্ত হয়েছে"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"এতে কাস্ট করুন"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"ডিভাইসগুলিকে খোঁজা হচ্ছে"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"সংযোগ বিচ্ছিন্ন করুন"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"প্রসারিত করুন"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"সঙ্কুচিত করুন"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"অ্যালবাম শৈলি"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"ভলিউম স্লাইডার"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"কোনো মিডিয়া নির্বাচন করা হয়নি"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"কোনো তথ্য উপলব্ধ নেই"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"স্ক্রীন কাস্ট করা হচ্ছে"</string>
diff --git a/v7/mediarouter/res/values-bs-rBA/strings.xml b/v7/mediarouter/res/values-bs-rBA/strings.xml
index a6894f5..df4e3ef 100644
--- a/v7/mediarouter/res/values-bs-rBA/strings.xml
+++ b/v7/mediarouter/res/values-bs-rBA/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"Sistem"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Uređaji"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Dugme za prebacivanje"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Dugme za prebacivanje. Veza je prekinuta"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Dugme za prebacivanje. Povezivanje"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Dugme za prebacivanje. Povezan"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Prebacujte na"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Traženje uređaja"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Prekini vezu"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Proširi"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Skupi"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Omot albuma"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Klizač za jačinu zvuka"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Nijedan medij nije odabran"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Nema dostupnih informacija"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Prebacuje se ekran"</string>
diff --git a/v7/mediarouter/res/values-ca/strings.xml b/v7/mediarouter/res/values-ca/strings.xml
index 7fc51f7..400d424 100644
--- a/v7/mediarouter/res/values-ca/strings.xml
+++ b/v7/mediarouter/res/values-ca/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"Sistema"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Dispositius"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Botó d\'emetre"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Botó Emet. Desconnectat."</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Botó Emet. S\'està connectant."</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Botó Emet. Connectat."</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Emet a"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"S\'estan cercant dispositius"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Desconnecta"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Desplega"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Replega"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Imatge de l\'àlbum"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Control lliscant de volum"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"No s\'ha seleccionat cap fitxer multimèdia"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"No hi ha informació disponible"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Emissió de pantalla"</string>
diff --git a/v7/mediarouter/res/values-cs/strings.xml b/v7/mediarouter/res/values-cs/strings.xml
index f5a286e..5a29bac 100644
--- a/v7/mediarouter/res/values-cs/strings.xml
+++ b/v7/mediarouter/res/values-cs/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"Systém"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Zařízení"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Tlačítko odesílání"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Tlačítko odesílání. Odpojeno"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Tlačítko odesílání. Připojování"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Tlačítko odesílání. Připojeno"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Odesílat do"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Hledání zařízení"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Odpojit"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Rozbalit"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Sbalit"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Obal alba"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Posuvník hlasitosti"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Nebyla vybrána žádná média"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Nejsou k dispozici žádné informace"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Odesílání obsahu obrazovky"</string>
diff --git a/v7/mediarouter/res/values-da/strings.xml b/v7/mediarouter/res/values-da/strings.xml
index 9e5f9a5..f33a4ee 100644
--- a/v7/mediarouter/res/values-da/strings.xml
+++ b/v7/mediarouter/res/values-da/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"System"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Enheder"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Cast-knap"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Cast-knap. Forbindelsen er afbrudt"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Cast-knap. Opretter forbindelse"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Cast-knap. Tilsluttet"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Cast til"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Finder enheder"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Afbryd"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Udvid"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Skjul"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Albumgrafik"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Lydstyrkeskyder"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Der er ikke valgt nogen medier"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Der er ingen tilgængelige oplysninger"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Skærmen castes"</string>
diff --git a/v7/mediarouter/res/values-de/strings.xml b/v7/mediarouter/res/values-de/strings.xml
index 91d764f..13686aa 100644
--- a/v7/mediarouter/res/values-de/strings.xml
+++ b/v7/mediarouter/res/values-de/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"System"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Geräte"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Cast-Symbol"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Streaming-Schaltfläche. Nicht verbunden"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Streaming-Schaltfläche. Verbindung wird hergestellt"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Streaming-Schaltfläche. Verbunden"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Streamen auf"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Geräte werden gesucht."</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Verbindung trennen"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Maximieren"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Minimieren"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Albumcover"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Schieberegler für die Lautstärke"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Keine Medien ausgewählt"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Keine Informationen verfügbar"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Bildschirm wird gestreamt."</string>
diff --git a/v7/mediarouter/res/values-el/strings.xml b/v7/mediarouter/res/values-el/strings.xml
index 0a1a62f..3f45621 100644
--- a/v7/mediarouter/res/values-el/strings.xml
+++ b/v7/mediarouter/res/values-el/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"Σύστημα"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Συσκευές"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Κουμπί Cast"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Κουμπί μετάδοσης. Αποσυνδέθηκε"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Κουμπί μετάδοση. Σύνδεση σε εξέλιξη"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Κουμπί μετάδοσης. Συνδέθηκε"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Μετάδοση σε"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Εύρεση συσκευών"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Αποσύνδεση"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Ανάπτυξη"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Σύμπτυξη"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Εξώφυλλο άλμπουμ"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Ρυθμιστικό έντασης ήχου"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Δεν έχουν επιλεγεί μέσα"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Δεν υπάρχουν διαθέσιμες πληροφορίες"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Μετάδοση οθόνης"</string>
diff --git a/v7/mediarouter/res/values-en-rAU/strings.xml b/v7/mediarouter/res/values-en-rAU/strings.xml
index d60689e..9201c1f 100644
--- a/v7/mediarouter/res/values-en-rAU/strings.xml
+++ b/v7/mediarouter/res/values-en-rAU/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"System"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Devices"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Cast button"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Cast button. Disconnected"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Cast button. Connecting"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Cast button. Connected"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Cast to"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Finding devices"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Disconnect"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Expand"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Collapse"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Album art"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Volume slider"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"No media selected"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"No info available"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Casting screen"</string>
diff --git a/v7/mediarouter/res/values-en-rGB/strings.xml b/v7/mediarouter/res/values-en-rGB/strings.xml
index d60689e..9201c1f 100644
--- a/v7/mediarouter/res/values-en-rGB/strings.xml
+++ b/v7/mediarouter/res/values-en-rGB/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"System"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Devices"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Cast button"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Cast button. Disconnected"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Cast button. Connecting"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Cast button. Connected"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Cast to"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Finding devices"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Disconnect"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Expand"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Collapse"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Album art"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Volume slider"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"No media selected"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"No info available"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Casting screen"</string>
diff --git a/v7/mediarouter/res/values-en-rIN/strings.xml b/v7/mediarouter/res/values-en-rIN/strings.xml
index d60689e..9201c1f 100644
--- a/v7/mediarouter/res/values-en-rIN/strings.xml
+++ b/v7/mediarouter/res/values-en-rIN/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"System"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Devices"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Cast button"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Cast button. Disconnected"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Cast button. Connecting"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Cast button. Connected"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Cast to"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Finding devices"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Disconnect"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Expand"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Collapse"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Album art"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Volume slider"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"No media selected"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"No info available"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Casting screen"</string>
diff --git a/v7/mediarouter/res/values-es-rUS/strings.xml b/v7/mediarouter/res/values-es-rUS/strings.xml
index 2318059..90aa823 100644
--- a/v7/mediarouter/res/values-es-rUS/strings.xml
+++ b/v7/mediarouter/res/values-es-rUS/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"Sistema"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Dispositivos"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Botón para transmitir"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Botón para transmitir (desconectado)"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Botón para transmitir (conectando)"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Botón para transmitir (conectado)"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Transmitir a"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Buscando dispositivos"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Desconectar"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Mostrar"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Ocultar"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Imagen del álbum"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Control deslizante del volumen"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"No se seleccionó ningún contenido multimedia"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Sin información disponible"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Transmitiendo pantalla"</string>
diff --git a/v7/mediarouter/res/values-es/strings.xml b/v7/mediarouter/res/values-es/strings.xml
index 9f108fe..52a886f 100644
--- a/v7/mediarouter/res/values-es/strings.xml
+++ b/v7/mediarouter/res/values-es/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"Sistema"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Dispositivos"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Botón de enviar"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Botón de enviar. Desconectado"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Botón de enviar. Conectando"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Botón de enviar. Conectado"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Enviar a"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Buscando dispositivos"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Desconectar"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Mostrar"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Ocultar"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Portada del álbum"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Control deslizante de volumen"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"No se ha seleccionado ningún medio"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"No hay información disponible"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Enviando pantalla"</string>
diff --git a/v7/mediarouter/res/values-et-rEE/strings.xml b/v7/mediarouter/res/values-et-rEE/strings.xml
index 3fab845..ce1847a 100644
--- a/v7/mediarouter/res/values-et-rEE/strings.xml
+++ b/v7/mediarouter/res/values-et-rEE/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"Süsteem"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Seadmed"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Ülekandenupp"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Ülekandenupp. Ühendus on katkestatud"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Ülekandenupp. Ühendamine"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Ülekandenupp. Ühendatud"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Ülekandmine seadmesse"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Seadmete otsimine"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Katkesta ühendus"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Laiendamine"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Ahendamine"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Albumi kujundus"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Helitugevuse liugur"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Meediat pole valitud"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Teave puudub"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Ekraanikuva ülekandmine"</string>
diff --git a/v7/mediarouter/res/values-eu-rES/strings.xml b/v7/mediarouter/res/values-eu-rES/strings.xml
index bae67ed..c03d73b 100644
--- a/v7/mediarouter/res/values-eu-rES/strings.xml
+++ b/v7/mediarouter/res/values-eu-rES/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"Sistema"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Gailuak"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Igorri botoia"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Igortzeko botoia. Deskonektatuta"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Igortzeko botoia. Konektatzen"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Igortzeko botoia. Konektatuta"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Igorri hona"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Gailuak bilatzen"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Deskonektatu"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Zabaldu"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Tolestu"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Albumaren azala"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Bolumenaren graduatzailea"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Ez da hautatu multimedia-edukirik"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Ez dago informaziorik"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Pantaila igortzen"</string>
diff --git a/v7/mediarouter/res/values-fa/strings.xml b/v7/mediarouter/res/values-fa/strings.xml
index eb34931..7cc9fbc 100644
--- a/v7/mediarouter/res/values-fa/strings.xml
+++ b/v7/mediarouter/res/values-fa/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"سیستم"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"دستگاه‌ها"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"دکمه ارسال محتوا"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"دکمه فرستادن. ارتباط قطع شد"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"دکمه فرستادن. درحال مرتبط‌سازی"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"دکمه فرستادن. مرتبط شد"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"ارسال محتوا به"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"پیدا کردن دستگاه‌ها"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"قطع ارتباط"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"بزرگ کردن"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"کوچک کردن"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"عکس روی جلد آلبوم"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"لغزنده میزان صدا"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"رسانه انتخاب نشده است"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"اطلاعات در دسترس نیست"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"درحال فرستادن صفحه"</string>
diff --git a/v7/mediarouter/res/values-fi/strings.xml b/v7/mediarouter/res/values-fi/strings.xml
index f37317a..2465802 100644
--- a/v7/mediarouter/res/values-fi/strings.xml
+++ b/v7/mediarouter/res/values-fi/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"Järjestelmä"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Laitteet"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Cast-painike"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Cast-painike. Yhteys katkaistu"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Cast-painike. Yhdistetään"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Cast-painike. Yhdistetty"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Suoratoiston kohde"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Etsitään laitteita"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Katkaise yhteys"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Laajenna"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Tiivistä"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Albumin kansikuva"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Äänenvoimakkuuden liukusäädin"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Ei valittua mediaa."</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Tietoja ei ole saatavilla"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Suoratoistetaan näyttöä"</string>
diff --git a/v7/mediarouter/res/values-fr-rCA/strings.xml b/v7/mediarouter/res/values-fr-rCA/strings.xml
index 5719479..fd1ea8c 100644
--- a/v7/mediarouter/res/values-fr-rCA/strings.xml
+++ b/v7/mediarouter/res/values-fr-rCA/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"Système"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Appareils"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Bouton Diffuser"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Bouton Diffuser. Déconnecté"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Bouton Diffuser. Connexion en cours…"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Bouton Diffuser. Connecté"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Diffuser sur"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Recherche d\'appareils"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Se déconnecter"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Développer"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Réduire"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Image de l\'album"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Curseur de réglage du volume"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Aucun média sélectionné"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Aucune information disponible"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Diffusion de l\'écran en cours"</string>
diff --git a/v7/mediarouter/res/values-fr/strings.xml b/v7/mediarouter/res/values-fr/strings.xml
index 6ce8329..8c96485 100644
--- a/v7/mediarouter/res/values-fr/strings.xml
+++ b/v7/mediarouter/res/values-fr/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"Système"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Appareils"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Icône Cast"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Icône Cast. Déconnecté"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Icône Cast. Connexion…"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Icône Cast. Connecté"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Caster sur"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Recherche d\'appareils en cours…"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Déconnecter"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Développer"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Réduire"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Image de l\'album"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Curseur de volume"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Aucun média sélectionné"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Aucune information disponible"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Diffusion de l\'écran en cours…"</string>
diff --git a/v7/mediarouter/res/values-gl-rES/strings.xml b/v7/mediarouter/res/values-gl-rES/strings.xml
index c922b68..d6d1888 100644
--- a/v7/mediarouter/res/values-gl-rES/strings.xml
+++ b/v7/mediarouter/res/values-gl-rES/strings.xml
@@ -19,16 +19,20 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"Sistema"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Dispositivos"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Botón de emitir"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Botón de emitir. Desconectado"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Botón de emitir. Conectando"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Botón de emitir. Conectado"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Emitir en"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Buscando dispositivos"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Desconectar"</string>
-    <string name="mr_controller_stop" msgid="4570331844078181931">"Parar de emitir"</string>
+    <string name="mr_controller_stop" msgid="4570331844078181931">"Deter emisión"</string>
     <string name="mr_controller_close_description" msgid="7333862312480583260">"Pechar"</string>
     <string name="mr_controller_play" msgid="683634565969987458">"Reproduce"</string>
     <string name="mr_controller_pause" msgid="5451884435510905406">"Pausa"</string>
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Ampliar"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Contraer"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Portada do álbum"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Control desprazable do volume"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Non se seleccionaron recursos"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Non hai información dispoñible"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Emisión de pantalla"</string>
diff --git a/v7/mediarouter/res/values-gu-rIN/strings.xml b/v7/mediarouter/res/values-gu-rIN/strings.xml
index e3be8fc..eb7a9b8 100644
--- a/v7/mediarouter/res/values-gu-rIN/strings.xml
+++ b/v7/mediarouter/res/values-gu-rIN/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"સિસ્ટમ"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"ઉપકરણો"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"કાસ્ટ કરો બટન"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"કાસ્ટ કરો બટન. ડિસ્કનેક્ટ કર્યું"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"કાસ્ટ કરો બટન. કનેક્ટ થઈ રહ્યું છે"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"કાસ્ટ કરો બટન. કનેક્ટ થયું"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"આના પર કાસ્ટ કરો"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"ઉપકરણો શોધી રહ્યાં છીએ"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"ડિસ્કનેક્ટ કરો"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"વિસ્તૃત કરો"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"સંકુચિત કરો"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"આલ્બમ કલા"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"વૉલ્યુમ સ્લાઇડર"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"કોઈ મીડિયા પસંદ કરેલ નથી"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"કોઈ માહિતી ઉપલબ્ધ નથી"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"સ્ક્રીનને કાસ્ટ કરી રહ્યાં છે"</string>
diff --git a/v7/mediarouter/res/values-hi/strings.xml b/v7/mediarouter/res/values-hi/strings.xml
index 9d0650b..e74967e 100644
--- a/v7/mediarouter/res/values-hi/strings.xml
+++ b/v7/mediarouter/res/values-hi/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"सिस्टम"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"डिवाइस"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"कास्ट करें बटन"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"कास्ट करें बटन. डिस्कनेक्ट है"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"कास्ट करें बटन. कनेक्ट हो रहा है"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"कास्ट करें बटन. कनेक्ट है"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"इस पर कास्‍ट करें"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"डिवाइस ढूंढ रहा है"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"डिस्कनेक्ट करें"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"विस्तृत करें"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"संक्षिप्त करें"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"एल्बम आर्ट"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"वॉल्यूम स्लाइडर"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"कोई मीडिया चयनित नहीं है"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"कोई जानकारी उपलब्‍ध नहीं"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"स्क्रीन कास्ट हो रही है"</string>
diff --git a/v7/mediarouter/res/values-hr/strings.xml b/v7/mediarouter/res/values-hr/strings.xml
index 371088b..f50d748 100644
--- a/v7/mediarouter/res/values-hr/strings.xml
+++ b/v7/mediarouter/res/values-hr/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"Sustav"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Uređaji"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Gumb za emitiranje"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Gumb za emitiranje. Veza prekinuta"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Gumb za emitiranje. Povezivanje"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Gumb za emitiranje. Povezan"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Emitiranje na"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Traženje uređaja"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Prekini vezu"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Proširivanje"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Sažimanje"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Naslovnica albuma"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Klizač za glasnoću"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Nije odabran nijedan medij"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Informacije nisu dostupne"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Emitiranje zaslona"</string>
diff --git a/v7/mediarouter/res/values-hu/strings.xml b/v7/mediarouter/res/values-hu/strings.xml
index a3d6990..6420985 100644
--- a/v7/mediarouter/res/values-hu/strings.xml
+++ b/v7/mediarouter/res/values-hu/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"Rendszer"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Eszközök"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Átküldés gomb"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Átküldés gomb. Kapcsolat bontva"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Átküldés gomb. Csatlakozás"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Átküldés gomb. Csatlakoztatva"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Átküldés ide"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Eszközök keresése"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Leválasztás"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Kibontás"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Összecsukás"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Lemezborító"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Hangerőszabályzó"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Nincs média kiválasztva"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Nincs információ"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Képernyőtartalom átküldése"</string>
diff --git a/v7/mediarouter/res/values-hy-rAM/strings.xml b/v7/mediarouter/res/values-hy-rAM/strings.xml
index a8c1cf3..6e46af8 100644
--- a/v7/mediarouter/res/values-hy-rAM/strings.xml
+++ b/v7/mediarouter/res/values-hy-rAM/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"Համակարգ"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Սարքեր"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Հեռարձակման կոճակ"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Հեռարձակման կոճակ: Սարքն անջատված է"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Հեռարձակման կոճակ: Սարքը կապակցվում է"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Հեռարձակման կոճակ: Սարքը կապակցված է"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Ընտրեք սարքը"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Սարքերի որոնում"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Անջատել"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Ընդարձակել"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Կոծկել"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Ալբոմի շապիկ"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Ձայնի ուժգնության կարգավորիչ"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Մեդիա ֆայլեր չեն ընտրվել"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Տեղեկությունները հասանելի չեն"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Էկրանը հեռարձակվում է"</string>
diff --git a/v7/mediarouter/res/values-in/strings.xml b/v7/mediarouter/res/values-in/strings.xml
index 4bc0852..43e0c62 100644
--- a/v7/mediarouter/res/values-in/strings.xml
+++ b/v7/mediarouter/res/values-in/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"Sistem"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Perangkat"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Tombol transmisi"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Tombol transmisi. Terputus"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Tombol transmisi. Menghubungkan"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Tombol transmisi. Terhubung"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Transmisikan ke"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Mencari perangkat"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Putuskan sambungan"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Luaskan"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Ciutkan"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Sampul album"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Bilah geser volume"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Tidak ada media yang dipilih"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Tidak ada info yang tersedia"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Transmisi layar"</string>
diff --git a/v7/mediarouter/res/values-is-rIS/strings.xml b/v7/mediarouter/res/values-is-rIS/strings.xml
index 08e41e6..53de253 100644
--- a/v7/mediarouter/res/values-is-rIS/strings.xml
+++ b/v7/mediarouter/res/values-is-rIS/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"Kerfi"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Tæki"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Útsendingarhnappur"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Útsendingarhnappur. Aftengt"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Útsendingarhnappur. Tengist"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Útsendingarhnappur. Tengt"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Senda út í"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Leitað að tækjum"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Aftengjast"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Stækka"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Minnka"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Plötuumslag"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Hljóðstyrkssleði"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Enginn miðill valinn"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Engar upplýsingar í boði"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Skjár sendur út"</string>
diff --git a/v7/mediarouter/res/values-it/strings.xml b/v7/mediarouter/res/values-it/strings.xml
index 87b570c..df6bbfe 100644
--- a/v7/mediarouter/res/values-it/strings.xml
+++ b/v7/mediarouter/res/values-it/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"Sistema"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Dispositivi"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Pulsante Trasmetti"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Pulsante Trasmetti. Disconnesso"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Pulsante Trasmetti. Connessione in corso"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Pulsante Trasmetti. Connesso"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Trasmetti a"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Ricerca di dispositivi in corso"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Scollega"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Espandi"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Comprimi"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Copertina"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Dispositivo di scorrimento del volume"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Nessun contenuto multimediale selezionato"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Nessuna informazione disponibile"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Trasmissione dello schermo in corso"</string>
diff --git a/v7/mediarouter/res/values-iw/strings.xml b/v7/mediarouter/res/values-iw/strings.xml
index 8b52adf..be705a6 100644
--- a/v7/mediarouter/res/values-iw/strings.xml
+++ b/v7/mediarouter/res/values-iw/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"מערכת"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"מכשירים"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"‏לחצן הפעלת Cast"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"‏לחצן הפעלת Cast. מנותק"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"‏לחצן הפעלת Cast. מתחבר"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"‏לחצן הפעלת Cast. מחובר"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"העבר אל"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"מחפש מכשירים"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"נתק"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"הרחב"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"כווץ"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"עטיפת אלבום"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"מחוון עוצמה"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"לא נבחרה מדיה"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"אין מידע זמין"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"העברת מסך מתבצעת"</string>
diff --git a/v7/mediarouter/res/values-ja/strings.xml b/v7/mediarouter/res/values-ja/strings.xml
index b126965..75d75d6 100644
--- a/v7/mediarouter/res/values-ja/strings.xml
+++ b/v7/mediarouter/res/values-ja/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"システム"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"端末"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"キャストアイコン"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"キャスト アイコン。接続解除済み"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"キャスト アイコン。接続中"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"キャスト アイコン。接続済み"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"キャストするデバイス"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"端末を検索しています"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"接続を解除"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"展開"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"折りたたむ"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"アルバムアート"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"音量スライダー"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"メディアが選択されていません"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"情報がありません"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"画面をキャストしています"</string>
diff --git a/v7/mediarouter/res/values-ka-rGE/strings.xml b/v7/mediarouter/res/values-ka-rGE/strings.xml
index 046e361..3bcc513 100644
--- a/v7/mediarouter/res/values-ka-rGE/strings.xml
+++ b/v7/mediarouter/res/values-ka-rGE/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"სისტემა"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"მოწყობილობები"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"ტრანსლირების ღილაკი"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"ტრანსლირების ღილაკი. გათიშული"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"ტრანსლირების ღილაკი. მიმდინარეობს დაკავშირება"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"ტრანსლირების ღილაკი. დაკავშირებული"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"ტრანსლირებული"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"მიმდინარეობს მოწყობილობების მოძიება"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"კავშირის გაწყვეტა"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"გაშლა"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"ჩაკეცვა"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"ალბომის გარეკანი"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"ხმის სლაიდერი"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"მედია არჩეული არ არის"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"ინფორმაცია არ არის ხელმისაწვდომი"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"მიმდინარეობს ეკრანის გადაცემა"</string>
diff --git a/v7/mediarouter/res/values-kk-rKZ/strings.xml b/v7/mediarouter/res/values-kk-rKZ/strings.xml
index 5cf4e5a..43e75b7 100644
--- a/v7/mediarouter/res/values-kk-rKZ/strings.xml
+++ b/v7/mediarouter/res/values-kk-rKZ/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"Жүйе"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Құрылғылар"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Трансляциялау түймесі"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"\"Трансляциялау\" түймесі. Ажыратулы"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"\"Трансляциялау\" түймесі. Қосылуда"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"\"Трансляциялау\" түймесі. Қосылды"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Келесіге трансляциялау"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Құрылғыларды табу"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Ажырату"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Жаю"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Жию"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Альбом шебері"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Дыбыс деңгейінің жүгірткісі"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Ешбір тасушы таңдалмаған"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Қол жетімді ақпарат жоқ"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Экранды трансляциялау"</string>
diff --git a/v7/mediarouter/res/values-km-rKH/strings.xml b/v7/mediarouter/res/values-km-rKH/strings.xml
index fd05668..44d88f4 100644
--- a/v7/mediarouter/res/values-km-rKH/strings.xml
+++ b/v7/mediarouter/res/values-km-rKH/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"ប្រព័ន្ធ"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"ឧបករណ៍"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"ប៊ូតុងខាស"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"ខាសប៊ូតុង៖ បានកាត់ផ្តាច់"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"ខាសប៊ូតុង៖ កំពុងភ្ជាប់"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"ខាសប៊ូតុង៖ បានភ្ជាប់ហើយ"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"ខាសទៅ"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"ស្វែងរកឧបករណ៍"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"ផ្ដាច់"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"ពង្រីក"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"បង្រួម"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"ស្នាដៃសិល្បៈអាល់ប៊ុម"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"របារកម្រិតសំឡេង"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"គ្មានការជ្រើសមេឌៀទេ"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"មិនមានព័ត៌មានទេ"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"កំពុងខាសអេក្រង់"</string>
diff --git a/v7/mediarouter/res/values-kn-rIN/strings.xml b/v7/mediarouter/res/values-kn-rIN/strings.xml
index 9cae5be..193d449 100644
--- a/v7/mediarouter/res/values-kn-rIN/strings.xml
+++ b/v7/mediarouter/res/values-kn-rIN/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"ಸಿಸ್ಟಂ"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"ಸಾಧನಗಳು"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"ಬಿತ್ತರಿಸು ಬಟನ್‌"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"ಬಿತ್ತರಿಸು ಬಟನ್‌. ಸಂಪರ್ಕ ಕಡಿತಗೊಳಿಸಲಾಗಿದೆ"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"ಬಿತ್ತರಿಸು ಬಟನ್‌. ಸಂಪರ್ಕಿಸಲಾಗುತ್ತಿದೆ"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"ಬಿತ್ತರಿಸು ಬಟನ್‌. ಸಂಪರ್ಕಿತಗೊಂಡಿದೆ"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"ಇದಕ್ಕೆ ಬಿತ್ತರಿಸಿ"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"ಸಾಧನಗಳನ್ನು ಹುಡುಕಲಾಗುತ್ತಿದೆ"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"ಸಂಪರ್ಕ ಕಡಿತಗೊಳಿಸು"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"ವಿಸ್ತರಿಸು"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"ಸಂಕುಚಿಸು"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"ಆಲ್ಬಮ್ ಕಲೆ"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"ವಾಲ್ಯೂಮ್ ಸ್ಲೈಡರ್"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"ಯಾವುದೇ ಮಾಧ್ಯಮ ಆಯ್ಕೆಮಾಡಲಾಗಿಲ್ಲ"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"ಯಾವುದೇ ಮಾಹಿತಿ ಲಭ್ಯವಿಲ್ಲ"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"ಪರದೆಯನ್ನು ಬಿತ್ತರಿಸಲಾಗುತ್ತಿದೆ"</string>
diff --git a/v7/mediarouter/res/values-ko/strings.xml b/v7/mediarouter/res/values-ko/strings.xml
index 7f53382..242560a 100644
--- a/v7/mediarouter/res/values-ko/strings.xml
+++ b/v7/mediarouter/res/values-ko/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"시스템"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"기기"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"전송 버튼"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"전송 버튼. 연결 해제됨"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"전송 버튼. 연결 중"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"전송 버튼. 연결됨"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"전송할 기기"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"기기를 찾는 중"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"연결 해제"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"펼치기"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"접기"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"앨범아트"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"볼륨 슬라이더"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"선택한 미디어 없음"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"정보가 없습니다."</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"화면 전송 중"</string>
diff --git a/v7/mediarouter/res/values-ky-rKG/strings.xml b/v7/mediarouter/res/values-ky-rKG/strings.xml
index 99201dc..0898ade 100644
--- a/v7/mediarouter/res/values-ky-rKG/strings.xml
+++ b/v7/mediarouter/res/values-ky-rKG/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"Тутум"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Түзмөктөр"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Тышкы экранга чыгаруу баскычы"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Тышкы экранга чыгаруу баскычы. Түзмөк ажырап турат."</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Тышкы экранга чыгаруу баскычы. Түзмөк туташууда"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Тышкы экранга чыгаруу баскычы. Түзмөк туташып турат"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Төмөнкүгө чыгаруу"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Түзмөктөр изделүүдө"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Ажыратуу"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Жайып көрсөтүү"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Жыйыштыруу"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Альбом мукабасы"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Үндү катуулатуучу сыдырма"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Бир да медиа файл тандалган жок"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Эч маалымат жок"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Тышкы экранга чыгарылууда"</string>
diff --git a/v7/mediarouter/res/values-lo-rLA/strings.xml b/v7/mediarouter/res/values-lo-rLA/strings.xml
index 2765364..65b3472 100644
--- a/v7/mediarouter/res/values-lo-rLA/strings.xml
+++ b/v7/mediarouter/res/values-lo-rLA/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"ລະບົບ"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"ອຸປະກອນ"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"ປຸ່ມ​ຄາ​ສ​ທ໌"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"ປຸ່ມສົ່ງສັນຍານ. ຕັດການເຊື່ອມຕໍ່ແລ້ວ"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"ປຸ່ມສົ່ງສັນຍານ. ກຳລັງເຊື່ອມຕໍ່"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"ປຸ່ມສົ່ງສັນຍານ. ເຊື່ອມຕໍ່ແລ້ວ"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"ຄາ​ສ​ທ໌​ຫາ"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"ກຳລັງ​ຊອກ​ຫາ​ອຸ​ປະ​ກອນ"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"ຕັດການເຊື່ອມຕໍ່"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"ຂະຫຍາຍ"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"ຫຍໍ້ລົງ"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"ໜ້າປົກອະລະບໍ້າ"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"ຕົວປັບລະດັບສຽງ"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"ບໍ່​ໄດ້​ເລືອກ​ມີ​ເດຍ​ໃດ​ໄວ້"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"ບໍ່​ມີ​ຂໍ້​ມູນ"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"ການສົ່ງພາບໜ້າຈໍ"</string>
diff --git a/v7/mediarouter/res/values-lt/strings.xml b/v7/mediarouter/res/values-lt/strings.xml
index 208752f..35931cf 100644
--- a/v7/mediarouter/res/values-lt/strings.xml
+++ b/v7/mediarouter/res/values-lt/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"Sistema"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Įrenginiai"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Perdavimo mygtukas"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Perdavimo mygtukas. Atsijungta"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Perdavimo mygtukas. Prisijungiama"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Perdavimo mygtukas. Prisijungta"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Perduoti į"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Randami įrenginiai"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Atjungti"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Išskleisti"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Sutraukti"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Albumo viršelis"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Garsumo šliaužiklis"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Nepasirinkta jokia medija"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Informacija nepasiekiama"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Perduodamas ekranas"</string>
diff --git a/v7/mediarouter/res/values-lv/strings.xml b/v7/mediarouter/res/values-lv/strings.xml
index 832a3ba..c146174 100644
--- a/v7/mediarouter/res/values-lv/strings.xml
+++ b/v7/mediarouter/res/values-lv/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"Sistēma"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Ierīces"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Apraides poga"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Apraides poga. Savienojums pārtraukts"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Apraides poga. Notiek savienojuma izveide"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Apraides poga. Savienojums izveidots"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Apraidīšana uz ierīci"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Notiek ierīču meklēšana"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Atvienot"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Izvērst"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Sakļaut"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Albuma vāciņš"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Skaļuma slīdnis"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Nav atlasīti multivides faili"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Nav pieejama informācija"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Notiek ekrāna apraide"</string>
diff --git a/v7/mediarouter/res/values-mk-rMK/strings.xml b/v7/mediarouter/res/values-mk-rMK/strings.xml
index 726e285..6fd428f 100644
--- a/v7/mediarouter/res/values-mk-rMK/strings.xml
+++ b/v7/mediarouter/res/values-mk-rMK/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"Систем"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Уреди"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Копчето за Cast"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Копче за Cast. Исклучено"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Копче за Cast. Се поврзува"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Копче за Cast. Поврзано"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Емитувај на"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Наоѓање уреди"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Исклучи"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Прошири"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Собери"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Корица на албум"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Лизгач за јачина на звук"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Не се избрани медиуми"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Нема достапни информации"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Екранот се емитува"</string>
diff --git a/v7/mediarouter/res/values-ml-rIN/strings.xml b/v7/mediarouter/res/values-ml-rIN/strings.xml
index b1d2cbe..63a37f8 100644
--- a/v7/mediarouter/res/values-ml-rIN/strings.xml
+++ b/v7/mediarouter/res/values-ml-rIN/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"സിസ്റ്റം"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"ഉപകരണങ്ങൾ"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"ടാപ്പുചെയ്യുക"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"കാസ്റ്റ് ബട്ടൺ. വിച്ഛേദിച്ചു"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"കാസ്റ്റ് ബട്ടൺ. കണക്‌റ്റുചെയ്യുന്നു"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"കാസ്റ്റ് ബട്ടൺ. കണക്റ്റുചെയ്തു"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"ഇതിലേക്ക് കാസ്റ്റുചെയ്യുക"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"ഉപകരണങ്ങൾ കണ്ടെത്തുന്നു"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"വിച്ഛേദിക്കുക"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"വികസിപ്പിക്കുക"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"ചുരുക്കുക"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"ആൽബം ആർട്ട്"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"വോളിയം സ്ലൈഡർ"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"മീഡിയയൊന്നും തിരഞ്ഞെടുത്തിട്ടില്ല"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"വിവരങ്ങളൊന്നും ലഭ്യമല്ല"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"സ്‌ക്രീൻ കാസ്റ്റുചെയ്യുന്നു"</string>
diff --git a/v7/mediarouter/res/values-mn-rMN/strings.xml b/v7/mediarouter/res/values-mn-rMN/strings.xml
index d07d314..1197bfe 100644
--- a/v7/mediarouter/res/values-mn-rMN/strings.xml
+++ b/v7/mediarouter/res/values-mn-rMN/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"Систем"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Төхөөрөмжүүд"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Дамжуулах товчлуур"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Дамжуулах товчлуур. Салсан"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Дамжуулах товчлуур. Холбож байна"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Дамжуулах товчлуур. Холбогдсон"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Дамжуулах"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Төхөөрөмж хайж байна"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Салгах"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Дэлгэх"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Хураах"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Цомгийн зураг"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Дууны түвшин тааруулагч"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Ямар ч медиа сонгоогүй"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Мэдээлэл байхгүй байна"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Дэлгэцийг дамжуулж байна"</string>
diff --git a/v7/mediarouter/res/values-mr-rIN/strings.xml b/v7/mediarouter/res/values-mr-rIN/strings.xml
index 4e24aff..40d7d66 100644
--- a/v7/mediarouter/res/values-mr-rIN/strings.xml
+++ b/v7/mediarouter/res/values-mr-rIN/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"सिस्टम"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"डिव्हाइसेस"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"कास्ट बटण"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"कास्ट बटण. डिस्कनेक्ट केले"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"कास्ट बटण. कनेक्ट करीत आहे"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"कास्ट बटण. कनेक्ट केले"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"यावर कास्ट करा"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"डिव्हाइसेस शोधत आहे"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"डिस्‍कनेक्‍ट करा"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"विस्तृत करा"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"संकुचित करा"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"अल्बम कला"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"व्हॉल्यूम स्लायडर"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"मीडिया निवडला नाही"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"कोणतीही माहिती उपलब्ध नाही"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"स्क्रीन कास्‍ट करीत आहे"</string>
diff --git a/v7/mediarouter/res/values-ms-rMY/strings.xml b/v7/mediarouter/res/values-ms-rMY/strings.xml
index 2a4cd1c..cc32b96 100644
--- a/v7/mediarouter/res/values-ms-rMY/strings.xml
+++ b/v7/mediarouter/res/values-ms-rMY/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"Sistem"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Peranti"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Butang Hantar"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Butang hantar. Sambungan diputuskan"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Butang hantar. Menyambung"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Butang hantar. Disambungkan"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Hantar ke"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Mencari peranti"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Putuskan sambungan"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Kembangkan"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Runtuhkan"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Seni album"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Peluncur kelantangan"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Tiada media dipilih"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Maklumat tidak tersedia"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Menghantar skrin"</string>
diff --git a/v7/mediarouter/res/values-my-rMM/strings.xml b/v7/mediarouter/res/values-my-rMM/strings.xml
index eca8835..e31cc92 100644
--- a/v7/mediarouter/res/values-my-rMM/strings.xml
+++ b/v7/mediarouter/res/values-my-rMM/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"စနစ်"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"စက်ပစ္စည်းများ"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"ကာစ်တ်လုပ်ရန် ခလုတ်"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"ကာစ်ခလုတ်။ ချိတ်ဆက်မထားပါ"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"ကာစ်ခလုတ်။ ချိတ်ဆက်နေသည်"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"ကာစ်ခလုတ်။ ချိတ်ဆက်ထားသည်"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"သို့ ကာစ်တ်လုပ်ရန်"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"စက်ပစ္စည်းများ ရှာဖွေခြင်း"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"ဆက်သွယ်မှု ဖြတ်ရန်"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"ဖြန့်ချရန်၃"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"ခေါက်သိမ်းရန်..."</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"အယ်လ်ဘမ်ပုံ"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"အသံအတိုးအကျယ်ချိန်သည့် ဆလိုက်ဒါ"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"မည်သည့်မီဒီမှ မရွေးချယ်ထားပါ"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"အချက်အလက် မရရှိနိုင်ပါ"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"တည်းဖြတ်ရေး မျက်နှာပြင်"</string>
diff --git a/v7/mediarouter/res/values-nb/strings.xml b/v7/mediarouter/res/values-nb/strings.xml
index 27f9f03..97ca73c 100644
--- a/v7/mediarouter/res/values-nb/strings.xml
+++ b/v7/mediarouter/res/values-nb/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"System"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Enheter"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Cast-ikonet"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Cast-knappen. Frakoblet"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Cast-knappen. Kobler til"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Cast-knappen. Tilkoblet"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Cast til"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Finner enheter"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Koble fra"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Utvid"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Skjul"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Albumgrafikk"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Glidebryter for volum"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Du har ikke valgt noen medier"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Ingen informasjon er tilgjengelig"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Caster skjermen"</string>
diff --git a/v7/mediarouter/res/values-ne-rNP/strings.xml b/v7/mediarouter/res/values-ne-rNP/strings.xml
index 6abadbf..0e48b45 100644
--- a/v7/mediarouter/res/values-ne-rNP/strings.xml
+++ b/v7/mediarouter/res/values-ne-rNP/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"प्रणाली"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"उपकरणहरू"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Cast बटन"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Cast बटन। जडान विच्छेद भयो"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Cast बटन। जडान हुँदै"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Cast बटन। जडान भयो"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"यसमा Cast गर्नुहोस्"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"यन्त्रहरू पत्ता लगाउँदै"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"विच्छेद गर्नुहोस्"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"विस्तार गर्नुहोस्"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"संक्षिप्त पार्नुहोस्"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"एल्बम आर्ट"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"भोल्युमको स्लाइडर"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"कुनै मिडिया चयन भएको छैन"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"जानकारी उपलब्ध छैन"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"स्क्रिन cast गर्दै"</string>
diff --git a/v7/mediarouter/res/values-nl/strings.xml b/v7/mediarouter/res/values-nl/strings.xml
index 4a9346d..5c899fd 100644
--- a/v7/mediarouter/res/values-nl/strings.xml
+++ b/v7/mediarouter/res/values-nl/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"Systeem"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Apparaten"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Cast-icoon"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Cast-icoon. Verbinding verbroken"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Cast-icoon. Verbinding maken"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Cast-icoon. Verbonden"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Casten naar"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Apparaten zoeken"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Loskoppelen"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Uitvouwen"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Samenvouwen"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Albumhoes"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Volumeschuifregelaar"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Geen media geselecteerd"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Geen informatie beschikbaar"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Scherm casten"</string>
diff --git a/v7/mediarouter/res/values-pa-rIN/strings.xml b/v7/mediarouter/res/values-pa-rIN/strings.xml
index 842a8b4..258529d 100644
--- a/v7/mediarouter/res/values-pa-rIN/strings.xml
+++ b/v7/mediarouter/res/values-pa-rIN/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"ਸਿਸਟਮ"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"ਡਿਵਾਈਸਾਂ"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"ਕਾਸਟ ਬਟਨ"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"ਕਾਸਟ ਬਟਨ। ਡਿਸਕਨੈਕਟ ਕੀਤਾ ਗਿਆ"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"ਕਾਸਟ ਬਟਨ। ਕਨੈਕਟ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"ਕਾਸਟ ਬਟਨ। ਕਨੈਕਟ ਕੀਤਾ ਗਿਆ"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"ਇਸ ਨਾਲ ਕਾਸਟ ਕਰੋ"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"ਡਿਵਾਈਸਾਂ ਲੱਭ ਰਿਹਾ ਹੈ"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"ਡਿਸਕਨੈਕਟ ਕਰੋ"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"ਵਿਸਤਾਰ ਕਰੋ"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"ਬੰਦ ਕਰੋ"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"ਐਲਬਮ ਆਰਟ"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"ਵੌਲਯੂਮ ਸਲਾਈਡਰ"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"ਕੋਈ ਵੀ ਮੀਡੀਆ ਨਹੀਂ ਚੁਣਿਆ ਗਿਆ"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"ਕੋਈ ਜਾਣਕਾਰੀ ਉਪਲਬਧ ਨਹੀਂ"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"ਸਕ੍ਰੀਨ ਜੋੜ ਰਿਹਾ ਹੈ"</string>
diff --git a/v7/mediarouter/res/values-pl/strings.xml b/v7/mediarouter/res/values-pl/strings.xml
index d66be1a..0320550 100644
--- a/v7/mediarouter/res/values-pl/strings.xml
+++ b/v7/mediarouter/res/values-pl/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"System"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Urządzenia"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Przycisk Cast"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Przycisk Prześlij ekran. Rozłączono"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Przycisk Prześlij ekran. Łączę"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Przycisk Prześlij ekran. Połączono"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Przesyłaj na"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Znajdowanie urządzeń"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Odłącz"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Rozwiń"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Zwiń"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Okładka albumu"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Suwak głośności"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Nie wybrano multimediów"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Brak informacji"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Przesyłam ekran"</string>
diff --git a/v7/mediarouter/res/values-pt-rBR/strings.xml b/v7/mediarouter/res/values-pt-rBR/strings.xml
index 4d7e6cc..2fd84b1 100644
--- a/v7/mediarouter/res/values-pt-rBR/strings.xml
+++ b/v7/mediarouter/res/values-pt-rBR/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"Sistema"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Dispositivos"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Botão Transmitir"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Botão \"Transmitir\". Desconectado"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Botão \"Transmitir\". Conectando"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Botão \"Transmitir\". Conectado"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Transmitir para"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Localizando dispositivos"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Desconectar"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Expandir"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Recolher"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Arte do álbum"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Controle deslizante de volume"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Nenhuma mídia selecionada"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Nenhuma informação disponível"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Transmitindo a tela"</string>
diff --git a/v7/mediarouter/res/values-pt-rPT/strings.xml b/v7/mediarouter/res/values-pt-rPT/strings.xml
index 0c68b92..b62f363 100644
--- a/v7/mediarouter/res/values-pt-rPT/strings.xml
+++ b/v7/mediarouter/res/values-pt-rPT/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"Sistema"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Dispositivos"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Botão Transmitir"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Botão Transmitir. Desligado"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Botão Transmitir. A ligar..."</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Botão Transmitir. Ligado"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Transmitir para"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"A localizar dispositivos"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Desassociar"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Expandir"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Reduzir"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Imagem do álbum"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Controlo de deslize do volume"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Nenhum suporte multimédia selecionado"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Nenhuma informação disponível"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"A transmitir o ecrã"</string>
diff --git a/v7/mediarouter/res/values-pt/strings.xml b/v7/mediarouter/res/values-pt/strings.xml
index 4d7e6cc..2fd84b1 100644
--- a/v7/mediarouter/res/values-pt/strings.xml
+++ b/v7/mediarouter/res/values-pt/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"Sistema"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Dispositivos"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Botão Transmitir"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Botão \"Transmitir\". Desconectado"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Botão \"Transmitir\". Conectando"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Botão \"Transmitir\". Conectado"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Transmitir para"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Localizando dispositivos"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Desconectar"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Expandir"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Recolher"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Arte do álbum"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Controle deslizante de volume"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Nenhuma mídia selecionada"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Nenhuma informação disponível"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Transmitindo a tela"</string>
diff --git a/v7/mediarouter/res/values-ro/strings.xml b/v7/mediarouter/res/values-ro/strings.xml
index 9fe26a9..769a0ac 100644
--- a/v7/mediarouter/res/values-ro/strings.xml
+++ b/v7/mediarouter/res/values-ro/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"Sistem"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Dispozitive"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Butonul de proiecție"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Butonul de proiecție. Deconectat"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Butonul de proiecție. Se conectează"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Butonul de proiecție. Conectat"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Proiectați pe"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Se caută dispozitive"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Deconectați-vă"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Extindeți"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Restrângeți"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Grafica albumului"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Glisor pentru volum"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Niciun fișier media selectat"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Nu sunt disponibile informații"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Se proiectează ecranul"</string>
diff --git a/v7/mediarouter/res/values-ru/strings.xml b/v7/mediarouter/res/values-ru/strings.xml
index 4607a8c..9bd2170 100644
--- a/v7/mediarouter/res/values-ru/strings.xml
+++ b/v7/mediarouter/res/values-ru/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"Система"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Устройства"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Кнопка трансляции"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Кнопка трансляции. Устройство отключено."</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Кнопка трансляции. Устройство подключается."</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Кнопка трансляции. Устройство подключено."</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Выберите устройство"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Поиск устройств…"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Отключить"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Развернуть"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Свернуть"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Обложка"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Регулятор громкости"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Медиафайл не выбран"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Данных нет"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Подключение к удаленному монитору"</string>
diff --git a/v7/mediarouter/res/values-si-rLK/strings.xml b/v7/mediarouter/res/values-si-rLK/strings.xml
index 144a0d5..baeac3e 100644
--- a/v7/mediarouter/res/values-si-rLK/strings.xml
+++ b/v7/mediarouter/res/values-si-rLK/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"පද්ධතිය"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"උපාංග"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"විකාශ බොත්තම"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"විකාශ බොත්තම. විසන්ධි කරන ලදී"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"විකාශ බොත්තම සම්බන්ධ කරමින්"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"විකාශ බොත්තම සම්බන්ධ කරන ලදී"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"විකාශය"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"උපාංග සෙවීම"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"විසන්ධි කරන්න"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"දිග හරින්න"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"හකුළන්න"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"ඇල්බම කලාව"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"හඬ පරිමා ස්ලයිඩරය"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"මාධ්‍යය තෝරා නැත"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"ලබා ගත හැකි තොරතුරු නොමැත"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"විකාශ තිරය"</string>
diff --git a/v7/mediarouter/res/values-sk/strings.xml b/v7/mediarouter/res/values-sk/strings.xml
index b546bde..4a0f4bf 100644
--- a/v7/mediarouter/res/values-sk/strings.xml
+++ b/v7/mediarouter/res/values-sk/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"Systém"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Zariadenia"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Tlačidlo prenosu"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Tlačidlo prenosu. Odpojené"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Tlačidlo prenosu. Pripája sa"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Tlačidlo prenosu. Pripojené"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Prenos do"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Vyhľadávanie zariadení"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Odpojiť"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Rozbaliť"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Zbaliť"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Obrázok albumu"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Posúvač hlasitosti"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Nie sú vybrané žiadne médiá"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Nie sú k dispozícii žiadne informácie"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Prenáša sa obrazovka"</string>
diff --git a/v7/mediarouter/res/values-sl/strings.xml b/v7/mediarouter/res/values-sl/strings.xml
index 110c548..4ca2bdc 100644
--- a/v7/mediarouter/res/values-sl/strings.xml
+++ b/v7/mediarouter/res/values-sl/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"Sistem"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Naprave"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Gumb za predvajanje"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Gumb za predvajanje. Povezava je prekinjena."</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Gumb za predvajanje. Vzpostavljanje povezave."</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Gumb za predvajanje. Povezava je vzpostavljena."</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Predvajanje prek:"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Iskanje naprav"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Prekini povezavo"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Razširi"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Strni"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Naslovnica albuma"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Drsnik za glasnost"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Ni izbrane predstavnosti"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Podatki niso na voljo"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Predvajanje zaslona"</string>
diff --git a/v7/mediarouter/res/values-sq-rAL/strings.xml b/v7/mediarouter/res/values-sq-rAL/strings.xml
index 8ed93c3..45e3a34 100644
--- a/v7/mediarouter/res/values-sq-rAL/strings.xml
+++ b/v7/mediarouter/res/values-sq-rAL/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"Sistemi"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Pajisjet"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Butoni i transmetimit"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Butoni i transmetimit. Je i shkëputur"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Butoni i transmetimit. Po lidhet"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Butoni i transmetimit. Je i lidhur"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Transmeto te"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Gjetja e pajisjeve"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Shkëpute"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Zgjeroje"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Palose"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Kopertina e albumit"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Rrëshqitësi i volumit"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Nuk u zgjodh asnjë media"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Nuk jepet asnjë informacion"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Po transmeton ekranin"</string>
diff --git a/v7/mediarouter/res/values-sr/strings.xml b/v7/mediarouter/res/values-sr/strings.xml
index 5a72bd4..bddc045 100644
--- a/v7/mediarouter/res/values-sr/strings.xml
+++ b/v7/mediarouter/res/values-sr/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"Систем"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Уређаји"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Дугме Пребаци"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Дугме Пребаци. Веза је прекинута"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Дугме Пребаци. Повезује се"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Дугме Пребаци. Повезан је"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Пребацујте на"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Проналажење уређаја"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Прекини везу"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Прошири"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Скупи"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Омот албума"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Клизач за јачину звука"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Нема изабраних медија"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Нису доступне никакве информације"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Пребацује се екран"</string>
diff --git a/v7/mediarouter/res/values-sv/strings.xml b/v7/mediarouter/res/values-sv/strings.xml
index 3724902..9597bf9 100644
--- a/v7/mediarouter/res/values-sv/strings.xml
+++ b/v7/mediarouter/res/values-sv/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"System"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Enheter"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Cast-knappen"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Cast-knappen. Frånkopplad"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Cast-knappen. Ansluter"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Cast-knappen. Ansluten"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Casta till"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Letar efter enheter"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Koppla från"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Utöka"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Komprimera"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Skivomslag"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Volymreglage"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Inga media har valts"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Det finns ingen information"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Skärmen castas"</string>
diff --git a/v7/mediarouter/res/values-sw/strings.xml b/v7/mediarouter/res/values-sw/strings.xml
index f12fd5c..f7ae8f5 100644
--- a/v7/mediarouter/res/values-sw/strings.xml
+++ b/v7/mediarouter/res/values-sw/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"Mfumo"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Vifaa"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Kitufe cha kutuma"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Kitufe cha kutuma. Kimeondolewa"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Kitufe cha kutuma. Kinaunganisha"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Kitufe cha kutuma. Kimeunganishwa"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Tuma kwenye"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Inatafuta vifaa"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Ondoa"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Panua"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Kunja"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Sanaa ya albamu"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Kitelezi cha sauti"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Hakuna maudhui yaliyochaguliwa"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Hakuna maelezo yaliyopatikana"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Inatuma skrini"</string>
diff --git a/v7/mediarouter/res/values-ta-rIN/strings.xml b/v7/mediarouter/res/values-ta-rIN/strings.xml
index c314178..0ef3fc3 100644
--- a/v7/mediarouter/res/values-ta-rIN/strings.xml
+++ b/v7/mediarouter/res/values-ta-rIN/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"அமைப்பு"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"சாதனங்கள்"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"திரையிடு பட்டன்"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"அனுப்புதல் பொத்தான். துண்டிக்கப்பட்டது"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"அனுப்புதல் பொத்தான். இணைக்கிறது"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"அனுப்புதல் பொத்தான். இணைக்கப்பட்டது"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"இதில் திரையிடு"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"சாதனங்களைத் தேடுகிறது"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"தொடர்பைத் துண்டி"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"விரிவாக்கு"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"சுருக்கு"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"ஆல்பம் ஆர்ட்"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"ஒலியளவு ஸ்லைடர்"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"மீடியா எதுவும் தேர்ந்தெடுக்கப்படவில்லை"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"தகவல் எதுவுமில்லை"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"திரையை அனுப்புகிறீர்கள்"</string>
diff --git a/v7/mediarouter/res/values-te-rIN/strings.xml b/v7/mediarouter/res/values-te-rIN/strings.xml
index 59a4f19..c7ae34f 100644
--- a/v7/mediarouter/res/values-te-rIN/strings.xml
+++ b/v7/mediarouter/res/values-te-rIN/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"సిస్టమ్"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"పరికరాలు"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"ప్రసారం చేయి బటన్"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"ప్రసార బటన్. డిస్‌కనెక్ట్ చేయబడింది"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"ప్రసార బటన్. కనెక్ట్ చేస్తోంది"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"ప్రసార బటన్. కనెక్ట్ చేయబడింది"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"దీనికి ప్రసారం చేయండి"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"పరికరాలను కనుగొంటోంది"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"డిస్‌కనెక్ట్ చేయి"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"విస్తరింపజేస్తుంది"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"కుదిస్తుంది"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"ఆల్బమ్ ఆర్ట్"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"వాల్యూమ్ స్లయిడర్"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"మీడియా ఏదీ ఎంచుకోబడలేదు"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"సమాచారం అందుబాటులో లేదు"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"స్క్రీన్‌ను ప్రసారం చేస్తోంది"</string>
diff --git a/v7/mediarouter/res/values-th/strings.xml b/v7/mediarouter/res/values-th/strings.xml
index 1bfd091..219374c 100644
--- a/v7/mediarouter/res/values-th/strings.xml
+++ b/v7/mediarouter/res/values-th/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"ระบบ"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"อุปกรณ์"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"ปุ่ม \"แคสต์\""</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"ปุ่ม \"แคสต์\" ยกเลิกการเชื่อมต่อ"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"ปุ่ม \"แคสต์\" กำลังเชื่อมต่อ"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"ปุ่ม \"แคสต์\" เชื่อมต่อแล้ว"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"แคสต์ไปยัง"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"กำลังค้นหาอุปกรณ์"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"ยกเลิกการเชื่อมต่อ"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"ขยาย"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"ยุบ"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"ปกอัลบั้ม"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"แถบเลื่อนปรับระดับเสียง"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"ไม่ได้เลือกสื่อไว้"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"ไม่มีข้อมูล"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"กำลังแคสต์หน้าจอ"</string>
diff --git a/v7/mediarouter/res/values-tl/strings.xml b/v7/mediarouter/res/values-tl/strings.xml
index 82396e1..e2bb7c7 100644
--- a/v7/mediarouter/res/values-tl/strings.xml
+++ b/v7/mediarouter/res/values-tl/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"System"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Mga Device"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Button na I-cast"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Button na I-cast. Nadiskonekta"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Button na I-cast. Kumokonekta"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Button na I-cast. Nakakonekta"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"I-cast sa"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Naghahanap ng mga device"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Idiskonekta"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Palawakin"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"I-collapse"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Album art"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Slider ng volume"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Walang piniling media"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Walang available na impormasyon"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Kina-cast ang screen"</string>
diff --git a/v7/mediarouter/res/values-tr/strings.xml b/v7/mediarouter/res/values-tr/strings.xml
index e639963..187682f 100644
--- a/v7/mediarouter/res/values-tr/strings.xml
+++ b/v7/mediarouter/res/values-tr/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"Sistem"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Cihazlar"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Yayın düğmesi"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Yayınla düğmesi. Bağlantı kesildi"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Yayınla düğmesi. Bağlanıyor"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Yayınla düğmesi. Bağlandı"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Şuraya yayınla:"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Cihazlar bulunuyor"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Bağlantıyı kes"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Genişlet"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Daralt"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Albüm kapağı"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Ses düzeyi kaydırma çubuğu"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Medya seçilmedi"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Bilgi yok"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Ekran yayınlanıyor"</string>
diff --git a/v7/mediarouter/res/values-uk/strings.xml b/v7/mediarouter/res/values-uk/strings.xml
index a768e2c..8c2a16a 100644
--- a/v7/mediarouter/res/values-uk/strings.xml
+++ b/v7/mediarouter/res/values-uk/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"Система"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Пристрої"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Кнопка трансляції"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Кнопка трансляції. Від’єднано"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Кнопка трансляції. Під’єднання"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Кнопка трансляції. Під’єднано"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Транслювати на"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Пошук пристроїв"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Відключити"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Розгорнути"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Згорнути"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Обкладинка альбому"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Повзунок гучності"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Медіа-файл не вибрано"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Немає даних"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Трансляція екрана"</string>
diff --git a/v7/mediarouter/res/values-ur-rPK/strings.xml b/v7/mediarouter/res/values-ur-rPK/strings.xml
index 5cb3b36..053373f 100644
--- a/v7/mediarouter/res/values-ur-rPK/strings.xml
+++ b/v7/mediarouter/res/values-ur-rPK/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"سسٹم"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"آلات"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"کاسٹ کرنے کا بٹن"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"کاسٹ کرنے کا بٹن۔ غیر منسلک ہے"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"کاسٹ کرنے کا بٹن۔ منسلک ہو رہا ہے"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"کاسٹ کرنے کا بٹن۔ منسلک ہے"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"اس میں کاسٹ کریں"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"آلات تلاش ہو رہے ہیں"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"غیر منسلک کریں"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"پھیلائیں"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"سکیڑیں"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"البم آرٹ"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"والیوم سلائیڈر"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"کوئی میڈیا منتخب نہیں ہے"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"کوئی معلومات دستیاب نہیں"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"سکرین کاسٹ ہو رہی ہے"</string>
diff --git a/v7/mediarouter/res/values-uz-rUZ/strings.xml b/v7/mediarouter/res/values-uz-rUZ/strings.xml
index 9955cdfd..9d1e455 100644
--- a/v7/mediarouter/res/values-uz-rUZ/strings.xml
+++ b/v7/mediarouter/res/values-uz-rUZ/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"Tizim"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Qurilmalar"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Translatsiya tugmasi"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Translatsiya tugmasi. Uzildi"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Translatsiya tugmasi. Ulanmoqda"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Translatsiya tugmasi. Ulandi"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Quyidagiga translatsiya qilish:"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Qurilmalarni topish"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Ulanishni uzish"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Yoyish"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Yig‘ish"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Albom muqovasi"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Ovoz balandligi slayderi"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Multimedia tanlamagan"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Hech qanday ma’lumot yo‘q"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Ekranni translatsiya qilish"</string>
diff --git a/v7/mediarouter/res/values-vi/strings.xml b/v7/mediarouter/res/values-vi/strings.xml
index 0080e3e..488b9f0 100644
--- a/v7/mediarouter/res/values-vi/strings.xml
+++ b/v7/mediarouter/res/values-vi/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"Hệ thống"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Thiết bị"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Nút truyền"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Nút truyền. Đã ngắt kết nối"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Nút truyền. Đang kết nối"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Nút truyền. Đã kết nối"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Truyền tới"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Tìm thiết bị"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Ngắt kết nối"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Mở rộng"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Thu gọn"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Ảnh bìa album"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Thanh trượt âm lượng"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Không có phương tiện nào được chọn"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Không có thông tin nào"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Đang truyền màn hình"</string>
diff --git a/v7/mediarouter/res/values-zh-rCN/strings.xml b/v7/mediarouter/res/values-zh-rCN/strings.xml
index aabe727..c22a91c 100644
--- a/v7/mediarouter/res/values-zh-rCN/strings.xml
+++ b/v7/mediarouter/res/values-zh-rCN/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"系统"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"设备"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"投射按钮"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"投射按钮。已断开连接"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"投射按钮。正在连接"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"投射按钮。已连接"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"投射到"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"正在查找设备"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"断开连接"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"展开"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"折叠"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"专辑封面"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"音量滑块"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"未选择任何媒体"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"没有任何相关信息"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"正在投射屏幕"</string>
diff --git a/v7/mediarouter/res/values-zh-rHK/strings.xml b/v7/mediarouter/res/values-zh-rHK/strings.xml
index d01c823..d17469b 100644
--- a/v7/mediarouter/res/values-zh-rHK/strings.xml
+++ b/v7/mediarouter/res/values-zh-rHK/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"系統"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"裝置"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"投放按鈕"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"投放按鈕。已解除連接"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"投放按鈕。正在連接"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"投放按鈕。已連接"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"投放至"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"正在尋找裝置"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"中斷連線"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"展開"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"收合"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"專輯封面"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"音量滑桿"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"尚未選擇媒體"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"沒有詳細資料"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"正在投放螢幕"</string>
diff --git a/v7/mediarouter/res/values-zh-rTW/strings.xml b/v7/mediarouter/res/values-zh-rTW/strings.xml
index 68347e5..1a71c84 100644
--- a/v7/mediarouter/res/values-zh-rTW/strings.xml
+++ b/v7/mediarouter/res/values-zh-rTW/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"系統"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"裝置"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"投放按鈕"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"投放按鈕;已中斷連線"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"投放按鈕;連線中"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"投放按鈕;已連線"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"投放到"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"正在尋找裝置"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"中斷連線"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"展開"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"收合"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"專輯封面"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"音量滑桿"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"未選取任何媒體"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"沒有可用的資訊"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"正在投放螢幕"</string>
diff --git a/v7/mediarouter/res/values-zu/strings.xml b/v7/mediarouter/res/values-zu/strings.xml
index e50acc8..860aa09 100644
--- a/v7/mediarouter/res/values-zu/strings.xml
+++ b/v7/mediarouter/res/values-zu/strings.xml
@@ -19,6 +19,9 @@
     <string name="mr_system_route_name" msgid="5441529851481176817">"Isistimu"</string>
     <string name="mr_user_route_category_name" msgid="7498112907524977311">"Amadivayisi"</string>
     <string name="mr_button_content_description" msgid="3698378085901466129">"Inkinobho ye-Cast"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Inkinobho yokusakaza. Kunqanyuliwe"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Inkinobho yokusakaza. Kuyaxhunywa"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Inkinobho yokusakaza. Kuxhunyiwe"</string>
     <string name="mr_chooser_title" msgid="414301941546135990">"Sakaza ku-"</string>
     <string name="mr_chooser_searching" msgid="6349900579507521956">"Ithola amadivayisi"</string>
     <string name="mr_controller_disconnect" msgid="1227264889412989580">"Nqamula"</string>
@@ -29,6 +32,7 @@
     <string name="mr_controller_expand_group" msgid="8062427022744266907">"Nweba"</string>
     <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Goqa"</string>
     <string name="mr_controller_album_art" msgid="6422801843540543585">"Ubuciko be-albhamu"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Isilayida sevolumu"</string>
     <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Ayikho imidiya ekhethiwe"</string>
     <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Alukho ulwazi olutholakalayo"</string>
     <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Isikrini sokusakaza"</string>
diff --git a/v7/mediarouter/res/values/attrs.xml b/v7/mediarouter/res/values/attrs.xml
index b0f24ea..5ebc0ee 100644
--- a/v7/mediarouter/res/values/attrs.xml
+++ b/v7/mediarouter/res/values/attrs.xml
@@ -26,7 +26,6 @@
         <attr name="android:minHeight" />
     </declare-styleable>
 
-    <attr name="MediaRouteControllerWindowBackground" format="reference" />
     <attr name="mediaRouteButtonStyle" format="reference" />
     <attr name="mediaRouteCloseDrawable" format="reference" />
     <attr name="mediaRoutePlayDrawable" format="reference" />
@@ -36,9 +35,5 @@
     <attr name="mediaRouteTvIconDrawable" format="reference" />
     <attr name="mediaRouteSpeakerIconDrawable" format="reference" />
     <attr name="mediaRouteSpeakerGroupIconDrawable" format="reference" />
-    <attr name="mediaRouteChooserPrimaryTextStyle" format="reference" />
-    <attr name="mediaRouteChooserSecondaryTextStyle" format="reference" />
-    <attr name="mediaRouteControllerTitleTextStyle" format="reference" />
-    <attr name="mediaRouteControllerPrimaryTextStyle" format="reference" />
-    <attr name="mediaRouteControllerSecondaryTextStyle" format="reference" />
+    <attr name="mediaRouteControlPanelThemeOverlay" format="reference" />
 </resources>
diff --git a/v7/mediarouter/res/values/styles.xml b/v7/mediarouter/res/values/styles.xml
index ea53cf3..e8e00e7 100644
--- a/v7/mediarouter/res/values/styles.xml
+++ b/v7/mediarouter/res/values/styles.xml
@@ -25,73 +25,9 @@
         <item name="externalRouteEnabledDrawable">@drawable/mr_button_light</item>
     </style>
 
-    <!-- MediaRouteChooserDialog text styles -->
-    <style name="Widget.MediaRouter.ChooserText" parent="">
-        <item name="android:fontFamily">sans-serif</item>
-        <item name="android:textStyle">normal</item>
-    </style>
+    <style name="TextAppearance.MediaRouter.Title" parent="TextAppearance.AppCompat.Title" />
 
-    <style name="Widget.MediaRouter.ChooserText.Primary">
-        <item name="android:textSize">16sp</item>
-    </style>
+    <style name="TextAppearance.MediaRouter.PrimaryText" parent="TextAppearance.AppCompat.Subhead" />
 
-    <style name="Widget.MediaRouter.ChooserText.Secondary">
-        <item name="android:textSize">14sp</item>
-    </style>
-
-    <style name="Widget.MediaRouter.ChooserText.Primary.Dark">
-        <item name="android:textColor">#FFFFFFFF</item>
-    </style>
-
-    <style name="Widget.MediaRouter.ChooserText.Primary.Light">
-        <item name="android:textColor">#DE000000</item>
-    </style>
-
-    <style name="Widget.MediaRouter.ChooserText.Secondary.Dark">
-        <item name="android:textColor">#8AFFFFFF</item>
-    </style>
-
-    <style name="Widget.MediaRouter.ChooserText.Secondary.Light">
-        <item name="android:textColor">#8A000000</item>
-    </style>
-
-    <!-- MediaRouteControllerDialog text styles -->
-    <style name="Widget.MediaRouter.ControllerText" parent="Widget.MediaRouter.ChooserText" />
-
-    <style name="Widget.MediaRouter.ControllerText.Title">
-        <item name="android:fontFamily">sans-serif-medium</item>
-        <item name="android:textSize">20sp</item>
-    </style>
-
-    <style name="Widget.MediaRouter.ControllerText.Primary">
-        <item name="android:textSize">16sp</item>
-    </style>
-
-    <style name="Widget.MediaRouter.ControllerText.Secondary">
-        <item name="android:textSize">14sp</item>
-    </style>
-
-    <style name="Widget.MediaRouter.ControllerText.Title.Dark">
-        <item name="android:textColor">#FFFFFFFF</item>
-    </style>
-
-    <style name="Widget.MediaRouter.ControllerText.Title.Light">
-        <item name="android:textColor">#DE000000</item>
-    </style>
-
-    <style name="Widget.MediaRouter.ControllerText.Primary.Dark">
-        <item name="android:textColor">#FFFFFFFF</item>
-    </style>
-
-    <style name="Widget.MediaRouter.ControllerText.Primary.Light">
-        <item name="android:textColor">#DE000000</item>
-    </style>
-
-    <style name="Widget.MediaRouter.ControllerText.Secondary.Dark">
-        <item name="android:textColor">#FFFFFFFF</item>
-    </style>
-
-    <style name="Widget.MediaRouter.ControllerText.Secondary.Light">
-        <item name="android:textColor">#DE000000</item>
-    </style>
+    <style name="TextAppearance.MediaRouter.SecondaryText" parent="TextAppearance.AppCompat.Body1" />
 </resources>
diff --git a/v7/mediarouter/res/values/themes.xml b/v7/mediarouter/res/values/themes.xml
index 4ea3a9f..1eb4bfd 100644
--- a/v7/mediarouter/res/values/themes.xml
+++ b/v7/mediarouter/res/values/themes.xml
@@ -16,11 +16,10 @@
 
 <resources>
 
-    <style name="Theme.MediaRouter" parent="">
-        <item name="android:windowNoTitle">false</item>
+    <style name="Theme.MediaRouter" parent="ThemeOverlay.AppCompat.Dark">
+        <item name="windowNoTitle">true</item>
         <item name="mediaRouteButtonStyle">@style/Widget.MediaRouter.MediaRouteButton</item>
 
-        <item name="MediaRouteControllerWindowBackground">@drawable/mr_dialog_material_background_dark</item>
         <item name="mediaRouteCloseDrawable">@drawable/mr_dialog_close_dark</item>
         <item name="mediaRoutePlayDrawable">@drawable/mr_media_play_dark</item>
         <item name="mediaRoutePauseDrawable">@drawable/mr_media_pause_dark</item>
@@ -29,25 +28,18 @@
         <item name="mediaRouteTvIconDrawable">@drawable/ic_vol_type_tv_dark</item>
         <item name="mediaRouteSpeakerIconDrawable">@drawable/ic_vol_type_speaker_dark</item>
         <item name="mediaRouteSpeakerGroupIconDrawable">@drawable/ic_vol_type_speaker_group_dark</item>
-        <item name="mediaRouteChooserPrimaryTextStyle">@style/Widget.MediaRouter.ChooserText.Primary.Dark</item>
-        <item name="mediaRouteChooserSecondaryTextStyle">@style/Widget.MediaRouter.ChooserText.Secondary.Dark</item>
-        <item name="mediaRouteControllerTitleTextStyle">@style/Widget.MediaRouter.ControllerText.Title.Dark</item>
-        <item name="mediaRouteControllerPrimaryTextStyle">@style/Widget.MediaRouter.ControllerText.Primary.Dark</item>
-        <item name="mediaRouteControllerSecondaryTextStyle">@style/Widget.MediaRouter.ControllerText.Secondary.Dark</item>
+
+        <item name="mediaRouteControlPanelThemeOverlay">@null</item>
     </style>
 
     <style name="Theme.MediaRouter.LightControlPanel">
-        <item name="mediaRoutePlayDrawable">@drawable/mr_media_play_light</item>
-        <item name="mediaRoutePauseDrawable">@drawable/mr_media_pause_light</item>
-        <item name="mediaRouteAudioTrackDrawable">@drawable/mr_vol_type_audiotrack_light</item>
-        <item name="mediaRouteControllerPrimaryTextStyle">@style/Widget.MediaRouter.ControllerText.Primary.Light</item>
-        <item name="mediaRouteControllerSecondaryTextStyle">@style/Widget.MediaRouter.ControllerText.Secondary.Light</item>
+        <item name="mediaRouteControlPanelThemeOverlay">@style/ThemeOverlay.MediaRouter.Light</item>
     </style>
 
-    <style name="Theme.MediaRouter.Light">
+    <style name="Theme.MediaRouter.Light" parent="ThemeOverlay.AppCompat.Light">
+        <item name="windowNoTitle">true</item>
         <item name="mediaRouteButtonStyle">@style/Widget.MediaRouter.Light.MediaRouteButton</item>
 
-        <item name="MediaRouteControllerWindowBackground">@drawable/mr_dialog_material_background_light</item>
         <item name="mediaRouteCloseDrawable">@drawable/mr_dialog_close_light</item>
         <item name="mediaRoutePlayDrawable">@drawable/mr_media_play_light</item>
         <item name="mediaRoutePauseDrawable">@drawable/mr_media_pause_light</item>
@@ -56,19 +48,24 @@
         <item name="mediaRouteTvIconDrawable">@drawable/ic_vol_type_tv_light</item>
         <item name="mediaRouteSpeakerIconDrawable">@drawable/ic_vol_type_speaker_light</item>
         <item name="mediaRouteSpeakerGroupIconDrawable">@drawable/ic_vol_type_speaker_group_light</item>
-        <item name="mediaRouteChooserPrimaryTextStyle">@style/Widget.MediaRouter.ChooserText.Primary.Light</item>
-        <item name="mediaRouteChooserSecondaryTextStyle">@style/Widget.MediaRouter.ChooserText.Secondary.Light</item>
-        <item name="mediaRouteControllerTitleTextStyle">@style/Widget.MediaRouter.ControllerText.Title.Light</item>
-        <item name="mediaRouteControllerPrimaryTextStyle">@style/Widget.MediaRouter.ControllerText.Primary.Light</item>
-        <item name="mediaRouteControllerSecondaryTextStyle">@style/Widget.MediaRouter.ControllerText.Secondary.Light</item>
+
+        <item name="mediaRouteControlPanelThemeOverlay">@null</item>
     </style>
 
     <style name="Theme.MediaRouter.Light.DarkControlPanel">
+        <item name="mediaRouteControlPanelThemeOverlay">@style/ThemeOverlay.MediaRouter.Dark</item>
+    </style>
+
+    <style name="ThemeOverlay.MediaRouter.Dark" parent="ThemeOverlay.AppCompat.Dark">
         <item name="mediaRoutePlayDrawable">@drawable/mr_media_play_dark</item>
         <item name="mediaRoutePauseDrawable">@drawable/mr_media_pause_dark</item>
         <item name="mediaRouteAudioTrackDrawable">@drawable/mr_vol_type_audiotrack_dark</item>
-        <item name="mediaRouteControllerPrimaryTextStyle">@style/Widget.MediaRouter.ControllerText.Primary.Dark</item>
-        <item name="mediaRouteControllerSecondaryTextStyle">@style/Widget.MediaRouter.ControllerText.Secondary.Dark</item>
+
+    </style>
+    <style name="ThemeOverlay.MediaRouter.Light" parent="ThemeOverlay.AppCompat.Light">
+        <item name="mediaRoutePlayDrawable">@drawable/mr_media_play_light</item>
+        <item name="mediaRoutePauseDrawable">@drawable/mr_media_pause_light</item>
+        <item name="mediaRouteAudioTrackDrawable">@drawable/mr_vol_type_audiotrack_light</item>
     </style>
 
 </resources>
diff --git a/v7/mediarouter/src/android/support/v7/app/MediaRouteActionProvider.java b/v7/mediarouter/src/android/support/v7/app/MediaRouteActionProvider.java
index ad8fc1b..4eb98aa 100644
--- a/v7/mediarouter/src/android/support/v7/app/MediaRouteActionProvider.java
+++ b/v7/mediarouter/src/android/support/v7/app/MediaRouteActionProvider.java
@@ -69,7 +69,7 @@
  * </pre><p>
  * Then configure the menu and set the route selector for the chooser.
  * </p><pre>
- * public class MyActivity extends ActionBarActivity {
+ * public class MyActivity extends AppCompatActivity {
  *     private MediaRouter mRouter;
  *     private MediaRouter.Callback mCallback;
  *     private MediaRouteSelector mSelector;
diff --git a/v7/mediarouter/src/android/support/v7/app/MediaRouteChooserDialog.java b/v7/mediarouter/src/android/support/v7/app/MediaRouteChooserDialog.java
index 01cb1fd..ac79f2d 100644
--- a/v7/mediarouter/src/android/support/v7/app/MediaRouteChooserDialog.java
+++ b/v7/mediarouter/src/android/support/v7/app/MediaRouteChooserDialog.java
@@ -19,7 +19,6 @@
 import static android.support.v7.media.MediaRouter.RouteInfo.CONNECTION_STATE_CONNECTED;
 import static android.support.v7.media.MediaRouter.RouteInfo.CONNECTION_STATE_CONNECTING;
 
-import android.app.Dialog;
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.graphics.drawable.Drawable;
@@ -60,7 +59,7 @@
  * @see MediaRouteButton
  * @see MediaRouteActionProvider
  */
-public class MediaRouteChooserDialog extends Dialog {
+public class MediaRouteChooserDialog extends AppCompatDialog {
     static final String TAG = "MediaRouteChooserDialog";
 
     // Do not update the route list immediately to avoid unnatural dialog change.
@@ -70,6 +69,7 @@
     private final MediaRouter mRouter;
     private final MediaRouterCallback mCallback;
 
+    private TextView mTitleView;
     private MediaRouteSelector mSelector = MediaRouteSelector.EMPTY;
     private ArrayList<MediaRouter.RouteInfo> mRoutes;
     private RouteAdapter mAdapter;
@@ -166,11 +166,20 @@
     }
 
     @Override
+    public void setTitle(CharSequence title) {
+        mTitleView.setText(title);
+    }
+
+    @Override
+    public void setTitle(int titleId) {
+        mTitleView.setText(titleId);
+    }
+
+    @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
         setContentView(R.layout.mr_chooser_dialog);
-        setTitle(R.string.mr_chooser_title);
 
         mRoutes = new ArrayList<>();
         mAdapter = new RouteAdapter(getContext(), mRoutes);
@@ -178,6 +187,7 @@
         mListView.setAdapter(mAdapter);
         mListView.setOnItemClickListener(mAdapter);
         mListView.setEmptyView(findViewById(android.R.id.empty));
+        mTitleView = (TextView) findViewById(R.id.mr_chooser_title);
 
         updateLayout();
     }
diff --git a/v7/mediarouter/src/android/support/v7/app/MediaRouteControllerDialog.java b/v7/mediarouter/src/android/support/v7/app/MediaRouteControllerDialog.java
index ee3d26f..961e37e 100644
--- a/v7/mediarouter/src/android/support/v7/app/MediaRouteControllerDialog.java
+++ b/v7/mediarouter/src/android/support/v7/app/MediaRouteControllerDialog.java
@@ -400,7 +400,8 @@
 
         mVolumeGroupList = (OverlayListView) findViewById(R.id.mr_volume_group_list);
         mGroupMemberRoutes = new ArrayList<MediaRouter.RouteInfo>();
-        mVolumeGroupAdapter = new VolumeGroupAdapter(mContext, mGroupMemberRoutes);
+        mVolumeGroupAdapter = new VolumeGroupAdapter(mVolumeGroupList.getContext(),
+                mGroupMemberRoutes);
         mVolumeGroupList.setAdapter(mVolumeGroupAdapter);
         mGroupMemberRoutesAnimatingWithBitmap = new HashSet<>();
 
@@ -523,8 +524,12 @@
         mRouteNameTextView.setText(mRoute.getName());
         mDisconnectButton.setVisibility(mRoute.canDisconnect() ? View.VISIBLE : View.GONE);
         if (mCustomControlView == null && mArtIconIsLoaded) {
-            mArtView.setImageBitmap(mArtIconLoadedBitmap);
-            mArtView.setBackgroundColor(mArtIconBackgroundColor);
+            if (isBitmapRecycled(mArtIconLoadedBitmap)) {
+                Log.w(TAG, "Can't set artwork image with recycled bitmap: " + mArtIconLoadedBitmap);
+            } else {
+                mArtView.setImageBitmap(mArtIconLoadedBitmap);
+                mArtView.setBackgroundColor(mArtIconBackgroundColor);
+            }
             clearLoadedBitmap();
         }
         updateVolumeControlLayout();
@@ -532,6 +537,10 @@
         updateLayoutHeight(animate);
     }
 
+    private boolean isBitmapRecycled(Bitmap bitmap) {
+        return bitmap != null && bitmap.isRecycled();
+    }
+
     private boolean canShowPlaybackControlLayout() {
         return mCustomControlView == null && (mDescription != null || mState != null);
     }
@@ -1001,17 +1010,18 @@
                         | PlaybackStateCompat.ACTION_PLAY_PAUSE)) != 0;
                 boolean supportsPause = (mState.getActions() & (PlaybackStateCompat.ACTION_PAUSE
                         | PlaybackStateCompat.ACTION_PLAY_PAUSE)) != 0;
+                Context playPauseButtonContext = mPlayPauseButton.getContext();
                 if (isPlaying && supportsPause) {
                     mPlayPauseButton.setVisibility(View.VISIBLE);
                     mPlayPauseButton.setImageResource(MediaRouterThemeHelper.getThemeResource(
-                            mContext, R.attr.mediaRoutePauseDrawable));
-                    mPlayPauseButton.setContentDescription(mContext.getResources()
+                            playPauseButtonContext, R.attr.mediaRoutePauseDrawable));
+                    mPlayPauseButton.setContentDescription(playPauseButtonContext.getResources()
                             .getText(R.string.mr_controller_pause));
                 } else if (!isPlaying && supportsPlay) {
                     mPlayPauseButton.setVisibility(View.VISIBLE);
                     mPlayPauseButton.setImageResource(MediaRouterThemeHelper.getThemeResource(
-                            mContext, R.attr.mediaRoutePlayDrawable));
-                    mPlayPauseButton.setContentDescription(mContext.getResources()
+                            playPauseButtonContext, R.attr.mediaRoutePlayDrawable));
+                    mPlayPauseButton.setContentDescription(playPauseButtonContext.getResources()
                             .getText(R.string.mr_controller_play));
                 } else {
                     mPlayPauseButton.setVisibility(View.GONE);
@@ -1245,7 +1255,7 @@
         public View getView(final int position, View convertView, ViewGroup parent) {
             View v = convertView;
             if (v == null) {
-                v = LayoutInflater.from(mContext).inflate(
+                v = LayoutInflater.from(parent.getContext()).inflate(
                         R.layout.mr_controller_volume_item, parent, false);
             } else {
                 updateVolumeGroupItemHeight(v);
@@ -1262,7 +1272,7 @@
                 MediaRouteVolumeSlider volumeSlider =
                         (MediaRouteVolumeSlider) v.findViewById(R.id.mr_volume_slider);
                 MediaRouterThemeHelper.setVolumeSliderColor(
-                        mContext, volumeSlider, mVolumeGroupList);
+                        parent.getContext(), volumeSlider, mVolumeGroupList);
                 volumeSlider.setTag(route);
                 mVolumeSliderMap.put(route, volumeSlider);
                 volumeSlider.setHideThumb(!isEnabled);
@@ -1313,7 +1323,12 @@
         private long mStartTimeMillis;
 
         FetchArtTask() {
-            mIconBitmap = mDescription == null ? null : mDescription.getIconBitmap();
+            Bitmap bitmap = mDescription == null ? null : mDescription.getIconBitmap();
+            if (isBitmapRecycled(bitmap)) {
+                Log.w(TAG, "Can't fetch the given art bitmap because it's already recycled.");
+                bitmap = null;
+            }
+            mIconBitmap = bitmap;
             mIconUri = mDescription == null ? null : mDescription.getIconUri();
         }
 
@@ -1381,6 +1396,10 @@
                     }
                 }
             }
+            if (isBitmapRecycled(art)) {
+                Log.w(TAG, "Can't use recycled bitmap: " + art);
+                return null;
+            }
             if (art != null && art.getWidth() < art.getHeight()) {
                 // Portrait art requires dominant color as background color.
                 Palette palette = new Palette.Builder(art).maximumColorCount(1).generate();
diff --git a/v7/mediarouter/src/android/support/v7/app/MediaRouterThemeHelper.java b/v7/mediarouter/src/android/support/v7/app/MediaRouterThemeHelper.java
index 60c878f..e78c516 100644
--- a/v7/mediarouter/src/android/support/v7/app/MediaRouterThemeHelper.java
+++ b/v7/mediarouter/src/android/support/v7/app/MediaRouterThemeHelper.java
@@ -55,6 +55,8 @@
      * @return The themed context.
      */
     public static Context createThemedContext(Context context, int style) {
+        // First, apply dialog property overlay.
+
         int theme;
         if (isLightTheme(context)) {
             if (getControllerColor(context, style) == COLOR_DARK_ON_LIGHT_BACKGROUND) {
diff --git a/v7/preference/build.gradle b/v7/preference/build.gradle
index ed752ee..61334f9 100644
--- a/v7/preference/build.gradle
+++ b/v7/preference/build.gradle
@@ -22,11 +22,23 @@
     compile project(':support-v4')
     compile project(':support-appcompat-v7')
     compile project(':support-recyclerview-v7')
+
+    androidTestCompile ("com.android.support.test:runner:${project.rootProject.ext.testRunnerVersion}") {
+        exclude module: 'support-annotations'
+    }
+    androidTestCompile ("com.android.support.test.espresso:espresso-core:${project.rootProject.ext.espressoVersion}") {
+        exclude module: 'support-annotations'
+    }
+    testCompile 'junit:junit:4.12'
 }
 
 android {
     compileSdkVersion project.ext.currentSdk
 
+    defaultConfig {
+        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+    }
+
     sourceSets {
         main.manifest.srcFile 'AndroidManifest.xml'
         main.java.srcDir 'src'
@@ -40,6 +52,8 @@
         // This is a *reset* so it replaces the default paths
         androidTest.setRoot('tests')
         androidTest.java.srcDir 'tests/src'
+        androidTest.res.srcDir 'tests/res'
+        androidTest.manifest.srcFile 'tests/AndroidManifest.xml'
     }
 
     compileOptions {
diff --git a/v7/preference/src/android/support/v7/preference/Preference.java b/v7/preference/src/android/support/v7/preference/Preference.java
index f12fcbd..7d2bd3f 100644
--- a/v7/preference/src/android/support/v7/preference/Preference.java
+++ b/v7/preference/src/android/support/v7/preference/Preference.java
@@ -140,6 +140,7 @@
 
     private List<Preference> mDependents;
 
+    private boolean mWasDetached;
     private boolean mBaseMethodCalled;
 
     private final View.OnClickListener mClickListener = new View.OnClickListener() {
@@ -246,10 +247,10 @@
         mKey = TypedArrayUtils.getString(a, R.styleable.Preference_key,
                 R.styleable.Preference_android_key);
 
-        mTitle = TypedArrayUtils.getString(a, R.styleable.Preference_title,
+        mTitle = TypedArrayUtils.getText(a, R.styleable.Preference_title,
                 R.styleable.Preference_android_title);
 
-        mSummary = TypedArrayUtils.getString(a, R.styleable.Preference_summary,
+        mSummary = TypedArrayUtils.getText(a, R.styleable.Preference_summary,
                 R.styleable.Preference_android_summary);
 
         mOrder = TypedArrayUtils.getInt(a, R.styleable.Preference_order,
@@ -668,6 +669,9 @@
      * @see #setIcon(Drawable)
      */
     public Drawable getIcon() {
+        if (mIcon == null && mIconResId != 0) {
+            mIcon = ContextCompat.getDrawable(mContext, mIconResId);
+        }
         return mIcon;
     }
 
@@ -1138,6 +1142,24 @@
      */
     public void onDetached() {
         unregisterDependency();
+        mWasDetached = true;
+    }
+
+    /**
+     * Returns true if {@link #onDetached()} was called. Used for handling the case when a
+     * preference was removed, modified, and re-added to a {@link PreferenceGroup}
+     * @hide
+     */
+    public final boolean wasDetached() {
+        return mWasDetached;
+    }
+
+    /**
+     * Clears the {@link #wasDetached()} status
+     * @hide
+     */
+    public final void clearWasDetached() {
+        mWasDetached = false;
     }
 
     private void registerDependency() {
diff --git a/v7/preference/src/android/support/v7/preference/PreferenceGroupAdapter.java b/v7/preference/src/android/support/v7/preference/PreferenceGroupAdapter.java
index 27d2a13..c8af738 100644
--- a/v7/preference/src/android/support/v7/preference/PreferenceGroupAdapter.java
+++ b/v7/preference/src/android/support/v7/preference/PreferenceGroupAdapter.java
@@ -21,6 +21,7 @@
 import android.os.Handler;
 import android.support.annotation.RestrictTo;
 import android.support.v4.view.ViewCompat;
+import android.support.v7.util.DiffUtil;
 import android.support.v7.widget.RecyclerView;
 import android.text.TextUtils;
 import android.view.LayoutInflater;
@@ -149,10 +150,49 @@
             }
         }
 
+        final List<Preference> oldVisibleList = mPreferenceList;
         mPreferenceList = visiblePreferenceList;
         mPreferenceListInternal = fullPreferenceList;
 
-        notifyDataSetChanged();
+        final PreferenceManager preferenceManager = mPreferenceGroup.getPreferenceManager();
+        if (preferenceManager != null
+                && preferenceManager.getPreferenceComparisonCallback() != null) {
+            final PreferenceManager.PreferenceComparisonCallback comparisonCallback =
+                    preferenceManager.getPreferenceComparisonCallback();
+            final DiffUtil.DiffResult result = DiffUtil.calculateDiff(new DiffUtil.Callback() {
+                @Override
+                public int getOldListSize() {
+                    return oldVisibleList.size();
+                }
+
+                @Override
+                public int getNewListSize() {
+                    return visiblePreferenceList.size();
+                }
+
+                @Override
+                public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
+                    return comparisonCallback.arePreferenceItemsTheSame(
+                            oldVisibleList.get(oldItemPosition),
+                            visiblePreferenceList.get(newItemPosition));
+                }
+
+                @Override
+                public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
+                    return comparisonCallback.arePreferenceContentsTheSame(
+                            oldVisibleList.get(oldItemPosition),
+                            visiblePreferenceList.get(newItemPosition));
+                }
+            });
+
+            result.dispatchUpdatesTo(this);
+        } else {
+            notifyDataSetChanged();
+        }
+
+        for (final Preference preference : fullPreferenceList) {
+            preference.clearWasDetached();
+        }
     }
 
     private void flattenPreferenceGroup(List<Preference> preferences, PreferenceGroup group) {
diff --git a/v7/preference/src/android/support/v7/preference/PreferenceManager.java b/v7/preference/src/android/support/v7/preference/PreferenceManager.java
index 34adf6d..7af430f 100644
--- a/v7/preference/src/android/support/v7/preference/PreferenceManager.java
+++ b/v7/preference/src/android/support/v7/preference/PreferenceManager.java
@@ -18,10 +18,12 @@
 
 import android.content.Context;
 import android.content.SharedPreferences;
+import android.graphics.drawable.Drawable;
 import android.support.annotation.RestrictTo;
 import android.support.v4.content.ContextCompat;
 import android.support.v4.content.SharedPreferencesCompat;
 import android.support.v4.os.BuildCompat;
+import android.text.TextUtils;
 
 import static android.support.annotation.RestrictTo.Scope.GROUP_ID;
 
@@ -91,6 +93,7 @@
      */
     private PreferenceScreen mPreferenceScreen;
 
+    private PreferenceComparisonCallback mPreferenceComparisonCallback;
     private OnPreferenceTreeClickListener mOnPreferenceTreeClickListener;
     private OnDisplayPreferenceDialogListener mOnDisplayPreferenceDialogListener;
     private OnNavigateToScreenListener mOnNavigateToScreenListener;
@@ -384,7 +387,6 @@
      *            parameter set to true.
      */
     public static void setDefaultValues(Context context, int resId, boolean readAgain) {
-
         // Use the default shared preferences name and mode
         setDefaultValues(context, getDefaultSharedPreferencesName(context),
                 getDefaultSharedPreferencesMode(), resId, readAgain);
@@ -484,6 +486,15 @@
         return mContext;
     }
 
+    public PreferenceComparisonCallback getPreferenceComparisonCallback() {
+        return mPreferenceComparisonCallback;
+    }
+
+    public void setPreferenceComparisonCallback(
+            PreferenceComparisonCallback preferenceComparisonCallback) {
+        mPreferenceComparisonCallback = preferenceComparisonCallback;
+    }
+
     public OnDisplayPreferenceDialogListener getOnDisplayPreferenceDialogListener() {
         return mOnDisplayPreferenceDialogListener;
     }
@@ -536,6 +547,102 @@
     }
 
     /**
+     * Callback class to be used by the {@link android.support.v7.widget.RecyclerView.Adapter}
+     * associated with the {@link PreferenceScreen}, used to determine when two {@link Preference}
+     * objects are semantically and visually the same.
+     */
+    public static abstract class PreferenceComparisonCallback {
+        /**
+         * Called to determine if two {@link Preference} objects represent the same item
+         *
+         * @param p1 {@link Preference} object to compare
+         * @param p2 {@link Preference} object to compare
+         * @return {@code true} if the objects represent the same item
+         */
+        public abstract boolean arePreferenceItemsTheSame(Preference p1, Preference p2);
+
+        /**
+         * Called to determine if two {@link Preference} objects will display the same data
+         *
+         * @param p1 {@link Preference} object to compare
+         * @param p2 {@link Preference} object to compare
+         * @return {@code true} if the objects are visually identical
+         */
+        public abstract boolean arePreferenceContentsTheSame(Preference p1, Preference p2);
+    }
+
+    /**
+     * A basic implementation of {@link PreferenceComparisonCallback} suitable for use with the
+     * default {@link Preference} classes. If the {@link PreferenceScreen} contains custom
+     * {@link Preference} subclasses, you must override
+     * {@link #arePreferenceContentsTheSame(Preference, Preference)}
+     */
+    public static class SimplePreferenceComparisonCallback extends PreferenceComparisonCallback {
+        /**
+         * {@inheritDoc}
+         *
+         * <p>This method will not be able to track replaced {@link Preference} objects if they
+         * do not have a unique key.</p>
+         *
+         * @see Preference#setKey(String)
+         */
+        @Override
+        public boolean arePreferenceItemsTheSame(Preference p1, Preference p2) {
+            return p1.getId() == p2.getId();
+        }
+
+        /**
+         * {@inheritDoc}
+         *
+         * <p>The result of this method is only valid for the default {@link Preference} objects,
+         * and custom subclasses which do not override
+         * {@link Preference#onBindViewHolder(PreferenceViewHolder)}. This method also assumes
+         * that if a preference object is being replaced by a new instance, the old instance was
+         * not modified after being removed from its containing {@link PreferenceGroup}.</p>
+         */
+        @Override
+        public boolean arePreferenceContentsTheSame(Preference p1, Preference p2) {
+            if (p1.getClass() != p2.getClass()) {
+                return false;
+            }
+            if (p1 == p2 && p1.wasDetached()) {
+                // Defensively handle the case where a preference was removed, updated and re-added.
+                // Hopefully this is rare.
+                return false;
+            }
+            if (!TextUtils.equals(p1.getTitle(), p2.getTitle())) {
+                return false;
+            }
+            if (!TextUtils.equals(p1.getSummary(), p2.getSummary())) {
+                return false;
+            }
+            final Drawable p1Icon = p1.getIcon();
+            final Drawable p2Icon = p2.getIcon();
+            if (p1Icon != p2Icon && (p1Icon == null || !p1Icon.equals(p2Icon))) {
+                return false;
+            }
+            if (p1.isEnabled() != p2.isEnabled()) {
+                return false;
+            }
+            if (p1.isSelectable() != p2.isSelectable()) {
+                return false;
+            }
+            if (p1 instanceof TwoStatePreference) {
+                if (((TwoStatePreference) p1).isChecked()
+                        != ((TwoStatePreference) p2).isChecked()) {
+                    return false;
+                }
+            }
+            if (p1 instanceof DropDownPreference && p1 != p2) {
+                // Different object, must re-bind spinner adapter
+                return false;
+            }
+
+            return true;
+        }
+    }
+
+    /**
      * Interface definition for a callback to be invoked when a
      * {@link Preference} in the hierarchy rooted at this {@link PreferenceScreen} is
      * clicked.
diff --git a/v7/preference/src/android/support/v7/preference/PreferenceViewHolder.java b/v7/preference/src/android/support/v7/preference/PreferenceViewHolder.java
index 97a907a..262fcdf 100644
--- a/v7/preference/src/android/support/v7/preference/PreferenceViewHolder.java
+++ b/v7/preference/src/android/support/v7/preference/PreferenceViewHolder.java
@@ -17,6 +17,7 @@
 package android.support.v7.preference;
 
 import android.support.annotation.IdRes;
+import android.support.annotation.RestrictTo;
 import android.support.v7.widget.RecyclerView;
 import android.util.SparseArray;
 import android.view.View;
@@ -31,7 +32,9 @@
     private boolean mDividerAllowedAbove;
     private boolean mDividerAllowedBelow;
 
-    /* package */ PreferenceViewHolder(View itemView) {
+    /** @hide */
+    @RestrictTo(RestrictTo.Scope.TESTS)
+    public PreferenceViewHolder(View itemView) {
         super(itemView);
 
         // Pre-cache the views that we know in advance we'll want to find
diff --git a/v7/preference/tests/AndroidManifest.xml b/v7/preference/tests/AndroidManifest.xml
new file mode 100644
index 0000000..d47fd5b
--- /dev/null
+++ b/v7/preference/tests/AndroidManifest.xml
@@ -0,0 +1,33 @@
+<!--
+  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
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    package="android.support.v7.preference.tests">
+
+    <uses-sdk
+        android:minSdkVersion="9"
+        android:targetSdkVersion="24"
+        tools:overrideLibrary="android.support.test, android.app, android.support.test.rule,
+                android.support.test.espresso, android.support.test.espresso.idling" />
+
+    <application/>
+
+    <instrumentation
+        android:name="android.test.InstrumentationTestRunner"
+        android:targetPackage="android.support.v7.preference.tests" />
+
+</manifest>
diff --git a/v7/preference/tests/src/android/support/v7/preference/tests/SimplePreferenceComparisonCallbackTest.java b/v7/preference/tests/src/android/support/v7/preference/tests/SimplePreferenceComparisonCallbackTest.java
new file mode 100644
index 0000000..64c65fa
--- /dev/null
+++ b/v7/preference/tests/src/android/support/v7/preference/tests/SimplePreferenceComparisonCallbackTest.java
@@ -0,0 +1,304 @@
+/*
+ * 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 android.support.v7.preference.tests;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.ColorFilter;
+import android.graphics.drawable.Drawable;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.v7.preference.CheckBoxPreference;
+import android.support.v7.preference.DropDownPreference;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceManager;
+import android.support.v7.preference.TwoStatePreference;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class SimplePreferenceComparisonCallbackTest {
+
+    private Preference mPref1;
+    private Preference mPref2;
+    private PreferenceManager.PreferenceComparisonCallback mComparisonCallback;
+
+    @Before
+    public void setup() throws Exception {
+        final Context context = InstrumentationRegistry.getTargetContext();
+        mPref1 = new Preference(context);
+        mPref2 = new Preference(context);
+        mComparisonCallback = new PreferenceManager.SimplePreferenceComparisonCallback();
+    }
+
+    /**
+     * Basic sanity test, all fields blank should compare the same
+     * @throws Exception
+     */
+    @Test
+    public void testNull() throws Exception {
+        assertTrue("Compare all null",
+                mComparisonCallback.arePreferenceContentsTheSame(mPref1, mPref2));
+    }
+
+    /**
+     * Two different classes should not compare the same
+     * @throws Exception
+     */
+    @Test
+    public void testClassComparison() throws Exception {
+        final Preference checkboxPreference =
+                new CheckBoxPreference(InstrumentationRegistry.getTargetContext());
+        assertFalse("Compare class",
+                mComparisonCallback.arePreferenceContentsTheSame(mPref1, checkboxPreference));
+    }
+
+    /**
+     * Same instance, but detached and reattached should not compare the same
+     * @throws Exception
+     */
+    @Test
+    public void testDetached() throws Exception {
+        mPref1.onDetached();
+        mPref1.onAttached();
+        assertFalse("Compare same, detached",
+                mComparisonCallback.arePreferenceContentsTheSame(mPref1, mPref1));
+    }
+
+    /**
+     * Title differences should be detected
+     * @throws Exception
+     */
+    @Test
+    public void testTitleComparison() throws Exception {
+        mPref1.setTitle("value 1");
+
+        assertFalse("Compare non-null to null",
+                mComparisonCallback.arePreferenceContentsTheSame(mPref1, mPref2));
+        assertFalse("Compare null to non-null",
+                mComparisonCallback.arePreferenceContentsTheSame(mPref2, mPref1));
+
+        mPref2.setTitle("value 1");
+
+        assertTrue("Compare identical",
+                mComparisonCallback.arePreferenceContentsTheSame(mPref1, mPref2));
+
+        mPref2.setTitle("value 2");
+
+        assertFalse("Compare different",
+                mComparisonCallback.arePreferenceContentsTheSame(mPref1, mPref2));
+    }
+
+    /**
+     * Summary differences should be detected
+     * @throws Exception
+     */
+    @Test
+    public void testSummaryComparison() throws Exception {
+        mPref1.setSummary("value 1");
+
+        assertFalse("Compare non-null to null",
+                mComparisonCallback.arePreferenceContentsTheSame(mPref1, mPref2));
+        assertFalse("Compare null to non-null",
+                mComparisonCallback.arePreferenceContentsTheSame(mPref2, mPref1));
+
+        mPref2.setSummary("value 1");
+
+        assertTrue("Compare identical",
+                mComparisonCallback.arePreferenceContentsTheSame(mPref1, mPref2));
+
+        mPref2.setSummary("value 2");
+
+        assertFalse("Compare different",
+                mComparisonCallback.arePreferenceContentsTheSame(mPref1, mPref2));
+    }
+
+    private static class ComparisonDrawable extends Drawable {
+
+        private final int mId;
+
+        public ComparisonDrawable(int id) {
+            mId = id;
+        }
+
+        public int getId() {
+            return mId;
+        }
+
+        @Override
+        public void draw(Canvas canvas) {}
+
+        @Override
+        public void setAlpha(int alpha) {}
+
+        @Override
+        public void setColorFilter(ColorFilter colorFilter) {}
+
+        @Override
+        public int getOpacity() {
+            return 0;
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            return o instanceof ComparisonDrawable && ((ComparisonDrawable)o).getId() == mId;
+        }
+
+        @Override
+        public int hashCode() {
+            return mId;
+        }
+    }
+
+    /**
+     * Icon differences should be detected
+     * @throws Exception
+     */
+    @Test
+    public void testIconComparison() throws Exception {
+        final Drawable drawable1 = new ComparisonDrawable(1);
+        final Drawable drawable1a = new ComparisonDrawable(1);
+        final Drawable drawable2 = new ComparisonDrawable(2);
+
+        mPref1.setIcon(drawable1);
+
+        assertFalse("Compare non-null to null",
+                mComparisonCallback.arePreferenceContentsTheSame(mPref1, mPref2));
+        assertFalse("Compare null to non-null",
+                mComparisonCallback.arePreferenceContentsTheSame(mPref2, mPref1));
+
+        mPref2.setIcon(drawable1);
+
+        assertTrue("Compare aliased",
+                mComparisonCallback.arePreferenceContentsTheSame(mPref1, mPref2));
+
+        mPref2.setIcon(drawable1a);
+
+        assertTrue("Compare equal",
+                mComparisonCallback.arePreferenceContentsTheSame(mPref1, mPref2));
+
+        mPref2.setIcon(drawable2);
+
+        assertFalse("Compare unequal",
+                mComparisonCallback.arePreferenceContentsTheSame(mPref1, mPref2));
+    }
+
+    /**
+     * Enabled differences should be detected
+     * @throws Exception
+     */
+    @Test
+    public void testEnabledComparison() throws Exception {
+        mPref1.setEnabled(true);
+        mPref2.setEnabled(true);
+
+        assertTrue("Compare enabled",
+                mComparisonCallback.arePreferenceContentsTheSame(mPref1, mPref2));
+
+        mPref2.setEnabled(false);
+
+        assertFalse("Compare enabled/disabled",
+                mComparisonCallback.arePreferenceContentsTheSame(mPref1, mPref2));
+        assertFalse("Compare disable/enabled",
+                mComparisonCallback.arePreferenceContentsTheSame(mPref2, mPref1));
+
+        mPref1.setEnabled(false);
+
+        assertTrue("Compare disabled",
+                mComparisonCallback.arePreferenceContentsTheSame(mPref1, mPref2));
+    }
+
+    /**
+     * Selectable differences should be detected
+     * @throws Exception
+     */
+    @Test
+    public void testSelectableComparison() throws Exception {
+        mPref1.setSelectable(true);
+        mPref2.setSelectable(true);
+
+        assertTrue("Compare selectable",
+                mComparisonCallback.arePreferenceContentsTheSame(mPref1, mPref2));
+
+        mPref2.setSelectable(false);
+
+        assertFalse("Compare selectable/unselectable",
+                mComparisonCallback.arePreferenceContentsTheSame(mPref1, mPref2));
+        assertFalse("Compare unselectable/selectable",
+                mComparisonCallback.arePreferenceContentsTheSame(mPref2, mPref1));
+
+        mPref1.setSelectable(false);
+
+        assertTrue("Compare unselectable",
+                mComparisonCallback.arePreferenceContentsTheSame(mPref1, mPref2));
+    }
+
+    /**
+     * For {@link TwoStatePreference} objects, checked state differences should be detected
+     * @throws Exception
+     */
+    @Test
+    public void testTwoStateComparison() throws Exception {
+        final TwoStatePreference checkbox1 =
+                new CheckBoxPreference(InstrumentationRegistry.getTargetContext());
+        final TwoStatePreference checkbox2 =
+                new CheckBoxPreference(InstrumentationRegistry.getTargetContext());
+
+        checkbox1.setChecked(true);
+        checkbox2.setChecked(true);
+
+        assertTrue("Compare checked",
+                mComparisonCallback.arePreferenceContentsTheSame(checkbox1, checkbox2));
+
+        checkbox2.setChecked(false);
+
+        assertFalse("Compare checked/unchecked",
+                mComparisonCallback.arePreferenceContentsTheSame(checkbox1, checkbox2));
+        assertFalse("Compare unchecked/checked",
+                mComparisonCallback.arePreferenceContentsTheSame(checkbox2, checkbox1));
+
+        checkbox1.setChecked(false);
+
+        assertTrue("Compare unchecked",
+                mComparisonCallback.arePreferenceContentsTheSame(checkbox1, checkbox2));
+    }
+
+    /**
+     * {@link DropDownPreference} is a special case, the pref object will need to re-bind the
+     * spinner when recycled, so distinct instances are never evaluated as equal
+     * @throws Exception
+     */
+    @Test
+    public void testDropDownComparison() throws Exception {
+        final Preference dropdown1 =
+                new DropDownPreference(InstrumentationRegistry.getTargetContext());
+        final Preference dropdown2 =
+                new DropDownPreference(InstrumentationRegistry.getTargetContext());
+
+        assertTrue("Compare aliased drop down pref",
+                mComparisonCallback.arePreferenceContentsTheSame(dropdown1, dropdown1));
+        assertFalse("Compare distinct drop down prefs",
+                mComparisonCallback.arePreferenceContentsTheSame(dropdown1, dropdown2));
+    }
+}
diff --git a/v7/recyclerview/src/android/support/v7/widget/AdapterHelper.java b/v7/recyclerview/src/android/support/v7/widget/AdapterHelper.java
index 47e9722..c133a98 100644
--- a/v7/recyclerview/src/android/support/v7/widget/AdapterHelper.java
+++ b/v7/recyclerview/src/android/support/v7/widget/AdapterHelper.java
@@ -23,8 +23,6 @@
 import java.util.Collections;
 import java.util.List;
 
-import static android.support.v7.widget.RecyclerView.*;
-
 /**
  * Helper class that can enqueue and process adapter update operations.
  * <p>
@@ -138,7 +136,7 @@
         int type = -1;
         for (int position = op.positionStart; position < tmpEnd; position++) {
             boolean typeChanged = false;
-            ViewHolder vh = mCallback.findViewHolder(position);
+            RecyclerView.ViewHolder vh = mCallback.findViewHolder(position);
             if (vh != null || canFindInPreLayout(position)) {
                 // If a ViewHolder exists or this is a newly added item, we can defer this update
                 // to post layout stage.
@@ -191,7 +189,7 @@
         int tmpEnd = op.positionStart + op.itemCount;
         int type = -1;
         for (int position = op.positionStart; position < tmpEnd; position++) {
-            ViewHolder vh = mCallback.findViewHolder(position);
+            RecyclerView.ViewHolder vh = mCallback.findViewHolder(position);
             if (vh != null || canFindInPreLayout(position)) { // deferred
                 if (type == POSITION_TYPE_INVISIBLE) {
                     UpdateOp newOp = obtainUpdateOp(UpdateOp.UPDATE, tmpStart, tmpCount,
@@ -756,9 +754,9 @@
     /**
      * Contract between AdapterHelper and RecyclerView.
      */
-    static interface Callback {
+    interface Callback {
 
-        ViewHolder findViewHolder(int position);
+        RecyclerView.ViewHolder findViewHolder(int position);
 
         void offsetPositionsForRemovingInvisible(int positionStart, int itemCount);
 
diff --git a/v7/recyclerview/src/android/support/v7/widget/GapWorker.java b/v7/recyclerview/src/android/support/v7/widget/GapWorker.java
new file mode 100644
index 0000000..5fb0d6c
--- /dev/null
+++ b/v7/recyclerview/src/android/support/v7/widget/GapWorker.java
@@ -0,0 +1,131 @@
+/*
+ * 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 android.support.v7.widget;
+
+import android.support.v4.os.TraceCompat;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.concurrent.TimeUnit;
+
+class GapWorker implements Runnable {
+    static final ThreadLocal<GapWorker> sGapWorker = new ThreadLocal<>();
+
+    private static final long MIN_PREFETCH_TIME_NANOS = TimeUnit.MILLISECONDS.toNanos(4);
+
+    ArrayList<RecyclerView> mRecyclerViews = new ArrayList<>();
+    long mPostTimeNs;
+    long mFrameIntervalNs;
+
+    public void add(RecyclerView recyclerView) {
+        if (RecyclerView.DEBUG && mRecyclerViews.contains(recyclerView)) {
+            throw new IllegalStateException("RecyclerView already present in worker list!");
+        }
+        mRecyclerViews.add(recyclerView);
+    }
+
+    public void remove(RecyclerView recyclerView) {
+        boolean removeSuccess = mRecyclerViews.remove(recyclerView);
+        if (RecyclerView.DEBUG && !removeSuccess) {
+            throw new IllegalStateException("RecyclerView removal failed!");
+        }
+    }
+
+    /**
+     * Schedule a prefetch immediately after the current traversal.
+     */
+    void postFromTraversal(RecyclerView recyclerView, int prefetchDx, int prefetchDy) {
+        if (recyclerView.isAttachedToWindow()) {
+            if (RecyclerView.DEBUG && !mRecyclerViews.contains(recyclerView)) {
+                throw new IllegalStateException("attempting to post unregistered view!");
+            }
+            if (mPostTimeNs == 0) {
+                mPostTimeNs = System.nanoTime();
+                recyclerView.post(this);
+            }
+        }
+
+        recyclerView.mPrefetchDx = prefetchDx;
+        recyclerView.mPrefetchDy = prefetchDy;
+
+    }
+
+    void layoutPrefetch(long deadlineNs, RecyclerView view) {
+        final int prefetchCount = view.mLayout.getItemPrefetchCount();
+        if (view.mAdapter == null
+                || view.mLayout == null
+                || !view.mLayout.isItemPrefetchEnabled()
+                || prefetchCount < 1
+                || view.hasPendingAdapterUpdates()) {
+            // abort - no work
+            return;
+        }
+
+        long nowNanos = System.nanoTime();
+        if (nowNanos - mPostTimeNs > mFrameIntervalNs
+                || deadlineNs - nowNanos < MIN_PREFETCH_TIME_NANOS) {
+            // abort - Executing either too far after post,
+            // or too near next scheduled vsync
+            return;
+        }
+
+        if (view.mPrefetchArray == null
+                || view.mPrefetchArray.length < prefetchCount) {
+            view.mPrefetchArray = new int[prefetchCount];
+        }
+        Arrays.fill(view.mPrefetchArray, -1);
+        int viewCount = view.mLayout.gatherPrefetchIndices(
+                view.mPrefetchDx, view.mPrefetchDy,
+                view.mState, view.mPrefetchArray);
+        view.mRecycler.prefetch(view.mPrefetchArray, viewCount);
+    }
+
+    @Override
+    public void run() {
+        try {
+            TraceCompat.beginSection(RecyclerView.TRACE_PREFETCH_TAG);
+
+            if (mRecyclerViews.isEmpty()) {
+                // abort - no work to do
+                return;
+            }
+
+            // Query last vsync so we can predict next one. Note that drawing time not yet
+            // valid in animation/input callbacks, so query it here to be safe.
+            long lastFrameVsyncNanos = TimeUnit.MILLISECONDS.toNanos(
+                    mRecyclerViews.get(0).getDrawingTime());
+            if (lastFrameVsyncNanos == 0) {
+                // abort - couldn't get last vsync for estimating next
+                return;
+            }
+
+            long nextFrameNanos = lastFrameVsyncNanos + mFrameIntervalNs;
+
+            // NOTE: it's safe to iterate over mRecyclerViews since we know that (currently),
+            // no attach or detach will occur as a result of creating/binding view holders.
+            // If any prefetch work attached Views, we'd have to avoid fighting over the list.
+            final int count = mRecyclerViews.size();
+            for (int i = 0; i < count; i++) {
+                layoutPrefetch(nextFrameNanos, mRecyclerViews.get(i));
+            }
+
+            // TODO: consider rescheduling self, if there's more work to do
+        } finally {
+            mPostTimeNs = 0;
+            TraceCompat.endSection();
+        }
+    }
+}
diff --git a/v7/recyclerview/src/android/support/v7/widget/RecyclerView.java b/v7/recyclerview/src/android/support/v7/widget/RecyclerView.java
index a70c5de..71c3701 100644
--- a/v7/recyclerview/src/android/support/v7/widget/RecyclerView.java
+++ b/v7/recyclerview/src/android/support/v7/widget/RecyclerView.java
@@ -17,6 +17,8 @@
 
 package android.support.v7.widget;
 
+import static android.support.annotation.RestrictTo.Scope.GROUP_ID;
+
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.database.Observable;
@@ -57,7 +59,6 @@
 import android.util.AttributeSet;
 import android.util.Log;
 import android.util.SparseArray;
-import android.util.SparseIntArray;
 import android.util.TypedValue;
 import android.view.Display;
 import android.view.FocusFinder;
@@ -79,11 +80,6 @@
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
-import java.util.concurrent.TimeUnit;
-
-import static android.support.annotation.RestrictTo.Scope.GROUP_ID;
-import static android.support.v7.widget.AdapterHelper.Callback;
-import static android.support.v7.widget.AdapterHelper.UpdateOp;
 
 /**
  * A flexible view for providing a limited window into a large data set.
@@ -185,7 +181,7 @@
      * On L+, with RenderThread, the UI thread has idle time after it has passed a frame off to
      * RenderThread but before the next frame begins. We schedule prefetch work in this window.
      */
-    private static final boolean ALLOW_PREFETCHING = Build.VERSION.SDK_INT >= 21;
+    private static final boolean ALLOW_THREAD_GAP_WORK = Build.VERSION.SDK_INT >= 21;
 
     static final boolean DISPATCH_TEMP_DETACH = false;
     public static final int HORIZONTAL = 0;
@@ -252,7 +248,7 @@
     /**
      * RecyclerView is attempting to pre-populate off screen views.
      */
-    private static final String TRACE_PREFETCH_TAG = "RV Prefetch";
+    static final String TRACE_PREFETCH_TAG = "RV Prefetch";
 
     /**
      * RecyclerView is creating a new View.
@@ -421,9 +417,12 @@
 
     final ViewFlinger mViewFlinger = new ViewFlinger();
 
-    private static final long MIN_PREFETCH_TIME_NANOS = TimeUnit.MILLISECONDS.toNanos(4);
-    static long sFrameIntervalNanos = 0;
-    ViewPrefetcher mViewPrefetcher = ALLOW_PREFETCHING ? new ViewPrefetcher() : null;
+    GapWorker mGapWorker;
+
+    // Following mPrefetchXXX fields are all owned by mGapWorker
+    int mPrefetchDx;
+    int mPrefetchDy;
+    int[] mPrefetchArray;
 
     final State mState = new State();
 
@@ -765,7 +764,7 @@
     }
 
     void initAdapterManager() {
-        mAdapterHelper = new AdapterHelper(new Callback() {
+        mAdapterHelper = new AdapterHelper(new AdapterHelper.Callback() {
             @Override
             public ViewHolder findViewHolder(int position) {
                 final ViewHolder vh = findViewHolderForPosition(position, true);
@@ -803,30 +802,30 @@
             }
 
             @Override
-            public void onDispatchFirstPass(UpdateOp op) {
+            public void onDispatchFirstPass(AdapterHelper.UpdateOp op) {
                 dispatchUpdate(op);
             }
 
-            void dispatchUpdate(UpdateOp op) {
+            void dispatchUpdate(AdapterHelper.UpdateOp op) {
                 switch (op.cmd) {
-                    case UpdateOp.ADD:
+                    case AdapterHelper.UpdateOp.ADD:
                         mLayout.onItemsAdded(RecyclerView.this, op.positionStart, op.itemCount);
                         break;
-                    case UpdateOp.REMOVE:
+                    case AdapterHelper.UpdateOp.REMOVE:
                         mLayout.onItemsRemoved(RecyclerView.this, op.positionStart, op.itemCount);
                         break;
-                    case UpdateOp.UPDATE:
+                    case AdapterHelper.UpdateOp.UPDATE:
                         mLayout.onItemsUpdated(RecyclerView.this, op.positionStart, op.itemCount,
                                 op.payload);
                         break;
-                    case UpdateOp.MOVE:
+                    case AdapterHelper.UpdateOp.MOVE:
                         mLayout.onItemsMoved(RecyclerView.this, op.positionStart, op.itemCount, 1);
                         break;
                 }
             }
 
             @Override
-            public void onDispatchSecondPass(UpdateOp op) {
+            public void onDispatchSecondPass(AdapterHelper.UpdateOp op) {
                 dispatchUpdate(op);
             }
 
@@ -1573,8 +1572,9 @@
 
         // if it is only an item change (no add-remove-notifyDataSetChanged) we can check if any
         // of the visible items is affected and if not, just ignore the change.
-        if (mAdapterHelper.hasAnyUpdateTypes(UpdateOp.UPDATE) && !mAdapterHelper
-                .hasAnyUpdateTypes(UpdateOp.ADD | UpdateOp.REMOVE | UpdateOp.MOVE)) {
+        if (mAdapterHelper.hasAnyUpdateTypes(AdapterHelper.UpdateOp.UPDATE) && !mAdapterHelper
+                .hasAnyUpdateTypes(AdapterHelper.UpdateOp.ADD | AdapterHelper.UpdateOp.REMOVE
+                        | AdapterHelper.UpdateOp.MOVE)) {
             TraceCompat.beginSection(TRACE_HANDLE_ADAPTER_UPDATES_TAG);
             eatRequestLayout();
             mAdapterHelper.preProcess();
@@ -1919,6 +1919,18 @@
      * @param dy Pixels to scroll vertically
      */
     public void smoothScrollBy(int dx, int dy) {
+        smoothScrollBy(dx, dy, null);
+    }
+
+    /**
+     * Animate a scroll by the given amount of pixels along either axis.
+     *
+     * @param dx Pixels to scroll horizontally
+     * @param dy Pixels to scroll vertically
+     * @param interpolator {@link Interpolator} to be used for scrolling. If it is
+     *                     {@code null}, RecyclerView is going to use the default interpolator.
+     */
+    public void smoothScrollBy(int dx, int dy, Interpolator interpolator) {
         if (mLayout == null) {
             Log.e(TAG, "Cannot smooth scroll without a LayoutManager set. " +
                     "Call setLayoutManager with a non-null argument.");
@@ -1934,7 +1946,7 @@
             dy = 0;
         }
         if (dx != 0 || dy != 0) {
-            mViewFlinger.smoothScrollBy(dx, dy);
+            mViewFlinger.smoothScrollBy(dx, dy, interpolator);
         }
     }
 
@@ -2385,15 +2397,25 @@
             mLayout.dispatchAttachedToWindow(this);
         }
         mPostedAnimatorRunner = false;
-        if (ALLOW_PREFETCHING && sFrameIntervalNanos == 0) {
-            // We only query the display/refresh rate once, since it's an expensive binder call
-            float refreshRate = 60.0f;
-            Display display = ViewCompat.getDisplay(this);
-            if (display != null && display.getRefreshRate() >= 30.0f) {
-                // break 60 fps assumption if data appears good
-                refreshRate  = display.getRefreshRate();
+
+        if (ALLOW_THREAD_GAP_WORK) {
+            // Register with gap worker
+            mGapWorker = GapWorker.sGapWorker.get();
+            if (mGapWorker == null) {
+                mGapWorker = new GapWorker();
+
+                // break 60 fps assumption if data from display appears valid
+                // NOTE: we only do this query once, statically, because it's very expensive (> 1ms)
+                Display display = ViewCompat.getDisplay(this);
+                float refreshRate = 60.0f;
+                if (display != null
+                        && display.getRefreshRate() >= 30.0f) {
+                    refreshRate = display.getRefreshRate();
+                }
+                mGapWorker.mFrameIntervalNs = (long) (1000000000 / refreshRate);
+                GapWorker.sGapWorker.set(mGapWorker);
             }
-            sFrameIntervalNanos = (long) (1000000000 / refreshRate);
+            mGapWorker.add(this);
         }
     }
 
@@ -2411,6 +2433,12 @@
         mPendingAccessibilityImportanceChange.clear();
         removeCallbacks(mItemAnimatorRunner);
         mViewInfoStore.onDetach();
+
+        if (ALLOW_THREAD_GAP_WORK) {
+            // Unregister with gap worker
+            mGapWorker.remove(this);
+            mGapWorker = null;
+        }
     }
 
     /**
@@ -2762,8 +2790,8 @@
                             vtev)) {
                         getParent().requestDisallowInterceptTouchEvent(true);
                     }
-                    if (ALLOW_PREFETCHING) {
-                        mViewPrefetcher.postFromTraversal(dx, dy);
+                    if (ALLOW_THREAD_GAP_WORK) {
+                        mGapWorker.postFromTraversal(this, dx, dy);
                     }
                 }
             } break;
@@ -3224,7 +3252,9 @@
         // only recover focus if RV itself has the focus or the focused view is hidden
         if (!isFocused()) {
             final View focusedChild = getFocusedChild();
-            if (focusedChild == null || !mChildHelper.isHidden(focusedChild)) {
+            if (focusedChild == null || (!mChildHelper.isHidden(focusedChild)
+                    // on API 15, this happens :/.
+                    && focusedChild.getParent() == this && focusedChild.hasFocus())) {
                 return;
             }
         }
@@ -4441,98 +4471,29 @@
                 || mAdapterHelper.hasPendingUpdates();
     }
 
+    boolean lastPrefetchIncludedPosition(int position) {
+        if (mPrefetchArray != null) {
+            for (int i = 0; i < mPrefetchArray.length; i++) {
+                if (mPrefetchArray[i] == position) return true;
+            }
+        }
+        return false;
+    }
+
     /**
-     * Runs prefetch work immediately after a traversal, in the downtime while the UI thread is
-     * waiting for VSYNC.
+     * Called when prefetch indices are no longer valid for cache prioritization.
      */
-    class ViewPrefetcher implements Runnable {
-
-        long mPostTimeNanos;
-        private int mDx;
-        private int mDy;
-
-        int[] mItemPrefetchArray;
-
-        /**
-         * Schedule a prefetch immediately after the current traversal.
-         */
-        public void postFromTraversal(int dx, int dy) {
-            if (ALLOW_PREFETCHING
-                    && mAdapter != null
-                    && mLayout != null
-                    && mLayout.getItemPrefetchCount() > 0) {
-                mDx = dx;
-                mDy = dy;
-                mPostTimeNanos = System.nanoTime();
-                RecyclerView.this.post(this);
-            }
-        }
-
-        public boolean lastPrefetchIncludedPosition(int position) {
-            if (mItemPrefetchArray != null) {
-                for (int i = 0; i < mItemPrefetchArray.length; i++) {
-                    if (mItemPrefetchArray[i] == position) return true;
-                }
-            }
-            return false;
-        }
-
-        /**
-         * Called when prefetch indices are no longer valid for cache prioritization.
-         */
-        public void clearPrefetchPositions() {
-            if (mItemPrefetchArray != null) {
-                Arrays.fill(mItemPrefetchArray, -1);
-            }
-        }
-
-        @Override
-        public void run() {
-            try {
-                TraceCompat.beginSection(TRACE_PREFETCH_TAG);
-                final int prefetchCount = mLayout.getItemPrefetchCount();
-                if (mAdapter == null
-                        || mLayout == null
-                        || !mLayout.isItemPrefetchEnabled()
-                        || prefetchCount < 1
-                        || hasPendingAdapterUpdates()) {
-                    // abort - no work
-                    return;
-                }
-
-                // Query last vsync so we can predict next one. Note that drawing time not yet
-                // valid in animation/input callbacks, so query it here to be safe.
-                long lastFrameVsyncNanos = TimeUnit.MILLISECONDS.toNanos(getDrawingTime());
-                if (lastFrameVsyncNanos == 0 || sFrameIntervalNanos == 0) {
-                    // abort - couldn't get info for estimating next vsync
-                    return;
-                }
-
-                long nowNanos = System.nanoTime();
-                long nextFrameNanos = lastFrameVsyncNanos + sFrameIntervalNanos;
-                if (nowNanos - mPostTimeNanos > sFrameIntervalNanos
-                        || nextFrameNanos - nowNanos < MIN_PREFETCH_TIME_NANOS) {
-                    // abort - Executing either too far after post, or too near next scheduled vsync
-                    return;
-                }
-
-                if (mItemPrefetchArray == null || mItemPrefetchArray.length < prefetchCount) {
-                    mItemPrefetchArray = new int[prefetchCount];
-                }
-                Arrays.fill(mItemPrefetchArray, -1);
-                int viewCount = mLayout.gatherPrefetchIndices(mDx, mDy, mState, mItemPrefetchArray);
-                mRecycler.prefetch(mItemPrefetchArray, viewCount);
-            } finally {
-                TraceCompat.endSection();
-            }
+    void clearPrefetchPositions() {
+        if (mPrefetchArray != null) {
+            Arrays.fill(mPrefetchArray, -1);
         }
     }
 
-    private class ViewFlinger implements Runnable {
+    class ViewFlinger implements Runnable {
         private int mLastFlingX;
         private int mLastFlingY;
         private ScrollerCompat mScroller;
-        private Interpolator mInterpolator = sQuinticInterpolator;
+        Interpolator mInterpolator = sQuinticInterpolator;
 
 
         // When set to true, postOnAnimation callbacks are delayed until the run method completes
@@ -4642,13 +4603,13 @@
 
                 if (scroller.isFinished() || !fullyConsumedAny) {
                     setScrollState(SCROLL_STATE_IDLE); // setting state to idle will stop this.
-                    if (ALLOW_PREFETCHING) {
-                        mViewPrefetcher.clearPrefetchPositions();
+                    if (ALLOW_THREAD_GAP_WORK) {
+                        clearPrefetchPositions();
                     }
                 } else {
                     postOnAnimation();
-                    if (ALLOW_PREFETCHING) {
-                        mViewPrefetcher.postFromTraversal(dx, dy);
+                    if (ALLOW_THREAD_GAP_WORK) {
+                        mGapWorker.postFromTraversal(RecyclerView.this, dx, dy);
                     }
                 }
             }
@@ -4733,6 +4694,11 @@
             smoothScrollBy(dx, dy, duration, sQuinticInterpolator);
         }
 
+        public void smoothScrollBy(int dx, int dy, Interpolator interpolator) {
+            smoothScrollBy(dx, dy, computeScrollDuration(dx, dy, 0, 0),
+                    interpolator == null ? sQuinticInterpolator : interpolator);
+        }
+
         public void smoothScrollBy(int dx, int dy, int duration, Interpolator interpolator) {
             if (mInterpolator != interpolator) {
                 mInterpolator = interpolator;
@@ -4845,20 +4811,29 @@
      *
      */
     public static class RecycledViewPool {
-        private SparseArray<ArrayList<ViewHolder>> mScrap =
-                new SparseArray<ArrayList<ViewHolder>>();
-        private SparseIntArray mMaxScrap = new SparseIntArray();
-        private int mAttachCount = 0;
-
         private static final int DEFAULT_MAX_SCRAP = 5;
 
+        static class ScrapData {
+            ArrayList<ViewHolder> mScrapHeap = new ArrayList<>();
+            int mMaxScrap = DEFAULT_MAX_SCRAP;
+            long mCreateRunningAverageNs = 0;
+            long mBindRunningAverageNs = 0;
+        }
+        SparseArray<ScrapData> mScrap = new SparseArray<>();
+
+        private int mAttachCount = 0;
+
         public void clear() {
-            mScrap.clear();
+            for (int i = 0; i < mScrap.size(); i++) {
+                ScrapData data = mScrap.valueAt(i);
+                data.mScrapHeap.clear();
+            }
         }
 
         public void setMaxRecycledViews(int viewType, int max) {
-            mMaxScrap.put(viewType, max);
-            final ArrayList<ViewHolder> scrapHeap = mScrap.get(viewType);
+            ScrapData scrapData = getScrapDataForType(viewType);
+            scrapData.mMaxScrap = max;
+            final ArrayList<ViewHolder> scrapHeap = scrapData.mScrapHeap;
             if (scrapHeap != null) {
                 while (scrapHeap.size() > max) {
                     scrapHeap.remove(scrapHeap.size() - 1);
@@ -4866,13 +4841,18 @@
             }
         }
 
+        /**
+         * Returns the current number of Views held by the RecycledViewPool of the given view type.
+         */
+        public int getRecycledViewCount(int viewType) {
+            return getScrapDataForType(viewType).mScrapHeap.size();
+        }
+
         public ViewHolder getRecycledView(int viewType) {
-            final ArrayList<ViewHolder> scrapHeap = mScrap.get(viewType);
-            if (scrapHeap != null && !scrapHeap.isEmpty()) {
-                final int index = scrapHeap.size() - 1;
-                final ViewHolder scrap = scrapHeap.get(index);
-                scrapHeap.remove(index);
-                return scrap;
+            final ScrapData scrapData = mScrap.get(viewType);
+            if (scrapData != null && !scrapData.mScrapHeap.isEmpty()) {
+                final ArrayList<ViewHolder> scrapHeap = scrapData.mScrapHeap;
+                return scrapHeap.remove(scrapHeap.size() - 1);
             }
             return null;
         }
@@ -4880,7 +4860,7 @@
         int size() {
             int count = 0;
             for (int i = 0; i < mScrap.size(); i ++) {
-                ArrayList<ViewHolder> viewHolders = mScrap.valueAt(i);
+                ArrayList<ViewHolder> viewHolders = mScrap.valueAt(i).mScrapHeap;
                 if (viewHolders != null) {
                     count += viewHolders.size();
                 }
@@ -4890,8 +4870,8 @@
 
         public void putRecycledView(ViewHolder scrap) {
             final int viewType = scrap.getItemViewType();
-            final ArrayList scrapHeap = getScrapHeapForType(viewType);
-            if (mMaxScrap.get(viewType) <= scrapHeap.size()) {
+            final ArrayList scrapHeap = getScrapDataForType(viewType).mScrapHeap;
+            if (mScrap.get(viewType).mMaxScrap <= scrapHeap.size()) {
                 return;
             }
             if (DEBUG && scrapHeap.contains(scrap)) {
@@ -4901,6 +4881,25 @@
             scrapHeap.add(scrap);
         }
 
+        long runningAverage(long oldAverage, long newValue) {
+            if (oldAverage == 0) {
+                return newValue;
+            }
+            return (oldAverage / 8 * 7) + (newValue / 8);
+        }
+
+        void factorInCreateTime(int viewType, long createTimeNs) {
+            ScrapData scrapData = getScrapDataForType(viewType);
+            scrapData.mCreateRunningAverageNs = runningAverage(
+                    scrapData.mCreateRunningAverageNs, createTimeNs);
+        }
+
+        void factorInBindTime(int viewType, long bindTimeNs) {
+            ScrapData scrapData = getScrapDataForType(viewType);
+            scrapData.mBindRunningAverageNs = runningAverage(
+                    scrapData.mBindRunningAverageNs, bindTimeNs);
+        }
+
         void attach(Adapter adapter) {
             mAttachCount++;
         }
@@ -4934,16 +4933,13 @@
             }
         }
 
-        private ArrayList<ViewHolder> getScrapHeapForType(int viewType) {
-            ArrayList<ViewHolder> scrap = mScrap.get(viewType);
-            if (scrap == null) {
-                scrap = new ArrayList<>();
-                mScrap.put(viewType, scrap);
-                if (mMaxScrap.indexOfKey(viewType) < 0) {
-                    mMaxScrap.put(viewType, DEFAULT_MAX_SCRAP);
-                }
+        private ScrapData getScrapDataForType(int viewType) {
+            ScrapData scrapData = mScrap.get(viewType);
+            if (scrapData == null) {
+                scrapData = new ScrapData();
+                mScrap.put(viewType, scrapData);
             }
-            return scrap;
+            return scrapData;
         }
     }
 
@@ -4972,7 +4968,7 @@
         private int mRequestedCacheMax = DEFAULT_CACHE_SIZE;
         int mViewCacheMax = DEFAULT_CACHE_SIZE;
 
-        private RecycledViewPool mRecyclerPool;
+        RecycledViewPool mRecyclerPool;
 
         private ViewCacheExtension mViewCacheExtension;
 
@@ -4999,7 +4995,7 @@
 
         void updateViewCacheSize() {
             int extraCache = 0;
-            if (mLayout != null && ALLOW_PREFETCHING) {
+            if (mLayout != null && ALLOW_THREAD_GAP_WORK) {
                 extraCache = mLayout.isItemPrefetchEnabled() ? mLayout.getItemPrefetchCount() : 0;
             }
             mViewCacheMax = mRequestedCacheMax + extraCache;
@@ -5054,6 +5050,18 @@
             return true;
         }
 
+        private void bindViewImpl(ViewHolder holder, int offsetPosition, int position) {
+            holder.mOwnerRecyclerView = RecyclerView.this;
+            long startBindNs = System.nanoTime();
+            mAdapter.bindViewHolder(holder, offsetPosition);
+            long endBindNs = System.nanoTime();
+            mRecyclerPool.factorInBindTime(holder.getItemViewType(), endBindNs - startBindNs);
+            attachAccessibilityDelegate(holder.itemView);
+            if (mState.isPreLayout()) {
+                holder.mPreLayoutPosition = position;
+            }
+        }
+
         /**
          * Binds the given View to the position. The View can be a View previously retrieved via
          * {@link #getViewForPosition(int)} or created by
@@ -5082,12 +5090,7 @@
                         + "position " + position + "(offset:" + offsetPosition + ")."
                         + "state:" + mState.getItemCount());
             }
-            holder.mOwnerRecyclerView = RecyclerView.this;
-            mAdapter.bindViewHolder(holder, offsetPosition);
-            attachAccessibilityDelegate(view);
-            if (mState.isPreLayout()) {
-                holder.mPreLayoutPosition = position;
-            }
+            bindViewImpl(holder, offsetPosition, position);
 
             final ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams();
             final LayoutParams rvLayoutParams;
@@ -5240,7 +5243,10 @@
                     }
                 }
                 if (holder == null) {
+                    long start = System.nanoTime();
                     holder = mAdapter.createViewHolder(RecyclerView.this, type);
+                    long end = System.nanoTime();
+                    mRecyclerPool.factorInCreateTime(type, end - start);
                     if (DEBUG) {
                         Log.d(TAG, "getViewForPosition created new ViewHolder");
                     }
@@ -5273,13 +5279,8 @@
                             + " come here only in pre-layout. Holder: " + holder);
                 }
                 final int offsetPosition = mAdapterHelper.findPositionOffset(position);
-                holder.mOwnerRecyclerView = RecyclerView.this;
-                mAdapter.bindViewHolder(holder, offsetPosition);
-                attachAccessibilityDelegate(holder.itemView);
+                bindViewImpl(holder, offsetPosition, position);
                 bound = true;
-                if (mState.isPreLayout()) {
-                    holder.mPreLayoutPosition = position;
-                }
             }
 
             final ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams();
@@ -5379,8 +5380,8 @@
                 recycleCachedViewAt(i);
             }
             mCachedViews.clear();
-            if (ALLOW_PREFETCHING) {
-                mViewPrefetcher.clearPrefetchPositions();
+            if (ALLOW_THREAD_GAP_WORK) {
+                clearPrefetchPositions();
             }
         }
 
@@ -5453,14 +5454,14 @@
                     }
 
                     int targetCacheIndex = cachedViewSize;
-                    if (ALLOW_PREFETCHING
+                    if (ALLOW_THREAD_GAP_WORK
                             && cachedViewSize > 0
-                            && !mViewPrefetcher.lastPrefetchIncludedPosition(holder.mPosition)) {
+                            && !lastPrefetchIncludedPosition(holder.mPosition)) {
                         // when adding the view, skip past most recently prefetched views
                         int cacheIndex = cachedViewSize - 1;
                         while (cacheIndex >= 0) {
                             int cachedPos = mCachedViews.get(cacheIndex).mPosition;
-                            if (!mViewPrefetcher.lastPrefetchIncludedPosition(cachedPos)) {
+                            if (!lastPrefetchIncludedPosition(cachedPos)) {
                                 break;
                             }
                             cacheIndex--;
@@ -8199,11 +8200,11 @@
             int size = Math.max(0, parentSize - padding);
             int resultSize = 0;
             int resultMode = 0;
-            if (childDimension >= 0) {
-                resultSize = childDimension;
-                resultMode = MeasureSpec.EXACTLY;
-            } else if (canScroll) {
-                 if (childDimension == LayoutParams.MATCH_PARENT){
+            if (canScroll) {
+                if (childDimension >= 0) {
+                    resultSize = childDimension;
+                    resultMode = MeasureSpec.EXACTLY;
+                } else if (childDimension == LayoutParams.MATCH_PARENT) {
                     switch (parentMode) {
                         case MeasureSpec.AT_MOST:
                         case MeasureSpec.EXACTLY:
@@ -8220,7 +8221,10 @@
                     resultMode = MeasureSpec.UNSPECIFIED;
                 }
             } else {
-                if (childDimension == LayoutParams.MATCH_PARENT) {
+                if (childDimension >= 0) {
+                    resultSize = childDimension;
+                    resultMode = MeasureSpec.EXACTLY;
+                } else if (childDimension == LayoutParams.MATCH_PARENT) {
                     resultSize = size;
                     resultMode = parentMode;
                 } else if (childDimension == LayoutParams.WRAP_CONTENT) {
@@ -10009,6 +10013,8 @@
          *
          * @param recyclable Whether this item is available to be recycled. Default value
          * is true.
+         *
+         * @see #isRecyclable()
          */
         public final void setIsRecyclable(boolean recyclable) {
             mIsRecyclableCount = recyclable ? mIsRecyclableCount - 1 : mIsRecyclableCount + 1;
@@ -10031,9 +10037,9 @@
         }
 
         /**
-         * @see {@link #setIsRecyclable(boolean)}
-         *
          * @return true if this item is available to be recycled, false otherwise.
+         *
+         * @see #setIsRecyclable(boolean)
          */
         public final boolean isRecyclable() {
             return (mFlags & FLAG_NOT_RECYCLABLE) == 0 &&
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/BaseGridLayoutManagerTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/BaseGridLayoutManagerTest.java
index 3a72152..955ac95 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/BaseGridLayoutManagerTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/BaseGridLayoutManagerTest.java
@@ -15,9 +15,18 @@
  */
 package android.support.v7.widget;
 
+import static android.support.v7.widget.LinearLayoutManager.HORIZONTAL;
+import static android.support.v7.widget.LinearLayoutManager.VERTICAL;
+
+import static org.junit.Assert.assertEquals;
+
+import static java.util.concurrent.TimeUnit.SECONDS;
+
 import android.content.Context;
 import android.view.View;
-import android.view.ViewGroup;
+
+import org.hamcrest.CoreMatchers;
+import org.hamcrest.MatcherAssert;
 
 import java.lang.reflect.Field;
 import java.util.ArrayList;
@@ -26,14 +35,6 @@
 import java.util.Set;
 import java.util.concurrent.CountDownLatch;
 
-import static android.support.v7.widget.LinearLayoutManager.HORIZONTAL;
-import static android.support.v7.widget.LinearLayoutManager.VERTICAL;
-import static java.util.concurrent.TimeUnit.SECONDS;
-import static org.junit.Assert.assertEquals;
-
-import org.hamcrest.CoreMatchers;
-import org.hamcrest.MatcherAssert;
-
 public class BaseGridLayoutManagerTest extends BaseRecyclerViewInstrumentationTest {
 
     static final String TAG = "GridLayoutManagerTest";
@@ -127,12 +128,12 @@
 
         @Override
         public String toString() {
-            return "Config{" +
-                    "mSpanCount=" + mSpanCount +
-                    ", mOrientation=" + (mOrientation == GridLayoutManager.HORIZONTAL ? "h" : "v") +
-                    ", mItemCount=" + mItemCount +
-                    ", mReverseLayout=" + mReverseLayout +
-                    '}';
+            return "Config{"
+                    + "mSpanCount=" + mSpanCount
+                    + ",mOrientation=" + (mOrientation == GridLayoutManager.HORIZONTAL ? "h" : "v")
+                    + ",mItemCount=" + mItemCount
+                    + ",mReverseLayout=" + mReverseLayout
+                    + '}';
         }
 
         public Config reverseLayout(boolean reverseLayout) {
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/BaseLinearLayoutManagerTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/BaseLinearLayoutManagerTest.java
index 50c9ba3..4d25434 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/BaseLinearLayoutManagerTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/BaseLinearLayoutManagerTest.java
@@ -27,7 +27,6 @@
 
 import android.content.Context;
 import android.graphics.Rect;
-import android.support.v4.util.Pair;
 import android.util.Log;
 import android.view.View;
 import android.view.ViewGroup;
@@ -323,14 +322,14 @@
 
         @Override
         public String toString() {
-            return "Config{" +
-                    "mStackFromEnd=" + mStackFromEnd +
-                    ", mOrientation=" + mOrientation +
-                    ", mReverseLayout=" + mReverseLayout +
-                    ", mRecycleChildrenOnDetach=" + mRecycleChildrenOnDetach +
-                    ", mItemCount=" + mItemCount +
-                    ", wrap=" + mWrap +
-                    '}';
+            return "Config{"
+                    + "mStackFromEnd=" + mStackFromEnd
+                    + ",mOrientation=" + mOrientation
+                    + ",mReverseLayout=" + mReverseLayout
+                    + ",mRecycleChildrenOnDetach=" + mRecycleChildrenOnDetach
+                    + ",mItemCount=" + mItemCount
+                    + ",wrap=" + mWrap
+                    + '}';
         }
 
         public Config wrap(boolean wrap) {
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/BaseStaggeredGridLayoutManagerTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/BaseStaggeredGridLayoutManagerTest.java
index d872eca..01d5b6a 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/BaseStaggeredGridLayoutManagerTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/BaseStaggeredGridLayoutManagerTest.java
@@ -1,11 +1,28 @@
 package android.support.v7.widget;
 
+import static android.support.v7.widget.LayoutState.LAYOUT_END;
+import static android.support.v7.widget.LayoutState.LAYOUT_START;
+import static android.support.v7.widget.LinearLayoutManager.VERTICAL;
+import static android.support.v7.widget.StaggeredGridLayoutManager.GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS;
+import static android.support.v7.widget.StaggeredGridLayoutManager.GAP_HANDLING_NONE;
+import static android.support.v7.widget.StaggeredGridLayoutManager.HORIZONTAL;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import static java.util.concurrent.TimeUnit.SECONDS;
+
 import android.graphics.Rect;
 import android.support.annotation.Nullable;
 import android.util.Log;
 import android.view.View;
 import android.view.ViewGroup;
 
+import org.hamcrest.CoreMatchers;
+import org.hamcrest.MatcherAssert;
+
 import java.lang.reflect.Field;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -17,22 +34,6 @@
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicInteger;
 
-import static android.support.v7.widget.LayoutState.LAYOUT_END;
-import static android.support.v7.widget.LayoutState.LAYOUT_START;
-import static android.support.v7.widget.LinearLayoutManager.VERTICAL;
-import static android.support.v7.widget.StaggeredGridLayoutManager.GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS;
-import static android.support.v7.widget.StaggeredGridLayoutManager.GAP_HANDLING_NONE;
-import static android.support.v7.widget.StaggeredGridLayoutManager.HORIZONTAL;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-
-import static java.util.concurrent.TimeUnit.SECONDS;
-
-import org.hamcrest.CoreMatchers;
-import org.hamcrest.MatcherAssert;
-
 public class BaseStaggeredGridLayoutManagerTest extends BaseRecyclerViewInstrumentationTest {
 
     protected static final boolean DEBUG = false;
@@ -441,13 +442,13 @@
 
         @Override
         public String toString() {
-            return "[CONFIG:" +
-                    " span:" + mSpanCount + "," +
-                    " orientation:" + (mOrientation == HORIZONTAL ? "horz," : "vert,") +
-                    " reverse:" + (mReverseLayout ? "T" : "F") +
-                    " itemCount:" + mItemCount +
-                    " wrapContent:" + mWrap +
-                    " gap strategy: " + gapStrategyName(mGapStrategy);
+            return "[CONFIG:"
+                    + "span:" + mSpanCount
+                    + ",orientation:" + (mOrientation == HORIZONTAL ? "horz," : "vert,")
+                    + ",reverse:" + (mReverseLayout ? "T" : "F")
+                    + ",itemCount:" + mItemCount
+                    + ",wrapContent:" + mWrap
+                    + ",gap_strategy:" + gapStrategyName(mGapStrategy);
         }
 
         protected static String gapStrategyName(int gapStrategy) {
@@ -455,9 +456,9 @@
                 case GAP_HANDLING_NONE:
                     return "none";
                 case GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS:
-                    return "move spans";
+                    return "move_spans";
             }
-            return "gap strategy: unknown";
+            return "gap_strategy:unknown";
         }
 
         @Override
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/BaseWrapContentTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/BaseWrapContentTest.java
index 2dd16ef..a0c1a84 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/BaseWrapContentTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/BaseWrapContentTest.java
@@ -15,8 +15,6 @@
  */
 package android.support.v7.widget;
 
-import static android.support.v7.widget.StaggeredGridLayoutManager.HORIZONTAL;
-
 import static org.hamcrest.CoreMatchers.is;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertEquals;
@@ -24,7 +22,6 @@
 import static org.junit.Assert.assertTrue;
 
 import android.app.Activity;
-import android.content.Context;
 import android.graphics.Color;
 import android.graphics.Rect;
 import android.support.annotation.Nullable;
@@ -37,16 +34,10 @@
 import android.widget.TextView;
 
 import org.hamcrest.CoreMatchers;
-import org.junit.Test;
-
-import org.hamcrest.CoreMatchers;
-import org.hamcrest.MatcherAssert;
 
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
 
 /**
  * Class to test any generic wrap content behavior.
@@ -540,8 +531,8 @@
         public String toString() {
             return "WrapContentConfig{"
                     + "unlimitedWidth=" + unlimitedWidth
-                    + ", unlimitedHeight=" + unlimitedHeight
-                    + ", padding=" + padding
+                    + ",unlimitedHeight=" + unlimitedHeight
+                    + ",padding=" + padding
                     + '}';
         }
 
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/FocusSearchNavigationTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/FocusSearchNavigationTest.java
index 48bd6c5..d6a4479 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/FocusSearchNavigationTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/FocusSearchNavigationTest.java
@@ -21,6 +21,11 @@
 import static android.support.v7.widget.RecyclerView.SCROLL_STATE_IDLE;
 import static android.support.v7.widget.RecyclerView.VERTICAL;
 
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.notNullValue;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertTrue;
+
 import android.app.Activity;
 import android.content.Context;
 import android.os.Looper;
@@ -35,11 +40,6 @@
 import android.view.ViewParent;
 import android.widget.LinearLayout;
 
-import static org.hamcrest.CoreMatchers.notNullValue;
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.junit.Assert.assertTrue;
-import static org.hamcrest.CoreMatchers.is;
-
 import org.hamcrest.BaseMatcher;
 import org.hamcrest.CoreMatchers;
 import org.hamcrest.Description;
@@ -70,7 +70,7 @@
         mLayoutDir = layoutDir;
     }
 
-    @Parameterized.Parameters(name = "orientation:{0} layoutDir:{1}")
+    @Parameterized.Parameters(name = "orientation:{0},layoutDir:{1}")
     public static List<Object[]> params() {
         return Arrays.asList(
                 new Object[]{VERTICAL, ViewCompat.LAYOUT_DIRECTION_LTR},
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerCacheTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerCacheTest.java
index 6819a6a..705e541 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerCacheTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerCacheTest.java
@@ -16,6 +16,12 @@
 
 package android.support.v7.widget;
 
+import static android.support.v7.widget.LinearLayoutManager.HORIZONTAL;
+import static android.support.v7.widget.LinearLayoutManager.VERTICAL;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
 import android.os.Build;
 import android.support.test.filters.SdkSuppress;
 import android.test.suitebuilder.annotation.MediumTest;
@@ -28,11 +34,6 @@
 import java.util.List;
 import java.util.concurrent.TimeUnit;
 
-import static android.support.v7.widget.LinearLayoutManager.HORIZONTAL;
-import static android.support.v7.widget.LinearLayoutManager.VERTICAL;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
 @RunWith(Parameterized.class)
 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.LOLLIPOP)
 public class GridLayoutManagerCacheTest extends BaseGridLayoutManagerTest {
@@ -47,7 +48,7 @@
         mDy = dy;
     }
 
-    @Parameterized.Parameters(name = "config:{0}, dx:{1}, dy:{2}")
+    @Parameterized.Parameters(name = "config:{0},dx:{1},dy:{2}")
     public static List<Object[]> getParams() {
         List<Object[]> result = new ArrayList<>();
         List<Config> configs = createBaseVariations();
@@ -99,10 +100,10 @@
                 @Override
                 public void run() {
                     mRecyclerView.mRecycler.recycleAndClearCachedViews();
-                    mRecyclerView.mViewPrefetcher.postFromTraversal(mDx, mDy);
+                    mRecyclerView.mGapWorker.postFromTraversal(mRecyclerView, mDx, mDy);
 
                     // Lie about post time, so prefetch executes even if it is delayed
-                    mRecyclerView.mViewPrefetcher.mPostTimeNanos += TimeUnit.SECONDS.toNanos(5);
+                    mRecyclerView.mGapWorker.mPostTimeNs += TimeUnit.SECONDS.toNanos(5);
                 }
             });
             mGlm.waitForPrefetch(1);
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerCustomSizeInScrollDirectionTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerCustomSizeInScrollDirectionTest.java
index 77a0723..183c652 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerCustomSizeInScrollDirectionTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerCustomSizeInScrollDirectionTest.java
@@ -34,7 +34,7 @@
 
 @RunWith(Parameterized.class)
 public class GridLayoutManagerCustomSizeInScrollDirectionTest extends BaseGridLayoutManagerTest {
-    @Parameterized.Parameters(name = "addDecorOffsets:{1} addMargins:{2} config:{0}")
+    @Parameterized.Parameters(name = "addDecorOffsets:{1},addMargins:{2},config:{0}")
     public static List<Object[]> getParams() {
         List<Object[]> params = new ArrayList<>();
         Boolean[] options = new Boolean[]{true, false};
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerNoOpUpdateTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerNoOpUpdateTest.java
index cd0fac4..843e9d24 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerNoOpUpdateTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerNoOpUpdateTest.java
@@ -36,7 +36,7 @@
  */
 @RunWith(Parameterized.class)
 public class GridLayoutManagerNoOpUpdateTest extends BaseGridLayoutManagerTest {
-    @Parameterized.Parameters(name = "conf:{0} rtl={1}")
+    @Parameterized.Parameters(name = "conf:{0},rtl={1}")
     public static List<Object[]> getParams() {
         List<Object[]> result = new ArrayList<>();
         for (BaseGridLayoutManagerTest.Config config : createBaseVariations()) {
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerRtlTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerRtlTest.java
index 78f1576..a2d993e 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerRtlTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerRtlTest.java
@@ -17,22 +17,23 @@
 package android.support.v7.widget;
 
 
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
+import static android.support.v7.widget.LinearLayoutManager.HORIZONTAL;
+import static android.support.v7.widget.LinearLayoutManager.VERTICAL;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
 
 import android.view.View;
 import android.view.ViewGroup;
 
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
 import java.util.ArrayList;
 import java.util.List;
 
-import static android.support.v7.widget.LinearLayoutManager.HORIZONTAL;
-import static android.support.v7.widget.LinearLayoutManager.VERTICAL;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-
 @RunWith(Parameterized.class)
 public class GridLayoutManagerRtlTest extends BaseGridLayoutManagerTest {
 
@@ -44,7 +45,7 @@
         mItemsWrapContent = itemsWrapContent;
     }
 
-    @Parameterized.Parameters(name = "conf: {0} changeRl:{1} oneLine: {2} itemsWrap: {3}")
+    @Parameterized.Parameters(name = "conf:{0},changeRl:{1},oneLine:{2},itemsWrap:{3}")
     public static List<Object[]> params() {
         List<Object[]> result = new ArrayList<>();
         for (boolean changeRtlAfter : new boolean[]{false, true}) {
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerSnappingTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerSnappingTest.java
index 0ba8fed..445726b 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerSnappingTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerSnappingTest.java
@@ -16,6 +16,11 @@
 
 package android.support.v7.widget;
 
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNotSame;
+import static junit.framework.Assert.assertSame;
+import static junit.framework.Assert.assertTrue;
+
 import android.support.annotation.Nullable;
 import android.test.suitebuilder.annotation.MediumTest;
 import android.view.View;
@@ -28,11 +33,6 @@
 import java.util.List;
 import java.util.concurrent.atomic.AtomicBoolean;
 
-import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertNotSame;
-import static junit.framework.Assert.assertSame;
-import static junit.framework.Assert.assertTrue;
-
 @RunWith(Parameterized.class)
 public class GridLayoutManagerSnappingTest extends BaseGridLayoutManagerTest {
 
@@ -44,7 +44,7 @@
         mReverseScroll = reverseScroll;
     }
 
-    @Parameterized.Parameters(name = "config:{0}, reverseScroll:{1}")
+    @Parameterized.Parameters(name = "config:{0},reverseScroll:{1}")
     public static List<Object[]> getParams() {
         List<Object[]> result = new ArrayList<>();
         List<Config> configs = createBaseVariations();
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerWrapContentWithAspectRatioTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerWrapContentWithAspectRatioTest.java
index 6c311e4..f05d1ba 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerWrapContentWithAspectRatioTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerWrapContentWithAspectRatioTest.java
@@ -16,36 +16,37 @@
 
 package android.support.v7.widget;
 
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
+import static android.support.v7.widget.BaseWrapContentTest.WrapContentConfig;
+import static android.support.v7.widget.GridLayoutManagerTest.Config;
+import static android.support.v7.widget.LinearLayoutManager.HORIZONTAL;
+import static android.support.v7.widget.LinearLayoutManager.VERTICAL;
+import static android.view.View.MeasureSpec.AT_MOST;
+import static android.view.View.MeasureSpec.EXACTLY;
+import static android.view.View.MeasureSpec.UNSPECIFIED;
+import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
+import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
 
 import android.graphics.Color;
 import android.test.suitebuilder.annotation.MediumTest;
 import android.view.View;
 
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
 import java.util.ArrayList;
 import java.util.List;
 
-import static android.support.v7.widget.LinearLayoutManager.HORIZONTAL;
-import static android.support.v7.widget.LinearLayoutManager.VERTICAL;
-import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
-import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
-import static org.hamcrest.MatcherAssert.assertThat;
-import static android.support.v7.widget.BaseWrapContentTest.WrapContentConfig;
-import static android.support.v7.widget.GridLayoutManagerTest.Config;
-import static org.hamcrest.CoreMatchers.*;
-import static android.view.View.MeasureSpec.UNSPECIFIED;
-import static android.view.View.MeasureSpec.AT_MOST;
-import static android.view.View.MeasureSpec.EXACTLY;
-
 @RunWith(Parameterized.class)
 @MediumTest
 public class GridLayoutManagerWrapContentWithAspectRatioTest
         extends BaseWrapContentWithAspectRatioTest {
 
-    @Parameterized.Parameters(name = "{0} {1} {2}")
+    @Parameterized.Parameters(name = "{0},{1},{2}")
     public static List<Object[]> params() {
         List<Object[]> params = new ArrayList<>();
         for (int orientation : new int[]{VERTICAL, HORIZONTAL}) {
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/LinearLayoutManagerCacheTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/LinearLayoutManagerCacheTest.java
index cacc9f4..451d15e 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/LinearLayoutManagerCacheTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/LinearLayoutManagerCacheTest.java
@@ -16,10 +16,14 @@
 
 package android.support.v7.widget;
 
+import static android.support.v7.widget.LinearLayoutManager.HORIZONTAL;
+import static android.support.v7.widget.LinearLayoutManager.VERTICAL;
+
+import static org.junit.Assert.assertEquals;
+
 import android.os.Build;
 import android.support.test.filters.SdkSuppress;
 import android.test.suitebuilder.annotation.MediumTest;
-import android.widget.FrameLayout;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -29,10 +33,6 @@
 import java.util.List;
 import java.util.concurrent.TimeUnit;
 
-import static android.support.v7.widget.LinearLayoutManager.HORIZONTAL;
-import static android.support.v7.widget.LinearLayoutManager.VERTICAL;
-import static org.junit.Assert.assertEquals;
-
 @RunWith(Parameterized.class)
 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.LOLLIPOP)
 public class LinearLayoutManagerCacheTest extends BaseLinearLayoutManagerTest {
@@ -47,7 +47,7 @@
         mDy = dy;
     }
 
-    @Parameterized.Parameters(name = "config:{0}, dx:{1}, dy:{2}")
+    @Parameterized.Parameters(name = "config:{0},dx:{1},dy:{2}")
     public static List<Object[]> getParams() {
         List<Object[]> result = new ArrayList<>();
         List<Config> configs = createBaseVariations();
@@ -89,10 +89,10 @@
                 @Override
                 public void run() {
                     mRecyclerView.mRecycler.recycleAndClearCachedViews();
-                    mRecyclerView.mViewPrefetcher.postFromTraversal(mDx, mDy);
+                    mRecyclerView.mGapWorker.postFromTraversal(mRecyclerView, mDx, mDy);
 
                     // Lie about post time, so prefetch executes even if it is delayed
-                    mRecyclerView.mViewPrefetcher.mPostTimeNanos += TimeUnit.SECONDS.toNanos(5);
+                    mRecyclerView.mGapWorker.mPostTimeNs += TimeUnit.SECONDS.toNanos(5);
                 }
             });
             mLayoutManager.waitForPrefetch(1);
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/LinearLayoutManagerPrepareForDropTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/LinearLayoutManagerPrepareForDropTest.java
index 27c93fc..453ac8a 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/LinearLayoutManagerPrepareForDropTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/LinearLayoutManagerPrepareForDropTest.java
@@ -44,7 +44,7 @@
         mSelectTargetChildren = selectTargetChildren;
     }
 
-    @Parameterized.Parameters(name = "{0}_{1}")
+    @Parameterized.Parameters(name = "{0},selectTargetChildren:{1}")
     public static Iterable<Object[]> params() {
         SelectTargetChildren[] selectors
                 = new SelectTargetChildren[]{
@@ -53,36 +53,60 @@
                     public int[] selectTargetChildren(int childCount) {
                         return new int[]{1, 0};
                     }
+                    @Override
+                    public String toString() {
+                        return "{1,0}";
+                    }
                 },
                 new SelectTargetChildren() {
                     @Override
                     public int[] selectTargetChildren(int childCount) {
                         return new int[]{0, 1};
                     }
+                    @Override
+                    public String toString() {
+                        return "{0,1}";
+                    }
                 },
                 new SelectTargetChildren() {
                     @Override
                     public int[] selectTargetChildren(int childCount) {
                         return new int[]{childCount - 1, childCount - 2};
                     }
+                    @Override
+                    public String toString() {
+                        return "{childCount-1,childCount-2}";
+                    }
                 },
                 new SelectTargetChildren() {
                     @Override
                     public int[] selectTargetChildren(int childCount) {
                         return new int[]{childCount - 2, childCount - 1};
                     }
+                    @Override
+                    public String toString() {
+                        return "{childCount-2,childCount-1}";
+                    }
                 },
                 new SelectTargetChildren() {
                     @Override
                     public int[] selectTargetChildren(int childCount) {
                         return new int[]{childCount / 2, childCount / 2 + 1};
                     }
+                    @Override
+                    public String toString() {
+                        return "{childCount/2,childCount/2+1}";
+                    }
                 },
                 new SelectTargetChildren() {
                     @Override
                     public int[] selectTargetChildren(int childCount) {
                         return new int[]{childCount / 2 + 1, childCount / 2};
                     }
+                    @Override
+                    public String toString() {
+                        return "{childCount/2+1,childCount/2}";
+                    }
                 }
         };
         List<Object[]> variations = new ArrayList<>();
@@ -166,7 +190,6 @@
     }
 
     protected interface SelectTargetChildren {
-
         int[] selectTargetChildren(int childCount);
     }
 }
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/LinearLayoutManagerSavedStateTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/LinearLayoutManagerSavedStateTest.java
index 5fcd33c..850dd98 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/LinearLayoutManagerSavedStateTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/LinearLayoutManagerSavedStateTest.java
@@ -16,9 +16,7 @@
 
 package android.support.v7.widget;
 
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
+import static org.junit.Assert.assertEquals;
 
 import android.graphics.Rect;
 import android.os.Parcel;
@@ -27,11 +25,14 @@
 import android.test.suitebuilder.annotation.LargeTest;
 import android.util.Log;
 
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
 import java.util.UUID;
-import static org.junit.Assert.*;
 
 @RunWith(Parameterized.class)
 @LargeTest
@@ -76,8 +77,8 @@
         };
     }
 
-    @Parameterized.Parameters(name = "{0}_waitForLayout:{1}_loadDataAfterRestore:{2}"
-            + "_postLayout:{3}_postRestore:{4}")
+    @Parameterized.Parameters(name = "{0},waitForLayout:{1},loadDataAfterRestore:{2}"
+            + ",postLayout:{3},postRestore:{4}")
     public static Iterable<Object[]> params()
             throws IllegalAccessException, CloneNotSupportedException, NoSuchFieldException {
         PostLayoutRunnable[] postLayoutOptions = new PostLayoutRunnable[]{
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/LinearLayoutManagerSnappingTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/LinearLayoutManagerSnappingTest.java
index ae19fc1..61492e8 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/LinearLayoutManagerSnappingTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/LinearLayoutManagerSnappingTest.java
@@ -16,24 +16,23 @@
 
 package android.support.v7.widget;
 
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNotSame;
+import static junit.framework.Assert.assertSame;
+import static junit.framework.Assert.assertTrue;
 
 import android.support.annotation.Nullable;
 import android.test.suitebuilder.annotation.MediumTest;
 import android.view.View;
 
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.List;
 import java.util.concurrent.atomic.AtomicBoolean;
 
-import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertNotSame;
-import static junit.framework.Assert.assertSame;
-import static junit.framework.Assert.assertTrue;
-
 @RunWith(Parameterized.class)
 public class LinearLayoutManagerSnappingTest extends BaseLinearLayoutManagerTest {
 
@@ -45,7 +44,7 @@
         mReverseScroll = reverseScroll;
     }
 
-    @Parameterized.Parameters(name = "config:{0}, reverseScroll:{1}")
+    @Parameterized.Parameters(name = "config:{0},reverseScroll:{1}")
     public static List<Object[]> getParams() {
         List<Object[]> result = new ArrayList<>();
         List<Config> configs = createBaseVariations();
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/LinearLayoutManagerWrapContentWithAspectRatioTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/LinearLayoutManagerWrapContentWithAspectRatioTest.java
index 185aa4b..051ebeb 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/LinearLayoutManagerWrapContentWithAspectRatioTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/LinearLayoutManagerWrapContentWithAspectRatioTest.java
@@ -16,25 +16,26 @@
 
 package android.support.v7.widget;
 
-import org.hamcrest.CoreMatchers;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
+import static android.support.v7.widget.LinearLayoutManager.HORIZONTAL;
+import static android.support.v7.widget.LinearLayoutManager.VERTICAL;
+import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
+import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
+
+import static org.hamcrest.MatcherAssert.assertThat;
 
 import android.graphics.Color;
 import android.test.suitebuilder.annotation.MediumTest;
 import android.view.View;
 import android.view.ViewGroup;
 
+import org.hamcrest.CoreMatchers;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
 import java.util.ArrayList;
 import java.util.List;
 
-import static android.support.v7.widget.LinearLayoutManager.HORIZONTAL;
-import static android.support.v7.widget.LinearLayoutManager.VERTICAL;
-import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
-import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
-import static org.hamcrest.MatcherAssert.assertThat;
-
 @RunWith(Parameterized.class)
 @MediumTest
 public class LinearLayoutManagerWrapContentWithAspectRatioTest
@@ -52,7 +53,7 @@
         mRatio = ratio;
     }
 
-    @Parameterized.Parameters(name = "{0} {1} ratio:{2}")
+    @Parameterized.Parameters(name = "{0},{1},ratio:{2}")
     public static Iterable<Object[]> data() {
         List<Object[]> params = new ArrayList<>();
         for (float ratio : new float[]{.5f, 1f, 2f}) {
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/RecycledViewPoolTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/RecycledViewPoolTest.java
new file mode 100644
index 0000000..f6ba14a
--- /dev/null
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/RecycledViewPoolTest.java
@@ -0,0 +1,95 @@
+/*
+ * 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 android.support.v7.widget;
+
+import android.content.Context;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.view.View;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class RecycledViewPoolTest {
+    static class MockViewHolder extends RecyclerView.ViewHolder {
+        public MockViewHolder(Context context) {
+            super(new View(context));
+        }
+    }
+
+    private Context getContext() {
+        return InstrumentationRegistry.getContext();
+    }
+
+    @Test
+    public void construct() {
+        RecyclerView.RecycledViewPool pool = new RecyclerView.RecycledViewPool();
+        assertEquals(0, pool.getRecycledViewCount(0));
+        assertEquals(0, pool.size());
+    }
+
+    private RecyclerView.ViewHolder makeHolder(int viewType) {
+        RecyclerView.ViewHolder holder = new MockViewHolder(getContext());
+        holder.mItemViewType = viewType;
+        return holder;
+    }
+
+    @Test
+    public void put() {
+        RecyclerView.RecycledViewPool pool = new RecyclerView.RecycledViewPool();
+        pool.putRecycledView(makeHolder(0));
+        pool.putRecycledView(makeHolder(1));
+        pool.putRecycledView(makeHolder(2));
+        pool.putRecycledView(makeHolder(2));
+
+        assertEquals(1, pool.getRecycledViewCount(0));
+        assertEquals(1, pool.getRecycledViewCount(1));
+        assertEquals(2, pool.getRecycledViewCount(2));
+        assertEquals(0, pool.getRecycledViewCount(3));
+        assertEquals(4, pool.size());
+    }
+
+    @Test
+    public void putAndGet() {
+        RecyclerView.RecycledViewPool pool = new RecyclerView.RecycledViewPool();
+        pool.putRecycledView(makeHolder(3));
+        pool.putRecycledView(makeHolder(3));
+
+        assertEquals(2, pool.size());
+        assertEquals(2, pool.getRecycledViewCount(3));
+
+        RecyclerView.ViewHolder a = pool.getRecycledView(3);
+
+        assertNotNull(a);
+        assertEquals(1, pool.size());
+        assertEquals(1, pool.getRecycledViewCount(3));
+
+        RecyclerView.ViewHolder b = pool.getRecycledView(3);
+
+        assertNotNull(b);
+        assertNotEquals(a, b);
+        assertEquals(0, pool.size());
+        assertEquals(0, pool.getRecycledViewCount(3));
+    }
+}
\ No newline at end of file
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewAccessibilityTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewAccessibilityTest.java
index be0fc10..f57a59f 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewAccessibilityTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewAccessibilityTest.java
@@ -16,10 +16,12 @@
 
 package android.support.v7.widget;
 
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
 
+import android.os.Build;
 import android.support.v4.view.AccessibilityDelegateCompat;
 import android.support.v4.view.accessibility.AccessibilityEventCompat;
 import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
@@ -28,33 +30,34 @@
 import android.view.View;
 import android.view.accessibility.AccessibilityEvent;
 
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.List;
 import java.util.concurrent.atomic.AtomicBoolean;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-
 @MediumTest
 @RunWith(Parameterized.class)
 public class RecyclerViewAccessibilityTest extends BaseRecyclerViewInstrumentationTest {
-
-    final boolean verticalScrollBefore, horizontalScrollBefore, verticalScrollAfter,
-            horizontalScrollAfter;
+    private static final boolean SUPPORTS_COLLECTION_INFO =
+            Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
+    private final boolean mVerticalScrollBefore;
+    private final boolean mHorizontalScrollBefore;
+    private final boolean mVerticalScrollAfter;
+    private final boolean mHorizontalScrollAfter;
 
     public RecyclerViewAccessibilityTest(boolean verticalScrollBefore,
             boolean horizontalScrollBefore, boolean verticalScrollAfter,
             boolean horizontalScrollAfter) {
-        this.verticalScrollBefore = verticalScrollBefore;
-        this.horizontalScrollBefore = horizontalScrollBefore;
-        this.verticalScrollAfter = verticalScrollAfter;
-        this.horizontalScrollAfter = horizontalScrollAfter;
+        mVerticalScrollBefore = verticalScrollBefore;
+        mHorizontalScrollBefore = horizontalScrollBefore;
+        mVerticalScrollAfter = verticalScrollAfter;
+        mHorizontalScrollAfter = horizontalScrollAfter;
     }
 
-    @Parameterized.Parameters(name = "vBefore={0} vAfter={1} hBefore={2} hAfter={3}")
+    @Parameterized.Parameters(name = "vBefore={0},vAfter={1},hBefore={2},hAfter={3}")
     public static List<Object[]> getParams() {
         List<Object[]> params = new ArrayList<>();
         for (boolean vBefore : new boolean[]{true, false}) {
@@ -74,14 +77,14 @@
         final RecyclerView recyclerView = new RecyclerView(getActivity()) {
             //@Override
             public boolean canScrollHorizontally(int direction) {
-                return direction < 0 && horizontalScrollBefore ||
-                        direction > 0 && horizontalScrollAfter;
+                return direction < 0 && mHorizontalScrollBefore ||
+                        direction > 0 && mHorizontalScrollAfter;
             }
 
             //@Override
             public boolean canScrollVertically(int direction) {
-                return direction < 0 && verticalScrollBefore ||
-                        direction > 0 && verticalScrollAfter;
+                return direction < 0 && mVerticalScrollBefore ||
+                        direction > 0 && mVerticalScrollAfter;
             }
         };
         final TestAdapter adapter = new TestAdapter(10);
@@ -104,7 +107,7 @@
 
             @Override
             public boolean canScrollVertically() {
-                return verticalScrollAfter || verticalScrollBefore;
+                return mVerticalScrollAfter || mVerticalScrollBefore;
             }
 
             @Override
@@ -131,7 +134,7 @@
 
             @Override
             public boolean canScrollHorizontally() {
-                return horizontalScrollAfter || horizontalScrollBefore;
+                return mHorizontalScrollAfter || mHorizontalScrollBefore;
             }
         });
         setRecyclerView(recyclerView);
@@ -144,20 +147,22 @@
                 delegateCompat.onInitializeAccessibilityNodeInfo(recyclerView, info);
             }
         });
-        assertEquals(horizontalScrollAfter || horizontalScrollBefore
-                || verticalScrollAfter || verticalScrollBefore, info.isScrollable());
-        assertEquals(horizontalScrollBefore || verticalScrollBefore,
+        assertEquals(mHorizontalScrollAfter || mHorizontalScrollBefore
+                || mVerticalScrollAfter || mVerticalScrollBefore, info.isScrollable());
+        assertEquals(mHorizontalScrollBefore || mVerticalScrollBefore,
                 (info.getActions() & AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD) != 0);
-        assertEquals(horizontalScrollAfter || verticalScrollAfter,
+        assertEquals(mHorizontalScrollAfter || mVerticalScrollAfter,
                 (info.getActions() & AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD) != 0);
-        final AccessibilityNodeInfoCompat.CollectionInfoCompat collectionInfo = info
-                .getCollectionInfo();
-        assertNotNull(collectionInfo);
-        if (recyclerView.getLayoutManager().canScrollVertically()) {
-            assertEquals(adapter.getItemCount(), collectionInfo.getRowCount());
-        }
-        if (recyclerView.getLayoutManager().canScrollHorizontally()) {
-            assertEquals(adapter.getItemCount(), collectionInfo.getColumnCount());
+        if (SUPPORTS_COLLECTION_INFO) {
+            final AccessibilityNodeInfoCompat.CollectionInfoCompat collectionInfo = info
+                    .getCollectionInfo();
+            assertNotNull(collectionInfo);
+            if (recyclerView.getLayoutManager().canScrollVertically()) {
+                assertEquals(adapter.getItemCount(), collectionInfo.getRowCount());
+            }
+            if (recyclerView.getLayoutManager().canScrollHorizontally()) {
+                assertEquals(adapter.getItemCount(), collectionInfo.getColumnCount());
+            }
         }
 
         final AccessibilityEvent event = AccessibilityEvent.obtain();
@@ -169,34 +174,36 @@
         });
         final AccessibilityRecordCompat record = AccessibilityEventCompat
                 .asRecord(event);
-        assertEquals(record.isScrollable(), verticalScrollAfter || horizontalScrollAfter ||
-                verticalScrollBefore || horizontalScrollBefore);
+        assertEquals(record.isScrollable(), mVerticalScrollAfter || mHorizontalScrollAfter ||
+                mVerticalScrollBefore || mHorizontalScrollBefore);
         assertEquals(record.getItemCount(), adapter.getItemCount());
 
         getInstrumentation().waitForIdleSync();
-        for (int i = 0; i < mRecyclerView.getChildCount(); i++) {
-            final View view = mRecyclerView.getChildAt(i);
-            final AccessibilityNodeInfoCompat childInfo = AccessibilityNodeInfoCompat.obtain();
-            runTestOnUiThread(new Runnable() {
-                @Override
-                public void run() {
-                    delegateCompat.getItemDelegate().
-                            onInitializeAccessibilityNodeInfo(view, childInfo);
+        if (SUPPORTS_COLLECTION_INFO) {
+            for (int i = 0; i < mRecyclerView.getChildCount(); i++) {
+                final View view = mRecyclerView.getChildAt(i);
+                final AccessibilityNodeInfoCompat childInfo = AccessibilityNodeInfoCompat.obtain();
+                runTestOnUiThread(new Runnable() {
+                    @Override
+                    public void run() {
+                        delegateCompat.getItemDelegate().
+                                onInitializeAccessibilityNodeInfo(view, childInfo);
+                    }
+                });
+                final AccessibilityNodeInfoCompat.CollectionItemInfoCompat collectionItemInfo
+                        = childInfo.getCollectionItemInfo();
+                assertNotNull(collectionItemInfo);
+                if (recyclerView.getLayoutManager().canScrollHorizontally()) {
+                    assertEquals(i, collectionItemInfo.getColumnIndex());
+                } else {
+                    assertEquals(0, collectionItemInfo.getColumnIndex());
                 }
-            });
-            final AccessibilityNodeInfoCompat.CollectionItemInfoCompat collectionItemInfo
-                    = childInfo.getCollectionItemInfo();
-            assertNotNull(collectionItemInfo);
-            if (recyclerView.getLayoutManager().canScrollHorizontally()) {
-                assertEquals(i, collectionItemInfo.getColumnIndex());
-            } else {
-                assertEquals(0, collectionItemInfo.getColumnIndex());
-            }
 
-            if (recyclerView.getLayoutManager().canScrollVertically()) {
-                assertEquals(i, collectionItemInfo.getRowIndex());
-            } else {
-                assertEquals(0, collectionItemInfo.getRowIndex());
+                if (recyclerView.getLayoutManager().canScrollVertically()) {
+                    assertEquals(i, collectionItemInfo.getRowIndex());
+                } else {
+                    assertEquals(0, collectionItemInfo.getRowIndex());
+                }
             }
         }
 
@@ -212,8 +219,8 @@
         vScrolledBack.set(false);
         performAccessibilityAction(delegateCompat, recyclerView,
                 AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD);
-        assertEquals(horizontalScrollBefore, hScrolledBack.get());
-        assertEquals(verticalScrollBefore, vScrolledBack.get());
+        assertEquals(mHorizontalScrollBefore, hScrolledBack.get());
+        assertEquals(mVerticalScrollBefore, vScrolledBack.get());
         assertEquals(false, hScrolledFwd.get());
         assertEquals(false, vScrolledFwd.get());
 
@@ -225,8 +232,8 @@
                 AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD);
         assertEquals(false, hScrolledBack.get());
         assertEquals(false, vScrolledBack.get());
-        assertEquals(horizontalScrollAfter, hScrolledFwd.get());
-        assertEquals(verticalScrollAfter, vScrolledFwd.get());
+        assertEquals(mHorizontalScrollAfter, hScrolledFwd.get());
+        assertEquals(mVerticalScrollAfter, vScrolledFwd.get());
     }
 
     @Test
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewAnimationsTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewAnimationsTest.java
index 2ddbabf..40448c6 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewAnimationsTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewAnimationsTest.java
@@ -22,7 +22,9 @@
 import org.junit.runner.RunWith;
 
 import android.graphics.Rect;
+import android.os.Build;
 import android.support.annotation.NonNull;
+import android.support.test.filters.SdkSuppress;
 import android.support.test.runner.AndroidJUnit4;
 import android.support.v4.view.ViewCompat;
 import android.test.suitebuilder.annotation.MediumTest;
@@ -664,6 +666,7 @@
     }
 
     @Test
+    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.KITKAT)
     public void importantForAccessibilityWhileDetelingAuto() throws Throwable {
         runTestImportantForAccessibilityWhileDeteling(
                 ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_AUTO,
@@ -671,6 +674,7 @@
     }
 
     @Test
+    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.KITKAT)
     public void importantForAccessibilityWhileDetelingNo() throws Throwable {
         runTestImportantForAccessibilityWhileDeteling(
                 ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO,
@@ -678,6 +682,7 @@
     }
 
     @Test
+    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.KITKAT)
     public void importantForAccessibilityWhileDetelingNoHideDescandants() throws Throwable {
         runTestImportantForAccessibilityWhileDeteling(
                 ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS,
@@ -685,6 +690,7 @@
     }
 
     @Test
+    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.KITKAT)
     public void importantForAccessibilityWhileDetelingYes() throws Throwable {
         runTestImportantForAccessibilityWhileDeteling(
                 ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES,
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewBasicTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewBasicTest.java
index 97f9b92..fbe835d 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewBasicTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewBasicTest.java
@@ -38,6 +38,8 @@
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.animation.Interpolator;
+import android.view.animation.LinearInterpolator;
 import android.widget.TextView;
 
 import org.junit.Before;
@@ -349,6 +351,18 @@
                 loggingView.getOnSavedInstanceCnt());
     }
 
+    @Test
+    public void smoothScrollWithCustomInterpolator() {
+        mRecyclerView.setLayoutManager(new MockLayoutManager());
+        mRecyclerView.setAdapter(new MockAdapter(20));
+        Interpolator interpolator = new LinearInterpolator();
+        mRecyclerView.smoothScrollBy(0, 100, interpolator);
+        assertSame(interpolator, mRecyclerView.mViewFlinger.mInterpolator);
+
+        mRecyclerView.smoothScrollBy(0, -100);
+        assertSame(RecyclerView.sQuinticInterpolator, mRecyclerView.mViewFlinger.mInterpolator);
+    }
+
     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.LOLLIPOP)
     @Test
     public void prefetchChangesCacheSize() {
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewCacheTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewCacheTest.java
index f0225d3..e0bcb5d 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewCacheTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewCacheTest.java
@@ -49,13 +49,11 @@
 public class RecyclerViewCacheTest {
     RecyclerView mRecyclerView;
     RecyclerView.Recycler mRecycler;
-    RecyclerView.ViewPrefetcher mViewPrefetcher;
 
     @Before
     public void setUp() throws Exception {
         mRecyclerView = new RecyclerView(getContext());
         mRecycler = mRecyclerView.mRecycler;
-        mViewPrefetcher = mRecyclerView.mViewPrefetcher;
     }
 
     private Context getContext() {
@@ -160,8 +158,8 @@
         mRecyclerView.measure(View.MeasureSpec.AT_MOST | 320, View.MeasureSpec.AT_MOST | 320);
         mRecyclerView.layout(0, 0, 320, 320);
 
-        mViewPrefetcher.mItemPrefetchArray = new int[] { 0, 1, 2 };
-        mRecycler.prefetch(mViewPrefetcher.mItemPrefetchArray, 3);
+        mRecyclerView.mPrefetchArray = new int[] { 0, 1, 2 };
+        mRecycler.prefetch(mRecyclerView.mPrefetchArray, 3);
         verifyCacheContainsPositions(0, 1, 2);
 
         // further views recycled, as though from scrolling, shouldn't evict prefetched views:
@@ -218,10 +216,10 @@
         assertTrue(mRecycler.mCachedViews.isEmpty());
 
         // rows 0, 1, and 2 are all attached and visible. Prefetch row 3:
-        mViewPrefetcher.mItemPrefetchArray = new int[] {-1, -1, -1};
+        mRecyclerView.mPrefetchArray = new int[] {-1, -1, -1};
         int viewCount = mRecyclerView.getLayoutManager().gatherPrefetchIndices(0, 1,
-                mRecyclerView.mState, mViewPrefetcher.mItemPrefetchArray);
-        mRecycler.prefetch(mViewPrefetcher.mItemPrefetchArray, viewCount);
+                mRecyclerView.mState, mRecyclerView.mPrefetchArray);
+        mRecycler.prefetch(mRecyclerView.mPrefetchArray, viewCount);
 
         // row 3 is cached:
         verifyCacheContainsPositions(9, 10, 11);
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewFocusRecoveryTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewFocusRecoveryTest.java
index 768f2f1..44d4a06 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewFocusRecoveryTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewFocusRecoveryTest.java
@@ -53,7 +53,7 @@
     private final boolean mFocusOnChild;
     private final boolean mDisableRecovery;
 
-    @Parameterized.Parameters(name = "focusSubChild:{0}, disable:{1}")
+    @Parameterized.Parameters(name = "focusSubChild:{0},disable:{1}")
     public static List<Object[]> getParams() {
         return Arrays.asList(
                 new Object[]{false, false},
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerCacheTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerCacheTest.java
index e11a576..dd4a099 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerCacheTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerCacheTest.java
@@ -16,6 +16,12 @@
 
 package android.support.v7.widget;
 
+import static android.support.v7.widget.LinearLayoutManager.HORIZONTAL;
+import static android.support.v7.widget.LinearLayoutManager.VERTICAL;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertTrue;
+
 import android.os.Build;
 import android.support.test.filters.SdkSuppress;
 import android.test.suitebuilder.annotation.MediumTest;
@@ -29,11 +35,6 @@
 import java.util.List;
 import java.util.concurrent.TimeUnit;
 
-import static android.support.v7.widget.LinearLayoutManager.HORIZONTAL;
-import static android.support.v7.widget.LinearLayoutManager.VERTICAL;
-import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertTrue;
-
 @RunWith(Parameterized.class)
 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.LOLLIPOP)
 public class StaggeredGridLayoutManagerCacheTest extends BaseStaggeredGridLayoutManagerTest {
@@ -48,7 +49,7 @@
         mDy = dy;
     }
 
-    @Parameterized.Parameters(name = "config:{0}, dx:{1}, dy: {2}")
+    @Parameterized.Parameters(name = "config:{0},dx:{1},dy:{2}")
     public static List<Object[]> getParams() {
         List<Object[]> result = new ArrayList<>();
         List<Config> configs = createBaseVariations();
@@ -113,10 +114,10 @@
                 @Override
                 public void run() {
                     mRecyclerView.mRecycler.recycleAndClearCachedViews();
-                    mRecyclerView.mViewPrefetcher.postFromTraversal(mDx, mDy);
+                    mRecyclerView.mGapWorker.postFromTraversal(mRecyclerView, mDx, mDy);
 
                     // Lie about post time, so prefetch executes even if it is delayed
-                    mRecyclerView.mViewPrefetcher.mPostTimeNanos += TimeUnit.SECONDS.toNanos(5);
+                    mRecyclerView.mGapWorker.mPostTimeNs += TimeUnit.SECONDS.toNanos(5);
                 }
             });
             mLayoutManager.waitForPrefetch(1);
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerGapTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerGapTest.java
index 1a4d225..dcb5e88 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerGapTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerGapTest.java
@@ -16,20 +16,21 @@
 
 package android.support.v7.widget;
 
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
+import static android.support.v7.widget.StaggeredGridLayoutManager.GAP_HANDLING_NONE;
+
+import static org.junit.Assert.assertNull;
 
 import android.graphics.Rect;
 import android.test.suitebuilder.annotation.MediumTest;
 
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
 
-import static android.support.v7.widget.StaggeredGridLayoutManager.GAP_HANDLING_NONE;
-import static org.junit.Assert.assertNull;
-
 @RunWith(Parameterized.class)
 @MediumTest
 public class StaggeredGridLayoutManagerGapTest extends BaseStaggeredGridLayoutManagerTest {
@@ -43,7 +44,7 @@
         mDeleteCount = deleteCount;
     }
 
-    @Parameterized.Parameters(name = "config={0} deletePos={1} deleteCount={2}")
+    @Parameterized.Parameters(name = "config={0},deletePos={1},deleteCount={2}")
     public static List<Object[]> getParams() throws CloneNotSupportedException {
         List<Config> variations = createBaseVariations();
         List<Object[]> params = new ArrayList<>();
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerSavedStateTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerSavedStateTest.java
index 3c9ab73..0a39a25 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerSavedStateTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerSavedStateTest.java
@@ -16,9 +16,7 @@
 
 package android.support.v7.widget;
 
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
+import static org.junit.Assert.assertEquals;
 
 import android.graphics.Rect;
 import android.os.Parcel;
@@ -26,13 +24,15 @@
 import android.test.suitebuilder.annotation.LargeTest;
 import android.util.Log;
 
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
 import java.util.UUID;
 
-import static org.junit.Assert.assertEquals;
-
 @RunWith(Parameterized.class)
 @LargeTest
 public class StaggeredGridLayoutManagerSavedStateTest extends BaseStaggeredGridLayoutManagerTest {
@@ -53,8 +53,8 @@
         }
     }
 
-    @Parameterized.Parameters(name = "config={0} waitForLayout={1} loadDataAfterRestore={2}"
-            + " postLayoutRunnable={3}")
+    @Parameterized.Parameters(name = "config={0},waitForLayout={1},loadDataAfterRestore={2}"
+            + ",postLayoutRunnable={3}")
     public static List<Object[]> getParams() throws CloneNotSupportedException {
         List<Config> variations = createBaseVariations();
 
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerSnappingTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerSnappingTest.java
index 51b469d..678b32b 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerSnappingTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerSnappingTest.java
@@ -16,10 +16,12 @@
 
 package android.support.v7.widget;
 
-import android.graphics.Rect;
-import android.support.annotation.NonNull;
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNotSame;
+import static junit.framework.Assert.assertSame;
+import static junit.framework.Assert.assertTrue;
+
 import android.support.annotation.Nullable;
-import android.support.v4.util.Pair;
 import android.test.suitebuilder.annotation.MediumTest;
 import android.view.View;
 
@@ -29,14 +31,8 @@
 
 import java.util.ArrayList;
 import java.util.List;
-import java.util.Map;
 import java.util.concurrent.atomic.AtomicBoolean;
 
-import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertNotSame;
-import static junit.framework.Assert.assertSame;
-import static junit.framework.Assert.assertTrue;
-
 @RunWith(Parameterized.class)
 public class StaggeredGridLayoutManagerSnappingTest extends BaseStaggeredGridLayoutManagerTest {
 
@@ -48,7 +44,7 @@
         mReverseScroll = reverseScroll;
     }
 
-    @Parameterized.Parameters(name = "config:{0}, reverseScroll:{1}")
+    @Parameterized.Parameters(name = "config:{0},reverseScroll:{1}")
     public static List<Object[]> getParams() {
         List<Object[]> result = new ArrayList<>();
         List<Config> configs = createBaseVariations();
diff --git a/v8/renderscript/Android.mk b/v8/renderscript/Android.mk
deleted file mode 100644
index 8815a0a..0000000
--- a/v8/renderscript/Android.mk
+++ /dev/null
@@ -1,38 +0,0 @@
-#
-# Copyright (C) 2012 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.
-#
-
-# Don't build the library in unbundled branches.
-ifeq (,$(TARGET_BUILD_APPS))
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_CFLAGS += -std=c++11
-
-LOCAL_MODULE := android-support-v8-renderscript
-LOCAL_SDK_VERSION := 23
-LOCAL_SRC_FILES := $(call all-java-files-under, java/src)
-LOCAL_SHARED_ANDROID_LIBRARIES := android-support-annotations
-
-LOCAL_JAVA_LANGUAGE_VERSION := 1.7
-include $(BUILD_STATIC_JAVA_LIBRARY)
-
-# TODO: Build the tests as an APK here
-
-include $(call all-makefiles-under, $(LOCAL_PATH))
-
-endif
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/Allocation.java b/v8/renderscript/java/src/android/support/v8/renderscript/Allocation.java
deleted file mode 100644
index 2384518..0000000
--- a/v8/renderscript/java/src/android/support/v8/renderscript/Allocation.java
+++ /dev/null
@@ -1,3032 +0,0 @@
-/*
- * Copyright (C) 2008-2012 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 android.support.v8.renderscript;
-
-import java.nio.ByteBuffer;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
-
-import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.graphics.Canvas;
-import android.util.Log;
-import android.view.Surface;
-
-/**
- * <p> This class provides the primary method through which data is passed to
- * and from RenderScript kernels.  An Allocation provides the backing store for
- * a given {@link android.support.v8.renderscript.Type}.  </p>
- *
- * <p>An Allocation also contains a set of usage flags that denote how the
- * Allocation could be used. For example, an Allocation may have usage flags
- * specifying that it can be used from a script as well as input to a {@link
- * android.support.v8.renderscript.Sampler}. A developer must synchronize
- * across these different usages using
- * {@link android.support.v8.renderscript.Allocation#syncAll} in
- * order to ensure that different users of the Allocation have a consistent view
- * of memory. For example, in the case where an Allocation is used as the output
- * of one kernel and as Sampler input in a later kernel, a developer must call
- * {@link #syncAll syncAll(Allocation.USAGE_SCRIPT)} prior to launching the
- * second kernel to ensure correctness.
- *
- * <p>An Allocation can be populated with the {@link #copyFrom} routines. For
- * more complex Element types, the {@link #copyFromUnchecked} methods can be
- * used to copy from byte arrays or similar constructs.</p>
- *
- * <div class="special reference">
- * <h3>Developer Guides</h3>
- * <p>For more information about creating an application that uses
- * RenderScript, read the
- * <a href="{@docRoot}guide/topics/renderscript/index.html">RenderScript</a>
- * developer guide.</p>
- * </div>
- **/
-public class Allocation extends BaseObj {
-    Type mType;
-    Bitmap mBitmap;
-    int mUsage;
-    int mSize;
-    Allocation mAdaptedAllocation;
-    ByteBuffer mByteBuffer = null;
-    long mByteBufferStride = 0;
-
-    boolean mConstrainedLOD;
-    boolean mConstrainedFace;
-    boolean mConstrainedY;
-    boolean mConstrainedZ;
-    boolean mReadAllowed = true;
-    boolean mWriteAllowed = true;
-    boolean mAutoPadding = false;
-    int mSelectedY;
-    int mSelectedZ;
-    int mSelectedLOD;
-    Type.CubemapFace mSelectedFace = Type.CubemapFace.POSITIVE_X;
-
-    int mCurrentDimX;
-    int mCurrentDimY;
-    int mCurrentDimZ;
-    int mCurrentCount;
-
-    private Element.DataType validateObjectIsPrimitiveArray(Object d, boolean checkType) {
-        final Class c = d.getClass();
-        if (!c.isArray()) {
-            throw new RSIllegalArgumentException("Object passed is not an array of primitives.");
-        }
-        final Class cmp = c.getComponentType();
-        if (!cmp.isPrimitive()) {
-            throw new RSIllegalArgumentException("Object passed is not an Array of primitives.");
-        }
-
-        if (cmp == Long.TYPE) {
-            if (checkType) {
-                validateIsInt64();
-                return mType.mElement.mType;
-            }
-            return Element.DataType.SIGNED_64;
-        }
-
-        if (cmp == Integer.TYPE) {
-            if (checkType) {
-                validateIsInt32();
-                return mType.mElement.mType;
-            }
-            return Element.DataType.SIGNED_32;
-        }
-
-        if (cmp == Short.TYPE) {
-            if (checkType) {
-                validateIsInt16();
-                return mType.mElement.mType;
-            }
-            return Element.DataType.SIGNED_16;
-        }
-
-        if (cmp == Byte.TYPE) {
-            if (checkType) {
-                validateIsInt8();
-                return mType.mElement.mType;
-            }
-            return Element.DataType.SIGNED_8;
-        }
-
-        if (cmp == Float.TYPE) {
-            if (checkType) {
-                validateIsFloat32();
-            }
-            return Element.DataType.FLOAT_32;
-        }
-
-        if (cmp == Double.TYPE) {
-            if (checkType) {
-                validateIsFloat64();
-            }
-            return Element.DataType.FLOAT_64;
-        }
-        return null;
-    }
-
-    /*
-     * Hold reference to the shared allocation in compat context
-     * for Incremental Support Lib.
-     */
-    long mIncCompatAllocation;
-    boolean mIncAllocDestroyed;
-    /**
-     * The usage of the Allocation.  These signal to RenderScript where to place
-     * the Allocation in memory.
-     *
-     */
-
-    /**
-     * The Allocation will be bound to and accessed by scripts.
-     */
-    public static final int USAGE_SCRIPT = 0x0001;
-
-    /**
-     * The Allocation will be used as a texture source by one or more graphics
-     * programs.
-     *
-     */
-    public static final int USAGE_GRAPHICS_TEXTURE = 0x0002;
-
-    /**
-     * The Allocation will be used as a {@link android.graphics.SurfaceTexture}
-     * consumer.  This usage will cause the Allocation to be created as
-     * read-only.
-     *
-     */
-    public static final int USAGE_IO_INPUT = 0x0020;
-
-    /**
-     * The Allocation will be used as a {@link android.graphics.SurfaceTexture}
-     * producer.  The dimensions and format of the {@link
-     * android.graphics.SurfaceTexture} will be forced to those of the
-     * Allocation.
-     *
-     */
-    public static final int USAGE_IO_OUTPUT = 0x0040;
-
-    /**
-     * The Allocation's backing store will be inherited from another object
-     * (usually a {@link android.graphics.Bitmap}); copying to or from the
-     * original source Bitmap will cause a synchronization rather than a full
-     * copy.  {@link #syncAll} may also be used to synchronize the Allocation
-     * and the source Bitmap.
-     *
-     * <p>This is set by default for allocations created with {@link
-     * #createFromBitmap} in API version 18 and higher.</p>
-     *
-     */
-    public static final int USAGE_SHARED = 0x0080;
-
-    /**
-     * Controls mipmap behavior when using the bitmap creation and update
-     * functions.
-     */
-    public enum MipmapControl {
-        /**
-         * No mipmaps will be generated and the type generated from the incoming
-         * bitmap will not contain additional LODs.
-         */
-        MIPMAP_NONE(0),
-
-        /**
-         * A full mipmap chain will be created in script memory.  The Type of
-         * the Allocation will contain a full mipmap chain.  On upload, the full
-         * chain will be transferred.
-         */
-        MIPMAP_FULL(1),
-
-        /**
-         * The Type of the Allocation will be the same as MIPMAP_NONE.  It will
-         * not contain mipmaps.  On upload, the allocation data will contain a
-         * full mipmap chain generated from the top level in script memory.
-         */
-        MIPMAP_ON_SYNC_TO_TEXTURE(2);
-
-        int mID;
-        MipmapControl(int id) {
-            mID = id;
-        }
-    }
-
-    /**
-     * Getter & Setter for the dummy allocation for Inc Support Lib.
-     *
-     */
-    public long getIncAllocID() {
-        return mIncCompatAllocation;
-    }
-    public void setIncAllocID(long id) {
-        mIncCompatAllocation = id;
-    }
-
-    private long getIDSafe() {
-        if (mAdaptedAllocation != null) {
-            return mAdaptedAllocation.getID(mRS);
-        }
-        return getID(mRS);
-    }
-
-
-   /**
-     * Get the {@link android.support.v8.renderscript.Element} of the {@link
-     * android.support.v8.renderscript.Type} of the Allocation.
-     *
-     * @return Element
-     *
-     */
-    public Element getElement() {
-        return mType.getElement();
-    }
-
-    /**
-     * Get the usage flags of the Allocation.
-     *
-     * @return usage this Allocation's set of the USAGE_* flags OR'd together
-     *
-     */
-    public int getUsage() {
-        return mUsage;
-    }
-
-    /**
-     * Specifies the mapping between the Allocation's cells and an array's elements
-     * when data is copied from the Allocation to the array, or vice-versa.
-     *
-     * Only applies to an Allocation whose Element is a vector of length 3 (such as
-     * {@link Element#U8_3} or {@link Element#RGB_888}). Enabling this feature may make
-     * copying data from the Allocation to an array or vice-versa less efficient.
-     *
-     * <p> Vec3 Element cells are stored in an Allocation as Vec4 Element cells with
-     * the same {@link android.support.v8.renderscript.Element.DataType}, with the fourth vector
-     * component treated as padding. When this feature is enabled, only the data components,
-     * i.e. the first 3 vector components of each cell, will be mapped between the array
-     * and the Allocation. When disabled, explicit mapping of the padding components
-     * is required, as described in the following example.
-     *
-     * <p> For example, when copying an integer array to an Allocation of two {@link
-     * Element#I32_3} cells using {@link #copyFrom(int[])}:
-     * <p> When disabled:
-     *     The array must have at least 8 integers, with the first 4 integers copied
-     *     to the first cell of the Allocation, and the next 4 integers copied to
-     *     the second cell. The 4th and 8th integers are mapped as the padding components.
-     *
-     * <p> When enabled:
-     *     The array just needs to have at least 6 integers, with the first 3 integers
-     *     copied to the the first cell as data components, and the next 3 copied to
-     *     the second cell. There is no mapping for the padding components.
-     *
-     * <p> Similarly, when copying a byte array to an Allocation of two {@link
-     * Element#I32_3} cells, using {@link #copyFromUnchecked(int[])}:
-     * <p> When disabled:
-     *     The array must have at least 32 bytes, with the first 16 bytes copied
-     *     to the first cell of the Allocation, and the next 16 bytes copied to
-     *     the second cell. The 13th-16th and 29th-32nd bytes are mapped as padding
-     *     components.
-     *
-     * <p> When enabled:
-     *     The array just needs to have at least 24 bytes, with the first 12 bytes copied
-     *     to the first cell of the Allocation, and the next 12 bytes copied to
-     *     the second cell. There is no mapping for the padding components.
-     *
-     * <p> Similar to copying data to an Allocation from an array, when copying data from an
-     * Allocation to an array, the padding components for Vec3 Element cells will not be
-     * copied/mapped to the array if AutoPadding is enabled.
-     *
-     * <p> Default: Disabled.
-     *
-     * @param useAutoPadding True: enable AutoPadding; False: disable AutoPadding
-     *
-     */
-    public void setAutoPadding(boolean useAutoPadding) {
-        mAutoPadding = useAutoPadding;
-    }
-
-    /**
-     * Get the size of the Allocation in bytes.
-     *
-     * @return size of the Allocation in bytes.
-     *
-     */
-    public int getBytesSize() {
-        if (mType.mDimYuv != 0) {
-            return (int)Math.ceil(mType.getCount() * mType.getElement().getBytesSize() * 1.5);
-        }
-        return mType.getCount() * mType.getElement().getBytesSize();
-    }
-
-    private void updateCacheInfo(Type t) {
-        mCurrentDimX = t.getX();
-        mCurrentDimY = t.getY();
-        mCurrentDimZ = t.getZ();
-        mCurrentCount = mCurrentDimX;
-        if (mCurrentDimY > 1) {
-            mCurrentCount *= mCurrentDimY;
-        }
-        if (mCurrentDimZ > 1) {
-            mCurrentCount *= mCurrentDimZ;
-        }
-    }
-
-    private void setBitmap(Bitmap b) {
-        mBitmap = b;
-    }
-
-    Allocation(long id, RenderScript rs, Type t, int usage) {
-        super(id, rs);
-        if ((usage & ~(USAGE_SCRIPT |
-                       USAGE_GRAPHICS_TEXTURE |
-                       USAGE_IO_INPUT |
-                       USAGE_IO_OUTPUT |
-                       USAGE_SHARED)) != 0) {
-            throw new RSIllegalArgumentException("Unknown usage specified.");
-        }
-
-        if ((usage & USAGE_IO_INPUT) != 0) {
-            mWriteAllowed = false;
-
-            if ((usage & ~(USAGE_IO_INPUT |
-                           USAGE_GRAPHICS_TEXTURE |
-                           USAGE_SCRIPT)) != 0) {
-                throw new RSIllegalArgumentException("Invalid usage combination.");
-            }
-        }
-
-        mType = t;
-        mUsage = usage;
-        mIncCompatAllocation = 0;
-        mIncAllocDestroyed = false;
-
-        if (t != null) {
-            // TODO: A3D doesn't have Type info during creation, so we can't
-            // calculate the size ahead of time. We can possibly add a method
-            // to update the size in the future if it seems reasonable.
-            mSize = mType.getCount() * mType.getElement().getBytesSize();
-            updateCacheInfo(t);
-        }
-        if (RenderScript.sUseGCHooks == true) {
-            try {
-                RenderScript.registerNativeAllocation.invoke(RenderScript.sRuntime, mSize);
-            } catch (Exception e) {
-                Log.e(RenderScript.LOG_TAG, "Couldn't invoke registerNativeAllocation:" + e);
-                throw new RSRuntimeException("Couldn't invoke registerNativeAllocation:" + e);
-            }
-        }
-    }
-
-    protected void finalize() throws Throwable {
-        if (RenderScript.sUseGCHooks == true) {
-            RenderScript.registerNativeFree.invoke(RenderScript.sRuntime, mSize);
-        }
-        super.finalize();
-    }
-
-    private void validateIsInt64() {
-        if ((mType.mElement.mType == Element.DataType.SIGNED_64) ||
-            (mType.mElement.mType == Element.DataType.UNSIGNED_64)) {
-            return;
-        }
-        throw new RSIllegalArgumentException(
-            "64 bit integer source does not match allocation type " + mType.mElement.mType);
-    }
-
-    private void validateIsInt32() {
-        if ((mType.mElement.mType == Element.DataType.SIGNED_32) ||
-            (mType.mElement.mType == Element.DataType.UNSIGNED_32)) {
-            return;
-        }
-        throw new RSIllegalArgumentException(
-            "32 bit integer source does not match allocation type " + mType.mElement.mType);
-    }
-
-    private void validateIsInt16() {
-        if ((mType.mElement.mType == Element.DataType.SIGNED_16) ||
-            (mType.mElement.mType == Element.DataType.UNSIGNED_16)) {
-            return;
-        }
-        throw new RSIllegalArgumentException(
-            "16 bit integer source does not match allocation type " + mType.mElement.mType);
-    }
-
-    private void validateIsInt8() {
-        if ((mType.mElement.mType == Element.DataType.SIGNED_8) ||
-            (mType.mElement.mType == Element.DataType.UNSIGNED_8)) {
-            return;
-        }
-        throw new RSIllegalArgumentException(
-            "8 bit integer source does not match allocation type " + mType.mElement.mType);
-    }
-
-    private void validateIsFloat32() {
-        if (mType.mElement.mType == Element.DataType.FLOAT_32) {
-            return;
-        }
-        throw new RSIllegalArgumentException(
-            "32 bit float source does not match allocation type " + mType.mElement.mType);
-    }
-
-    private void validateIsFloat64() {
-        if (mType.mElement.mType == Element.DataType.FLOAT_64) {
-            return;
-        }
-        throw new RSIllegalArgumentException(
-            "64 bit float source does not match allocation type " + mType.mElement.mType);
-    }
-
-    private void validateIsObject() {
-        if ((mType.mElement.mType == Element.DataType.RS_ELEMENT) ||
-            (mType.mElement.mType == Element.DataType.RS_TYPE) ||
-            (mType.mElement.mType == Element.DataType.RS_ALLOCATION) ||
-            (mType.mElement.mType == Element.DataType.RS_SAMPLER) ||
-            (mType.mElement.mType == Element.DataType.RS_SCRIPT)) {
-            return;
-        }
-        throw new RSIllegalArgumentException(
-            "Object source does not match allocation type " + mType.mElement.mType);
-    }
-
-    /**
-     * Get the {@link android.support.v8.renderscript.Type} of the Allocation.
-     *
-     * @return Type
-     *
-     */
-    public Type getType() {
-        return mType;
-    }
-
-    /**
-     * Propagate changes from one usage of the Allocation to the
-     * other usages of the Allocation.
-     *
-     */
-    public void syncAll(int srcLocation) {
-        switch (srcLocation) {
-        case USAGE_SCRIPT:
-        case USAGE_GRAPHICS_TEXTURE:
-            break;
-        default:
-            throw new RSIllegalArgumentException("Source must be exactly one usage type.");
-        }
-        mRS.validate();
-        mRS.nAllocationSyncAll(getIDSafe(), srcLocation);
-    }
-
-    /**
-     * Send a buffer to the output stream.  The contents of the Allocation will
-     * be undefined after this operation. This operation is only valid if {@link
-     * #USAGE_IO_OUTPUT} is set on the Allocation.
-     *
-     *
-     */
-    public void ioSend() {
-        if ((mUsage & USAGE_IO_OUTPUT) == 0) {
-            throw new RSIllegalArgumentException(
-                "Can only send buffer if IO_OUTPUT usage specified.");
-        }
-        mRS.validate();
-        mRS.nAllocationIoSend(getID(mRS));
-    }
-
-    /**
-     * Delete once code is updated.
-     */
-    public void ioSendOutput() {
-        ioSend();
-    }
-    /**
-     * Gets or creates a ByteBuffer that contains the raw data of the current Allocation.
-     * <p> If the Allocation is created with USAGE_IO_INPUT, the returned ByteBuffer
-     * would contain the up-to-date data as READ ONLY.
-     * For a 2D or 3D Allocation, the raw data maybe padded so that each row of
-     * the Allocation has certain alignment. The size of each row including padding,
-     * called stride, can be queried using the {@link #getStride()} method.
-     *
-     * Note: Operating on the ByteBuffer of a destroyed Allocation will triger errors.
-     *       The ByteBuffer will be Read-Only for devices before Lollopop (API 21).
-     *
-     * @return ByteBuffer The ByteBuffer associated with raw data pointer of the Allocation.
-     */
-    public ByteBuffer getByteBuffer() {
-        int xBytesSize = mType.getX() * mType.getElement().getBytesSize();
-        // When running on devices before L, we need to construct the ByteBuffer
-        // and explicitly copy the data from the allocation to it.
-        if (mRS.getDispatchAPILevel() < 21) {
-            byte[] data = null;
-            if (mType.getZ() > 0) {
-                // TODO: add support for 3D allocations.
-                return null;
-            } else if (mType.getY() > 0) {
-                // 2D Allocation
-                data = new byte[xBytesSize * mType.getY()];
-                copy2DRangeToUnchecked(0, 0, mType.getX(), mType.getY(), data,
-                                       Element.DataType.SIGNED_8, xBytesSize * mType.getY());
-            } else {
-                // 1D Allocation
-                data = new byte[xBytesSize];
-                copy1DRangeToUnchecked(0, mType.getX(), data);
-            }
-            ByteBuffer bBuffer = ByteBuffer.wrap(data).asReadOnlyBuffer();
-            mByteBufferStride = xBytesSize;
-            return bBuffer;
-        }
-        // Create a new ByteBuffer if it is not initialized or using IO_INPUT.
-        if (mByteBuffer == null || (mUsage & USAGE_IO_INPUT) != 0) {
-            mByteBuffer = mRS.nAllocationGetByteBuffer(getID(mRS), xBytesSize, mType.getY(), mType.getZ());
-        }
-        return mByteBuffer;
-    }
-
-    /**
-     * Gets the stride of the Allocation.
-     * For a 2D or 3D Allocation, the raw data maybe padded so that each row of
-     * the Allocation has certain alignment. The size of each row including such
-     * padding is called stride.
-     *
-     * @return the stride. For 1D Allocation, the stride will be the number of
-     *         bytes of this Allocation. For 2D and 3D Allocations, the stride
-     *         will be the stride in X dimension measuring in bytes.
-     */
-    public long getStride() {
-        if (mByteBufferStride ==0) {
-            if (mRS.getDispatchAPILevel() > 21) {
-                mByteBufferStride = mRS.nAllocationGetStride(getID(mRS));
-            } else {
-                mByteBufferStride = mType.getX() * mType.getElement().getBytesSize();
-            }
-        }
-        return mByteBufferStride;
-    }
-
-    /**
-     * Receive the latest input into the Allocation. This operation
-     * is only valid if {@link #USAGE_IO_INPUT} is set on the Allocation.
-     *
-     */
-    public void ioReceive() {
-        if ((mUsage & USAGE_IO_INPUT) == 0) {
-            throw new RSIllegalArgumentException(
-                "Can only receive if IO_INPUT usage specified.");
-        }
-        mRS.validate();
-        mRS.nAllocationIoReceive(getID(mRS));
-    }
-
-    /**
-     * Copy an array of RS objects to the Allocation.
-     *
-     * @param d Source array.
-     */
-    public void copyFrom(BaseObj[] d) {
-        mRS.validate();
-        validateIsObject();
-        if (d.length != mCurrentCount) {
-            throw new RSIllegalArgumentException("Array size mismatch, allocation sizeX = " +
-                                                 mCurrentCount + ", array length = " + d.length);
-        }
-
-        if (RenderScript.sPointerSize == 8) {
-            long i[] = new long[d.length * 4];
-            for (int ct=0; ct < d.length; ct++) {
-                i[ct * 4] = d[ct].getID(mRS);
-            }
-            copy1DRangeFromUnchecked(0, mCurrentCount, i);
-        } else {
-            int i[] = new int[d.length];
-            for (int ct=0; ct < d.length; ct++) {
-                i[ct] = (int)d[ct].getID(mRS);
-            }
-            copy1DRangeFromUnchecked(0, mCurrentCount, i);
-        }
-    }
-
-    private void validateBitmapFormat(Bitmap b) {
-        Bitmap.Config bc = b.getConfig();
-        if (bc == null) {
-            throw new RSIllegalArgumentException("Bitmap has an unsupported format for this operation");
-        }
-        switch (bc) {
-        case ALPHA_8:
-            if (mType.getElement().mKind != Element.DataKind.PIXEL_A) {
-                throw new RSIllegalArgumentException("Allocation kind is " +
-                                                     mType.getElement().mKind + ", type " +
-                                                     mType.getElement().mType +
-                                                     " of " + mType.getElement().getBytesSize() +
-                                                     " bytes, passed bitmap was " + bc);
-            }
-            break;
-        case ARGB_8888:
-            if ((mType.getElement().mKind != Element.DataKind.PIXEL_RGBA) ||
-                (mType.getElement().getBytesSize() != 4)) {
-                throw new RSIllegalArgumentException("Allocation kind is " +
-                                                     mType.getElement().mKind + ", type " +
-                                                     mType.getElement().mType +
-                                                     " of " + mType.getElement().getBytesSize() +
-                                                     " bytes, passed bitmap was " + bc);
-            }
-            break;
-        case RGB_565:
-            if ((mType.getElement().mKind != Element.DataKind.PIXEL_RGB) ||
-                (mType.getElement().getBytesSize() != 2)) {
-                throw new RSIllegalArgumentException("Allocation kind is " +
-                                                     mType.getElement().mKind + ", type " +
-                                                     mType.getElement().mType +
-                                                     " of " + mType.getElement().getBytesSize() +
-                                                     " bytes, passed bitmap was " + bc);
-            }
-            break;
-        case ARGB_4444:
-            if ((mType.getElement().mKind != Element.DataKind.PIXEL_RGBA) ||
-                (mType.getElement().getBytesSize() != 2)) {
-                throw new RSIllegalArgumentException("Allocation kind is " +
-                                                     mType.getElement().mKind + ", type " +
-                                                     mType.getElement().mType +
-                                                     " of " + mType.getElement().getBytesSize() +
-                                                     " bytes, passed bitmap was " + bc);
-            }
-            break;
-
-        }
-    }
-
-    private void validateBitmapSize(Bitmap b) {
-        if((mCurrentDimX != b.getWidth()) || (mCurrentDimY != b.getHeight())) {
-            throw new RSIllegalArgumentException("Cannot update allocation from bitmap, sizes mismatch");
-        }
-    }
-
-    private void copyFromUnchecked(Object array, Element.DataType dt, int arrayLen) {
-        mRS.validate();
-        if (mCurrentDimZ > 0) {
-            copy3DRangeFromUnchecked(0, 0, 0, mCurrentDimX, mCurrentDimY, mCurrentDimZ, array, dt, arrayLen);
-        } else if (mCurrentDimY > 0) {
-            copy2DRangeFromUnchecked(0, 0, mCurrentDimX, mCurrentDimY, array, dt, arrayLen);
-        } else {
-            copy1DRangeFromUnchecked(0, mCurrentCount, array, dt, arrayLen);
-        }
-    }
-
-    /**
-     * Copy into this Allocation from an array. This method does not guarantee
-     * that the Allocation is compatible with the input buffer; it copies memory
-     * without reinterpretation.
-     *
-     * <p> If the Allocation does not have Vec3 Elements, then the size of the
-     * array in bytes must be at least the size of the Allocation {@link
-     * #getBytesSize getBytesSize()}.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is disabled, then the size of the array in bytes must be at least the size
-     * of the Allocation {@link #getBytesSize getBytesSize()}. The padding bytes for
-     * the cells must be part of the array.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is enabled, then the size of the array in bytes must be at least 3/4 the size
-     * of the Allocation {@link #getBytesSize getBytesSize()}. The padding bytes for
-     * the cells must not be part of the array.
-     *
-     * @param array The source array
-     */
-    public void copyFromUnchecked(Object array) {
-        copyFromUnchecked(array, validateObjectIsPrimitiveArray(array, false),
-                          java.lang.reflect.Array.getLength(array));
-    }
-
-    /**
-     * Copy into this Allocation from an array. This method does not guarantee
-     * that the Allocation is compatible with the input buffer; it copies memory
-     * without reinterpretation.
-     *
-     * <p> If the Allocation does not have Vec3 Elements, then the size of the
-     * array in bytes must be at least the size of the Allocation {@link
-     * #getBytesSize getBytesSize()}.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is disabled, then the size of the array in bytes must be at least the size
-     * of the Allocation {@link #getBytesSize getBytesSize()}. The padding bytes for
-     * the cells must be part of the array.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is enabled, then the size of the array in bytes must be at least 3/4 the size
-     * of the Allocation {@link #getBytesSize getBytesSize()}. The padding bytes for
-     * the cells must not be part of the array.
-     *
-     * @param d the source array
-     */
-    public void copyFromUnchecked(int[] d) {
-        copyFromUnchecked(d, Element.DataType.SIGNED_32, d.length);
-    }
-
-    /**
-     * Copy into this Allocation from an array. This method does not guarantee
-     * that the Allocation is compatible with the input buffer; it copies memory
-     * without reinterpretation.
-     *
-     * <p> If the Allocation does not have Vec3 Elements, then the size of the
-     * array in bytes must be at least the size of the Allocation {@link
-     * #getBytesSize getBytesSize()}.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is disabled, then the size of the array in bytes must be at least the size
-     * of the Allocation {@link #getBytesSize getBytesSize()}. The padding bytes for
-     * the cells must be part of the array.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is enabled, then the size of the array in bytes must be at least 3/4 the size
-     * of the Allocation {@link #getBytesSize getBytesSize()}. The padding bytes for
-     * the cells must not be part of the array.
-     *
-     * @param d the source array
-     */
-    public void copyFromUnchecked(short[] d) {
-        copyFromUnchecked(d, Element.DataType.SIGNED_16, d.length);
-    }
-
-    /**
-     * Copy into this Allocation from an array. This method does not guarantee
-     * that the Allocation is compatible with the input buffer; it copies memory
-     * without reinterpretation.
-     *
-     * <p> If the Allocation does not have Vec3 Elements, then the size of the
-     * array in bytes must be at least the size of the Allocation {@link
-     * #getBytesSize getBytesSize()}.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is disabled, then the size of the array in bytes must be at least the size
-     * of the Allocation {@link #getBytesSize getBytesSize()}. The padding bytes for
-     * the cells must be part of the array.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is enabled, then the size of the array in bytes must be at least 3/4 the size
-     * of the Allocation {@link #getBytesSize getBytesSize()}. The padding bytes for
-     * the cells must not be part of the array.
-     *
-     * @param d the source array
-     */
-    public void copyFromUnchecked(byte[] d) {
-        copyFromUnchecked(d, Element.DataType.SIGNED_8, d.length);
-    }
-
-    /**
-     * Copy into this Allocation from an array. This method does not guarantee
-     * that the Allocation is compatible with the input buffer; it copies memory
-     * without reinterpretation.
-     *
-     * <p> If the Allocation does not have Vec3 Elements, then the size of the
-     * array in bytes must be at least the size of the Allocation {@link
-     * #getBytesSize getBytesSize()}.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is disabled, then the size of the array in bytes must be at least the size
-     * of the Allocation {@link #getBytesSize getBytesSize()}. The padding bytes for
-     * the cells must be part of the array.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is enabled, then the size of the array in bytes must be at least 3/4 the size
-     * of the Allocation {@link #getBytesSize getBytesSize()}. The padding bytes for
-     * the cells must not be part of the array.
-     *
-     * @param d the source array
-     */
-    public void copyFromUnchecked(float[] d) {
-        copyFromUnchecked(d, Element.DataType.FLOAT_32, d.length);
-    }
-
-
-    /**
-     * Copy into this Allocation from an array.  This variant is type checked
-     * and will generate exceptions if the Allocation's {@link
-     * android.support.v8.renderscript.Element} does not match the array's
-     * primitive type.
-     *
-     * <p> If the Allocation does not have Vec3 Elements, then the size of the
-     * array in bytes must be at least the size of the Allocation {@link
-     * #getBytesSize getBytesSize()}.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is disabled, then the size of the array in bytes must be at least the size
-     * of the Allocation {@link #getBytesSize getBytesSize()}. The padding bytes for
-     * the cells must be part of the array.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is enabled, then the size of the array in bytes must be at least 3/4 the size
-     * of the Allocation {@link #getBytesSize getBytesSize()}. The padding bytes for
-     * the cells must not be part of the array.
-     *
-     * @param array The source array
-     */
-    public void copyFrom(Object array) {
-        copyFromUnchecked(array, validateObjectIsPrimitiveArray(array, true),
-                          java.lang.reflect.Array.getLength(array));
-    }
-
-    /**
-     * Copy into this Allocation from an array.  This variant is type checked
-     * and will generate exceptions if the Allocation's {@link
-     * android.support.v8.renderscript.Element} is not a 32 bit integer nor a vector of 32 bit
-     * integers {@link android.support.v8.renderscript.Element.DataType}.
-     *
-     * <p> If the Allocation does not have Vec3 Elements, then the size of the
-     * array in bytes must be at least the size of the Allocation {@link
-     * #getBytesSize getBytesSize()}.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is disabled, then the size of the array in bytes must be at least the size
-     * of the Allocation {@link #getBytesSize getBytesSize()}. The padding bytes for
-     * the cells must be part of the array.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is enabled, then the size of the array in bytes must be at least 3/4 the size
-     * of the Allocation {@link #getBytesSize getBytesSize()}. The padding bytes for
-     * the cells must not be part of the array.
-     *
-     * @param d the source array
-     */
-    public void copyFrom(int[] d) {
-        validateIsInt32();
-        copyFromUnchecked(d, Element.DataType.SIGNED_32, d.length);
-    }
-
-    /**
-     * Copy into this Allocation from an array.  This variant is type checked
-     * and will generate exceptions if the Allocation's {@link
-     * android.support.v8.renderscript.Element} is not a 16 bit integer nor a vector of 16 bit
-     * integers {@link android.support.v8.renderscript.Element.DataType}.
-     *
-     * <p> If the Allocation does not have Vec3 Elements, then the size of the
-     * array in bytes must be at least the size of the Allocation {@link
-     * #getBytesSize getBytesSize()}.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is disabled, then the size of the array in bytes must be at least the size
-     * of the Allocation {@link #getBytesSize getBytesSize()}. The padding bytes for
-     * the cells must be part of the array.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is enabled, then the size of the array in bytes must be at least 3/4 the size
-     * of the Allocation {@link #getBytesSize getBytesSize()}. The padding bytes for
-     * the cells must not be part of the array.
-     *
-     * @param d the source array
-     */
-    public void copyFrom(short[] d) {
-        validateIsInt16();
-        copyFromUnchecked(d, Element.DataType.SIGNED_16, d.length);
-    }
-
-    /**
-     * Copy into this Allocation from an array.  This variant is type checked
-     * and will generate exceptions if the Allocation's {@link
-     * android.support.v8.renderscript.Element} is not an 8 bit integer nor a vector of 8 bit
-     * integers {@link android.support.v8.renderscript.Element.DataType}.
-     *
-     * <p> If the Allocation does not have Vec3 Elements, then the size of the
-     * array in bytes must be at least the size of the Allocation {@link
-     * #getBytesSize getBytesSize()}.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is disabled, then the size of the array in bytes must be at least the size
-     * of the Allocation {@link #getBytesSize getBytesSize()}. The padding bytes for
-     * the cells must be part of the array.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is enabled, then the size of the array in bytes must be at least 3/4 the size
-     * of the Allocation {@link #getBytesSize getBytesSize()}. The padding bytes for
-     * the cells must not be part of the array.
-     *
-     * @param d the source array
-     */
-    public void copyFrom(byte[] d) {
-        validateIsInt8();
-        copyFromUnchecked(d, Element.DataType.SIGNED_8, d.length);
-    }
-
-    /**
-     * Copy into this Allocation from an array.  This variant is type checked
-     * and will generate exceptions if the Allocation's {@link
-     * android.support.v8.renderscript.Element} is neither a 32 bit float nor a vector of
-     * 32 bit floats {@link android.support.v8.renderscript.Element.DataType}.
-     *
-     * <p> If the Allocation does not have Vec3 Elements, then the size of the
-     * array in bytes must be at least the size of the Allocation {@link
-     * #getBytesSize getBytesSize()}.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is disabled, then the size of the array in bytes must be at least the size
-     * of the Allocation {@link #getBytesSize getBytesSize()}. The padding bytes for
-     * the cells must be part of the array.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is enabled, then the size of the array in bytes must be at least 3/4 the size
-     * of the Allocation {@link #getBytesSize getBytesSize()}. The padding bytes for
-     * the cells must not be part of the array.
-     *
-     * @param d the source array
-     */
-    public void copyFrom(float[] d) {
-        validateIsFloat32();
-        copyFromUnchecked(d, Element.DataType.FLOAT_32, d.length);
-    }
-
-    /**
-     * Copy into an Allocation from a {@link android.graphics.Bitmap}.  The
-     * height, width, and format of the bitmap must match the existing
-     * allocation.
-     *
-     * <p>If the {@link android.graphics.Bitmap} is the same as the {@link
-     * android.graphics.Bitmap} used to create the Allocation with {@link
-     * #createFromBitmap} and {@link #USAGE_SHARED} is set on the Allocation,
-     * this will synchronize the Allocation with the latest data from the {@link
-     * android.graphics.Bitmap}, potentially avoiding the actual copy.</p>
-     *
-     * @param b the source bitmap
-     */
-    public void copyFrom(Bitmap b) {
-        mRS.validate();
-        if (b.getConfig() == null) {
-            Bitmap newBitmap = Bitmap.createBitmap(b.getWidth(), b.getHeight(), Bitmap.Config.ARGB_8888);
-            Canvas c = new Canvas(newBitmap);
-            c.drawBitmap(b, 0, 0, null);
-            copyFrom(newBitmap);
-            return;
-        }
-        validateBitmapSize(b);
-        validateBitmapFormat(b);
-        mRS.nAllocationCopyFromBitmap(getID(mRS), b);
-    }
-
-    /**
-     * Copy an Allocation from an Allocation.  The types of both allocations
-     * must be identical.
-     *
-     * @param a the source allocation
-     */
-    public void copyFrom(Allocation a) {
-        mRS.validate();
-        if (!mType.equals(a.getType())) {
-            throw new RSIllegalArgumentException("Types of allocations must match.");
-        }
-        copy2DRangeFrom(0, 0, mCurrentDimX, mCurrentDimY, a, 0, 0);
-    }
-
-
-    /**
-     * This is only intended to be used by auto-generated code reflected from
-     * the RenderScript script files and should not be used by developers.
-     *
-     * @param xoff
-     * @param fp
-     */
-    public void setFromFieldPacker(int xoff, FieldPacker fp) {
-        mRS.validate();
-        int eSize = mType.mElement.getBytesSize();
-        final byte[] data = fp.getData();
-        int data_length = fp.getPos();
-
-        int count = data_length / eSize;
-        if ((eSize * count) != data_length) {
-            throw new RSIllegalArgumentException("Field packer length " + data_length +
-                                               " not divisible by element size " + eSize + ".");
-        }
-        copy1DRangeFromUnchecked(xoff, count, data);
-    }
-
-    /**
-     * This is only intended to be used by auto-generated code reflected from
-     * the RenderScript script files.
-     *
-     * @param xoff
-     * @param component_number
-     * @param fp
-     */
-    public void setFromFieldPacker(int xoff, int component_number, FieldPacker fp) {
-        mRS.validate();
-        if (component_number >= mType.mElement.mElements.length) {
-            throw new RSIllegalArgumentException("Component_number " + component_number + " out of range.");
-        }
-        if(xoff < 0) {
-            throw new RSIllegalArgumentException("Offset must be >= 0.");
-        }
-
-        final byte[] data = fp.getData();
-        int data_length = fp.getPos();
-        int eSize = mType.mElement.mElements[component_number].getBytesSize();
-        eSize *= mType.mElement.mArraySizes[component_number];
-
-        if (data_length != eSize) {
-            throw new RSIllegalArgumentException("Field packer sizelength " + data_length +
-                                               " does not match component size " + eSize + ".");
-        }
-
-        mRS.nAllocationElementData1D(getIDSafe(), xoff, mSelectedLOD,
-                                     component_number, data, data_length);
-    }
-
-    /**
-     * @hide
-     * This is only intended to be used by auto-generated code reflected from
-     * the RenderScript script files.
-     *
-     * @param xoff
-     * @param yoff
-     * @param zoff
-     * @param component_number
-     * @param fp
-     */
-    /*
-    public void setFromFieldPacker(int xoff, int yoff, int zoff, int component_number, FieldPacker fp) {
-        mRS.validate();
-        if (component_number >= mType.mElement.mElements.length) {
-            throw new RSIllegalArgumentException("Component_number " + component_number + " out of range.");
-        }
-        if(xoff < 0) {
-            throw new RSIllegalArgumentException("Offset x must be >= 0.");
-        }
-        if(yoff < 0) {
-            throw new RSIllegalArgumentException("Offset y must be >= 0.");
-        }
-        if(zoff < 0) {
-            throw new RSIllegalArgumentException("Offset z must be >= 0.");
-        }
-
-        final byte[] data = fp.getData();
-        int data_length = fp.getPos();
-        int eSize = mType.mElement.mElements[component_number].getBytesSize();
-        eSize *= mType.mElement.mArraySizes[component_number];
-
-        if (data_length != eSize) {
-            throw new RSIllegalArgumentException("Field packer sizelength " + data_length +
-                                               " does not match component size " + eSize + ".");
-        }
-
-        mRS.nAllocationElementData(getIDSafe(), xoff, yoff, zoff, mSelectedLOD,
-                                   component_number, data, data_length);
-    }
-    */
-
-    private void data1DChecks(int off, int count, int len, int dataSize, boolean usePadding) {
-        mRS.validate();
-        if(off < 0) {
-            throw new RSIllegalArgumentException("Offset must be >= 0.");
-        }
-        if(count < 1) {
-            throw new RSIllegalArgumentException("Count must be >= 1.");
-        }
-        if((off + count) > mCurrentCount) {
-            throw new RSIllegalArgumentException("Overflow, Available count " + mCurrentCount +
-                                               ", got " + count + " at offset " + off + ".");
-        }
-        if(usePadding) {
-            if(len < dataSize / 4 * 3) {
-                throw new RSIllegalArgumentException("Array too small for allocation type.");
-            }
-        } else {
-            if(len < dataSize) {
-                throw new RSIllegalArgumentException("Array too small for allocation type.");
-            }
-        }
-    }
-
-    /**
-     * Generate a mipmap chain. This is only valid if the Type of the Allocation
-     * includes mipmaps.
-     *
-     * <p>This function will generate a complete set of mipmaps from the top
-     * level LOD and place them into the script memory space.</p>
-     *
-     * <p>If the Allocation is also using other memory spaces, a call to {@link
-     * #syncAll syncAll(Allocation.USAGE_SCRIPT)} is required.</p>
-     */
-    public void generateMipmaps() {
-        mRS.nAllocationGenerateMipmaps(getID(mRS));
-    }
-
-    private void copy1DRangeFromUnchecked(int off, int count, Object array,
-                                          Element.DataType dt, int arrayLen) {
-        final int dataSize = mType.mElement.getBytesSize() * count;
-        // AutoPadding for Vec3 Element
-        boolean usePadding = false;
-        if (mAutoPadding && (mType.getElement().getVectorSize() == 3)) {
-            usePadding = true;
-        }
-        data1DChecks(off, count, arrayLen * dt.mSize, dataSize, usePadding);
-        mRS.nAllocationData1D(getIDSafe(), off, mSelectedLOD, count, array, dataSize, dt,
-                              mType.mElement.mType.mSize, usePadding);
-    }
-
-    /**
-     * Copy an array into a 1D region of this Allocation.  This method does not
-     * guarantee that the Allocation is compatible with the input buffer.
-     *
-     * <p> The size of the region is: count * {@link #getElement}.{@link
-     * Element#getBytesSize}.
-     *
-     * <p> If the Allocation does not have Vec3 Elements, then the size of the
-     * array in bytes must be at least the size of the region.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is disabled, then the size of the array in bytes must be at least the size
-     * of the region. The padding bytes for the cells must be part of the array.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is enabled, then the size of the array in bytes must be at least 3/4 the size
-     * of the region. The padding bytes for the cells must not be part of the array.
-     *
-     * @param off The offset of the first element to be copied.
-     * @param count The number of elements to be copied.
-     * @param array The source array
-     */
-    public void copy1DRangeFromUnchecked(int off, int count, Object array) {
-        copy1DRangeFromUnchecked(off, count, array,
-                                 validateObjectIsPrimitiveArray(array, false),
-                                 java.lang.reflect.Array.getLength(array));
-    }
-
-    /**
-     * Copy an array into a 1D region of this Allocation.  This method does not
-     * guarantee that the Allocation is compatible with the input buffer.
-     *
-     * <p> The size of the region is: count * {@link #getElement}.{@link
-     * Element#getBytesSize}.
-     *
-     * <p> If the Allocation does not have Vec3 Elements, then the size of the
-     * array in bytes must be at least the size of the region.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is disabled, then the size of the array in bytes must be at least the size
-     * of the region. The padding bytes for the cells must be part of the array.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is enabled, then the size of the array in bytes must be at least 3/4 the size
-     * of the region. The padding bytes for the cells must not be part of the array.
-     *
-     * @param off The offset of the first element to be copied.
-     * @param count The number of elements to be copied.
-     * @param d the source array
-     */
-    public void copy1DRangeFromUnchecked(int off, int count, int[] d) {
-        copy1DRangeFromUnchecked(off, count, (Object)d, Element.DataType.SIGNED_32, d.length);
-    }
-
-    /**
-     * Copy an array into a 1D region of this Allocation.  This method does not
-     * guarantee that the Allocation is compatible with the input buffer.
-     *
-     * <p> The size of the region is: count * {@link #getElement}.{@link
-     * Element#getBytesSize}.
-     *
-     * <p> If the Allocation does not have Vec3 Elements, then the size of the
-     * array in bytes must be at least the size of the region.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is disabled, then the size of the array in bytes must be at least the size
-     * of the region. The padding bytes for the cells must be part of the array.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is enabled, then the size of the array in bytes must be at least 3/4 the size
-     * of the region. The padding bytes for the cells must not be part of the array.
-     *
-     * @param off The offset of the first element to be copied.
-     * @param count The number of elements to be copied.
-     * @param d the source array
-     */
-    public void copy1DRangeFromUnchecked(int off, int count, short[] d) {
-        copy1DRangeFromUnchecked(off, count, (Object)d, Element.DataType.SIGNED_16, d.length);
-    }
-
-    /**
-     * Copy an array into a 1D region of this Allocation.  This method does not
-     * guarantee that the Allocation is compatible with the input buffer.
-     *
-     * <p> The size of the region is: count * {@link #getElement}.{@link
-     * Element#getBytesSize}.
-     *
-     * <p> If the Allocation does not have Vec3 Elements, then the size of the
-     * array in bytes must be at least the size of the region.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is disabled, then the size of the array in bytes must be at least the size
-     * of the region. The padding bytes for the cells must be part of the array.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is enabled, then the size of the array in bytes must be at least 3/4 the size
-     * of the region. The padding bytes for the cells must not be part of the array.
-     *
-     * @param off The offset of the first element to be copied.
-     * @param count The number of elements to be copied.
-     * @param d the source array
-     */
-    public void copy1DRangeFromUnchecked(int off, int count, byte[] d) {
-        copy1DRangeFromUnchecked(off, count, (Object)d, Element.DataType.SIGNED_8, d.length);
-    }
-
-    /**
-     * Copy an array into a 1D region of this Allocation.  This method does not
-     * guarantee that the Allocation is compatible with the input buffer.
-     *
-     * <p> The size of the region is: count * {@link #getElement}.{@link
-     * Element#getBytesSize}.
-     *
-     * <p> If the Allocation does not have Vec3 Elements, then the size of the
-     * array in bytes must be at least the size of the region.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is disabled, then the size of the array in bytes must be at least the size
-     * of the region. The padding bytes for the cells must be part of the array.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is enabled, then the size of the array in bytes must be at least 3/4 the size
-     * of the region. The padding bytes for the cells must not be part of the array.
-     *
-     * @param off The offset of the first element to be copied.
-     * @param count The number of elements to be copied.
-     * @param d the source array
-     */
-    public void copy1DRangeFromUnchecked(int off, int count, float[] d) {
-        copy1DRangeFromUnchecked(off, count, (Object)d, Element.DataType.FLOAT_32, d.length);
-    }
-
-
-    /**
-     * Copy an array into a 1D region of this Allocation.  This variant is type checked
-     * and will generate exceptions if the Allocation's {@link
-     * android.support.v8.renderscript.Element} does not match the component type
-     * of the array passed in.
-     *
-     * <p> The size of the region is: count * {@link #getElement}.{@link
-     * Element#getBytesSize}.
-     *
-     * <p> If the Allocation does not have Vec3 Elements, then the size of the
-     * array in bytes must be at least the size of the region.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is disabled, then the size of the array in bytes must be at least the size
-     * of the region. The padding bytes for the cells must be part of the array.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is enabled, then the size of the array in bytes must be at least 3/4 the size
-     * of the region. The padding bytes for the cells must not be part of the array.
-     *
-     * @param off The offset of the first element to be copied.
-     * @param count The number of elements to be copied.
-     * @param array The source array.
-     */
-    public void copy1DRangeFrom(int off, int count, Object array) {
-        copy1DRangeFromUnchecked(off, count, array,
-                                 validateObjectIsPrimitiveArray(array, true),
-                                 java.lang.reflect.Array.getLength(array));
-    }
-
-    /**
-     * Copy an array into a 1D region of this Allocation.  This variant is type checked
-     * and will generate exceptions if the Allocation's {@link
-     * android.support.v8.renderscript.Element} is not an 32 bit integer nor a vector of 32 bit
-     * integers {@link android.support.v8.renderscript.Element.DataType}.
-     *
-     * <p> The size of the region is: count * {@link #getElement}.{@link
-     * Element#getBytesSize}.
-     *
-     * <p> If the Allocation does not have Vec3 Elements, then the size of the
-     * array in bytes must be at least the size of the region.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is disabled, then the size of the array in bytes must be at least the size
-     * of the region. The padding bytes for the cells must be part of the array.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is enabled, then the size of the array in bytes must be at least 3/4 the size
-     * of the region. The padding bytes for the cells must not be part of the array.
-     *
-     * @param off The offset of the first element to be copied.
-     * @param count The number of elements to be copied.
-     * @param d the source array
-     */
-    public void copy1DRangeFrom(int off, int count, int[] d) {
-        validateIsInt32();
-        copy1DRangeFromUnchecked(off, count, d, Element.DataType.SIGNED_32, d.length);
-    }
-
-    /**
-     * Copy an array into a 1D region of this Allocation.  This variant is type checked
-     * and will generate exceptions if the Allocation's {@link
-     * android.support.v8.renderscript.Element} is not an 16 bit integer nor a vector of 16 bit
-     * integers {@link android.support.v8.renderscript.Element.DataType}.
-     *
-     * <p> The size of the region is: count * {@link #getElement}.{@link
-     * Element#getBytesSize}.
-     *
-     * <p> If the Allocation does not have Vec3 Elements, then the size of the
-     * array in bytes must be at least the size of the region.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is disabled, then the size of the array in bytes must be at least the size
-     * of the region. The padding bytes for the cells must be part of the array.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is enabled, then the size of the array in bytes must be at least 3/4 the size
-     * of the region. The padding bytes for the cells must not be part of the array.
-     *
-     * @param off The offset of the first element to be copied.
-     * @param count The number of elements to be copied.
-     * @param d the source array
-     */
-    public void copy1DRangeFrom(int off, int count, short[] d) {
-        validateIsInt16();
-        copy1DRangeFromUnchecked(off, count, d, Element.DataType.SIGNED_16, d.length);
-    }
-
-    /**
-     * Copy an array into a 1D region of this Allocation.  This variant is type checked
-     * and will generate exceptions if the Allocation's {@link
-     * android.support.v8.renderscript.Element} is not an 8 bit integer nor a vector of 8 bit
-     * integers {@link android.support.v8.renderscript.Element.DataType}.
-     *
-     * <p> The size of the region is: count * {@link #getElement}.{@link
-     * Element#getBytesSize}.
-     *
-     * <p> If the Allocation does not have Vec3 Elements, then the size of the
-     * array in bytes must be at least the size of the region.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is disabled, then the size of the array in bytes must be at least the size
-     * of the region. The padding bytes for the cells must be part of the array.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is enabled, then the size of the array in bytes must be at least 3/4 the size
-     * of the region. The padding bytes for the cells must not be part of the array.
-     *
-     * @param off The offset of the first element to be copied.
-     * @param count The number of elements to be copied.
-     * @param d the source array
-     */
-    public void copy1DRangeFrom(int off, int count, byte[] d) {
-        validateIsInt8();
-        copy1DRangeFromUnchecked(off, count, d, Element.DataType.SIGNED_8, d.length);
-    }
-
-    /**
-     * Copy an array into a 1D region of this Allocation.  This variant is type checked
-     * and will generate exceptions if the Allocation's {@link
-     * android.support.v8.renderscript.Element} is neither a 32 bit float nor a vector of
-     * 32 bit floats {@link android.support.v8.renderscript.Element.DataType}.
-     *
-     * <p> The size of the region is: count * {@link #getElement}.{@link
-     * Element#getBytesSize}.
-     *
-     * <p> If the Allocation does not have Vec3 Elements, then the size of the
-     * array in bytes must be at least the size of the region.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is disabled, then the size of the array in bytes must be at least the size
-     * of the region. The padding bytes for the cells must be part of the array.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is enabled, then the size of the array in bytes must be at least 3/4 the size
-     * of the region. The padding bytes for the cells must not be part of the array.
-     *
-     * @param off The offset of the first element to be copied.
-     * @param count The number of elements to be copied.
-     * @param d the source array.
-     */
-    public void copy1DRangeFrom(int off, int count, float[] d) {
-        validateIsFloat32();
-        copy1DRangeFromUnchecked(off, count, d, Element.DataType.FLOAT_32, d.length);
-    }
-
-     /**
-     * Copy part of an Allocation into this Allocation.
-     *
-     * @param off The offset of the first element to be copied.
-     * @param count The number of elements to be copied.
-     * @param data the source data allocation.
-     * @param dataOff off The offset of the first element in data to
-     *          be copied.
-     */
-    public void copy1DRangeFrom(int off, int count, Allocation data, int dataOff) {
-        mRS.nAllocationData2D(getIDSafe(), off, 0,
-                              mSelectedLOD, mSelectedFace.mID,
-                              count, 1, data.getID(mRS), dataOff, 0,
-                              data.mSelectedLOD, data.mSelectedFace.mID);
-    }
-
-    private void validate2DRange(int xoff, int yoff, int w, int h) {
-        if (mAdaptedAllocation != null) {
-
-        } else {
-
-            if (xoff < 0 || yoff < 0) {
-                throw new RSIllegalArgumentException("Offset cannot be negative.");
-            }
-            if (h < 0 || w < 0) {
-                throw new RSIllegalArgumentException("Height or width cannot be negative.");
-            }
-            if (((xoff + w) > mCurrentDimX) || ((yoff + h) > mCurrentDimY)) {
-                throw new RSIllegalArgumentException("Updated region larger than allocation.");
-            }
-        }
-    }
-
-    void copy2DRangeFromUnchecked(int xoff, int yoff, int w, int h, Object array,
-                                  Element.DataType dt, int arrayLen) {
-        mRS.validate();
-        validate2DRange(xoff, yoff, w, h);
-        final int dataSize = mType.mElement.getBytesSize() * w * h;
-        // AutoPadding for Vec3 Element
-        boolean usePadding = false;
-        int sizeBytes = arrayLen * dt.mSize;
-        if (mAutoPadding && (mType.getElement().getVectorSize() == 3)) {
-            if (dataSize / 4 * 3 > sizeBytes) {
-                throw new RSIllegalArgumentException("Array too small for allocation type.");
-            }
-            usePadding = true;
-            sizeBytes = dataSize;
-        } else {
-            if (dataSize > sizeBytes) {
-                throw new RSIllegalArgumentException("Array too small for allocation type.");
-            }
-        }
-        mRS.nAllocationData2D(getIDSafe(), xoff, yoff, mSelectedLOD, mSelectedFace.mID, w, h,
-                              array, sizeBytes, dt,
-                              mType.mElement.mType.mSize, usePadding);
-    }
-
-    /**
-     * Copy from an array into a rectangular region in this Allocation.  The
-     * array is assumed to be tightly packed. This variant is type checked
-     * and will generate exceptions if the Allocation's {@link
-     * android.support.v8.renderscript.Element} does not match the input data type.
-     *
-     * <p> The size of the region is: w * h * {@link #getElement}.{@link
-     * Element#getBytesSize}.
-     *
-     * <p> If the Allocation does not have Vec3 Elements, then the size of the
-     * array in bytes must be at least the size of the region.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is disabled, then the size of the array in bytes must be at least the size
-     * of the region. The padding bytes for the cells must be part of the array.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is enabled, then the size of the array in bytes must be at least 3/4 the size
-     * of the region. The padding bytes for the cells must not be part of the array.
-     *
-     * @param xoff X offset of the region to update in this Allocation
-     * @param yoff Y offset of the region to update in this Allocation
-     * @param w Width of the region to update
-     * @param h Height of the region to update
-     * @param array Data to be placed into the Allocation
-     */
-    public void copy2DRangeFrom(int xoff, int yoff, int w, int h, Object array) {
-        copy2DRangeFromUnchecked(xoff, yoff, w, h, array,
-                                 validateObjectIsPrimitiveArray(array, true),
-                                 java.lang.reflect.Array.getLength(array));
-    }
-
-    /**
-     * Copy from an array into a rectangular region in this Allocation.  The
-     * array is assumed to be tightly packed. This variant is type checked
-     * and will generate exceptions if the Allocation's {@link
-     * android.support.v8.renderscript.Element} is not an 8 bit integer nor a vector of 8 bit
-     * integers {@link android.support.v8.renderscript.Element.DataType}.
-     *
-     * <p> The size of the region is: w * h * {@link #getElement}.{@link
-     * Element#getBytesSize}.
-     *
-     * <p> If the Allocation does not have Vec3 Elements, then the size of the
-     * array in bytes must be at least the size of the region.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is disabled, then the size of the array in bytes must be at least the size
-     * of the region. The padding bytes for the cells must be part of the array.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is enabled, then the size of the array in bytes must be at least 3/4 the size
-     * of the region. The padding bytes for the cells must not be part of the array.
-     *
-     * @param xoff X offset of the region to update in this Allocation
-     * @param yoff Y offset of the region to update in this Allocation
-     * @param w Width of the region to update
-     * @param h Height of the region to update
-     * @param data to be placed into the Allocation
-     */
-    public void copy2DRangeFrom(int xoff, int yoff, int w, int h, byte[] data) {
-        validateIsInt8();
-        copy2DRangeFromUnchecked(xoff, yoff, w, h, data,
-                                 Element.DataType.SIGNED_8, data.length);
-    }
-
-    /**
-     * Copy from an array into a rectangular region in this Allocation.  The
-     * array is assumed to be tightly packed. This variant is type checked
-     * and will generate exceptions if the Allocation's {@link
-     * android.support.v8.renderscript.Element} is not a 16 bit integer nor a vector of 16 bit
-     * integers {@link android.support.v8.renderscript.Element.DataType}.
-     *
-     * <p> The size of the region is: w * h * {@link #getElement}.{@link
-     * Element#getBytesSize}.
-     *
-     * <p> If the Allocation does not have Vec3 Elements, then the size of the
-     * array in bytes must be at least the size of the region.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is disabled, then the size of the array in bytes must be at least the size
-     * of the region. The padding bytes for the cells must be part of the array.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is enabled, then the size of the array in bytes must be at least 3/4 the size
-     * of the region. The padding bytes for the cells must not be part of the array.
-     *
-     * @param xoff X offset of the region to update in this Allocation
-     * @param yoff Y offset of the region to update in this Allocation
-     * @param w Width of the region to update
-     * @param h Height of the region to update
-     * @param data to be placed into the Allocation
-     */
-    public void copy2DRangeFrom(int xoff, int yoff, int w, int h, short[] data) {
-        validateIsInt16();
-        copy2DRangeFromUnchecked(xoff, yoff, w, h, data,
-                                 Element.DataType.SIGNED_16, data.length);
-    }
-
-    /**
-     * Copy from an array into a rectangular region in this Allocation.  The
-     * array is assumed to be tightly packed. This variant is type checked
-     * and will generate exceptions if the Allocation's {@link
-     * android.support.v8.renderscript.Element} is not a 32 bit integer nor a vector of 32 bit
-     * integers {@link android.support.v8.renderscript.Element.DataType}.
-     *
-     * <p> The size of the region is: w * h * {@link #getElement}.{@link
-     * Element#getBytesSize}.
-     *
-     * <p> If the Allocation does not have Vec3 Elements, then the size of the
-     * array in bytes must be at least the size of the region.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is disabled, then the size of the array in bytes must be at least the size
-     * of the region. The padding bytes for the cells must be part of the array.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is enabled, then the size of the array in bytes must be at least 3/4 the size
-     * of the region. The padding bytes for the cells must not be part of the array.
-     *
-     * @param xoff X offset of the region to update in this Allocation
-     * @param yoff Y offset of the region to update in this Allocation
-     * @param w Width of the region to update
-     * @param h Height of the region to update
-     * @param data to be placed into the Allocation
-     */
-    public void copy2DRangeFrom(int xoff, int yoff, int w, int h, int[] data) {
-        validateIsInt32();
-        copy2DRangeFromUnchecked(xoff, yoff, w, h, data,
-                                 Element.DataType.SIGNED_32, data.length);
-    }
-
-    /**
-     * Copy from an array into a rectangular region in this Allocation.  The
-     * array is assumed to be tightly packed. This variant is type checked
-     * and will generate exceptions if the Allocation's {@link
-     * android.support.v8.renderscript.Element} is neither a 32 bit float nor a vector of
-     * 32 bit floats {@link android.support.v8.renderscript.Element.DataType}.
-     *
-     * <p> The size of the region is: w * h * {@link #getElement}.{@link
-     * Element#getBytesSize}.
-     *
-     * <p> If the Allocation does not have Vec3 Elements, then the size of the
-     * array in bytes must be at least the size of the region.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is disabled, then the size of the array in bytes must be at least the size
-     * of the region. The padding bytes for the cells must be part of the array.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is enabled, then the size of the array in bytes must be at least 3/4 the size
-     * of the region. The padding bytes for the cells must not be part of the array.
-     *
-     * @param xoff X offset of the region to update in this Allocation
-     * @param yoff Y offset of the region to update in this Allocation
-     * @param w Width of the region to update
-     * @param h Height of the region to update
-     * @param data to be placed into the Allocation
-     */
-    public void copy2DRangeFrom(int xoff, int yoff, int w, int h, float[] data) {
-        validateIsFloat32();
-        copy2DRangeFromUnchecked(xoff, yoff, w, h, data,
-                                 Element.DataType.FLOAT_32, data.length);
-    }
-
-    /**
-     * Copy a rectangular region from an Allocation into a rectangular region in
-     * this Allocation.
-     *
-     * @param xoff X offset of the region in this Allocation
-     * @param yoff Y offset of the region in this Allocation
-     * @param w Width of the region to update.
-     * @param h Height of the region to update.
-     * @param data source Allocation.
-     * @param dataXoff X offset in source Allocation
-     * @param dataYoff Y offset in source Allocation
-     */
-    public void copy2DRangeFrom(int xoff, int yoff, int w, int h,
-                                Allocation data, int dataXoff, int dataYoff) {
-        mRS.validate();
-        validate2DRange(xoff, yoff, w, h);
-        mRS.nAllocationData2D(getIDSafe(), xoff, yoff,
-                              mSelectedLOD, mSelectedFace.mID,
-                              w, h, data.getID(mRS), dataXoff, dataYoff,
-                              data.mSelectedLOD, data.mSelectedFace.mID);
-    }
-
-    /**
-     * Copy a {@link android.graphics.Bitmap} into an Allocation.  The height
-     * and width of the update will use the height and width of the {@link
-     * android.graphics.Bitmap}.
-     *
-     * @param xoff X offset of the region to update in this Allocation
-     * @param yoff Y offset of the region to update in this Allocation
-     * @param data the Bitmap to be copied
-     */
-    public void copy2DRangeFrom(int xoff, int yoff, Bitmap data) {
-        mRS.validate();
-        if (data.getConfig() == null) {
-            Bitmap newBitmap = Bitmap.createBitmap(data.getWidth(), data.getHeight(), Bitmap.Config.ARGB_8888);
-            Canvas c = new Canvas(newBitmap);
-            c.drawBitmap(data, 0, 0, null);
-            copy2DRangeFrom(xoff, yoff, newBitmap);
-            return;
-        }
-        validateBitmapFormat(data);
-        validate2DRange(xoff, yoff, data.getWidth(), data.getHeight());
-        mRS.nAllocationData2D(getIDSafe(), xoff, yoff, mSelectedLOD, mSelectedFace.mID, data);
-    }
-
-    private void validate3DRange(int xoff, int yoff, int zoff, int w, int h, int d) {
-        if (mAdaptedAllocation != null) {
-
-        } else {
-
-            if (xoff < 0 || yoff < 0 || zoff < 0) {
-                throw new RSIllegalArgumentException("Offset cannot be negative.");
-            }
-            if (h < 0 || w < 0 || d < 0) {
-                throw new RSIllegalArgumentException("Height or width cannot be negative.");
-            }
-            if (((xoff + w) > mCurrentDimX) || ((yoff + h) > mCurrentDimY) || ((zoff + d) > mCurrentDimZ)) {
-                throw new RSIllegalArgumentException("Updated region larger than allocation.");
-            }
-        }
-    }
-
-    /**
-     * Copy a rectangular region from the array into the allocation.
-     * The array is assumed to be tightly packed.
-     *
-     * The data type of the array is not required to be the same as
-     * the element data type.
-     */
-    private void copy3DRangeFromUnchecked(int xoff, int yoff, int zoff, int w, int h, int d,
-                                          Object array, Element.DataType dt, int arrayLen) {
-        mRS.validate();
-        validate3DRange(xoff, yoff, zoff, w, h, d);
-        final int dataSize = mType.mElement.getBytesSize() * w * h * d;
-        // AutoPadding for Vec3 Element
-        boolean usePadding = false;
-        int sizeBytes = arrayLen * dt.mSize;
-        if (mAutoPadding && (mType.getElement().getVectorSize() == 3)) {
-            if (dataSize / 4 * 3 > sizeBytes) {
-                throw new RSIllegalArgumentException("Array too small for allocation type.");
-            }
-            usePadding = true;
-            sizeBytes = dataSize;
-        } else {
-            if (dataSize > sizeBytes) {
-                throw new RSIllegalArgumentException("Array too small for allocation type.");
-            }
-        }
-        mRS.nAllocationData3D(getIDSafe(), xoff, yoff, zoff, mSelectedLOD, w, h, d,
-                              array, sizeBytes, dt,
-                              mType.mElement.mType.mSize, usePadding);
-    }
-
-    /**
-     * Copy from an array into a 3D region in this Allocation.  The
-     * array is assumed to be tightly packed. This variant is type checked
-     * and will generate exceptions if the Allocation's {@link
-     * android.support.v8.renderscript.Element} does not match the input data type.
-     *
-     * <p> The size of the region is: w * h * d * {@link #getElement}.{@link
-     * Element#getBytesSize}.
-     *
-     * <p> If the Allocation does not have Vec3 Elements, then the size of the
-     * array in bytes must be at least the size of the region.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is disabled, then the size of the array in bytes must be at least the size
-     * of the region. The padding bytes for the cells must be part of the array.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is enabled, then the size of the array in bytes must be at least 3/4 the size
-     * of the region. The padding bytes for the cells must not be part of the array.
-     *
-     * @param xoff X offset of the region to update in this Allocation
-     * @param yoff Y offset of the region to update in this Allocation
-     * @param zoff Z offset of the region to update in this Allocation
-     * @param w Width of the region to update
-     * @param h Height of the region to update
-     * @param d Depth of the region to update
-     * @param array to be placed into the allocation
-     */
-    public void copy3DRangeFrom(int xoff, int yoff, int zoff, int w, int h, int d, Object array) {
-        copy3DRangeFromUnchecked(xoff, yoff, zoff, w, h, d, array,
-                                 validateObjectIsPrimitiveArray(array, true),
-                                 java.lang.reflect.Array.getLength(array));
-    }
-
-    /**
-     * Copy a rectangular region into the allocation from another
-     * allocation.
-     *
-     * @param xoff X offset of the region to update in this Allocation
-     * @param yoff Y offset of the region to update in this Allocation
-     * @param zoff Z offset of the region to update in this Allocation
-     * @param w Width of the region to update.
-     * @param h Height of the region to update.
-     * @param d Depth of the region to update.
-     * @param data source allocation.
-     * @param dataXoff X offset of the region in the source Allocation
-     * @param dataYoff Y offset of the region in the source Allocation
-     * @param dataZoff Z offset of the region in the source Allocation
-     */
-    public void copy3DRangeFrom(int xoff, int yoff, int zoff, int w, int h, int d,
-                                Allocation data, int dataXoff, int dataYoff, int dataZoff) {
-        mRS.validate();
-        validate3DRange(xoff, yoff, zoff, w, h, d);
-        mRS.nAllocationData3D(getIDSafe(), xoff, yoff, zoff, mSelectedLOD,
-                              w, h, d, data.getID(mRS), dataXoff, dataYoff, dataZoff,
-                              data.mSelectedLOD);
-    }
-
-
-    /**
-     * Copy from the Allocation into a {@link android.graphics.Bitmap}.  The
-     * bitmap must match the dimensions of the Allocation.
-     *
-     * @param b The bitmap to be set from the Allocation.
-     */
-    public void copyTo(Bitmap b) {
-        mRS.validate();
-        validateBitmapFormat(b);
-        validateBitmapSize(b);
-        mRS.nAllocationCopyToBitmap(getID(mRS), b);
-    }
-
-    private void copyTo(Object array, Element.DataType dt, int arrayLen) {
-        mRS.validate();
-        boolean usePadding = false;
-        if (mAutoPadding && (mType.getElement().getVectorSize() == 3)) {
-            usePadding = true;
-        }
-        if (usePadding) {
-            if (dt.mSize * arrayLen < mSize / 4 * 3) {
-                throw new RSIllegalArgumentException(
-                    "Size of output array cannot be smaller than size of allocation.");
-            }
-        } else {
-            if (dt.mSize * arrayLen < mSize) {
-                throw new RSIllegalArgumentException(
-                    "Size of output array cannot be smaller than size of allocation.");
-            }
-        }
-        mRS.nAllocationRead(getID(mRS), array, dt, mType.mElement.mType.mSize, usePadding);
-    }
-
-    /**
-     * Copy from the Allocation into an array. The method is type checked
-     * and will generate exceptions if the Allocation's {@link
-     * android.support.v8.renderscript.Element} does not match the input data type.
-     *
-     * <p> If the Allocation does not have Vec3 Elements, then the size of the
-     * array in bytes must be at least the size of the Allocation {@link
-     * #getBytesSize getBytesSize()}.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is disabled, then the size of the array in bytes must be at least the size
-     * of the Allocation {@link #getBytesSize getBytesSize()}. The padding bytes for
-     * the cells will be part of the array.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is enabled, then the size of the array in bytes must be at least 3/4 the size
-     * of the Allocation {@link #getBytesSize getBytesSize()}. The padding bytes for
-     * the cells must not be part of the array.
-     *
-     * @param array The array to be set from the Allocation.
-     */
-    public void copyTo(Object array) {
-        copyTo(array, validateObjectIsPrimitiveArray(array, true),
-               java.lang.reflect.Array.getLength(array));
-    }
-
-    /**
-     * Copy from the Allocation into a byte array. This variant is type checked
-     * and will generate exceptions if the Allocation's {@link
-     * android.support.v8.renderscript.Element} is neither an 8 bit integer nor a vector of 8 bit
-     * integers {@link android.support.v8.renderscript.Element.DataType}.
-     *
-     * <p> If the Allocation does not have Vec3 Elements, then the size of the
-     * array in bytes must be at least the size of the Allocation {@link
-     * #getBytesSize getBytesSize()}.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is disabled, then the size of the array in bytes must be at least the size
-     * of the Allocation {@link #getBytesSize getBytesSize()}. The padding bytes for
-     * the cells will be part of the array.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is enabled, then the size of the array in bytes must be at least 3/4 the size
-     * of the Allocation {@link #getBytesSize getBytesSize()}. The padding bytes for
-     * the cells must not be part of the array.
-     *
-     * @param d The array to be set from the Allocation.
-     */
-    public void copyTo(byte[] d) {
-        validateIsInt8();
-        copyTo(d, Element.DataType.SIGNED_8, d.length);
-    }
-
-    /**
-     * Copy from the Allocation into a short array. This variant is type checked
-     * and will generate exceptions if the Allocation's {@link
-     * android.support.v8.renderscript.Element} is not a 16 bit integer nor a vector of 16 bit
-     * integers {@link android.support.v8.renderscript.Element.DataType}.
-     *
-     * <p> If the Allocation does not have Vec3 Elements, then the size of the
-     * array in bytes must be at least the size of the Allocation {@link
-     * #getBytesSize getBytesSize()}.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is disabled, then the size of the array in bytes must be at least the size
-     * of the Allocation {@link #getBytesSize getBytesSize()}. The padding bytes for
-     * the cells will be part of the array.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is enabled, then the size of the array in bytes must be at least 3/4 the size
-     * of the Allocation {@link #getBytesSize getBytesSize()}. The padding bytes for
-     * the cells must not be part of the array.
-     *
-     * @param d The array to be set from the Allocation.
-     */
-    public void copyTo(short[] d) {
-        validateIsInt16();
-        copyTo(d, Element.DataType.SIGNED_16, d.length);
-    }
-
-    /**
-     * Copy from the Allocation into a int array. This variant is type checked
-     * and will generate exceptions if the Allocation's {@link
-     * android.support.v8.renderscript.Element} is not a 32 bit integer nor a vector of 32 bit
-     * integers {@link android.support.v8.renderscript.Element.DataType}.
-     *
-     * <p> If the Allocation does not have Vec3 Elements, then the size of the
-     * array in bytes must be at least the size of the Allocation {@link
-     * #getBytesSize getBytesSize()}.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is disabled, then the size of the array in bytes must be at least the size
-     * of the Allocation {@link #getBytesSize getBytesSize()}. The padding bytes for
-     * the cells will be part of the array.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is enabled, then the size of the array in bytes must be at least 3/4 the size
-     * of the Allocation {@link #getBytesSize getBytesSize()}. The padding bytes for
-     * the cells must not be part of the array.
-     *
-     * @param d The array to be set from the Allocation.
-     */
-    public void copyTo(int[] d) {
-        validateIsInt32();
-        copyTo(d, Element.DataType.SIGNED_32, d.length);
-    }
-
-    /**
-     * Copy from the Allocation into a float array. This variant is type checked
-     * and will generate exceptions if the Allocation's {@link
-     * android.support.v8.renderscript.Element} is neither a 32 bit float nor a vector of
-     * 32 bit floats {@link android.support.v8.renderscript.Element.DataType}.
-     *
-     * <p> If the Allocation does not have Vec3 Elements, then the size of the
-     * array in bytes must be at least the size of the Allocation {@link
-     * #getBytesSize getBytesSize()}.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is disabled, then the size of the array in bytes must be at least the size
-     * of the Allocation {@link #getBytesSize getBytesSize()}. The padding bytes for
-     * the cells will be part of the array.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is enabled, then the size of the array in bytes must be at least 3/4 the size
-     * of the Allocation {@link #getBytesSize getBytesSize()}. The padding bytes for
-     * the cells must not be part of the array.
-     *
-     * @param d The array to be set from the Allocation.
-     */
-    public void copyTo(float[] d) {
-        validateIsFloat32();
-        copyTo(d, Element.DataType.FLOAT_32, d.length);
-    }
-
-    /**
-     * @hide
-     * This is only intended to be used by auto-generated code reflected from
-     * the RenderScript script files and should not be used by developers.
-     *
-     * @param xoff
-     * @param yoff
-     * @param zoff
-     * @param component_number
-     * @param fp
-     */
-    /*
-    public void copyToFieldPacker(int xoff, int yoff, int zoff, int component_number, FieldPacker fp) {
-        mRS.validate();
-        if (component_number >= mType.mElement.mElements.length) {
-            throw new RSIllegalArgumentException("Component_number " + component_number + " out of range.");
-        }
-        if(xoff < 0) {
-            throw new RSIllegalArgumentException("Offset x must be >= 0.");
-        }
-        if(yoff < 0) {
-            throw new RSIllegalArgumentException("Offset y must be >= 0.");
-        }
-        if(zoff < 0) {
-            throw new RSIllegalArgumentException("Offset z must be >= 0.");
-        }
-
-        final byte[] data = fp.getData();
-        int data_length = data.length;
-        int eSize = mType.mElement.mElements[component_number].getBytesSize();
-        eSize *= mType.mElement.mArraySizes[component_number];
-
-        if (data_length != eSize) {
-            throw new RSIllegalArgumentException("Field packer sizelength " + data_length +
-                                               " does not match component size " + eSize + ".");
-        }
-
-        mRS.nAllocationElementRead(getIDSafe(), xoff, yoff, zoff, mSelectedLOD,
-                                   component_number, data, data_length);
-    }
-    */
-
-    private void copy1DRangeToUnchecked(int off, int count, Object array,
-                                        Element.DataType dt, int arrayLen) {
-        final int dataSize = mType.mElement.getBytesSize() * count;
-        // AutoPadding for Vec3 Element
-        boolean usePadding = false;
-        if (mAutoPadding && (mType.getElement().getVectorSize() == 3)) {
-            usePadding = true;
-        }
-        data1DChecks(off, count, arrayLen * dt.mSize, dataSize, usePadding);
-        mRS.nAllocationRead1D(getIDSafe(), off, mSelectedLOD, count, array, dataSize, dt,
-                              mType.mElement.mType.mSize, usePadding);
-    }
-
-    /**
-     * Copy a 1D region of this Allocation into an array.  This method does not
-     * guarantee that the Allocation is compatible with the input buffer.
-     *
-     * <p> The size of the region is: count * {@link #getElement}.{@link
-     * Element#getBytesSize}.
-     *
-     * <p> If the Allocation does not have Vec3 Elements, then the size of the
-     * array in bytes must be at least the size of the region.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is disabled, then the size of the array in bytes must be at least the size
-     * of the region. The padding bytes for the cells must be part of the array.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is enabled, then the size of the array in bytes must be at least 3/4 the size
-     * of the region. The padding bytes for the cells must not be part of the array.
-     *
-     * @param off The offset of the first element to be copied.
-     * @param count The number of elements to be copied.
-     * @param array The dest array
-     */
-    public void copy1DRangeToUnchecked(int off, int count, Object array) {
-        copy1DRangeToUnchecked(off, count, array,
-                               validateObjectIsPrimitiveArray(array, false),
-                               java.lang.reflect.Array.getLength(array));
-    }
-
-    /**
-     * Copy a 1D region of this Allocation into an array.  This method does not
-     * guarantee that the Allocation is compatible with the input buffer.
-     *
-     * <p> The size of the region is: count * {@link #getElement}.{@link
-     * Element#getBytesSize}.
-     *
-     * <p> If the Allocation does not have Vec3 Elements, then the size of the
-     * array in bytes must be at least the size of the region.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is disabled, then the size of the array in bytes must be at least the size
-     * of the region. The padding bytes for the cells must be part of the array.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is enabled, then the size of the array in bytes must be at least 3/4 the size
-     * of the region. The padding bytes for the cells must not be part of the array.
-     *
-     * @param off The offset of the first element to be copied.
-     * @param count The number of elements to be copied.
-     * @param d the source array
-     */
-    public void copy1DRangeToUnchecked(int off, int count, int[] d) {
-        copy1DRangeToUnchecked(off, count, (Object)d, Element.DataType.SIGNED_32, d.length);
-    }
-
-    /**
-     * Copy a 1D region of this Allocation into an array.  This method does not
-     * guarantee that the Allocation is compatible with the input buffer.
-     *
-     * <p> The size of the region is: count * {@link #getElement}.{@link
-     * Element#getBytesSize}.
-     *
-     * <p> If the Allocation does not have Vec3 Elements, then the size of the
-     * array in bytes must be at least the size of the region.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is disabled, then the size of the array in bytes must be at least the size
-     * of the region. The padding bytes for the cells must be part of the array.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is enabled, then the size of the array in bytes must be at least 3/4 the size
-     * of the region. The padding bytes for the cells must not be part of the array.
-     *
-     * @param off The offset of the first element to be copied.
-     * @param count The number of elements to be copied.
-     * @param d the source array
-     */
-    public void copy1DRangeToUnchecked(int off, int count, short[] d) {
-        copy1DRangeToUnchecked(off, count, (Object)d, Element.DataType.SIGNED_16, d.length);
-    }
-
-    /**
-     * Copy a 1D region of this Allocation into an array.  This method does not
-     * guarantee that the Allocation is compatible with the input buffer.
-     *
-     * <p> The size of the region is: count * {@link #getElement}.{@link
-     * Element#getBytesSize}.
-     *
-     * <p> If the Allocation does not have Vec3 Elements, then the size of the
-     * array in bytes must be at least the size of the region.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is disabled, then the size of the array in bytes must be at least the size
-     * of the region. The padding bytes for the cells must be part of the array.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is enabled, then the size of the array in bytes must be at least 3/4 the size
-     * of the region. The padding bytes for the cells must not be part of the array.
-     *
-     * @param off The offset of the first element to be copied.
-     * @param count The number of elements to be copied.
-     * @param d the source array
-     */
-    public void copy1DRangeToUnchecked(int off, int count, byte[] d) {
-        copy1DRangeToUnchecked(off, count, (Object)d, Element.DataType.SIGNED_8, d.length);
-    }
-
-    /**
-     * Copy a 1D region of this Allocation into an array.  This method does not
-     * guarantee that the Allocation is compatible with the input buffer.
-     *
-     * <p> The size of the region is: count * {@link #getElement}.{@link
-     * Element#getBytesSize}.
-     *
-     * <p> If the Allocation does not have Vec3 Elements, then the size of the
-     * array in bytes must be at least the size of the region.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is disabled, then the size of the array in bytes must be at least the size
-     * of the region. The padding bytes for the cells must be part of the array.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is enabled, then the size of the array in bytes must be at least 3/4 the size
-     * of the region. The padding bytes for the cells must not be part of the array.
-     *
-     * @param off The offset of the first element to be copied.
-     * @param count The number of elements to be copied.
-     * @param d the source array
-     */
-    public void copy1DRangeToUnchecked(int off, int count, float[] d) {
-        copy1DRangeToUnchecked(off, count, (Object)d, Element.DataType.FLOAT_32, d.length);
-    }
-
-
-    /**
-     * Copy a 1D region of this Allocation into an array.  This method is type checked
-     * and will generate exceptions if the Allocation's {@link
-     * android.support.v8.renderscript.Element} does not match the component type
-     * of the array passed in.
-     *
-     * <p> The size of the region is: count * {@link #getElement}.{@link
-     * Element#getBytesSize}.
-     *
-     * <p> If the Allocation does not have Vec3 Elements, then the size of the
-     * array in bytes must be at least the size of the region.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is disabled, then the size of the array in bytes must be at least the size
-     * of the region. The padding bytes for the cells must be part of the array.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is enabled, then the size of the array in bytes must be at least 3/4 the size
-     * of the region. The padding bytes for the cells must not be part of the array.
-     *
-     * @param off The offset of the first element to be copied.
-     * @param count The number of elements to be copied.
-     * @param array The source array.
-     */
-    public void copy1DRangeTo(int off, int count, Object array) {
-        copy1DRangeToUnchecked(off, count, array,
-                               validateObjectIsPrimitiveArray(array, true),
-                               java.lang.reflect.Array.getLength(array));
-    }
-
-    /**
-     * Copy a 1D region of this Allocation into an array. This variant is type checked
-     * and will generate exceptions if the Allocation's {@link
-     * android.support.v8.renderscript.Element} is neither a 32 bit integer nor a vector of 32 bit
-     * integers {@link android.support.v8.renderscript.Element.DataType}.
-     *
-     * <p> The size of the region is: count * {@link #getElement}.{@link
-     * Element#getBytesSize}.
-     *
-     * <p> If the Allocation does not have Vec3 Elements, then the size of the
-     * array in bytes must be at least the size of the region.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is disabled, then the size of the array in bytes must be at least the size
-     * of the region. The padding bytes for the cells must be part of the array.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is enabled, then the size of the array in bytes must be at least 3/4 the size
-     * of the region. The padding bytes for the cells must not be part of the array.
-     *
-     * @param off The offset of the first element to be copied.
-     * @param count The number of elements to be copied.
-     * @param d the source array
-     */
-    public void copy1DRangeTo(int off, int count, int[] d) {
-        validateIsInt32();
-        copy1DRangeToUnchecked(off, count, d, Element.DataType.SIGNED_32, d.length);
-    }
-
-    /**
-     * Copy a 1D region of this Allocation into an array. This variant is type checked
-     * and will generate exceptions if the Allocation's {@link
-     * android.support.v8.renderscript.Element} is neither a 16 bit integer nor a vector of 16 bit
-     * integers {@link android.support.v8.renderscript.Element.DataType}.
-     *
-     * <p> The size of the region is: count * {@link #getElement}.{@link
-     * Element#getBytesSize}.
-     *
-     * <p> If the Allocation does not have Vec3 Elements, then the size of the
-     * array in bytes must be at least the size of the region.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is disabled, then the size of the array in bytes must be at least the size
-     * of the region. The padding bytes for the cells must be part of the array.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is enabled, then the size of the array in bytes must be at least 3/4 the size
-     * of the region. The padding bytes for the cells must not be part of the array.
-     *
-     * @param off The offset of the first element to be copied.
-     * @param count The number of elements to be copied.
-     * @param d the source array
-     */
-    public void copy1DRangeTo(int off, int count, short[] d) {
-        validateIsInt16();
-        copy1DRangeToUnchecked(off, count, d, Element.DataType.SIGNED_16, d.length);
-    }
-
-    /**
-     * Copy a 1D region of this Allocation into an array. This variant is type checked
-     * and will generate exceptions if the Allocation's {@link
-     * android.support.v8.renderscript.Element} is neither an 8 bit integer nor a vector of 8 bit
-     * integers {@link android.support.v8.renderscript.Element.DataType}.
-     *
-     * <p> The size of the region is: count * {@link #getElement}.{@link
-     * Element#getBytesSize}.
-     *
-     * <p> If the Allocation does not have Vec3 Elements, then the size of the
-     * array in bytes must be at least the size of the region.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is disabled, then the size of the array in bytes must be at least the size
-     * of the region. The padding bytes for the cells must be part of the array.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is enabled, then the size of the array in bytes must be at least 3/4 the size
-     * of the region. The padding bytes for the cells must not be part of the array.
-     *
-     * @param off The offset of the first element to be copied.
-     * @param count The number of elements to be copied.
-     * @param d the source array
-     */
-    public void copy1DRangeTo(int off, int count, byte[] d) {
-        validateIsInt8();
-        copy1DRangeToUnchecked(off, count, d, Element.DataType.SIGNED_8, d.length);
-    }
-
-    /**
-     * Copy a 1D region of this Allocation into an array. This variant is type checked
-     * and will generate exceptions if the Allocation's {@link
-     * android.support.v8.renderscript.Element} is neither a 32 bit float nor a vector of
-     * 32 bit floats {@link android.support.v8.renderscript.Element.DataType}.
-     *
-     * <p> The size of the region is: count * {@link #getElement}.{@link
-     * Element#getBytesSize}.
-     *
-     * <p> If the Allocation does not have Vec3 Elements, then the size of the
-     * array in bytes must be at least the size of the region.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is disabled, then the size of the array in bytes must be at least the size
-     * of the region. The padding bytes for the cells must be part of the array.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is enabled, then the size of the array in bytes must be at least 3/4 the size
-     * of the region. The padding bytes for the cells must not be part of the array.
-     *
-     * @param off The offset of the first element to be copied.
-     * @param count The number of elements to be copied.
-     * @param d the source array.
-     */
-    public void copy1DRangeTo(int off, int count, float[] d) {
-        validateIsFloat32();
-        copy1DRangeToUnchecked(off, count, d, Element.DataType.FLOAT_32, d.length);
-    }
-
-
-    void copy2DRangeToUnchecked(int xoff, int yoff, int w, int h, Object array,
-                                Element.DataType dt, int arrayLen) {
-        mRS.validate();
-        validate2DRange(xoff, yoff, w, h);
-        final int dataSize = mType.mElement.getBytesSize() * w * h;
-        // AutoPadding for Vec3 Element
-        boolean usePadding = false;
-        int sizeBytes = arrayLen * dt.mSize;
-        if (mAutoPadding && (mType.getElement().getVectorSize() == 3)) {
-            if (dataSize / 4 * 3 > sizeBytes) {
-                throw new RSIllegalArgumentException("Array too small for allocation type.");
-            }
-            usePadding = true;
-            sizeBytes = dataSize;
-        } else {
-            if (dataSize > sizeBytes) {
-                throw new RSIllegalArgumentException("Array too small for allocation type.");
-            }
-        }
-        mRS.nAllocationRead2D(getIDSafe(), xoff, yoff, mSelectedLOD, mSelectedFace.mID, w, h,
-                              array, sizeBytes, dt, mType.mElement.mType.mSize, usePadding);
-    }
-
-    /**
-     * Copy from a rectangular region in this Allocation into an array. This
-     * method is type checked and will generate exceptions if the Allocation's
-     * {@link android.support.v8.renderscript.Element} does not match the component type
-     * of the array passed in.
-     *
-     * <p> The size of the region is: w * h * {@link #getElement}.{@link
-     * Element#getBytesSize}.
-     *
-     * <p> If the Allocation does not have Vec3 Elements, then the size of the
-     * array in bytes must be at least the size of the region.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is disabled, then the size of the array in bytes must be at least the size
-     * of the region. The padding bytes for the cells must be part of the array.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is enabled, then the size of the array in bytes must be at least 3/4 the size
-     * of the region. The padding bytes for the cells must not be part of the array.
-     *
-     * @param xoff X offset of the region to copy in this Allocation
-     * @param yoff Y offset of the region to copy in this Allocation
-     * @param w Width of the region to copy
-     * @param h Height of the region to copy
-     * @param array Dest Array to be copied into
-     */
-    public void copy2DRangeTo(int xoff, int yoff, int w, int h, Object array) {
-        copy2DRangeToUnchecked(xoff, yoff, w, h, array,
-                               validateObjectIsPrimitiveArray(array, true),
-                               java.lang.reflect.Array.getLength(array));
-    }
-
-    /**
-     * Copy from a rectangular region in this Allocation into an array. This
-     * variant is type checked and will generate exceptions if the Allocation's
-     * {@link android.support.v8.renderscript.Element} is neither an 8 bit integer nor a vector
-     * of 8 bit integers {@link android.support.v8.renderscript.Element.DataType}.
-     *
-     * <p> The size of the region is: w * h * {@link #getElement}.{@link
-     * Element#getBytesSize}.
-     *
-     * <p> If the Allocation does not have Vec3 Elements, then the size of the
-     * array in bytes must be at least the size of the region.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is disabled, then the size of the array in bytes must be at least the size
-     * of the region. The padding bytes for the cells must be part of the array.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is enabled, then the size of the array in bytes must be at least 3/4 the size
-     * of the region. The padding bytes for the cells must not be part of the array.
-     *
-     * @param xoff X offset of the region to copy in this Allocation
-     * @param yoff Y offset of the region to copy in this Allocation
-     * @param w Width of the region to copy
-     * @param h Height of the region to copy
-     * @param data Dest Array to be copied into
-     */
-    public void copy2DRangeTo(int xoff, int yoff, int w, int h, byte[] data) {
-        validateIsInt8();
-        copy2DRangeToUnchecked(xoff, yoff, w, h, data,
-                               Element.DataType.SIGNED_8, data.length);
-    }
-
-    /**
-     * Copy from a rectangular region in this Allocation into an array. This
-     * variant is type checked and will generate exceptions if the Allocation's
-     * {@link android.support.v8.renderscript.Element} is neither a 16 bit integer nor a vector
-     * of 16 bit integers {@link android.support.v8.renderscript.Element.DataType}.
-     *
-     * <p> The size of the region is: w * h * {@link #getElement}.{@link
-     * Element#getBytesSize}.
-     *
-     * <p> If the Allocation does not have Vec3 Elements, then the size of the
-     * array in bytes must be at least the size of the region.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is disabled, then the size of the array in bytes must be at least the size
-     * of the region. The padding bytes for the cells must be part of the array.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is enabled, then the size of the array in bytes must be at least 3/4 the size
-     * of the region. The padding bytes for the cells must not be part of the array.
-     *
-     * @param xoff X offset of the region to copy in this Allocation
-     * @param yoff Y offset of the region to copy in this Allocation
-     * @param w Width of the region to copy
-     * @param h Height of the region to copy
-     * @param data Dest Array to be copied into
-     */
-    public void copy2DRangeTo(int xoff, int yoff, int w, int h, short[] data) {
-        validateIsInt16();
-        copy2DRangeToUnchecked(xoff, yoff, w, h, data,
-                               Element.DataType.SIGNED_16, data.length);
-    }
-
-    /**
-     * Copy from a rectangular region in this Allocation into an array. This
-     * variant is type checked and will generate exceptions if the Allocation's
-     * {@link android.support.v8.renderscript.Element} is neither a 32 bit integer nor a vector
-     * of 32 bit integers {@link android.support.v8.renderscript.Element.DataType}.
-     *
-     * <p> The size of the region is: w * h * {@link #getElement}.{@link
-     * Element#getBytesSize}.
-     *
-     * <p> If the Allocation does not have Vec3 Elements, then the size of the
-     * array in bytes must be at least the size of the region.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is disabled, then the size of the array in bytes must be at least the size
-     * of the region. The padding bytes for the cells must be part of the array.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is enabled, then the size of the array in bytes must be at least 3/4 the size
-     * of the region. The padding bytes for the cells must not be part of the array.
-     *
-     * @param xoff X offset of the region to copy in this Allocation
-     * @param yoff Y offset of the region to copy in this Allocation
-     * @param w Width of the region to copy
-     * @param h Height of the region to copy
-     * @param data Dest Array to be copied into
-     */
-    public void copy2DRangeTo(int xoff, int yoff, int w, int h, int[] data) {
-        validateIsInt32();
-        copy2DRangeToUnchecked(xoff, yoff, w, h, data,
-                               Element.DataType.SIGNED_32, data.length);
-    }
-
-    /**
-     * Copy from a rectangular region in this Allocation into an array. This
-     * variant is type checked and will generate exceptions if the Allocation's
-     * {@link android.support.v8.renderscript.Element} is neither a 32 bit float nor a vector
-     * of 32 bit floats {@link android.support.v8.renderscript.Element.DataType}.
-     *
-     * <p> The size of the region is: w * h * {@link #getElement}.{@link
-     * Element#getBytesSize}.
-     *
-     * <p> If the Allocation does not have Vec3 Elements, then the size of the
-     * array in bytes must be at least the size of the region.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is disabled, then the size of the array in bytes must be at least the size
-     * of the region. The padding bytes for the cells must be part of the array.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is enabled, then the size of the array in bytes must be at least 3/4 the size
-     * of the region. The padding bytes for the cells must not be part of the array.
-     *
-     * @param xoff X offset of the region to copy in this Allocation
-     * @param yoff Y offset of the region to copy in this Allocation
-     * @param w Width of the region to copy
-     * @param h Height of the region to copy
-     * @param data Dest Array to be copied into
-     */
-    public void copy2DRangeTo(int xoff, int yoff, int w, int h, float[] data) {
-        validateIsFloat32();
-        copy2DRangeToUnchecked(xoff, yoff, w, h, data,
-                               Element.DataType.FLOAT_32, data.length);
-    }
-
-
-    /**
-     * Copy from a 3D region in this Allocation into an array. This method does
-     * not guarantee that the Allocation is compatible with the input buffer.
-     * The array is assumed to be tightly packed.
-     *
-     * The data type of the array is not required to be the same as
-     * the element data type.
-     */
-    /*
-    private void copy3DRangeToUnchecked(int xoff, int yoff, int zoff, int w, int h, int d,
-                                        Object array, Element.DataType dt, int arrayLen) {
-        mRS.validate();
-        validate3DRange(xoff, yoff, zoff, w, h, d);
-        final int dataSize = mType.mElement.getBytesSize() * w * h * d;
-        // AutoPadding for Vec3 Element
-        boolean usePadding = false;
-        int sizeBytes = arrayLen * dt.mSize;
-        if (mAutoPadding && (mType.getElement().getVectorSize() == 3)) {
-            if (dataSize / 4 * 3 > sizeBytes) {
-                throw new RSIllegalArgumentException("Array too small for allocation type.");
-            }
-            usePadding = true;
-            sizeBytes = dataSize;
-        } else {
-            if (dataSize > sizeBytes) {
-                throw new RSIllegalArgumentException("Array too small for allocation type.");
-            }
-        }
-        mRS.nAllocationRead3D(getIDSafe(), xoff, yoff, zoff, mSelectedLOD, w, h, d,
-                              array, sizeBytes, dt, mType.mElement.mType.mSize, usePadding);
-    }
-    */
-
-    /**
-     * @hide
-     * Copy from a 3D region in this Allocation into an array. This
-     * method is type checked and will generate exceptions if the Allocation's
-     * {@link android.support.v8.renderscript.Element} does not match the component type
-     * of the array passed in.
-     *
-     * <p> The size of the region is: w * h * d * {@link #getElement}.{@link
-     * Element#getBytesSize}.
-     *
-     * <p> If the Allocation does not have Vec3 Elements, then the size of the
-     * array in bytes must be at least the size of the region.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is disabled, then the size of the array in bytes must be at least the size
-     * of the region. The padding bytes for the cells must be part of the array.
-     *
-     * <p> If the Allocation has Vec3 Elements and {@link #setAutoPadding AutoPadding}
-     * is enabled, then the size of the array in bytes must be at least 3/4 the size
-     * of the region. The padding bytes for the cells must not be part of the array.
-     *
-     * @param xoff X offset of the region to copy in this Allocation
-     * @param yoff Y offset of the region to copy in this Allocation
-     * @param zoff Z offset of the region to copy in this Allocation
-     * @param w Width of the region to copy
-     * @param h Height of the region to copy
-     * @param d Depth of the region to copy
-     * @param array Dest Array to be copied into
-     */
-    /*
-    public void copy3DRangeTo(int xoff, int yoff, int zoff, int w, int h, int d, Object array) {
-        copy3DRangeToUnchecked(xoff, yoff, zoff, w, h, d, array,
-                                 validateObjectIsPrimitiveArray(array, true),
-                                 java.lang.reflect.Array.getLength(array));
-    }
-    */
-
-    // creation
-
-    static BitmapFactory.Options mBitmapOptions = new BitmapFactory.Options();
-    static {
-        mBitmapOptions.inScaled = false;
-    }
-
-    /**
-     * Creates a new Allocation with the given {@link
-     * android.support.v8.renderscript.Type}, mipmap flag, and usage flags.
-     *
-     * @param type RenderScript type describing data layout
-     * @param mips specifies desired mipmap behaviour for the
-     *             allocation
-     * @param usage bit field specifying how the Allocation is
-     *              utilized
-     */
-    static public Allocation createTyped(RenderScript rs, Type type, MipmapControl mips, int usage) {
-        rs.validate();
-        if (type.getID(rs) == 0) {
-            throw new RSInvalidStateException("Bad Type");
-        }
-
-        if(!rs.usingIO() && (usage & (USAGE_IO_INPUT | USAGE_IO_INPUT)) != 0) {
-            throw new RSRuntimeException("USAGE_IO not supported, Allocation creation failed.");
-        }
-
-        long id = rs.nAllocationCreateTyped(type.getID(rs), mips.mID, usage, 0);
-        if (id == 0) {
-            throw new RSRuntimeException("Allocation creation failed.");
-        }
-        return new Allocation(id, rs, type, usage);
-    }
-
-    /**
-     * Creates an Allocation with the size specified by the type and no mipmaps
-     * generated by default
-     *
-     * @param rs Context to which the allocation will belong.
-     * @param type renderscript type describing data layout
-     * @param usage bit field specifying how the allocation is
-     *              utilized
-     *
-     * @return allocation
-     */
-    static public Allocation createTyped(RenderScript rs, Type type, int usage) {
-        return createTyped(rs, type, MipmapControl.MIPMAP_NONE, usage);
-    }
-
-    /**
-     * Creates an Allocation for use by scripts with a given {@link
-     * android.support.v8.renderscript.Type} and no mipmaps
-     *
-     * @param rs Context to which the Allocation will belong.
-     * @param type RenderScript Type describing data layout
-     *
-     * @return allocation
-     */
-    static public Allocation createTyped(RenderScript rs, Type type) {
-        return createTyped(rs, type, MipmapControl.MIPMAP_NONE, USAGE_SCRIPT);
-    }
-
-    /**
-     * Creates an Allocation with a specified number of given elements
-     *
-     * @param rs Context to which the Allocation will belong.
-     * @param e Element to use in the Allocation
-     * @param count the number of Elements in the Allocation
-     * @param usage bit field specifying how the Allocation is
-     *              utilized
-     *
-     * @return allocation
-     */
-    static public Allocation createSized(RenderScript rs, Element e,
-                                         int count, int usage) {
-        rs.validate();
-        Type.Builder b = new Type.Builder(rs, e);
-        b.setX(count);
-        Type t = b.create();
-
-        long id = rs.nAllocationCreateTyped(t.getID(rs), MipmapControl.MIPMAP_NONE.mID, usage, 0);
-        if (id == 0) {
-            throw new RSRuntimeException("Allocation creation failed.");
-        }
-        return new Allocation(id, rs, t, usage);
-    }
-
-    /**
-     * Creates an Allocation with a specified number of given elements
-     *
-     * @param rs Context to which the Allocation will belong.
-     * @param e Element to use in the Allocation
-     * @param count the number of Elements in the Allocation
-     *
-     * @return allocation
-     */
-    static public Allocation createSized(RenderScript rs, Element e, int count) {
-        return createSized(rs, e, count, USAGE_SCRIPT);
-    }
-
-    static Element elementFromBitmap(RenderScript rs, Bitmap b) {
-        final Bitmap.Config bc = b.getConfig();
-        if (bc == Bitmap.Config.ALPHA_8) {
-            return Element.A_8(rs);
-        }
-        if (bc == Bitmap.Config.ARGB_4444) {
-            return Element.RGBA_4444(rs);
-        }
-        if (bc == Bitmap.Config.ARGB_8888) {
-            return Element.RGBA_8888(rs);
-        }
-        if (bc == Bitmap.Config.RGB_565) {
-            return Element.RGB_565(rs);
-        }
-        throw new RSInvalidStateException("Bad bitmap type: " + bc);
-    }
-
-    static Type typeFromBitmap(RenderScript rs, Bitmap b,
-                                       MipmapControl mip) {
-        Element e = elementFromBitmap(rs, b);
-        Type.Builder tb = new Type.Builder(rs, e);
-        tb.setX(b.getWidth());
-        tb.setY(b.getHeight());
-        tb.setMipmaps(mip == MipmapControl.MIPMAP_FULL);
-        return tb.create();
-    }
-
-    /**
-     * Creates an Allocation from a {@link android.graphics.Bitmap}.
-     *
-     * @param rs Context to which the allocation will belong.
-     * @param b Bitmap source for the allocation data
-     * @param mips specifies desired mipmap behaviour for the
-     *             allocation
-     * @param usage bit field specifying how the allocation is
-     *              utilized
-     *
-     * @return Allocation containing bitmap data
-     *
-     */
-    static public Allocation createFromBitmap(RenderScript rs, Bitmap b,
-                                              MipmapControl mips,
-                                              int usage) {
-        rs.validate();
-
-        // WAR undocumented color formats
-        if (b.getConfig() == null) {
-            if ((usage & USAGE_SHARED) != 0) {
-                throw new RSIllegalArgumentException("USAGE_SHARED cannot be used with a Bitmap that has a null config.");
-            }
-            Bitmap newBitmap = Bitmap.createBitmap(b.getWidth(), b.getHeight(), Bitmap.Config.ARGB_8888);
-            Canvas c = new Canvas(newBitmap);
-            c.drawBitmap(b, 0, 0, null);
-            return createFromBitmap(rs, newBitmap, mips, usage);
-        }
-
-        Type t = typeFromBitmap(rs, b, mips);
-
-        // enable optimized bitmap path only with no mipmap and script-only usage
-        if (mips == MipmapControl.MIPMAP_NONE &&
-            t.getElement().isCompatible(Element.RGBA_8888(rs)) &&
-            usage == (USAGE_SHARED | USAGE_SCRIPT | USAGE_GRAPHICS_TEXTURE)) {
-            long id = rs.nAllocationCreateBitmapBackedAllocation(t.getID(rs), mips.mID, b, usage);
-            if (id == 0) {
-                throw new RSRuntimeException("Load failed.");
-            }
-
-            // keep a reference to the Bitmap around to prevent GC
-            Allocation alloc = new Allocation(id, rs, t, usage);
-            alloc.setBitmap(b);
-            return alloc;
-        }
-
-
-        long id = rs.nAllocationCreateFromBitmap(t.getID(rs), mips.mID, b, usage);
-        if (id == 0) {
-            throw new RSRuntimeException("Load failed.");
-        }
-        return new Allocation(id, rs, t, usage);
-    }
-
-    /**
-     * Associate a {@link android.view.Surface} with this Allocation. This
-     * operation is only valid for Allocations with {@link #USAGE_IO_OUTPUT}.
-     *
-     * @param sur Surface to associate with allocation
-     */
-    public void setSurface(Surface sur) {
-        mRS.validate();
-        if ((mUsage & USAGE_IO_OUTPUT) == 0) {
-            throw new RSInvalidStateException("Allocation is not USAGE_IO_OUTPUT.");
-        }
-
-        mRS.nAllocationSetSurface(getID(mRS), sur);
-    }
-
-    /**
-     * Creates an Allocation from a {@link android.graphics.Bitmap}.
-     *
-     * <p>This Allocation will be created with {@link #USAGE_SHARED}, and
-     * {@link #USAGE_SCRIPT}.</p>
-     *
-     * @param rs Context to which the allocation will belong.
-     * @param b bitmap source for the allocation data
-     *
-     * @return Allocation containing bitmap data
-     *
-     */
-    static public Allocation createFromBitmap(RenderScript rs, Bitmap b) {
-        return createFromBitmap(rs, b, MipmapControl.MIPMAP_NONE,
-                                USAGE_SHARED | USAGE_SCRIPT | USAGE_GRAPHICS_TEXTURE);
-    }
-
-    /**
-     * Creates a cubemap Allocation from a {@link android.graphics.Bitmap}
-     * containing the horizontal list of cube faces. Each face must be a square,
-     * have the same size as all other faces, and have a width that is a power
-     * of 2.
-     *
-     * @param rs Context to which the allocation will belong.
-     * @param b Bitmap with cubemap faces layed out in the following
-     *          format: right, left, top, bottom, front, back
-     * @param mips specifies desired mipmap behaviour for the cubemap
-     * @param usage bit field specifying how the cubemap is utilized
-     *
-     * @return allocation containing cubemap data
-     *
-     */
-    static public Allocation createCubemapFromBitmap(RenderScript rs, Bitmap b,
-                                                     MipmapControl mips,
-                                                     int usage) {
-        rs.validate();
-
-        int height = b.getHeight();
-        int width = b.getWidth();
-
-        if (width % 6 != 0) {
-            throw new RSIllegalArgumentException("Cubemap height must be multiple of 6");
-        }
-        if (width / 6 != height) {
-            throw new RSIllegalArgumentException("Only square cube map faces supported");
-        }
-        boolean isPow2 = (height & (height - 1)) == 0;
-        if (!isPow2) {
-            throw new RSIllegalArgumentException("Only power of 2 cube faces supported");
-        }
-
-        Element e = elementFromBitmap(rs, b);
-        Type.Builder tb = new Type.Builder(rs, e);
-        tb.setX(height);
-        tb.setY(height);
-        tb.setFaces(true);
-        tb.setMipmaps(mips == MipmapControl.MIPMAP_FULL);
-        Type t = tb.create();
-
-        long id = rs.nAllocationCubeCreateFromBitmap(t.getID(rs), mips.mID, b, usage);
-        if(id == 0) {
-            throw new RSRuntimeException("Load failed for bitmap " + b + " element " + e);
-        }
-        return new Allocation(id, rs, t, usage);
-    }
-
-    /**
-     * Creates a non-mipmapped cubemap Allocation for use as a graphics texture
-     * from a {@link android.graphics.Bitmap} containing the horizontal list of
-     * cube faces. Each face must be a square, have the same size as all other
-     * faces, and have a width that is a power of 2.
-     *
-     * @param rs Context to which the allocation will belong.
-     * @param b bitmap with cubemap faces layed out in the following
-     *          format: right, left, top, bottom, front, back
-     *
-     * @return allocation containing cubemap data
-     *
-     */
-    static public Allocation createCubemapFromBitmap(RenderScript rs,
-                                                     Bitmap b) {
-        return createCubemapFromBitmap(rs, b, MipmapControl.MIPMAP_NONE,
-                                       USAGE_GRAPHICS_TEXTURE);
-    }
-
-    /**
-     * Creates a cubemap Allocation from 6 {@link android.graphics.Bitmap}
-     * objects containing the cube faces. Each face must be a square, have the
-     * same size as all other faces, and have a width that is a power of 2.
-     *
-     * @param rs Context to which the allocation will belong.
-     * @param xpos cubemap face in the positive x direction
-     * @param xneg cubemap face in the negative x direction
-     * @param ypos cubemap face in the positive y direction
-     * @param yneg cubemap face in the negative y direction
-     * @param zpos cubemap face in the positive z direction
-     * @param zneg cubemap face in the negative z direction
-     * @param mips specifies desired mipmap behaviour for the cubemap
-     * @param usage bit field specifying how the cubemap is utilized
-     *
-     * @return allocation containing cubemap data
-     *
-     */
-    static public Allocation createCubemapFromCubeFaces(RenderScript rs,
-                                                        Bitmap xpos,
-                                                        Bitmap xneg,
-                                                        Bitmap ypos,
-                                                        Bitmap yneg,
-                                                        Bitmap zpos,
-                                                        Bitmap zneg,
-                                                        MipmapControl mips,
-                                                        int usage) {
-        /*
-        int height = xpos.getHeight();
-        if (xpos.getWidth() != height ||
-            xneg.getWidth() != height || xneg.getHeight() != height ||
-            ypos.getWidth() != height || ypos.getHeight() != height ||
-            yneg.getWidth() != height || yneg.getHeight() != height ||
-            zpos.getWidth() != height || zpos.getHeight() != height ||
-            zneg.getWidth() != height || zneg.getHeight() != height) {
-            throw new RSIllegalArgumentException("Only square cube map faces supported");
-        }
-        boolean isPow2 = (height & (height - 1)) == 0;
-        if (!isPow2) {
-            throw new RSIllegalArgumentException("Only power of 2 cube faces supported");
-        }
-
-        Element e = elementFromBitmap(rs, xpos);
-        Type.Builder tb = new Type.Builder(rs, e);
-        tb.setX(height);
-        tb.setY(height);
-        tb.setFaces(true);
-        tb.setMipmaps(mips == MipmapControl.MIPMAP_FULL);
-        Type t = tb.create();
-        Allocation cubemap = Allocation.createTyped(rs, t, mips, usage);
-
-        AllocationAdapter adapter = AllocationAdapter.create2D(rs, cubemap);
-        adapter.setFace(Type.CubemapFace.POSITIVE_X);
-        adapter.copyFrom(xpos);
-        adapter.setFace(Type.CubemapFace.NEGATIVE_X);
-        adapter.copyFrom(xneg);
-        adapter.setFace(Type.CubemapFace.POSITIVE_Y);
-        adapter.copyFrom(ypos);
-        adapter.setFace(Type.CubemapFace.NEGATIVE_Y);
-        adapter.copyFrom(yneg);
-        adapter.setFace(Type.CubemapFace.POSITIVE_Z);
-        adapter.copyFrom(zpos);
-        adapter.setFace(Type.CubemapFace.NEGATIVE_Z);
-        adapter.copyFrom(zneg);
-
-        return cubemap;
-        */
-        return null;
-    }
-
-    /**
-     * Creates a non-mipmapped cubemap Allocation for use as a sampler input
-     * from 6 {@link android.graphics.Bitmap} objects containing the cube
-     * faces. Each face must be a square, have the same size as all other faces,
-     * and have a width that is a power of 2.
-     *
-     * @param rs Context to which the allocation will belong.
-     * @param xpos cubemap face in the positive x direction
-     * @param xneg cubemap face in the negative x direction
-     * @param ypos cubemap face in the positive y direction
-     * @param yneg cubemap face in the negative y direction
-     * @param zpos cubemap face in the positive z direction
-     * @param zneg cubemap face in the negative z direction
-     *
-     * @return allocation containing cubemap data
-     *
-     */
-    static public Allocation createCubemapFromCubeFaces(RenderScript rs,
-                                                        Bitmap xpos,
-                                                        Bitmap xneg,
-                                                        Bitmap ypos,
-                                                        Bitmap yneg,
-                                                        Bitmap zpos,
-                                                        Bitmap zneg) {
-        return createCubemapFromCubeFaces(rs, xpos, xneg, ypos, yneg,
-                                          zpos, zneg, MipmapControl.MIPMAP_NONE,
-                                          USAGE_GRAPHICS_TEXTURE);
-    }
-
-    /**
-     * Creates an Allocation from the Bitmap referenced
-     * by resource ID.
-     *
-     * @param rs Context to which the allocation will belong.
-     * @param res application resources
-     * @param id resource id to load the data from
-     * @param mips specifies desired mipmap behaviour for the
-     *             allocation
-     * @param usage bit field specifying how the allocation is
-     *              utilized
-     *
-     * @return Allocation containing resource data
-     *
-     */
-    static public Allocation createFromBitmapResource(RenderScript rs,
-                                                      Resources res,
-                                                      int id,
-                                                      MipmapControl mips,
-                                                      int usage) {
-
-        rs.validate();
-        if ((usage & (USAGE_SHARED | USAGE_IO_INPUT | USAGE_IO_OUTPUT)) != 0) {
-            throw new RSIllegalArgumentException("Unsupported usage specified.");
-        }
-        Bitmap b = BitmapFactory.decodeResource(res, id);
-        Allocation alloc = createFromBitmap(rs, b, mips, usage);
-        b.recycle();
-        return alloc;
-    }
-
-    /**
-     * Creates a non-mipmapped Allocation to use as a graphics texture from the
-     * {@link android.graphics.Bitmap} referenced by resource ID.
-     *
-     * <p>This allocation will be created with {@link #USAGE_SCRIPT} and
-     * {@link #USAGE_GRAPHICS_TEXTURE}.</p>
-     *
-     * @param rs Context to which the allocation will belong.
-     * @param res application resources
-     * @param id resource id to load the data from
-     *
-     * @return Allocation containing resource data
-     *
-     */
-    static public Allocation createFromBitmapResource(RenderScript rs,
-                                                      Resources res,
-                                                      int id) {
-        return createFromBitmapResource(rs, res, id,
-                                        MipmapControl.MIPMAP_NONE,
-                                        USAGE_SCRIPT | USAGE_GRAPHICS_TEXTURE);
-    }
-
-    /**
-     * Creates an Allocation containing string data encoded in UTF-8 format.
-     *
-     * @param rs Context to which the allocation will belong.
-     * @param str string to create the allocation from
-     * @param usage bit field specifying how the allocaiton is
-     *              utilized
-     *
-     */
-    static public Allocation createFromString(RenderScript rs,
-                                              String str,
-                                              int usage) {
-        rs.validate();
-        byte[] allocArray = null;
-        try {
-            allocArray = str.getBytes("UTF-8");
-            Allocation alloc = Allocation.createSized(rs, Element.U8(rs), allocArray.length, usage);
-            alloc.copyFrom(allocArray);
-            return alloc;
-        }
-        catch (Exception e) {
-            throw new RSRuntimeException("Could not convert string to utf-8.");
-        }
-    }
-
-    /**
-     * Frees any native resources associated with this object.  The
-     * primary use is to force immediate cleanup of resources when it is
-     * believed the GC will not respond quickly enough.
-     * For USAGE_IO_OUTPUT, destroy() implies setSurface(null).
-     */
-    @Override
-    public void destroy() {
-        if (mIncCompatAllocation != 0) {
-            boolean shouldDestroy = false;
-            synchronized(this) {
-                if (!mIncAllocDestroyed) {
-                    shouldDestroy = true;
-                    mIncAllocDestroyed = true;
-                }
-            }
-
-            if (shouldDestroy) {
-                // must include nObjDestroy in the critical section
-                ReentrantReadWriteLock.ReadLock rlock = mRS.mRWLock.readLock();
-                rlock.lock();
-                if(mRS.isAlive()) {
-                    mRS.nIncObjDestroy(mIncCompatAllocation);
-                }
-                rlock.unlock();
-                mIncCompatAllocation = 0;
-            }
-        }
-        if ((mUsage & (USAGE_IO_INPUT | USAGE_IO_OUTPUT)) != 0) {
-            setSurface(null);
-        }
-        super.destroy();
-    }
-
-}
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/BaseObj.java b/v8/renderscript/java/src/android/support/v8/renderscript/BaseObj.java
deleted file mode 100644
index bb49600..0000000
--- a/v8/renderscript/java/src/android/support/v8/renderscript/BaseObj.java
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * Copyright (C) 2012 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 android.support.v8.renderscript;
-
-import android.util.Log;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
-
-/**
- * BaseObj is the base class for all RenderScript objects owned by a RS context.
- * It is responsible for lifetime management and resource tracking. This class
- * should not be used by a user application.
- *
- **/
-public class BaseObj {
-    BaseObj(long id, RenderScript rs) {
-        rs.validate();
-        mRS = rs;
-        mID = id;
-        mDestroyed = false;
-    }
-
-    void setID(long id) {
-        if (mID != 0) {
-            throw new RSRuntimeException("Internal Error, reset of object ID.");
-        }
-        mID = id;
-    }
-
-    /**
-     * Lookup the native object ID for this object.  Primarily used by the
-     * generated reflected code.
-     *
-     * @param rs Context to verify against internal context for
-     *           match.
-     *
-     * @return long
-     */
-    long getID(RenderScript rs) {
-        mRS.validate();
-        if (mDestroyed) {
-            throw new RSInvalidStateException("using a destroyed object.");
-        }
-        if (mID == 0) {
-            throw new RSRuntimeException("Internal error: Object id 0.");
-        }
-        if ((rs != null) && (rs != mRS)) {
-            throw new RSInvalidStateException("using object with mismatched context.");
-        }
-        return mID;
-    }
-
-    android.renderscript.BaseObj getNObj() {
-        return null;
-    }
-
-    void checkValid() {
-        if ((mID == 0) && (getNObj() == null)) {
-            throw new RSIllegalArgumentException("Invalid object.");
-        }
-    }
-
-    private long mID;
-    private boolean mDestroyed;
-    RenderScript mRS;
-
-    private void helpDestroy() {
-        boolean shouldDestroy = false;
-        synchronized(this) {
-            if (!mDestroyed) {
-                shouldDestroy = true;
-                mDestroyed = true;
-            }
-        }
-
-        if (shouldDestroy) {
-            // must include nObjDestroy in the critical section
-            ReentrantReadWriteLock.ReadLock rlock = mRS.mRWLock.readLock();
-            rlock.lock();
-            if(mRS.isAlive()) {
-                mRS.nObjDestroy(mID);
-            }
-            rlock.unlock();
-            mRS = null;
-            mID = 0;
-        }
-    }
-
-
-    protected void finalize() throws Throwable {
-        helpDestroy();
-        super.finalize();
-    }
-
-    /**
-     * Frees any native resources associated with this object.  The
-     * primary use is to force immediate cleanup of resources when it is
-     * believed the GC will not respond quickly enough.
-     */
-    public void destroy() {
-        if(mDestroyed) {
-            throw new RSInvalidStateException("Object already destroyed.");
-        }
-        helpDestroy();
-    }
-
-    /**
-     * Calculates the hash code value for a BaseObj.
-     *
-     * @return int
-     */
-    @Override
-    public int hashCode() {
-        return (int)((mID & 0xfffffff) ^ (mID >> 32));
-    }
-
-    /**
-     * Compare the current BaseObj with another BaseObj for equality.
-     *
-     * @param obj The object to check equality with.
-     *
-     * @return boolean
-     */
-    @Override
-    public boolean equals(Object obj) {
-        // Early-out check to see if both BaseObjs are actually the same
-        if (this == obj)
-            return true;
-
-        if (obj == null) {
-            return false;
-        }
-
-        if (getClass() != obj.getClass()) {
-            return false;
-        }
-
-        BaseObj b = (BaseObj) obj;
-        return mID == b.mID;
-    }
-}
-
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/Byte2.java b/v8/renderscript/java/src/android/support/v8/renderscript/Byte2.java
deleted file mode 100644
index 2371077..0000000
--- a/v8/renderscript/java/src/android/support/v8/renderscript/Byte2.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2012 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 android.support.v8.renderscript;
-
-import java.lang.Math;
-import android.util.Log;
-
-
-/**
- * Class for exposing the native RenderScript byte2 type back to the Android system.
- *
- **/
-public class Byte2 {
-    public Byte2() {
-    }
-
-    public Byte2(byte initX, byte initY) {
-        x = initX;
-        y = initY;
-    }
-
-    public byte x;
-    public byte y;
-}
-
-
-
-
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/Byte3.java b/v8/renderscript/java/src/android/support/v8/renderscript/Byte3.java
deleted file mode 100644
index 4ed6af6..0000000
--- a/v8/renderscript/java/src/android/support/v8/renderscript/Byte3.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2012 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 android.support.v8.renderscript;
-
-import java.lang.Math;
-import android.util.Log;
-
-
-/**
- * Class for exposing the native RenderScript byte3 type back to the Android system.
- *
- **/
-public class Byte3 {
-    public Byte3() {
-    }
-
-    public Byte3(byte initX, byte initY, byte initZ) {
-        x = initX;
-        y = initY;
-        z = initZ;
-    }
-
-    public byte x;
-    public byte y;
-    public byte z;
-}
-
-
-
-
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/Byte4.java b/v8/renderscript/java/src/android/support/v8/renderscript/Byte4.java
deleted file mode 100644
index 715a718..0000000
--- a/v8/renderscript/java/src/android/support/v8/renderscript/Byte4.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2012 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 android.support.v8.renderscript;
-
-import java.lang.Math;
-import android.util.Log;
-
-
-/**
- * Class for exposing the native RenderScript byte4 type back to the Android system.
- *
- **/
-public class Byte4 {
-    public Byte4() {
-    }
-
-    public Byte4(byte initX, byte initY, byte initZ, byte initW) {
-        x = initX;
-        y = initY;
-        z = initZ;
-        w = initW;
-    }
-
-    public byte x;
-    public byte y;
-    public byte z;
-    public byte w;
-}
-
-
-
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/Double2.java b/v8/renderscript/java/src/android/support/v8/renderscript/Double2.java
deleted file mode 100644
index cd73363..0000000
--- a/v8/renderscript/java/src/android/support/v8/renderscript/Double2.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2012 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 android.support.v8.renderscript;
-
-import java.lang.Math;
-import android.util.Log;
-
-
-/**
- * Class for exposing the native RenderScript double2 type back
- * to the Android system.
- *
- **/
-public class Double2 {
-    public Double2() {
-    }
-
-    public Double2(double initX, double initY) {
-        x = initX;
-        y = initY;
-    }
-
-    public double x;
-    public double y;
-}
-
-
-
-
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/Double3.java b/v8/renderscript/java/src/android/support/v8/renderscript/Double3.java
deleted file mode 100644
index 38a46a6..0000000
--- a/v8/renderscript/java/src/android/support/v8/renderscript/Double3.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2012 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 android.support.v8.renderscript;
-
-import java.lang.Math;
-import android.util.Log;
-
-
-/**
- * Class for exposing the native RenderScript double3 type back
- * to the Android system.
- *
- **/
-public class Double3 {
-    public Double3() {
-    }
-
-    public Double3(double initX, double initY, double initZ) {
-        x = initX;
-        y = initY;
-        z = initZ;
-    }
-
-    public double x;
-    public double y;
-    public double z;
-}
-
-
-
-
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/Double4.java b/v8/renderscript/java/src/android/support/v8/renderscript/Double4.java
deleted file mode 100644
index 6de0fa8..0000000
--- a/v8/renderscript/java/src/android/support/v8/renderscript/Double4.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2012 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 android.support.v8.renderscript;
-
-import java.lang.Math;
-import android.util.Log;
-
-
-/**
- * Class for exposing the native RenderScript double4 type back
- * to the Android system.
- *
- **/
-public class Double4 {
-    public Double4() {
-    }
-
-    public Double4(double initX, double initY, double initZ, double initW) {
-        x = initX;
-        y = initY;
-        z = initZ;
-        w = initW;
-    }
-
-    public double x;
-    public double y;
-    public double z;
-    public double w;
-}
-
-
-
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/Element.java b/v8/renderscript/java/src/android/support/v8/renderscript/Element.java
deleted file mode 100644
index 135d854..0000000
--- a/v8/renderscript/java/src/android/support/v8/renderscript/Element.java
+++ /dev/null
@@ -1,1020 +0,0 @@
-/*
- * Copyright (C) 2013 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 android.support.v8.renderscript;
-
-import java.lang.reflect.Field;
-
-import android.util.Log;
-
-/**
- * <p>An Element represents one item within an {@link
- * android.support.v8.renderscript.Allocation}.  An Element is roughly
- * equivalent to a C type in a RenderScript kernel. Elements may be basic or
- * complex. Some basic elements are</p> <ul> <li>A single float value
- * (equivalent to a float in a kernel)</li> <li>A four-element float vector
- * (equivalent to a float4 in a kernel)</li> <li>An unsigned 32-bit integer
- * (equivalent to an unsigned int in a kernel)</li> <li>A single signed 8-bit
- * integer (equivalent to a char in a kernel)</li> </ul> <p>A complex element is
- * roughly equivalent to a C struct and contains a number of basic or complex
- * Elements. From Java code, a complex element contains a list of sub-elements
- * and names that represents a particular data structure. Structs used in RS
- * scripts are available to Java code by using the
- * {@code ScriptField_structname} class that is reflected from a particular
- * script.</p>
- *
- * <p>Basic Elements are comprised of a {@link
- * android.support.v8.renderscript.Element.DataType} and a {@link
- * android.support.v8.renderscript.Element.DataKind}. The DataType encodes C
- * type information of an Element, while the DataKind encodes how that Element
- * should be interpreted by a {@link android.support.v8.renderscript.Sampler}.
- * Note that {@link android.support.v8.renderscript.Allocation} objects with
- * DataKind {@link android.support.v8.renderscript.Element.DataKind#USER} cannot
- * be used as input for a {@link android.support.v8.renderscript.Sampler}. In
- * general, {@link android.support.v8.renderscript.Allocation} objects that are
- * intended for use with a {@link android.support.v8.renderscript.Sampler}
- * should use bitmap-derived Elements such as
- * {@link android.support.v8.renderscript.Element#RGBA_8888} or {@link
- * android.support.v8.renderscript#Element.A_8}.</p>
- *
- * <div class="special reference">
- * <h3>Developer Guides</h3>
- * <p>For more information about creating an application that uses RenderScript,
- * read the
- * <a href="{@docRoot}guide/topics/renderscript/index.html">RenderScript</a>
- * developer guide.</p>
- * </div>
- **/
-public class Element extends BaseObj {
-    int mSize;
-    Element[] mElements;
-    String[] mElementNames;
-    int[] mArraySizes;
-    int[] mOffsetInBytes;
-    int[] mVisibleElementMap;
-
-    DataType mType;
-    DataKind mKind;
-    boolean mNormalized;
-    int mVectorSize;
-
-    private void updateVisibleSubElements() {
-        if (mElements == null) {
-            return;
-        }
-
-        int noPaddingFieldCount = 0;
-        int fieldCount = mElementNames.length;
-        // Find out how many elements are not padding
-        for (int ct = 0; ct < fieldCount; ct ++) {
-            if (mElementNames[ct].charAt(0) != '#') {
-                noPaddingFieldCount ++;
-            }
-        }
-        mVisibleElementMap = new int[noPaddingFieldCount];
-
-        // Make a map that points us at non-padding elements
-        for (int ct = 0, ctNoPadding = 0; ct < fieldCount; ct ++) {
-            if (mElementNames[ct].charAt(0) != '#') {
-                mVisibleElementMap[ctNoPadding ++] = ct;
-            }
-        }
-    }
-
-    /**
-    * @return element size in bytes
-    */
-    public int getBytesSize() {
-        return mSize;
-    }
-
-    /**
-    * Returns the number of vector components. 2 for float2, 4 for
-    * float4, etc.
-    * @return element vector size
-    */
-    public int getVectorSize() {
-        return mVectorSize;
-    }
-
-
-    /**
-     * DataType represents the basic type information for a basic element.  The
-     * naming convention follows.  For numeric types it is FLOAT,
-     * SIGNED, or UNSIGNED followed by the _BITS where BITS is the
-     * size of the data.  BOOLEAN is a true / false (1,0)
-     * represented in an 8 bit container.  The UNSIGNED variants
-     * with multiple bit definitions are for packed graphical data
-     * formats and represent vectors with per vector member sizes
-     * which are treated as a single unit for packing and alignment
-     * purposes.
-     *
-     * MATRIX the three matrix types contain FLOAT_32 elements and are treated
-     * as 32 bits for alignment purposes.
-     *
-     * RS_* objects.  32 bit opaque handles.
-     */
-    public enum DataType {
-        NONE (0, 0),
-        //FLOAT_16 (1, 2),
-        FLOAT_32 (2, 4),
-        FLOAT_64 (3, 8),
-        SIGNED_8 (4, 1),
-        SIGNED_16 (5, 2),
-        SIGNED_32 (6, 4),
-        SIGNED_64 (7, 8),
-        UNSIGNED_8 (8, 1),
-        UNSIGNED_16 (9, 2),
-        UNSIGNED_32 (10, 4),
-        UNSIGNED_64 (11, 8),
-
-        BOOLEAN(12, 1),
-
-        UNSIGNED_5_6_5 (13, 2),
-        UNSIGNED_5_5_5_1 (14, 2),
-        UNSIGNED_4_4_4_4 (15, 2),
-
-        MATRIX_4X4 (16, 64),
-        MATRIX_3X3 (17, 36),
-        MATRIX_2X2 (18, 16),
-
-        RS_ELEMENT (1000),
-        RS_TYPE (1001),
-        RS_ALLOCATION (1002),
-        RS_SAMPLER (1003),
-        RS_SCRIPT (1004);
-
-        int mID;
-        int mSize;
-        DataType(int id, int size) {
-            mID = id;
-            mSize = size;
-        }
-
-        DataType(int id) {
-            mID = id;
-            mSize = 4;
-            if (RenderScript.sPointerSize == 8) {
-                mSize = 32;
-            }
-        }
-    }
-
-    /**
-     * The special interpretation of the data if required.  This is primarly
-     * useful for graphical data.  USER indicates no special interpretation is
-     * expected.  PIXEL is used in conjunction with the standard data types for
-     * representing texture formats.
-     */
-    public enum DataKind {
-        USER (0),
-
-        PIXEL_L (7),
-        PIXEL_A (8),
-        PIXEL_LA (9),
-        PIXEL_RGB (10),
-        PIXEL_RGBA (11),
-        PIXEL_DEPTH (12),
-        PIXEL_YUV(13);
-
-        int mID;
-        DataKind(int id) {
-            mID = id;
-        }
-    }
-
-    /**
-     * Return if a element is too complex for use as a data source for a Mesh or
-     * a Program.
-     *
-     * @return boolean
-     */
-    public boolean isComplex() {
-        if (mElements == null) {
-            return false;
-        }
-        for (int ct=0; ct < mElements.length; ct++) {
-            if (mElements[ct].mElements != null) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    /**
-    * Elements could be simple, such as an int or a float, or a
-    * structure with multiple sub elements, such as a collection of
-    * floats, float2, float4. This function returns zero for simple
-    * elements or the number of sub-elements otherwise.
-    * @return number of sub-elements in this element
-    */
-    public int getSubElementCount() {
-        if (mVisibleElementMap == null) {
-            return 0;
-        }
-        return mVisibleElementMap.length;
-    }
-
-    /**
-    * For complex elements, this function will return the
-    * sub-element at index
-    * @param index index of the sub-element to return
-    * @return sub-element in this element at given index
-    */
-    public Element getSubElement(int index) {
-        if (mVisibleElementMap == null) {
-            throw new RSIllegalArgumentException("Element contains no sub-elements");
-        }
-        if (index < 0 || index >= mVisibleElementMap.length) {
-            throw new RSIllegalArgumentException("Illegal sub-element index");
-        }
-        return mElements[mVisibleElementMap[index]];
-    }
-
-    /**
-    * For complex elements, this function will return the
-    * sub-element name at index
-    * @param index index of the sub-element
-    * @return sub-element in this element at given index
-    */
-    public String getSubElementName(int index) {
-        if (mVisibleElementMap == null) {
-            throw new RSIllegalArgumentException("Element contains no sub-elements");
-        }
-        if (index < 0 || index >= mVisibleElementMap.length) {
-            throw new RSIllegalArgumentException("Illegal sub-element index");
-        }
-        return mElementNames[mVisibleElementMap[index]];
-    }
-
-    /**
-    * For complex elements, some sub-elements could be statically
-    * sized arrays. This function will return the array size for
-    * sub-element at index
-    * @param index index of the sub-element
-    * @return array size of sub-element in this element at given index
-    */
-    public int getSubElementArraySize(int index) {
-        if (mVisibleElementMap == null) {
-            throw new RSIllegalArgumentException("Element contains no sub-elements");
-        }
-        if (index < 0 || index >= mVisibleElementMap.length) {
-            throw new RSIllegalArgumentException("Illegal sub-element index");
-        }
-        return mArraySizes[mVisibleElementMap[index]];
-    }
-
-    /**
-    * This function specifies the location of a sub-element within
-    * the element
-    * @param index index of the sub-element
-    * @return offset in bytes of sub-element in this element at given index
-    */
-    public int getSubElementOffsetBytes(int index) {
-        if (mVisibleElementMap == null) {
-            throw new RSIllegalArgumentException("Element contains no sub-elements");
-        }
-        if (index < 0 || index >= mVisibleElementMap.length) {
-            throw new RSIllegalArgumentException("Illegal sub-element index");
-        }
-        return mOffsetInBytes[mVisibleElementMap[index]];
-    }
-
-    /**
-    * @return element data type
-    */
-    public DataType getDataType() {
-        return mType;
-    }
-
-    /**
-    * @return element data kind
-    */
-    public DataKind getDataKind() {
-        return mKind;
-    }
-
-    /**
-     * Utility function for returning an Element containing a single Boolean.
-     *
-     * @param rs Context to which the element will belong.
-     *
-     * @return Element
-     */
-    public static Element BOOLEAN(RenderScript rs) {
-        if(rs.mElement_BOOLEAN == null) {
-            rs.mElement_BOOLEAN = createUser(rs, DataType.BOOLEAN);
-        }
-        return rs.mElement_BOOLEAN;
-    }
-
-    /**
-     * Utility function for returning an Element containing a single UNSIGNED_8.
-     *
-     * @param rs Context to which the element will belong.
-     *
-     * @return Element
-     */
-    public static Element U8(RenderScript rs) {
-        if(rs.mElement_U8 == null) {
-            rs.mElement_U8 = createUser(rs, DataType.UNSIGNED_8);
-        }
-        return rs.mElement_U8;
-    }
-
-    /**
-     * Utility function for returning an Element containing a single SIGNED_8.
-     *
-     * @param rs Context to which the element will belong.
-     *
-     * @return Element
-     */
-    public static Element I8(RenderScript rs) {
-        if(rs.mElement_I8 == null) {
-            rs.mElement_I8 = createUser(rs, DataType.SIGNED_8);
-        }
-        return rs.mElement_I8;
-    }
-
-    public static Element U16(RenderScript rs) {
-        if(rs.mElement_U16 == null) {
-            rs.mElement_U16 = createUser(rs, DataType.UNSIGNED_16);
-        }
-        return rs.mElement_U16;
-    }
-
-    public static Element I16(RenderScript rs) {
-        if(rs.mElement_I16 == null) {
-            rs.mElement_I16 = createUser(rs, DataType.SIGNED_16);
-        }
-        return rs.mElement_I16;
-    }
-
-    public static Element U32(RenderScript rs) {
-        if(rs.mElement_U32 == null) {
-            rs.mElement_U32 = createUser(rs, DataType.UNSIGNED_32);
-        }
-        return rs.mElement_U32;
-    }
-
-    public static Element I32(RenderScript rs) {
-        if(rs.mElement_I32 == null) {
-            rs.mElement_I32 = createUser(rs, DataType.SIGNED_32);
-        }
-        return rs.mElement_I32;
-    }
-
-    public static Element U64(RenderScript rs) {
-        if(rs.mElement_U64 == null) {
-            rs.mElement_U64 = createUser(rs, DataType.UNSIGNED_64);
-        }
-        return rs.mElement_U64;
-    }
-
-    public static Element I64(RenderScript rs) {
-        if(rs.mElement_I64 == null) {
-            rs.mElement_I64 = createUser(rs, DataType.SIGNED_64);
-        }
-        return rs.mElement_I64;
-    }
-
-    public static Element F32(RenderScript rs) {
-        if(rs.mElement_F32 == null) {
-            rs.mElement_F32 = createUser(rs, DataType.FLOAT_32);
-        }
-        return rs.mElement_F32;
-    }
-
-    public static Element F64(RenderScript rs) {
-        if(rs.mElement_F64 == null) {
-            rs.mElement_F64 = createUser(rs, DataType.FLOAT_64);
-        }
-        return rs.mElement_F64;
-    }
-
-    public static Element ELEMENT(RenderScript rs) {
-        if(rs.mElement_ELEMENT == null) {
-            rs.mElement_ELEMENT = createUser(rs, DataType.RS_ELEMENT);
-        }
-        return rs.mElement_ELEMENT;
-    }
-
-    public static Element TYPE(RenderScript rs) {
-        if(rs.mElement_TYPE == null) {
-            rs.mElement_TYPE = createUser(rs, DataType.RS_TYPE);
-        }
-        return rs.mElement_TYPE;
-    }
-
-    public static Element ALLOCATION(RenderScript rs) {
-        if(rs.mElement_ALLOCATION == null) {
-            rs.mElement_ALLOCATION = createUser(rs, DataType.RS_ALLOCATION);
-        }
-        return rs.mElement_ALLOCATION;
-    }
-
-    public static Element SAMPLER(RenderScript rs) {
-        if(rs.mElement_SAMPLER == null) {
-            rs.mElement_SAMPLER = createUser(rs, DataType.RS_SAMPLER);
-        }
-        return rs.mElement_SAMPLER;
-    }
-
-    public static Element SCRIPT(RenderScript rs) {
-        if(rs.mElement_SCRIPT == null) {
-            rs.mElement_SCRIPT = createUser(rs, DataType.RS_SCRIPT);
-        }
-        return rs.mElement_SCRIPT;
-    }
-
-
-    public static Element A_8(RenderScript rs) {
-        if(rs.mElement_A_8 == null) {
-            rs.mElement_A_8 = createPixel(rs, DataType.UNSIGNED_8, DataKind.PIXEL_A);
-        }
-        return rs.mElement_A_8;
-    }
-
-    public static Element RGB_565(RenderScript rs) {
-        if(rs.mElement_RGB_565 == null) {
-            rs.mElement_RGB_565 = createPixel(rs, DataType.UNSIGNED_5_6_5, DataKind.PIXEL_RGB);
-        }
-        return rs.mElement_RGB_565;
-    }
-
-    public static Element RGB_888(RenderScript rs) {
-        if(rs.mElement_RGB_888 == null) {
-            rs.mElement_RGB_888 = createPixel(rs, DataType.UNSIGNED_8, DataKind.PIXEL_RGB);
-        }
-        return rs.mElement_RGB_888;
-    }
-
-    public static Element RGBA_5551(RenderScript rs) {
-        if(rs.mElement_RGBA_5551 == null) {
-            rs.mElement_RGBA_5551 = createPixel(rs, DataType.UNSIGNED_5_5_5_1, DataKind.PIXEL_RGBA);
-        }
-        return rs.mElement_RGBA_5551;
-    }
-
-    public static Element RGBA_4444(RenderScript rs) {
-        if(rs.mElement_RGBA_4444 == null) {
-            rs.mElement_RGBA_4444 = createPixel(rs, DataType.UNSIGNED_4_4_4_4, DataKind.PIXEL_RGBA);
-        }
-        return rs.mElement_RGBA_4444;
-    }
-
-    public static Element RGBA_8888(RenderScript rs) {
-        if(rs.mElement_RGBA_8888 == null) {
-            rs.mElement_RGBA_8888 = createPixel(rs, DataType.UNSIGNED_8, DataKind.PIXEL_RGBA);
-        }
-        return rs.mElement_RGBA_8888;
-    }
-
-    public static Element F32_2(RenderScript rs) {
-        if(rs.mElement_FLOAT_2 == null) {
-            rs.mElement_FLOAT_2 = createVector(rs, DataType.FLOAT_32, 2);
-        }
-        return rs.mElement_FLOAT_2;
-    }
-
-    public static Element F32_3(RenderScript rs) {
-        if(rs.mElement_FLOAT_3 == null) {
-            rs.mElement_FLOAT_3 = createVector(rs, DataType.FLOAT_32, 3);
-        }
-        return rs.mElement_FLOAT_3;
-    }
-
-    public static Element F32_4(RenderScript rs) {
-        if(rs.mElement_FLOAT_4 == null) {
-            rs.mElement_FLOAT_4 = createVector(rs, DataType.FLOAT_32, 4);
-        }
-        return rs.mElement_FLOAT_4;
-    }
-
-    public static Element F64_2(RenderScript rs) {
-        if(rs.mElement_DOUBLE_2 == null) {
-            rs.mElement_DOUBLE_2 = createVector(rs, DataType.FLOAT_64, 2);
-        }
-        return rs.mElement_DOUBLE_2;
-    }
-
-    public static Element F64_3(RenderScript rs) {
-        if(rs.mElement_DOUBLE_3 == null) {
-            rs.mElement_DOUBLE_3 = createVector(rs, DataType.FLOAT_64, 3);
-        }
-        return rs.mElement_DOUBLE_3;
-    }
-
-    public static Element F64_4(RenderScript rs) {
-        if(rs.mElement_DOUBLE_4 == null) {
-            rs.mElement_DOUBLE_4 = createVector(rs, DataType.FLOAT_64, 4);
-        }
-        return rs.mElement_DOUBLE_4;
-    }
-
-    public static Element U8_2(RenderScript rs) {
-        if(rs.mElement_UCHAR_2 == null) {
-            rs.mElement_UCHAR_2 = createVector(rs, DataType.UNSIGNED_8, 2);
-        }
-        return rs.mElement_UCHAR_2;
-    }
-
-    public static Element U8_3(RenderScript rs) {
-        if(rs.mElement_UCHAR_3 == null) {
-            rs.mElement_UCHAR_3 = createVector(rs, DataType.UNSIGNED_8, 3);
-        }
-        return rs.mElement_UCHAR_3;
-    }
-
-    public static Element U8_4(RenderScript rs) {
-        if(rs.mElement_UCHAR_4 == null) {
-            rs.mElement_UCHAR_4 = createVector(rs, DataType.UNSIGNED_8, 4);
-        }
-        return rs.mElement_UCHAR_4;
-    }
-
-    public static Element I8_2(RenderScript rs) {
-        if(rs.mElement_CHAR_2 == null) {
-            rs.mElement_CHAR_2 = createVector(rs, DataType.SIGNED_8, 2);
-        }
-        return rs.mElement_CHAR_2;
-    }
-
-    public static Element I8_3(RenderScript rs) {
-        if(rs.mElement_CHAR_3 == null) {
-            rs.mElement_CHAR_3 = createVector(rs, DataType.SIGNED_8, 3);
-        }
-        return rs.mElement_CHAR_3;
-    }
-
-    public static Element I8_4(RenderScript rs) {
-        if(rs.mElement_CHAR_4 == null) {
-            rs.mElement_CHAR_4 = createVector(rs, DataType.SIGNED_8, 4);
-        }
-        return rs.mElement_CHAR_4;
-    }
-
-    public static Element U16_2(RenderScript rs) {
-        if(rs.mElement_USHORT_2 == null) {
-            rs.mElement_USHORT_2 = createVector(rs, DataType.UNSIGNED_16, 2);
-        }
-        return rs.mElement_USHORT_2;
-    }
-
-    public static Element U16_3(RenderScript rs) {
-        if(rs.mElement_USHORT_3 == null) {
-            rs.mElement_USHORT_3 = createVector(rs, DataType.UNSIGNED_16, 3);
-        }
-        return rs.mElement_USHORT_3;
-    }
-
-    public static Element U16_4(RenderScript rs) {
-        if(rs.mElement_USHORT_4 == null) {
-            rs.mElement_USHORT_4 = createVector(rs, DataType.UNSIGNED_16, 4);
-        }
-        return rs.mElement_USHORT_4;
-    }
-
-    public static Element I16_2(RenderScript rs) {
-        if(rs.mElement_SHORT_2 == null) {
-            rs.mElement_SHORT_2 = createVector(rs, DataType.SIGNED_16, 2);
-        }
-        return rs.mElement_SHORT_2;
-    }
-
-    public static Element I16_3(RenderScript rs) {
-        if(rs.mElement_SHORT_3 == null) {
-            rs.mElement_SHORT_3 = createVector(rs, DataType.SIGNED_16, 3);
-        }
-        return rs.mElement_SHORT_3;
-    }
-
-    public static Element I16_4(RenderScript rs) {
-        if(rs.mElement_SHORT_4 == null) {
-            rs.mElement_SHORT_4 = createVector(rs, DataType.SIGNED_16, 4);
-        }
-        return rs.mElement_SHORT_4;
-    }
-
-    public static Element U32_2(RenderScript rs) {
-        if(rs.mElement_UINT_2 == null) {
-            rs.mElement_UINT_2 = createVector(rs, DataType.UNSIGNED_32, 2);
-        }
-        return rs.mElement_UINT_2;
-    }
-
-    public static Element U32_3(RenderScript rs) {
-        if(rs.mElement_UINT_3 == null) {
-            rs.mElement_UINT_3 = createVector(rs, DataType.UNSIGNED_32, 3);
-        }
-        return rs.mElement_UINT_3;
-    }
-
-    public static Element U32_4(RenderScript rs) {
-        if(rs.mElement_UINT_4 == null) {
-            rs.mElement_UINT_4 = createVector(rs, DataType.UNSIGNED_32, 4);
-        }
-        return rs.mElement_UINT_4;
-    }
-
-    public static Element I32_2(RenderScript rs) {
-        if(rs.mElement_INT_2 == null) {
-            rs.mElement_INT_2 = createVector(rs, DataType.SIGNED_32, 2);
-        }
-        return rs.mElement_INT_2;
-    }
-
-    public static Element I32_3(RenderScript rs) {
-        if(rs.mElement_INT_3 == null) {
-            rs.mElement_INT_3 = createVector(rs, DataType.SIGNED_32, 3);
-        }
-        return rs.mElement_INT_3;
-    }
-
-    public static Element I32_4(RenderScript rs) {
-        if(rs.mElement_INT_4 == null) {
-            rs.mElement_INT_4 = createVector(rs, DataType.SIGNED_32, 4);
-        }
-        return rs.mElement_INT_4;
-    }
-
-    public static Element U64_2(RenderScript rs) {
-        if(rs.mElement_ULONG_2 == null) {
-            rs.mElement_ULONG_2 = createVector(rs, DataType.UNSIGNED_64, 2);
-        }
-        return rs.mElement_ULONG_2;
-    }
-
-    public static Element U64_3(RenderScript rs) {
-        if(rs.mElement_ULONG_3 == null) {
-            rs.mElement_ULONG_3 = createVector(rs, DataType.UNSIGNED_64, 3);
-        }
-        return rs.mElement_ULONG_3;
-    }
-
-    public static Element U64_4(RenderScript rs) {
-        if(rs.mElement_ULONG_4 == null) {
-            rs.mElement_ULONG_4 = createVector(rs, DataType.UNSIGNED_64, 4);
-        }
-        return rs.mElement_ULONG_4;
-    }
-
-    public static Element I64_2(RenderScript rs) {
-        if(rs.mElement_LONG_2 == null) {
-            rs.mElement_LONG_2 = createVector(rs, DataType.SIGNED_64, 2);
-        }
-        return rs.mElement_LONG_2;
-    }
-
-    public static Element I64_3(RenderScript rs) {
-        if(rs.mElement_LONG_3 == null) {
-            rs.mElement_LONG_3 = createVector(rs, DataType.SIGNED_64, 3);
-        }
-        return rs.mElement_LONG_3;
-    }
-
-    public static Element I64_4(RenderScript rs) {
-        if(rs.mElement_LONG_4 == null) {
-            rs.mElement_LONG_4 = createVector(rs, DataType.SIGNED_64, 4);
-        }
-        return rs.mElement_LONG_4;
-    }
-
-    public static Element MATRIX_4X4(RenderScript rs) {
-        if(rs.mElement_MATRIX_4X4 == null) {
-            rs.mElement_MATRIX_4X4 = createUser(rs, DataType.MATRIX_4X4);
-        }
-        return rs.mElement_MATRIX_4X4;
-    }
-
-    public static Element MATRIX_3X3(RenderScript rs) {
-        if(rs.mElement_MATRIX_3X3 == null) {
-            rs.mElement_MATRIX_3X3 = createUser(rs, DataType.MATRIX_3X3);
-        }
-        return rs.mElement_MATRIX_3X3;
-    }
-
-    public static Element MATRIX_2X2(RenderScript rs) {
-        if(rs.mElement_MATRIX_2X2 == null) {
-            rs.mElement_MATRIX_2X2 = createUser(rs, DataType.MATRIX_2X2);
-        }
-        return rs.mElement_MATRIX_2X2;
-    }
-
-    Element(long id, RenderScript rs, Element[] e, String[] n, int[] as) {
-        super(id, rs);
-        mSize = 0;
-        mVectorSize = 1;
-        mElements = e;
-        mElementNames = n;
-        mArraySizes = as;
-        mType = DataType.NONE;
-        mKind = DataKind.USER;
-        mOffsetInBytes = new int[mElements.length];
-        for (int ct = 0; ct < mElements.length; ct++ ) {
-            mOffsetInBytes[ct] = mSize;
-            mSize += mElements[ct].mSize * mArraySizes[ct];
-        }
-        updateVisibleSubElements();
-    }
-
-    Element(long id, RenderScript rs, DataType dt, DataKind dk, boolean norm, int size) {
-        super(id, rs);
-        if ((dt != DataType.UNSIGNED_5_6_5) &&
-            (dt != DataType.UNSIGNED_4_4_4_4) &&
-            (dt != DataType.UNSIGNED_5_5_5_1)) {
-            if (size == 3) {
-                mSize = dt.mSize * 4;
-            } else {
-                mSize = dt.mSize * size;
-            }
-        } else {
-            mSize = dt.mSize;
-        }
-        mType = dt;
-        mKind = dk;
-        mNormalized = norm;
-        mVectorSize = size;
-    }
-
-    Element(long id, RenderScript rs) {
-        super(id, rs);
-    }
-
-    /*
-     * Get an identical dummy Element for Compat Context
-     *
-     */
-    public long getDummyElement(RenderScript mRS) {
-        return mRS.nIncElementCreate(mType.mID, mKind.mID, mNormalized, mVectorSize);
-    }
-    /**
-     * Create a custom Element of the specified DataType.  The DataKind will be
-     * set to USER and the vector size to 1 indicating non-vector.
-     *
-     * @param rs The context associated with the new Element.
-     * @param dt The DataType for the new element.
-     * @return Element
-     */
-    static Element createUser(RenderScript rs, DataType dt) {
-        DataKind dk = DataKind.USER;
-        boolean norm = false;
-        int vecSize = 1;
-        long id = rs.nElementCreate(dt.mID, dk.mID, norm, vecSize);
-        return new Element(id, rs, dt, dk, norm, vecSize);
-    }
-
-    /**
-     * Create a custom vector element of the specified DataType and vector size.
-     * DataKind will be set to USER. Only primitive types (FLOAT_32, FLOAT_64,
-     * SIGNED_8, SIGNED_16, SIGNED_32, SIGNED_64, UNSIGNED_8, UNSIGNED_16,
-     * UNSIGNED_32, UNSIGNED_64, BOOLEAN) are supported.
-     *
-     * @param rs The context associated with the new Element.
-     * @param dt The DataType for the new Element.
-     * @param size Vector size for the new Element.  Range 2-4 inclusive
-     *             supported.
-     *
-     * @return Element
-     */
-    public static Element createVector(RenderScript rs, DataType dt, int size) {
-        if (size < 2 || size > 4) {
-            throw new RSIllegalArgumentException("Vector size out of range 2-4.");
-        }
-
-        switch (dt) {
-        // Support only primitive integer/float/boolean types as vectors.
-        case FLOAT_32:
-        case FLOAT_64:
-        case SIGNED_8:
-        case SIGNED_16:
-        case SIGNED_32:
-        case SIGNED_64:
-        case UNSIGNED_8:
-        case UNSIGNED_16:
-        case UNSIGNED_32:
-        case UNSIGNED_64:
-        case BOOLEAN: {
-            DataKind dk = DataKind.USER;
-            boolean norm = false;
-            long id = rs.nElementCreate(dt.mID, dk.mID, norm, size);
-            return new Element(id, rs, dt, dk, norm, size);
-        }
-
-        default: {
-            throw new RSIllegalArgumentException("Cannot create vector of " +
-                "non-primitive type.");
-        }
-        }
-    }
-
-    /**
-     * Create a new pixel Element type.  A matching DataType and DataKind must
-     * be provided.  The DataType and DataKind must contain the same number of
-     * components.  Vector size will be set to 1.
-     *
-     * @param rs The context associated with the new Element.
-     * @param dt The DataType for the new element.
-     * @param dk The DataKind to specify the mapping of each component in the
-     *           DataType.
-     *
-     * @return Element
-     */
-    public static Element createPixel(RenderScript rs, DataType dt, DataKind dk) {
-        if (!(dk == DataKind.PIXEL_L ||
-              dk == DataKind.PIXEL_A ||
-              dk == DataKind.PIXEL_LA ||
-              dk == DataKind.PIXEL_RGB ||
-              dk == DataKind.PIXEL_RGBA ||
-              dk == DataKind.PIXEL_DEPTH ||
-              dk == DataKind.PIXEL_YUV)) {
-            throw new RSIllegalArgumentException("Unsupported DataKind");
-        }
-        if (!(dt == DataType.UNSIGNED_8 ||
-              dt == DataType.UNSIGNED_16 ||
-              dt == DataType.UNSIGNED_5_6_5 ||
-              dt == DataType.UNSIGNED_4_4_4_4 ||
-              dt == DataType.UNSIGNED_5_5_5_1)) {
-            throw new RSIllegalArgumentException("Unsupported DataType");
-        }
-        if (dt == DataType.UNSIGNED_5_6_5 && dk != DataKind.PIXEL_RGB) {
-            throw new RSIllegalArgumentException("Bad kind and type combo");
-        }
-        if (dt == DataType.UNSIGNED_5_5_5_1 && dk != DataKind.PIXEL_RGBA) {
-            throw new RSIllegalArgumentException("Bad kind and type combo");
-        }
-        if (dt == DataType.UNSIGNED_4_4_4_4 && dk != DataKind.PIXEL_RGBA) {
-            throw new RSIllegalArgumentException("Bad kind and type combo");
-        }
-        if (dt == DataType.UNSIGNED_16 &&
-            dk != DataKind.PIXEL_DEPTH) {
-            throw new RSIllegalArgumentException("Bad kind and type combo");
-        }
-
-        int size = 1;
-        switch (dk) {
-        case PIXEL_LA:
-            size = 2;
-            break;
-        case PIXEL_RGB:
-            size = 3;
-            break;
-        case PIXEL_RGBA:
-            size = 4;
-            break;
-        }
-
-        boolean norm = true;
-        long id = rs.nElementCreate(dt.mID, dk.mID, norm, size);
-        return new Element(id, rs, dt, dk, norm, size);
-    }
-
-    /**
-     * Check if the current Element is compatible with another Element.
-     * Primitive Elements are compatible if they share the same underlying
-     * size and type (i.e. U8 is compatible with A_8). User-defined Elements
-     * must be equal in order to be compatible. This requires strict name
-     * equivalence for all sub-Elements (in addition to structural equivalence).
-     *
-     * @param e The Element to check compatibility with.
-     *
-     * @return boolean true if the Elements are compatible, otherwise false.
-     */
-    public boolean isCompatible(Element e) {
-        // Try strict BaseObj equality to start with.
-        if (this.equals(e)) {
-            return true;
-        }
-
-        // Ignore mKind because it is allowed to be different (user vs. pixel).
-        // We also ignore mNormalized because it can be different. The mType
-        // field must not be NONE since we require name equivalence for
-        // all user-created Elements.
-        return ((mSize == e.mSize) &&
-                (mType != DataType.NONE) &&
-                (mType == e.mType) &&
-                (mVectorSize == e.mVectorSize));
-    }
-
-    /**
-     * Builder class for producing complex elements with matching field and name
-     * pairs.  The builder starts empty.  The order in which elements are added
-     * is retained for the layout in memory.
-     *
-     */
-    public static class Builder {
-
-        RenderScript mRS;
-        Element[] mElements;
-        String[] mElementNames;
-        int[] mArraySizes;
-        int mCount;
-        int mSkipPadding;
-
-        /**
-         * Create a builder object.
-         *
-         * @param rs
-         */
-        public Builder(RenderScript rs) {
-            mRS = rs;
-            mCount = 0;
-            mElements = new Element[8];
-            mElementNames = new String[8];
-            mArraySizes = new int[8];
-        }
-
-        /**
-         * Add an array of elements to this element.
-         *
-         * @param element
-         * @param name
-         * @param arraySize
-         */
-        public Builder add(Element element, String name, int arraySize) {
-            if (arraySize < 1) {
-                throw new RSIllegalArgumentException("Array size cannot be less than 1.");
-            }
-
-            // Skip padding fields after a vector 3 type.
-            if (mSkipPadding != 0) {
-                if (name.startsWith("#padding_")) {
-                    mSkipPadding = 0;
-                    return this;
-                }
-            }
-
-            if (element.mVectorSize == 3) {
-                mSkipPadding = 1;
-            } else {
-                mSkipPadding = 0;
-            }
-
-            if(mCount == mElements.length) {
-                Element[] e = new Element[mCount + 8];
-                String[] s = new String[mCount + 8];
-                int[] as = new int[mCount + 8];
-                System.arraycopy(mElements, 0, e, 0, mCount);
-                System.arraycopy(mElementNames, 0, s, 0, mCount);
-                System.arraycopy(mArraySizes, 0, as, 0, mCount);
-                mElements = e;
-                mElementNames = s;
-                mArraySizes = as;
-            }
-            mElements[mCount] = element;
-            mElementNames[mCount] = name;
-            mArraySizes[mCount] = arraySize;
-            mCount++;
-
-            return this;
-        }
-
-        /**
-         * Add a single element to this Element.
-         *
-         * @param element
-         * @param name
-         */
-        public Builder add(Element element, String name) {
-            return add(element, name, 1);
-        }
-
-        /**
-         * Create the element from this builder.
-         *
-         *
-         * @return Element
-         */
-        public Element create() {
-            mRS.validate();
-            Element[] ein = new Element[mCount];
-            String[] sin = new String[mCount];
-            int[] asin = new int[mCount];
-            java.lang.System.arraycopy(mElements, 0, ein, 0, mCount);
-            java.lang.System.arraycopy(mElementNames, 0, sin, 0, mCount);
-            java.lang.System.arraycopy(mArraySizes, 0, asin, 0, mCount);
-
-            long[] ids = new long[ein.length];
-            for (int ct = 0; ct < ein.length; ct++ ) {
-                ids[ct] = ein[ct].getID(mRS);
-            }
-
-            long id = mRS.nElementCreate2(ids, sin, asin);
-            return new Element(id, mRS, ein, sin, asin);
-        }
-    }
-}
-
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/FieldPacker.java b/v8/renderscript/java/src/android/support/v8/renderscript/FieldPacker.java
deleted file mode 100644
index 5f61920..0000000
--- a/v8/renderscript/java/src/android/support/v8/renderscript/FieldPacker.java
+++ /dev/null
@@ -1,946 +0,0 @@
-/*
- * Copyright (C) 2012 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 android.support.v8.renderscript;
-
-import android.support.v8.renderscript.RenderScript;
-import java.util.BitSet;
-
-/**
- * Utility class for packing arguments and structures from Android system objects to
- * RenderScript objects.
- *
- * This class is only intended to be used to support the
- * reflected code generated by the RS tool chain.  It should not
- * be called directly.
- *
- **/
-public class FieldPacker {
-    public FieldPacker(int len) {
-        mPos = 0;
-        mLen = len;
-        mData = new byte[len];
-        mAlignment = new BitSet();
-    }
-
-    public FieldPacker(byte[] data) {
-        // Advance mPos to the end of the buffer, since we are copying in the
-        // full data input.
-        mPos = data.length;
-        mLen = data.length;
-        mData = data;
-        mAlignment = new BitSet();
-        // TODO: We should either have an actual FieldPacker copy constructor
-        // or drop support for computing alignment like this. As it stands,
-        // subAlign() can never work correctly for copied FieldPacker objects.
-    }
-
-    static FieldPacker createFromArray(Object[] args) {
-        FieldPacker fp = new FieldPacker(RenderScript.sPointerSize * 8);
-        for (Object arg : args) {
-            fp.addSafely(arg);
-        }
-        fp.resize(fp.mPos);
-        return fp;
-    }
-
-    public void align(int v) {
-        if ((v <= 0) || ((v & (v - 1)) != 0)) {
-            throw new RSIllegalArgumentException("argument must be a non-negative non-zero power of 2: " + v);
-        }
-
-        while ((mPos & (v - 1)) != 0) {
-            mAlignment.flip(mPos);
-            mData[mPos++] = 0;
-        }
-    }
-
-    public void subalign(int v) {
-        if ((v & (v - 1)) != 0) {
-            throw new RSIllegalArgumentException("argument must be a non-negative non-zero power of 2: " + v);
-        }
-
-        while ((mPos & (v - 1)) != 0) {
-            mPos--;
-        }
-
-        if (mPos > 0) {
-            while (mAlignment.get(mPos - 1) == true) {
-                mPos--;
-                mAlignment.flip(mPos);
-            }
-        }
-
-    }
-
-    public void reset() {
-        mPos = 0;
-    }
-    public void reset(int i) {
-        if ((i < 0) || (i > mLen)) {
-            throw new RSIllegalArgumentException("out of range argument: " + i);
-        }
-        mPos = i;
-    }
-
-    public void skip(int i) {
-        int res = mPos + i;
-        if ((res < 0) || (res > mLen)) {
-            throw new RSIllegalArgumentException("out of range argument: " + i);
-        }
-        mPos = res;
-    }
-
-    public void addI8(byte v) {
-        mData[mPos++] = v;
-    }
-
-    public byte subI8() {
-        subalign(1);
-        return mData[--mPos];
-    }
-
-    public void addI16(short v) {
-        align(2);
-        mData[mPos++] = (byte)(v & 0xff);
-        mData[mPos++] = (byte)(v >> 8);
-    }
-
-    public short subI16() {
-        subalign(2);
-        short v = 0;
-        v = (short)((mData[--mPos] & 0xff) << 8);
-        v = (short)(v | (short)(mData[--mPos] & 0xff));
-        return v;
-    }
-
-
-    public void addI32(int v) {
-        align(4);
-        mData[mPos++] = (byte)(v & 0xff);
-        mData[mPos++] = (byte)((v >> 8) & 0xff);
-        mData[mPos++] = (byte)((v >> 16) & 0xff);
-        mData[mPos++] = (byte)((v >> 24) & 0xff);
-    }
-
-    public int subI32() {
-        subalign(4);
-        int v = 0;
-        v = ((mData[--mPos] & 0xff) << 24);
-        v = v | ((mData[--mPos] & 0xff) << 16);
-        v = v | ((mData[--mPos] & 0xff) << 8);
-        v = v | ((mData[--mPos] & 0xff));
-        return v;
-    }
-
-
-    public void addI64(long v) {
-        align(8);
-        mData[mPos++] = (byte)(v & 0xff);
-        mData[mPos++] = (byte)((v >> 8) & 0xff);
-        mData[mPos++] = (byte)((v >> 16) & 0xff);
-        mData[mPos++] = (byte)((v >> 24) & 0xff);
-        mData[mPos++] = (byte)((v >> 32) & 0xff);
-        mData[mPos++] = (byte)((v >> 40) & 0xff);
-        mData[mPos++] = (byte)((v >> 48) & 0xff);
-        mData[mPos++] = (byte)((v >> 56) & 0xff);
-    }
-
-    public long subI64() {
-        subalign(8);
-        long v = 0;
-        byte x = 0;
-        x = ((mData[--mPos]));
-        v = (long)(v | (((long)x) & 0xff) << 56l);
-        x = ((mData[--mPos]));
-        v = (long)(v | (((long)x) & 0xff) << 48l);
-        x = ((mData[--mPos]));
-        v = (long)(v | (((long)x) & 0xff) << 40l);
-        x = ((mData[--mPos]));
-        v = (long)(v | (((long)x) & 0xff) << 32l);
-        x = ((mData[--mPos]));
-        v = (long)(v | (((long)x) & 0xff) << 24l);
-        x = ((mData[--mPos]));
-        v = (long)(v | (((long)x) & 0xff) << 16l);
-        x = ((mData[--mPos]));
-        v = (long)(v | (((long)x) & 0xff) << 8l);
-        x = ((mData[--mPos]));
-        v = (long)(v | (((long)x) & 0xff));
-        return v;
-    }
-
-    public void addU8(short v) {
-        if ((v < 0) || (v > 0xff)) {
-            android.util.Log.e("rs", "FieldPacker.addU8( " + v + " )");
-            throw new IllegalArgumentException("Saving value out of range for type");
-        }
-        mData[mPos++] = (byte)v;
-    }
-
-    public void addU16(int v) {
-        if ((v < 0) || (v > 0xffff)) {
-            android.util.Log.e("rs", "FieldPacker.addU16( " + v + " )");
-            throw new IllegalArgumentException("Saving value out of range for type");
-        }
-        align(2);
-        mData[mPos++] = (byte)(v & 0xff);
-        mData[mPos++] = (byte)(v >> 8);
-    }
-
-    public void addU32(long v) {
-        if ((v < 0) || (v > 0xffffffffL)) {
-            android.util.Log.e("rs", "FieldPacker.addU32( " + v + " )");
-            throw new IllegalArgumentException("Saving value out of range for type");
-        }
-        align(4);
-        mData[mPos++] = (byte)(v & 0xff);
-        mData[mPos++] = (byte)((v >> 8) & 0xff);
-        mData[mPos++] = (byte)((v >> 16) & 0xff);
-        mData[mPos++] = (byte)((v >> 24) & 0xff);
-    }
-
-    public void addU64(long v) {
-        if (v < 0) {
-            android.util.Log.e("rs", "FieldPacker.addU64( " + v + " )");
-            throw new IllegalArgumentException("Saving value out of range for type");
-        }
-        align(8);
-        mData[mPos++] = (byte)(v & 0xff);
-        mData[mPos++] = (byte)((v >> 8) & 0xff);
-        mData[mPos++] = (byte)((v >> 16) & 0xff);
-        mData[mPos++] = (byte)((v >> 24) & 0xff);
-        mData[mPos++] = (byte)((v >> 32) & 0xff);
-        mData[mPos++] = (byte)((v >> 40) & 0xff);
-        mData[mPos++] = (byte)((v >> 48) & 0xff);
-        mData[mPos++] = (byte)((v >> 56) & 0xff);
-    }
-
-    public void addF32(float v) {
-        addI32(Float.floatToRawIntBits(v));
-    }
-
-    public float subF32() {
-        return Float.intBitsToFloat(subI32());
-    }
-
-    public void addF64(double v) {
-        addI64(Double.doubleToRawLongBits(v));
-    }
-
-    public double subF64() {
-        return Double.longBitsToDouble(subI64());
-    }
-
-    public void addObj(BaseObj obj) {
-        if (obj != null) {
-            if (RenderScript.sPointerSize == 8) {
-                addI64(obj.getID(null));
-                addI64(0);
-                addI64(0);
-                addI64(0);
-            } else {
-                addI32((int)obj.getID(null));
-            }
-        } else {
-            if (RenderScript.sPointerSize == 8) {
-                addI64(0);
-                addI64(0);
-                addI64(0);
-                addI64(0);
-            } else {
-                addI32(0);
-            }
-        }
-    }
-
-    public void addF32(Float2 v) {
-        addF32(v.x);
-        addF32(v.y);
-    }
-    public void addF32(Float3 v) {
-        addF32(v.x);
-        addF32(v.y);
-        addF32(v.z);
-    }
-    public void addF32(Float4 v) {
-        addF32(v.x);
-        addF32(v.y);
-        addF32(v.z);
-        addF32(v.w);
-    }
-
-    public void addF64(Double2 v) {
-        addF64(v.x);
-        addF64(v.y);
-    }
-    public void addF64(Double3 v) {
-        addF64(v.x);
-        addF64(v.y);
-        addF64(v.z);
-    }
-    public void addF64(Double4 v) {
-        addF64(v.x);
-        addF64(v.y);
-        addF64(v.z);
-        addF64(v.w);
-    }
-
-    public void addI8(Byte2 v) {
-        addI8(v.x);
-        addI8(v.y);
-    }
-    public void addI8(Byte3 v) {
-        addI8(v.x);
-        addI8(v.y);
-        addI8(v.z);
-    }
-    public void addI8(Byte4 v) {
-        addI8(v.x);
-        addI8(v.y);
-        addI8(v.z);
-        addI8(v.w);
-    }
-
-    public void addU8(Short2 v) {
-        addU8(v.x);
-        addU8(v.y);
-    }
-    public void addU8(Short3 v) {
-        addU8(v.x);
-        addU8(v.y);
-        addU8(v.z);
-    }
-    public void addU8(Short4 v) {
-        addU8(v.x);
-        addU8(v.y);
-        addU8(v.z);
-        addU8(v.w);
-    }
-
-    public void addI16(Short2 v) {
-        addI16(v.x);
-        addI16(v.y);
-    }
-    public void addI16(Short3 v) {
-        addI16(v.x);
-        addI16(v.y);
-        addI16(v.z);
-    }
-    public void addI16(Short4 v) {
-        addI16(v.x);
-        addI16(v.y);
-        addI16(v.z);
-        addI16(v.w);
-    }
-
-    public void addU16(Int2 v) {
-        addU16(v.x);
-        addU16(v.y);
-    }
-    public void addU16(Int3 v) {
-        addU16(v.x);
-        addU16(v.y);
-        addU16(v.z);
-    }
-    public void addU16(Int4 v) {
-        addU16(v.x);
-        addU16(v.y);
-        addU16(v.z);
-        addU16(v.w);
-    }
-
-    public void addI32(Int2 v) {
-        addI32(v.x);
-        addI32(v.y);
-    }
-    public void addI32(Int3 v) {
-        addI32(v.x);
-        addI32(v.y);
-        addI32(v.z);
-    }
-    public void addI32(Int4 v) {
-        addI32(v.x);
-        addI32(v.y);
-        addI32(v.z);
-        addI32(v.w);
-    }
-
-    public void addU32(Long2 v) {
-        addU32(v.x);
-        addU32(v.y);
-    }
-    public void addU32(Long3 v) {
-        addU32(v.x);
-        addU32(v.y);
-        addU32(v.z);
-    }
-    public void addU32(Long4 v) {
-        addU32(v.x);
-        addU32(v.y);
-        addU32(v.z);
-        addU32(v.w);
-    }
-
-    public void addI64(Long2 v) {
-        addI64(v.x);
-        addI64(v.y);
-    }
-    public void addI64(Long3 v) {
-        addI64(v.x);
-        addI64(v.y);
-        addI64(v.z);
-    }
-    public void addI64(Long4 v) {
-        addI64(v.x);
-        addI64(v.y);
-        addI64(v.z);
-        addI64(v.w);
-    }
-
-    public void addU64(Long2 v) {
-        addU64(v.x);
-        addU64(v.y);
-    }
-    public void addU64(Long3 v) {
-        addU64(v.x);
-        addU64(v.y);
-        addU64(v.z);
-    }
-    public void addU64(Long4 v) {
-        addU64(v.x);
-        addU64(v.y);
-        addU64(v.z);
-        addU64(v.w);
-    }
-
-
-    public Float2 subFloat2() {
-        Float2 v = new Float2();
-        v.y = subF32();
-        v.x = subF32();
-        return v;
-    }
-    public Float3 subFloat3() {
-        Float3 v = new Float3();
-        v.z = subF32();
-        v.y = subF32();
-        v.x = subF32();
-        return v;
-    }
-    public Float4 subFloat4() {
-        Float4 v = new Float4();
-        v.w = subF32();
-        v.z = subF32();
-        v.y = subF32();
-        v.x = subF32();
-        return v;
-    }
-
-    public Double2 subDouble2() {
-        Double2 v = new Double2();
-        v.y = subF64();
-        v.x = subF64();
-        return v;
-    }
-    public Double3 subDouble3() {
-        Double3 v = new Double3();
-        v.z = subF64();
-        v.y = subF64();
-        v.x = subF64();
-        return v;
-    }
-    public Double4 subDouble4() {
-        Double4 v = new Double4();
-        v.w = subF64();
-        v.z = subF64();
-        v.y = subF64();
-        v.x = subF64();
-        return v;
-    }
-
-    public Byte2 subByte2() {
-        Byte2 v = new Byte2();
-        v.y = subI8();
-        v.x = subI8();
-        return v;
-    }
-    public Byte3 subByte3() {
-        Byte3 v = new Byte3();
-        v.z = subI8();
-        v.y = subI8();
-        v.x = subI8();
-        return v;
-    }
-    public Byte4 subByte4() {
-        Byte4 v = new Byte4();
-        v.w = subI8();
-        v.z = subI8();
-        v.y = subI8();
-        v.x = subI8();
-        return v;
-    }
-
-    public Short2 subShort2() {
-        Short2 v = new Short2();
-        v.y = subI16();
-        v.x = subI16();
-        return v;
-    }
-    public Short3 subShort3() {
-        Short3 v = new Short3();
-        v.z = subI16();
-        v.y = subI16();
-        v.x = subI16();
-        return v;
-    }
-    public Short4 subShort4() {
-        Short4 v = new Short4();
-        v.w = subI16();
-        v.z = subI16();
-        v.y = subI16();
-        v.x = subI16();
-        return v;
-    }
-
-    public Int2 subInt2() {
-        Int2 v = new Int2();
-        v.y = subI32();
-        v.x = subI32();
-        return v;
-    }
-    public Int3 subInt3() {
-        Int3 v = new Int3();
-        v.z = subI32();
-        v.y = subI32();
-        v.x = subI32();
-        return v;
-    }
-    public Int4 subInt4() {
-        Int4 v = new Int4();
-        v.w = subI32();
-        v.z = subI32();
-        v.y = subI32();
-        v.x = subI32();
-        return v;
-    }
-
-    public Long2 subLong2() {
-        Long2 v = new Long2();
-        v.y = subI64();
-        v.x = subI64();
-        return v;
-    }
-    public Long3 subLong3() {
-        Long3 v = new Long3();
-        v.z = subI64();
-        v.y = subI64();
-        v.x = subI64();
-        return v;
-    }
-    public Long4 subLong4() {
-        Long4 v = new Long4();
-        v.w = subI64();
-        v.z = subI64();
-        v.y = subI64();
-        v.x = subI64();
-        return v;
-    }
-
-
-
-    public void addMatrix(Matrix4f v) {
-        for (int i=0; i < v.mMat.length; i++) {
-            addF32(v.mMat[i]);
-        }
-    }
-
-    public Matrix4f subMatrix4f() {
-        Matrix4f v = new Matrix4f();
-        for (int i = v.mMat.length - 1; i >= 0; i--) {
-            v.mMat[i] = subF32();
-        }
-        return v;
-    }
-
-    public void addMatrix(Matrix3f v) {
-        for (int i=0; i < v.mMat.length; i++) {
-            addF32(v.mMat[i]);
-        }
-    }
-
-    public Matrix3f subMatrix3f() {
-        Matrix3f v = new Matrix3f();
-        for (int i = v.mMat.length - 1; i >= 0; i--) {
-            v.mMat[i] = subF32();
-        }
-        return v;
-    }
-
-    public void addMatrix(Matrix2f v) {
-        for (int i=0; i < v.mMat.length; i++) {
-            addF32(v.mMat[i]);
-        }
-    }
-
-    public Matrix2f subMatrix2f() {
-        Matrix2f v = new Matrix2f();
-        for (int i = v.mMat.length - 1; i >= 0; i--) {
-            v.mMat[i] = subF32();
-        }
-        return v;
-    }
-
-    public void addBoolean(boolean v) {
-        addI8((byte)(v ? 1 : 0));
-    }
-
-    public boolean subBoolean() {
-        byte v = subI8();
-        if (v == 1) {
-            return true;
-        }
-        return false;
-    }
-
-    public final byte[] getData() {
-        return mData;
-    }
-
-    /**
-     * Get the actual length used for the FieldPacker.
-     *
-     * @hide
-     */
-    public int getPos() {
-        return mPos;
-    }
-
-    private static void addToPack(FieldPacker fp, Object obj) {
-        if (obj instanceof Boolean) {
-            fp.addBoolean(((Boolean)obj).booleanValue());
-            return;
-        }
-
-        if (obj instanceof Byte) {
-            fp.addI8(((Byte)obj).byteValue());
-            return;
-        }
-
-        if (obj instanceof Short) {
-            fp.addI16(((Short)obj).shortValue());
-            return;
-        }
-
-        if (obj instanceof Integer) {
-            fp.addI32(((Integer)obj).intValue());
-            return;
-        }
-
-        if (obj instanceof Long) {
-            fp.addI64(((Long)obj).longValue());
-            return;
-        }
-
-        if (obj instanceof Float) {
-            fp.addF32(((Float)obj).floatValue());
-            return;
-        }
-
-        if (obj instanceof Double) {
-            fp.addF64(((Double)obj).doubleValue());
-            return;
-        }
-
-        if (obj instanceof Byte2) {
-            fp.addI8((Byte2)obj);
-            return;
-        }
-
-        if (obj instanceof Byte3) {
-            fp.addI8((Byte3)obj);
-            return;
-        }
-
-        if (obj instanceof Byte4) {
-            fp.addI8((Byte4)obj);
-            return;
-        }
-
-        if (obj instanceof Short2) {
-            fp.addI16((Short2)obj);
-            return;
-        }
-
-        if (obj instanceof Short3) {
-            fp.addI16((Short3)obj);
-            return;
-        }
-
-        if (obj instanceof Short4) {
-            fp.addI16((Short4)obj);
-            return;
-        }
-
-        if (obj instanceof Int2) {
-            fp.addI32((Int2)obj);
-            return;
-        }
-
-        if (obj instanceof Int3) {
-            fp.addI32((Int3)obj);
-            return;
-        }
-
-        if (obj instanceof Int4) {
-            fp.addI32((Int4)obj);
-            return;
-        }
-
-        if (obj instanceof Long2) {
-            fp.addI64((Long2)obj);
-            return;
-        }
-
-        if (obj instanceof Long3) {
-            fp.addI64((Long3)obj);
-            return;
-        }
-
-        if (obj instanceof Long4) {
-            fp.addI64((Long4)obj);
-            return;
-        }
-
-        if (obj instanceof Float2) {
-            fp.addF32((Float2)obj);
-            return;
-        }
-
-        if (obj instanceof Float3) {
-            fp.addF32((Float3)obj);
-            return;
-        }
-
-        if (obj instanceof Float4) {
-            fp.addF32((Float4)obj);
-            return;
-        }
-
-        if (obj instanceof Double2) {
-            fp.addF64((Double2)obj);
-            return;
-        }
-
-        if (obj instanceof Double3) {
-            fp.addF64((Double3)obj);
-            return;
-        }
-
-        if (obj instanceof Double4) {
-            fp.addF64((Double4)obj);
-            return;
-        }
-
-        if (obj instanceof Matrix2f) {
-            fp.addMatrix((Matrix2f)obj);
-            return;
-        }
-
-        if (obj instanceof Matrix3f) {
-            fp.addMatrix((Matrix3f)obj);
-            return;
-        }
-
-        if (obj instanceof Matrix4f) {
-            fp.addMatrix((Matrix4f)obj);
-            return;
-        }
-
-        if (obj instanceof BaseObj) {
-            fp.addObj((BaseObj)obj);
-            return;
-        }
-    }
-
-    private static int getPackedSize(Object obj) {
-        if (obj instanceof Boolean) {
-            return 1;
-        }
-
-        if (obj instanceof Byte) {
-            return 1;
-        }
-
-        if (obj instanceof Short) {
-            return 2;
-        }
-
-        if (obj instanceof Integer) {
-            return 4;
-        }
-
-        if (obj instanceof Long) {
-            return 8;
-        }
-
-        if (obj instanceof Float) {
-            return 4;
-        }
-
-        if (obj instanceof Double) {
-            return 8;
-        }
-
-        if (obj instanceof Byte2) {
-            return 2;
-        }
-
-        if (obj instanceof Byte3) {
-            return 3;
-        }
-
-        if (obj instanceof Byte4) {
-            return 4;
-        }
-
-        if (obj instanceof Short2) {
-            return 4;
-        }
-
-        if (obj instanceof Short3) {
-            return 6;
-        }
-
-        if (obj instanceof Short4) {
-            return 8;
-        }
-
-        if (obj instanceof Int2) {
-            return 8;
-        }
-
-        if (obj instanceof Int3) {
-            return 12;
-        }
-
-        if (obj instanceof Int4) {
-            return 16;
-        }
-
-        if (obj instanceof Long2) {
-            return 16;
-        }
-
-        if (obj instanceof Long3) {
-            return 24;
-        }
-
-        if (obj instanceof Long4) {
-            return 32;
-        }
-
-        if (obj instanceof Float2) {
-            return 8;
-        }
-
-        if (obj instanceof Float3) {
-            return 12;
-        }
-
-        if (obj instanceof Float4) {
-            return 16;
-        }
-
-        if (obj instanceof Double2) {
-            return 16;
-        }
-
-        if (obj instanceof Double3) {
-            return 24;
-        }
-
-        if (obj instanceof Double4) {
-            return 32;
-        }
-
-        if (obj instanceof Matrix2f) {
-            return 16;
-        }
-
-        if (obj instanceof Matrix3f) {
-            return 36;
-        }
-
-        if (obj instanceof Matrix4f) {
-            return 64;
-        }
-
-        if (obj instanceof BaseObj) {
-            if (RenderScript.sPointerSize == 8) {
-                return 32;
-            } else {
-                return 4;
-            }
-        }
-
-        return 0;
-    }
-
-    static FieldPacker createFieldPack(Object[] args) {
-        int len = 0;
-        for (Object arg : args) {
-            len += getPackedSize(arg);
-        }
-        FieldPacker fp = new FieldPacker(len);
-        for (Object arg : args) {
-            addToPack(fp, arg);
-        }
-        return fp;
-    }
-
-
-    private boolean resize(int newSize) {
-        if (newSize == mLen) {
-            return false;
-        }
-
-        byte[] newData = new byte[newSize];
-        System.arraycopy(mData, 0, newData, 0, mPos);
-        mData = newData;
-        mLen = newSize;
-        return true;
-    }
-
-    private void addSafely(Object obj) {
-        boolean retry;
-        final int oldPos = mPos;
-        do {
-            retry = false;
-            try {
-                addToPack(this, obj);
-            } catch (ArrayIndexOutOfBoundsException e) {
-                mPos = oldPos;
-                resize(mLen * 2);
-                retry = true;
-            }
-        } while (retry);
-    }
-
-    private byte mData[];
-    private int mPos;
-    private int mLen;
-    private BitSet mAlignment;
-}
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/Float2.java b/v8/renderscript/java/src/android/support/v8/renderscript/Float2.java
deleted file mode 100644
index edbc5aa..0000000
--- a/v8/renderscript/java/src/android/support/v8/renderscript/Float2.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2009 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 android.support.v8.renderscript;
-
-import java.lang.Math;
-import android.util.Log;
-
-
-/**
- * Class for exposing the native RenderScript float2 type back to the Android system.
- *
- **/
-public class Float2 {
-    public Float2() {
-    }
-
-    public Float2(float initX, float initY) {
-        x = initX;
-        y = initY;
-    }
-
-    public float x;
-    public float y;
-}
-
-
-
-
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/Float3.java b/v8/renderscript/java/src/android/support/v8/renderscript/Float3.java
deleted file mode 100644
index 90162a1..0000000
--- a/v8/renderscript/java/src/android/support/v8/renderscript/Float3.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2009 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 android.support.v8.renderscript;
-
-import java.lang.Math;
-import android.util.Log;
-
-
-/**
- * Class for exposing the native RenderScript float2 type back to the Android system.
- *
- **/
-public class Float3 {
-    public Float3() {
-    }
-    public Float3(float initX, float initY, float initZ) {
-        x = initX;
-        y = initY;
-        z = initZ;
-    }
-
-    public float x;
-    public float y;
-    public float z;
-}
-
-
-
-
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/Float4.java b/v8/renderscript/java/src/android/support/v8/renderscript/Float4.java
deleted file mode 100644
index d0dc568..0000000
--- a/v8/renderscript/java/src/android/support/v8/renderscript/Float4.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2009 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 android.support.v8.renderscript;
-
-import java.lang.Math;
-import android.util.Log;
-
-
-/**
- * Class for exposing the native RenderScript float2 type back to the Android system.
- *
- **/
-public class Float4 {
-    public Float4() {
-    }
-
-    public Float4(float initX, float initY, float initZ, float initW) {
-        x = initX;
-        y = initY;
-        z = initZ;
-        w = initW;
-    }
-
-    public float x;
-    public float y;
-    public float z;
-    public float w;
-}
-
-
-
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/Int2.java b/v8/renderscript/java/src/android/support/v8/renderscript/Int2.java
deleted file mode 100644
index e5d04b8..0000000
--- a/v8/renderscript/java/src/android/support/v8/renderscript/Int2.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2009 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 android.support.v8.renderscript;
-
-import java.lang.Math;
-import android.util.Log;
-
-
-/**
- * Class for exposing the native RenderScript int2 type back to the Android system.
- *
- **/
-public class Int2 {
-    public Int2() {
-    }
-
-    public Int2(int initX, int initY) {
-        x = initX;
-        y = initY;
-    }
-
-    public int x;
-    public int y;
-}
-
-
-
-
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/Int3.java b/v8/renderscript/java/src/android/support/v8/renderscript/Int3.java
deleted file mode 100644
index 12f59e8..0000000
--- a/v8/renderscript/java/src/android/support/v8/renderscript/Int3.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2009 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 android.support.v8.renderscript;
-
-import java.lang.Math;
-import android.util.Log;
-
-
-/**
- * Class for exposing the native RenderScript int3 type back to the Android system.
- *
- **/
-public class Int3 {
-    public Int3() {
-    }
-
-    public Int3(int initX, int initY, int initZ) {
-        x = initX;
-        y = initY;
-        z = initZ;
-    }
-
-    public int x;
-    public int y;
-    public int z;
-}
-
-
-
-
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/Int4.java b/v8/renderscript/java/src/android/support/v8/renderscript/Int4.java
deleted file mode 100644
index bb49fb1..0000000
--- a/v8/renderscript/java/src/android/support/v8/renderscript/Int4.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2009 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 android.support.v8.renderscript;
-
-import java.lang.Math;
-import android.util.Log;
-
-
-/**
- * Class for exposing the native RenderScript int4 type back to the Android system.
- *
- **/
-public class Int4 {
-    public Int4() {
-    }
-
-    public Int4(int initX, int initY, int initZ, int initW) {
-        x = initX;
-        y = initY;
-        z = initZ;
-        w = initW;
-    }
-
-    public int x;
-    public int y;
-    public int z;
-    public int w;
-}
-
-
-
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/Long2.java b/v8/renderscript/java/src/android/support/v8/renderscript/Long2.java
deleted file mode 100644
index b3c95f2..0000000
--- a/v8/renderscript/java/src/android/support/v8/renderscript/Long2.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2009 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 android.support.v8.renderscript;
-
-import java.lang.Math;
-import android.util.Log;
-
-
-/**
- * Class for exposing the native RenderScript long2 type back to the Android system.
- **/
-public class Long2 {
-    public Long2() {
-    }
-
-    public Long2(long initX, long initY) {
-        x = initX;
-        y = initY;
-    }
-
-    public long x;
-    public long y;
-}
-
-
-
-
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/Long3.java b/v8/renderscript/java/src/android/support/v8/renderscript/Long3.java
deleted file mode 100644
index 6ce0f83..0000000
--- a/v8/renderscript/java/src/android/support/v8/renderscript/Long3.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2009 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 android.support.v8.renderscript;
-
-import java.lang.Math;
-import android.util.Log;
-
-
-/**
- * Class for exposing the native RenderScript long3 type back to the Android system.
- **/
-public class Long3 {
-    public Long3() {
-    }
-
-    public Long3(long initX, long initY, long initZ) {
-        x = initX;
-        y = initY;
-        z = initZ;
-    }
-
-    public long x;
-    public long y;
-    public long z;
-}
-
-
-
-
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/Long4.java b/v8/renderscript/java/src/android/support/v8/renderscript/Long4.java
deleted file mode 100644
index d44a321..0000000
--- a/v8/renderscript/java/src/android/support/v8/renderscript/Long4.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2009 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 android.support.v8.renderscript;
-
-import java.lang.Math;
-import android.util.Log;
-
-
-/**
- * Class for exposing the native RenderScript long4 type back to the Android system.
- **/
-public class Long4 {
-    public Long4() {
-    }
-
-    public Long4(long initX, long initY, long initZ, long initW) {
-        x = initX;
-        y = initY;
-        z = initZ;
-        w = initW;
-    }
-
-    public long x;
-    public long y;
-    public long z;
-    public long w;
-}
-
-
-
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/Matrix2f.java b/v8/renderscript/java/src/android/support/v8/renderscript/Matrix2f.java
deleted file mode 100644
index 9a8b5bf..0000000
--- a/v8/renderscript/java/src/android/support/v8/renderscript/Matrix2f.java
+++ /dev/null
@@ -1,196 +0,0 @@
-/*
- * Copyright (C) 2009-2012 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 android.support.v8.renderscript;
-
-import java.lang.Math;
-import android.util.Log;
-
-
-/**
- * Class for exposing the native RenderScript rs_matrix2x2 type back to the Android system.
- *
- **/
-public class Matrix2f {
-
-    /**
-    * Creates a new identity 2x2 matrix
-    */
-    public Matrix2f() {
-        mMat = new float[4];
-        loadIdentity();
-    }
-
-    /**
-    * Creates a new matrix and sets its values from the given
-    * parameter
-    *
-    * @param dataArray values to set the matrix to, must be 4
-    *                  floats long
-    */
-    public Matrix2f(float[] dataArray) {
-        mMat = new float[4];
-        System.arraycopy(dataArray, 0, mMat, 0, mMat.length);
-    }
-
-    /**
-    * Return a reference to the internal array representing matrix
-    * values. Modifying this array will also change the matrix
-    *
-    * @return internal array representing the matrix
-    */
-    public float[] getArray() {
-        return mMat;
-    }
-
-    /**
-    * Returns the value for a given row and column
-    *
-    * @param x column of the value to return
-    * @param y row of the value to return
-    *
-    * @return value in the yth row and xth column
-    */
-    public float get(int x, int y) {
-        return mMat[x*2 + y];
-    }
-
-    /**
-    * Sets the value for a given row and column
-    *
-    * @param x column of the value to set
-    * @param y row of the value to set
-    */
-    public void set(int x, int y, float v) {
-        mMat[x*2 + y] = v;
-    }
-
-    /**
-    * Sets the matrix values to identity
-    */
-    public void loadIdentity() {
-        mMat[0] = 1;
-        mMat[1] = 0;
-
-        mMat[2] = 0;
-        mMat[3] = 1;
-    }
-
-    /**
-    * Sets the values of the matrix to those of the parameter
-    *
-    * @param src matrix to load the values from
-    */
-    public void load(Matrix2f src) {
-        System.arraycopy(src.getArray(), 0, mMat, 0, mMat.length);
-    }
-
-    /**
-    * Sets current values to be a rotation matrix of given angle
-    *
-    * @param rot rotation angle
-    */
-    public void loadRotate(float rot) {
-        float c, s;
-        rot *= (float)(java.lang.Math.PI / 180.0f);
-        c = (float)java.lang.Math.cos(rot);
-        s = (float)java.lang.Math.sin(rot);
-        mMat[0] = c;
-        mMat[1] = -s;
-        mMat[2] = s;
-        mMat[3] = c;
-    }
-
-    /**
-    * Sets current values to be a scale matrix of given dimensions
-    *
-    * @param x scale component x
-    * @param y scale component y
-    */
-    public void loadScale(float x, float y) {
-        loadIdentity();
-        mMat[0] = x;
-        mMat[3] = y;
-    }
-
-    /**
-    * Sets current values to be the result of multiplying two given
-    * matrices
-    *
-    * @param lhs left hand side matrix
-    * @param rhs right hand side matrix
-    */
-    public void loadMultiply(Matrix2f lhs, Matrix2f rhs) {
-        for (int i=0 ; i<2 ; i++) {
-            float ri0 = 0;
-            float ri1 = 0;
-            for (int j=0 ; j<2 ; j++) {
-                float rhs_ij = rhs.get(i,j);
-                ri0 += lhs.get(j,0) * rhs_ij;
-                ri1 += lhs.get(j,1) * rhs_ij;
-            }
-            set(i,0, ri0);
-            set(i,1, ri1);
-        }
-    }
-
-    /**
-    * Post-multiplies the current matrix by a given parameter
-    *
-    * @param rhs right hand side to multiply by
-    */
-    public void multiply(Matrix2f rhs) {
-        Matrix2f tmp = new Matrix2f();
-        tmp.loadMultiply(this, rhs);
-        load(tmp);
-    }
-    /**
-    * Modifies the current matrix by post-multiplying it with a
-    * rotation matrix of given angle
-    *
-    * @param rot angle of rotation
-    */
-    public void rotate(float rot) {
-        Matrix2f tmp = new Matrix2f();
-        tmp.loadRotate(rot);
-        multiply(tmp);
-    }
-    /**
-    * Modifies the current matrix by post-multiplying it with a
-    * scale matrix of given dimensions
-    *
-    * @param x scale component x
-    * @param y scale component y
-    */
-    public void scale(float x, float y) {
-        Matrix2f tmp = new Matrix2f();
-        tmp.loadScale(x, y);
-        multiply(tmp);
-    }
-    /**
-    * Sets the current matrix to its transpose
-    */
-    public void transpose() {
-        float temp = mMat[1];
-        mMat[1] = mMat[2];
-        mMat[2] = temp;
-    }
-
-    final float[] mMat;
-}
-
-
-
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/Matrix3f.java b/v8/renderscript/java/src/android/support/v8/renderscript/Matrix3f.java
deleted file mode 100644
index 4528543..0000000
--- a/v8/renderscript/java/src/android/support/v8/renderscript/Matrix3f.java
+++ /dev/null
@@ -1,321 +0,0 @@
-/*
- * Copyright (C) 2009-2012 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 android.support.v8.renderscript;
-
-import java.lang.Math;
-import android.util.Log;
-
-
-/**
- * Class for exposing the native RenderScript rs_matrix3x3 type back to the Android system.
- *
- **/
-public class Matrix3f {
-
-    /**
-    * Creates a new identity 3x3 matrix
-    */
-    public Matrix3f() {
-        mMat = new float[9];
-        loadIdentity();
-    }
-
-    /**
-    * Creates a new matrix and sets its values from the given
-    * parameter
-    *
-    * @param dataArray values to set the matrix to, must be 9
-    *                  floats long
-    */
-    public Matrix3f(float[] dataArray) {
-        mMat = new float[9];
-        System.arraycopy(dataArray, 0, mMat, 0, mMat.length);
-    }
-
-    /**
-    * Return a reference to the internal array representing matrix
-    * values. Modifying this array will also change the matrix
-    *
-    * @return internal array representing the matrix
-    */
-    public float[] getArray() {
-        return mMat;
-    }
-
-    /**
-    * Returns the value for a given row and column
-    *
-    * @param x column of the value to return
-    * @param y row of the value to return
-    *
-    * @return value in the yth row and xth column
-    */
-    public float get(int x, int y) {
-        return mMat[x*3 + y];
-    }
-
-    /**
-    * Sets the value for a given row and column
-    *
-    * @param x column of the value to set
-    * @param y row of the value to set
-    */
-    public void set(int x, int y, float v) {
-        mMat[x*3 + y] = v;
-    }
-
-    /**
-    * Sets the matrix values to identity
-    */
-    public void loadIdentity() {
-        mMat[0] = 1;
-        mMat[1] = 0;
-        mMat[2] = 0;
-
-        mMat[3] = 0;
-        mMat[4] = 1;
-        mMat[5] = 0;
-
-        mMat[6] = 0;
-        mMat[7] = 0;
-        mMat[8] = 1;
-    }
-
-    /**
-    * Sets the values of the matrix to those of the parameter
-    *
-    * @param src matrix to load the values from
-    */
-    public void load(Matrix3f src) {
-        System.arraycopy(src.getArray(), 0, mMat, 0, mMat.length);
-    }
-
-    /**
-    * Sets current values to be a rotation matrix of certain angle
-    * about a given axis
-    *
-    * @param rot angle of rotation
-    * @param x rotation axis x
-    * @param y rotation axis y
-    * @param z rotation axis z
-    */
-    public void loadRotate(float rot, float x, float y, float z) {
-        float c, s;
-        rot *= (float)(java.lang.Math.PI / 180.0f);
-        c = (float)java.lang.Math.cos(rot);
-        s = (float)java.lang.Math.sin(rot);
-
-        float len = (float)java.lang.Math.sqrt(x*x + y*y + z*z);
-        if (!(len != 1)) {
-            float recipLen = 1.f / len;
-            x *= recipLen;
-            y *= recipLen;
-            z *= recipLen;
-        }
-        float nc = 1.0f - c;
-        float xy = x * y;
-        float yz = y * z;
-        float zx = z * x;
-        float xs = x * s;
-        float ys = y * s;
-        float zs = z * s;
-        mMat[0] = x*x*nc +  c;
-        mMat[3] =  xy*nc - zs;
-        mMat[6] =  zx*nc + ys;
-        mMat[1] =  xy*nc + zs;
-        mMat[4] = y*y*nc +  c;
-        mMat[7] =  yz*nc - xs;
-        mMat[2] =  zx*nc - ys;
-        mMat[5] =  yz*nc + xs;
-        mMat[8] = z*z*nc +  c;
-    }
-
-    /**
-    * Makes the upper 2x2 a rotation matrix of the given angle
-    *
-    * @param rot rotation angle
-    */
-    public void loadRotate(float rot) {
-        loadIdentity();
-        float c, s;
-        rot *= (float)(java.lang.Math.PI / 180.0f);
-        c = (float)java.lang.Math.cos(rot);
-        s = (float)java.lang.Math.sin(rot);
-        mMat[0] = c;
-        mMat[1] = -s;
-        mMat[3] = s;
-        mMat[4] = c;
-    }
-
-    /**
-    * Makes the upper 2x2 a scale matrix of given dimensions
-    *
-    * @param x scale component x
-    * @param y scale component y
-    */
-    public void loadScale(float x, float y) {
-        loadIdentity();
-        mMat[0] = x;
-        mMat[4] = y;
-    }
-
-    /**
-    * Sets current values to be a scale matrix of given dimensions
-    *
-    * @param x scale component x
-    * @param y scale component y
-    * @param z scale component z
-    */
-    public void loadScale(float x, float y, float z) {
-        loadIdentity();
-        mMat[0] = x;
-        mMat[4] = y;
-        mMat[8] = z;
-    }
-
-    /**
-    * Sets current values to be a translation matrix of given
-    * dimensions
-    *
-    * @param x translation component x
-    * @param y translation component y
-    */
-    public void loadTranslate(float x, float y) {
-        loadIdentity();
-        mMat[6] = x;
-        mMat[7] = y;
-    }
-
-    /**
-    * Sets current values to be the result of multiplying two given
-    * matrices
-    *
-    * @param lhs left hand side matrix
-    * @param rhs right hand side matrix
-    */
-    public void loadMultiply(Matrix3f lhs, Matrix3f rhs) {
-        for (int i=0 ; i<3 ; i++) {
-            float ri0 = 0;
-            float ri1 = 0;
-            float ri2 = 0;
-            for (int j=0 ; j<3 ; j++) {
-                float rhs_ij = rhs.get(i,j);
-                ri0 += lhs.get(j,0) * rhs_ij;
-                ri1 += lhs.get(j,1) * rhs_ij;
-                ri2 += lhs.get(j,2) * rhs_ij;
-            }
-            set(i,0, ri0);
-            set(i,1, ri1);
-            set(i,2, ri2);
-        }
-    }
-
-    /**
-    * Post-multiplies the current matrix by a given parameter
-    *
-    * @param rhs right hand side to multiply by
-    */
-    public void multiply(Matrix3f rhs) {
-        Matrix3f tmp = new Matrix3f();
-        tmp.loadMultiply(this, rhs);
-        load(tmp);
-    }
-
-    /**
-    * Modifies the current matrix by post-multiplying it with a
-    * rotation matrix of certain angle about a given axis
-    *
-    * @param rot angle of rotation
-    * @param x rotation axis x
-    * @param y rotation axis y
-    * @param z rotation axis z
-    */
-    public void rotate(float rot, float x, float y, float z) {
-        Matrix3f tmp = new Matrix3f();
-        tmp.loadRotate(rot, x, y, z);
-        multiply(tmp);
-    }
-
-    /**
-    * Modifies the upper 2x2 of the current matrix by
-    * post-multiplying it with a rotation matrix of given angle
-    *
-    * @param rot angle of rotation
-    */
-    public void rotate(float rot) {
-        Matrix3f tmp = new Matrix3f();
-        tmp.loadRotate(rot);
-        multiply(tmp);
-    }
-
-    /**
-    * Modifies the upper 2x2 of the current matrix by
-    * post-multiplying it with a scale matrix of given dimensions
-    *
-    * @param x scale component x
-    * @param y scale component y
-    */
-    public void scale(float x, float y) {
-        Matrix3f tmp = new Matrix3f();
-        tmp.loadScale(x, y);
-        multiply(tmp);
-    }
-
-    /**
-    * Modifies the current matrix by post-multiplying it with a
-    * scale matrix of given dimensions
-    *
-    * @param x scale component x
-    * @param y scale component y
-    * @param z scale component z
-    */
-    public void scale(float x, float y, float z) {
-        Matrix3f tmp = new Matrix3f();
-        tmp.loadScale(x, y, z);
-        multiply(tmp);
-    }
-
-    /**
-    * Modifies the current matrix by post-multiplying it with a
-    * translation matrix of given dimensions
-    *
-    * @param x translation component x
-    * @param y translation component y
-    */
-    public void translate(float x, float y) {
-        Matrix3f tmp = new Matrix3f();
-        tmp.loadTranslate(x, y);
-        multiply(tmp);
-    }
-
-    /**
-    * Sets the current matrix to its transpose
-    */
-    public void transpose() {
-        for(int i = 0; i < 2; ++i) {
-            for(int j = i + 1; j < 3; ++j) {
-                float temp = mMat[i*3 + j];
-                mMat[i*3 + j] = mMat[j*3 + i];
-                mMat[j*3 + i] = temp;
-            }
-        }
-    }
-
-    final float[] mMat;
-}
-
-
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/Matrix4f.java b/v8/renderscript/java/src/android/support/v8/renderscript/Matrix4f.java
deleted file mode 100644
index b9e5636..0000000
--- a/v8/renderscript/java/src/android/support/v8/renderscript/Matrix4f.java
+++ /dev/null
@@ -1,494 +0,0 @@
-/*
- * Copyright (C) 2009-2012 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 android.support.v8.renderscript;
-
-import java.lang.Math;
-import android.util.Log;
-
-
-/**
- * Class for exposing the native RenderScript rs_matrix4x4 type back to the Android system.
- *
- **/
-public class Matrix4f {
-
-    /**
-    * Creates a new identity 4x4 matrix
-    */
-    public Matrix4f() {
-        mMat = new float[16];
-        loadIdentity();
-    }
-
-    /**
-    * Creates a new matrix and sets its values from the given
-    * parameter
-    *
-    * @param dataArray values to set the matrix to, must be 16
-    *                  floats long
-    */
-    public Matrix4f(float[] dataArray) {
-        mMat = new float[16];
-        System.arraycopy(dataArray, 0, mMat, 0, mMat.length);
-    }
-
-    /**
-    * Return a reference to the internal array representing matrix
-    * values. Modifying this array will also change the matrix
-    *
-    * @return internal array representing the matrix
-    */
-    public float[] getArray() {
-        return mMat;
-    }
-
-    /**
-    * Returns the value for a given row and column
-    *
-    * @param x column of the value to return
-    * @param y row of the value to return
-    *
-    * @return value in the yth row and xth column
-    */
-    public float get(int x, int y) {
-        return mMat[x*4 + y];
-    }
-
-    /**
-    * Sets the value for a given row and column
-    *
-    * @param x column of the value to set
-    * @param y row of the value to set
-    */
-    public void set(int x, int y, float v) {
-        mMat[x*4 + y] = v;
-    }
-
-    /**
-    * Sets the matrix values to identity
-    */
-    public void loadIdentity() {
-        mMat[0] = 1;
-        mMat[1] = 0;
-        mMat[2] = 0;
-        mMat[3] = 0;
-
-        mMat[4] = 0;
-        mMat[5] = 1;
-        mMat[6] = 0;
-        mMat[7] = 0;
-
-        mMat[8] = 0;
-        mMat[9] = 0;
-        mMat[10] = 1;
-        mMat[11] = 0;
-
-        mMat[12] = 0;
-        mMat[13] = 0;
-        mMat[14] = 0;
-        mMat[15] = 1;
-    }
-
-    /**
-    * Sets the values of the matrix to those of the parameter
-    *
-    * @param src matrix to load the values from
-    */
-    public void load(Matrix4f src) {
-        System.arraycopy(src.getArray(), 0, mMat, 0, mMat.length);
-    }
-
-    /**
-    * Sets the values of the matrix to those of the parameter
-    *
-    * @param src matrix to load the values from
-    * @hide
-    */
-    public void load(Matrix3f src) {
-        mMat[0] = src.mMat[0];
-        mMat[1] = src.mMat[1];
-        mMat[2] = src.mMat[2];
-        mMat[3] = 0;
-
-        mMat[4] = src.mMat[3];
-        mMat[5] = src.mMat[4];
-        mMat[6] = src.mMat[5];
-        mMat[7] = 0;
-
-        mMat[8] = src.mMat[6];
-        mMat[9] = src.mMat[7];
-        mMat[10] = src.mMat[8];
-        mMat[11] = 0;
-
-        mMat[12] = 0;
-        mMat[13] = 0;
-        mMat[14] = 0;
-        mMat[15] = 1;
-    }
-
-    /**
-    * Sets current values to be a rotation matrix of certain angle
-    * about a given axis
-    *
-    * @param rot angle of rotation
-    * @param x rotation axis x
-    * @param y rotation axis y
-    * @param z rotation axis z
-    */
-    public void loadRotate(float rot, float x, float y, float z) {
-        float c, s;
-        mMat[3] = 0;
-        mMat[7] = 0;
-        mMat[11]= 0;
-        mMat[12]= 0;
-        mMat[13]= 0;
-        mMat[14]= 0;
-        mMat[15]= 1;
-        rot *= (float)(java.lang.Math.PI / 180.0f);
-        c = (float)java.lang.Math.cos(rot);
-        s = (float)java.lang.Math.sin(rot);
-
-        float len = (float)java.lang.Math.sqrt(x*x + y*y + z*z);
-        if (!(len != 1)) {
-            float recipLen = 1.f / len;
-            x *= recipLen;
-            y *= recipLen;
-            z *= recipLen;
-        }
-        float nc = 1.0f - c;
-        float xy = x * y;
-        float yz = y * z;
-        float zx = z * x;
-        float xs = x * s;
-        float ys = y * s;
-        float zs = z * s;
-        mMat[ 0] = x*x*nc +  c;
-        mMat[ 4] =  xy*nc - zs;
-        mMat[ 8] =  zx*nc + ys;
-        mMat[ 1] =  xy*nc + zs;
-        mMat[ 5] = y*y*nc +  c;
-        mMat[ 9] =  yz*nc - xs;
-        mMat[ 2] =  zx*nc - ys;
-        mMat[ 6] =  yz*nc + xs;
-        mMat[10] = z*z*nc +  c;
-    }
-
-    /**
-    * Sets current values to be a scale matrix of given dimensions
-    *
-    * @param x scale component x
-    * @param y scale component y
-    * @param z scale component z
-    */
-    public void loadScale(float x, float y, float z) {
-        loadIdentity();
-        mMat[0] = x;
-        mMat[5] = y;
-        mMat[10] = z;
-    }
-
-    /**
-    * Sets current values to be a translation matrix of given
-    * dimensions
-    *
-    * @param x translation component x
-    * @param y translation component y
-    * @param z translation component z
-    */
-    public void loadTranslate(float x, float y, float z) {
-        loadIdentity();
-        mMat[12] = x;
-        mMat[13] = y;
-        mMat[14] = z;
-    }
-
-    /**
-    * Sets current values to be the result of multiplying two given
-    * matrices
-    *
-    * @param lhs left hand side matrix
-    * @param rhs right hand side matrix
-    */
-    public void loadMultiply(Matrix4f lhs, Matrix4f rhs) {
-        for (int i=0 ; i<4 ; i++) {
-            float ri0 = 0;
-            float ri1 = 0;
-            float ri2 = 0;
-            float ri3 = 0;
-            for (int j=0 ; j<4 ; j++) {
-                float rhs_ij = rhs.get(i,j);
-                ri0 += lhs.get(j,0) * rhs_ij;
-                ri1 += lhs.get(j,1) * rhs_ij;
-                ri2 += lhs.get(j,2) * rhs_ij;
-                ri3 += lhs.get(j,3) * rhs_ij;
-            }
-            set(i,0, ri0);
-            set(i,1, ri1);
-            set(i,2, ri2);
-            set(i,3, ri3);
-        }
-    }
-
-    /**
-    * Set current values to be an orthographic projection matrix
-    *
-    * @param l location of the left vertical clipping plane
-    * @param r location of the right vertical clipping plane
-    * @param b location of the bottom horizontal clipping plane
-    * @param t location of the top horizontal clipping plane
-    * @param n location of the near clipping plane
-    * @param f location of the far clipping plane
-    */
-    public void loadOrtho(float l, float r, float b, float t, float n, float f) {
-        loadIdentity();
-        mMat[0] = 2 / (r - l);
-        mMat[5] = 2 / (t - b);
-        mMat[10]= -2 / (f - n);
-        mMat[12]= -(r + l) / (r - l);
-        mMat[13]= -(t + b) / (t - b);
-        mMat[14]= -(f + n) / (f - n);
-    }
-
-    /**
-    * Set current values to be an orthographic projection matrix
-    * with the right and bottom clipping planes set to the given
-    * values. Left and top clipping planes are set to 0. Near and
-    * far are set to -1, 1 respectively
-    *
-    * @param w location of the right vertical clipping plane
-    * @param h location of the bottom horizontal clipping plane
-    *
-    */
-    public void loadOrthoWindow(int w, int h) {
-        loadOrtho(0,w, h,0, -1,1);
-    }
-
-    /**
-    * Sets current values to be a perspective projection matrix
-    *
-    * @param l location of the left vertical clipping plane
-    * @param r location of the right vertical clipping plane
-    * @param b location of the bottom horizontal clipping plane
-    * @param t location of the top horizontal clipping plane
-    * @param n location of the near clipping plane, must be positive
-    * @param f location of the far clipping plane, must be positive
-    *
-    */
-    public void loadFrustum(float l, float r, float b, float t, float n, float f) {
-        loadIdentity();
-        mMat[0] = 2 * n / (r - l);
-        mMat[5] = 2 * n / (t - b);
-        mMat[8] = (r + l) / (r - l);
-        mMat[9] = (t + b) / (t - b);
-        mMat[10]= -(f + n) / (f - n);
-        mMat[11]= -1;
-        mMat[14]= -2*f*n / (f - n);
-        mMat[15]= 0;
-    }
-
-    /**
-    * Sets current values to be a perspective projection matrix
-    *
-    * @param fovy vertical field of view angle in degrees
-    * @param aspect aspect ratio of the screen
-    * @param near near cliping plane, must be positive
-    * @param far far clipping plane, must be positive
-    */
-    public void loadPerspective(float fovy, float aspect, float near, float far) {
-        float top = near * (float)Math.tan((float) (fovy * Math.PI / 360.0f));
-        float bottom = -top;
-        float left = bottom * aspect;
-        float right = top * aspect;
-        loadFrustum(left, right, bottom, top, near, far);
-    }
-
-    /**
-    * Helper function to set the current values to a perspective
-    * projection matrix with aspect ratio defined by the parameters
-    * and (near, far), (bottom, top) mapping to (-1, 1) at z = 0
-    *
-    * @param w screen width
-    * @param h screen height
-    */
-    public void loadProjectionNormalized(int w, int h) {
-        // range -1,1 in the narrow axis at z = 0.
-        Matrix4f m1 = new Matrix4f();
-        Matrix4f m2 = new Matrix4f();
-
-        if(w > h) {
-            float aspect = ((float)w) / h;
-            m1.loadFrustum(-aspect,aspect,  -1,1,  1,100);
-        } else {
-            float aspect = ((float)h) / w;
-            m1.loadFrustum(-1,1, -aspect,aspect, 1,100);
-        }
-
-        m2.loadRotate(180, 0, 1, 0);
-        m1.loadMultiply(m1, m2);
-
-        m2.loadScale(-2, 2, 1);
-        m1.loadMultiply(m1, m2);
-
-        m2.loadTranslate(0, 0, 2);
-        m1.loadMultiply(m1, m2);
-
-        load(m1);
-    }
-
-    /**
-    * Post-multiplies the current matrix by a given parameter
-    *
-    * @param rhs right hand side to multiply by
-    */
-    public void multiply(Matrix4f rhs) {
-        Matrix4f tmp = new Matrix4f();
-        tmp.loadMultiply(this, rhs);
-        load(tmp);
-    }
-    /**
-    * Modifies the current matrix by post-multiplying it with a
-    * rotation matrix of certain angle about a given axis
-    *
-    * @param rot angle of rotation
-    * @param x rotation axis x
-    * @param y rotation axis y
-    * @param z rotation axis z
-    */
-    public void rotate(float rot, float x, float y, float z) {
-        Matrix4f tmp = new Matrix4f();
-        tmp.loadRotate(rot, x, y, z);
-        multiply(tmp);
-    }
-
-    /**
-    * Modifies the current matrix by post-multiplying it with a
-    * scale matrix of given dimensions
-    *
-    * @param x scale component x
-    * @param y scale component y
-    * @param z scale component z
-    */
-    public void scale(float x, float y, float z) {
-        Matrix4f tmp = new Matrix4f();
-        tmp.loadScale(x, y, z);
-        multiply(tmp);
-    }
-
-    /**
-    * Modifies the current matrix by post-multiplying it with a
-    * translation matrix of given dimensions
-    *
-    * @param x translation component x
-    * @param y translation component y
-    * @param z translation component z
-    */
-    public void translate(float x, float y, float z) {
-        Matrix4f tmp = new Matrix4f();
-        tmp.loadTranslate(x, y, z);
-        multiply(tmp);
-    }
-    private float computeCofactor(int i, int j) {
-        int c0 = (i+1) % 4;
-        int c1 = (i+2) % 4;
-        int c2 = (i+3) % 4;
-        int r0 = (j+1) % 4;
-        int r1 = (j+2) % 4;
-        int r2 = (j+3) % 4;
-
-        float minor = (mMat[c0 + 4*r0] * (mMat[c1 + 4*r1] * mMat[c2 + 4*r2] -
-                                            mMat[c1 + 4*r2] * mMat[c2 + 4*r1]))
-                     - (mMat[c0 + 4*r1] * (mMat[c1 + 4*r0] * mMat[c2 + 4*r2] -
-                                            mMat[c1 + 4*r2] * mMat[c2 + 4*r0]))
-                     + (mMat[c0 + 4*r2] * (mMat[c1 + 4*r0] * mMat[c2 + 4*r1] -
-                                            mMat[c1 + 4*r1] * mMat[c2 + 4*r0]));
-
-        float cofactor = ((i+j) & 1) != 0 ? -minor : minor;
-        return cofactor;
-    }
-
-    /**
-    * Sets the current matrix to its inverse
-    */
-    public boolean inverse() {
-
-        Matrix4f result = new Matrix4f();
-
-        for (int i = 0; i < 4; ++i) {
-            for (int j = 0; j < 4; ++j) {
-                result.mMat[4*i + j] = computeCofactor(i, j);
-            }
-        }
-
-        // Dot product of 0th column of source and 0th row of result
-        float det = mMat[0]*result.mMat[0] + mMat[4]*result.mMat[1] +
-                     mMat[8]*result.mMat[2] + mMat[12]*result.mMat[3];
-
-        if (Math.abs(det) < 1e-6) {
-            return false;
-        }
-
-        det = 1.0f / det;
-        for (int i = 0; i < 16; ++i) {
-            mMat[i] = result.mMat[i] * det;
-        }
-
-        return true;
-    }
-
-    /**
-    * Sets the current matrix to its inverse transpose
-    */
-    public boolean inverseTranspose() {
-
-        Matrix4f result = new Matrix4f();
-
-        for (int i = 0; i < 4; ++i) {
-            for (int j = 0; j < 4; ++j) {
-                result.mMat[4*j + i] = computeCofactor(i, j);
-            }
-        }
-
-        float det = mMat[0]*result.mMat[0] + mMat[4]*result.mMat[4] +
-                     mMat[8]*result.mMat[8] + mMat[12]*result.mMat[12];
-
-        if (Math.abs(det) < 1e-6) {
-            return false;
-        }
-
-        det = 1.0f / det;
-        for (int i = 0; i < 16; ++i) {
-            mMat[i] = result.mMat[i] * det;
-        }
-
-        return true;
-    }
-
-    /**
-    * Sets the current matrix to its transpose
-    */
-    public void transpose() {
-        for(int i = 0; i < 3; ++i) {
-            for(int j = i + 1; j < 4; ++j) {
-                float temp = mMat[i*4 + j];
-                mMat[i*4 + j] = mMat[j*4 + i];
-                mMat[j*4 + i] = temp;
-            }
-        }
-    }
-
-    final float[] mMat;
-}
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/RSDriverException.java b/v8/renderscript/java/src/android/support/v8/renderscript/RSDriverException.java
deleted file mode 100644
index d4ae341..0000000
--- a/v8/renderscript/java/src/android/support/v8/renderscript/RSDriverException.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2010 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 android.support.v8.renderscript;
-
-
-/**
- * Base class for all exceptions thrown by the Android
- * RenderScript
- */
-public class RSDriverException extends RSRuntimeException {
-    public RSDriverException(String string) {
-        super(string);
-    }
-}
-
-
-
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/RSIllegalArgumentException.java b/v8/renderscript/java/src/android/support/v8/renderscript/RSIllegalArgumentException.java
deleted file mode 100644
index 378a49c..0000000
--- a/v8/renderscript/java/src/android/support/v8/renderscript/RSIllegalArgumentException.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2010 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 android.support.v8.renderscript;
-
-
-/**
- * Base class for all exceptions thrown by the Android
- * RenderScript
- */
-public class RSIllegalArgumentException extends RSRuntimeException {
-    public RSIllegalArgumentException(String string) {
-        super(string);
-    }
-}
-
-
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/RSInvalidStateException.java b/v8/renderscript/java/src/android/support/v8/renderscript/RSInvalidStateException.java
deleted file mode 100644
index a5676a3..0000000
--- a/v8/renderscript/java/src/android/support/v8/renderscript/RSInvalidStateException.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2010 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 android.support.v8.renderscript;
-
-
-/**
- * Base class for all exceptions thrown by the Android
- * RenderScript
- */
-public class RSInvalidStateException extends RSRuntimeException {
-    public RSInvalidStateException(String string) {
-        super(string);
-    }
-}
-
-
-
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/RSRuntimeException.java b/v8/renderscript/java/src/android/support/v8/renderscript/RSRuntimeException.java
deleted file mode 100644
index ec83365..0000000
--- a/v8/renderscript/java/src/android/support/v8/renderscript/RSRuntimeException.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2010 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 android.support.v8.renderscript;
-
-
-/**
- * Base class for all exceptions thrown by the Android
- * RenderScript
- */
-public class RSRuntimeException
-  extends java.lang.RuntimeException {
-    public RSRuntimeException(String string) {
-        super(string);
-    }
-}
-
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/RenderScript.java b/v8/renderscript/java/src/android/support/v8/renderscript/RenderScript.java
deleted file mode 100644
index a5c6f93..0000000
--- a/v8/renderscript/java/src/android/support/v8/renderscript/RenderScript.java
+++ /dev/null
@@ -1,1721 +0,0 @@
-/*
- * Copyright (C) 2013 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 android.support.v8.renderscript;
-
-import java.io.File;
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
-import java.util.ArrayList;
-import java.nio.ByteBuffer;
-
-import android.content.Context;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
-import android.content.res.AssetManager;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.os.Process;
-import android.util.Log;
-import android.view.Surface;
-
-/**
- * This class provides access to a RenderScript context, which controls RenderScript
- * initialization, resource management, and teardown. An instance of the RenderScript
- * class must be created before any other RS objects can be created.
- *
- * <div class="special reference">
- * <h3>Developer Guides</h3>
- * <p>For more information about creating an application that uses RenderScript, read the
- * <a href="{@docRoot}guide/topics/renderscript/index.html">RenderScript</a> developer guide.</p>
- * </div>
- **/
-public class RenderScript {
-    static final String LOG_TAG = "RenderScript_jni";
-    static final boolean DEBUG  = false;
-    @SuppressWarnings({"UnusedDeclaration", "deprecation"})
-    static final boolean LOG_ENABLED = false;
-    static final int SUPPORT_LIB_API = 23;
-    static final int SUPPORT_LIB_VERSION = 2301;
-
-    static private ArrayList<RenderScript> mProcessContextList = new ArrayList<RenderScript>();
-    private boolean mIsProcessContext = false;
-    private boolean mEnableMultiInput = false;
-    private int mDispatchAPILevel = 0;
-
-    private int mContextFlags = 0;
-    private int mContextSdkVersion = 0;
-
-    private Context mApplicationContext;
-    private String mNativeLibDir;
-
-    static private String mBlackList = "";
-     /**
-     * Sets the blackList of Models to only use support lib runtime.
-     * Should be used before context create.
-     *
-     * @param blackList User provided black list string.
-     *
-     * Format: "(MANUFACTURER1:PRODUCT1:MODEL1), (MANUFACTURER2:PRODUCT2:MODEL2)..."
-     * e.g. : To Blacklist Nexus 7(2013) and Nexus 5.
-     *        mBlackList = "(asus:razor:Nexus 7), (LGE:hammerhead:Nexus 5)";
-     */
-    static public void setBlackList(String blackList) {
-        if (blackList != null) {
-            mBlackList = blackList;
-        }
-    }
-     /**
-     * Force using support lib runtime.
-     * Should be used before context create.
-     *
-     */
-    static public void forceCompat() {
-        sNative = 0;
-    }
-    /*
-     * We use a class initializer to allow the native code to cache some
-     * field offsets.
-     */
-    @SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"})
-    static boolean sInitialized;
-    static boolean sUseGCHooks;
-    static Object sRuntime;
-    static Method registerNativeAllocation;
-    static Method registerNativeFree;
-
-    static Object lock = new Object();
-
-    // Non-threadsafe functions.
-    native boolean nLoadSO(boolean useNative, int deviceApi, String libPath);
-    native boolean nLoadIOSO();
-    native long nDeviceCreate();
-    native void nDeviceDestroy(long dev);
-    native void nDeviceSetConfig(long dev, int param, int value);
-    native int nContextGetUserMessage(long con, int[] data);
-    native String nContextGetErrorMessage(long con);
-    native int  nContextPeekMessage(long con, int[] subID);
-    native void nContextInitToClient(long con);
-    native void nContextDeinitToClient(long con);
-
-    static private int sNative = -1;
-    static private int sSdkVersion = -1;
-    static private boolean useIOlib = false;
-    static private boolean useNative;
-
-    /*
-     * Context creation flag that specifies a normal context.
-     * RenderScript Support lib only support normal context.
-     */
-    public static final int CREATE_FLAG_NONE = 0x0000;
-
-    int getDispatchAPILevel() {
-        return mDispatchAPILevel;
-    }
-
-    boolean isUseNative() {
-        return useNative;
-    }
-    /*
-     * Detect the bitness of the VM to allow FieldPacker to do the right thing.
-     */
-    static native int rsnSystemGetPointerSize();
-    static int sPointerSize;
-
-    /**
-     * Determines whether or not we should be thunking into the native
-     * RenderScript layer or actually using the compatibility library.
-     */
-    static private boolean setupNative(int sdkVersion, Context ctx) {
-        // if targetSdkVersion is higher than the device api version, always use compat mode.
-        // Workaround for KK
-        if (android.os.Build.VERSION.SDK_INT < sdkVersion &&
-            android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.LOLLIPOP) {
-            sNative = 0;
-        }
-
-        if (sNative == -1) {
-
-            // get the value of the debug.rs.forcecompat property
-            int forcecompat = 0;
-            try {
-                Class<?> sysprop = Class.forName("android.os.SystemProperties");
-                Class[] signature = {String.class, Integer.TYPE};
-                Method getint = sysprop.getDeclaredMethod("getInt", signature);
-                Object[] args = {"debug.rs.forcecompat", new Integer(0)};
-                forcecompat = ((java.lang.Integer)getint.invoke(null, args)).intValue();
-            } catch (Exception e) {
-
-            }
-
-            if ((android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT)
-                     && forcecompat == 0) {
-                sNative = 1;
-            } else {
-                sNative = 0;
-            }
-
-
-            if (sNative == 1) {
-                // Workarounds that may disable thunking go here
-                ApplicationInfo info;
-                try {
-                    info = ctx.getPackageManager().getApplicationInfo(ctx.getPackageName(),
-                                                                      PackageManager.GET_META_DATA);
-                } catch (PackageManager.NameNotFoundException e) {
-                    // assume no workarounds needed
-                    return true;
-                }
-                long minorVersion = 0;
-
-                // load minorID from reflection
-                try {
-                    Class<?> javaRS = Class.forName("android.renderscript.RenderScript");
-                    Method getMinorID = javaRS.getDeclaredMethod("getMinorID");
-                    minorVersion = ((java.lang.Long)getMinorID.invoke(null)).longValue();
-                } catch (Exception e) {
-                    // minor version remains 0 on devices with no possible WARs
-                }
-
-                if (info.metaData != null) {
-                    // asynchronous teardown: minor version 1+
-                    if (info.metaData.getBoolean("com.android.support.v8.renderscript.EnableAsyncTeardown") == true) {
-                        if (minorVersion == 0) {
-                            sNative = 0;
-                        }
-                    }
-
-                    // blur issues on some drivers with 4.4
-                    if (info.metaData.getBoolean("com.android.support.v8.renderscript.EnableBlurWorkaround") == true) {
-                        if (android.os.Build.VERSION.SDK_INT <= 19) {
-                            //android.util.Log.e("rs", "war on");
-                            sNative = 0;
-                        }
-                    }
-                }
-                // end of workarounds
-            }
-        }
-
-        if (sNative == 1) {
-            // check against the blacklist
-            if (mBlackList.length() > 0) {
-                String deviceInfo = '(' +
-                                    android.os.Build.MANUFACTURER +
-                                    ':' +
-                                    android.os.Build.PRODUCT +
-                                    ':' +
-                                    android.os.Build.MODEL +
-                                    ')';
-                if (mBlackList.contains(deviceInfo)) {
-                    sNative = 0;
-                    return false;
-                }
-            }
-            return true;
-        }
-        return false;
-    }
-
-    /**
-     * Name of the file that holds the object cache.
-     */
-    private static final String CACHE_PATH = "com.android.renderscript.cache";
-    static String mCachePath;
-
-     /**
-     * Sets the directory to use as a persistent storage for the
-     * renderscript object file cache.
-     *
-     * @hide
-     * @param cacheDir A directory the current process can write to
-     */
-    public static void setupDiskCache(File cacheDir) {
-        File f = new File(cacheDir, CACHE_PATH);
-        mCachePath = f.getAbsolutePath();
-        f.mkdirs();
-    }
-
-    /**
-     * ContextType specifies the specific type of context to be created.
-     *
-     */
-    public enum ContextType {
-        /**
-         * NORMAL context, this is the default and what shipping apps should
-         * use.
-         */
-        NORMAL (0),
-
-        /**
-         * DEBUG context, perform extra runtime checks to validate the
-         * kernels and APIs are being used as intended.  Get and SetElementAt
-         * will be bounds checked in this mode.
-         */
-        DEBUG (1),
-
-        /**
-         * PROFILE context, Intended to be used once the first time an
-         * application is run on a new device.  This mode allows the runtime to
-         * do additional testing and performance tuning.
-         */
-        PROFILE (2);
-
-        int mID;
-        ContextType(int id) {
-            mID = id;
-        }
-    }
-
-    ContextType mContextType;
-    // Methods below are wrapped to protect the non-threadsafe
-    // lockless fifo.
-
-    native long  rsnContextCreate(long dev, int ver, int sdkVer, int contextType, String nativeLibDir);
-    synchronized long nContextCreate(long dev, int ver, int sdkVer, int contextType, String nativeLibDir) {
-        return rsnContextCreate(dev, ver, sdkVer, contextType, nativeLibDir);
-    }
-    native void rsnContextDestroy(long con);
-    synchronized void nContextDestroy() {
-        validate();
-
-        // take teardown lock
-        // teardown lock can only be taken when no objects are being destroyed
-        ReentrantReadWriteLock.WriteLock wlock = mRWLock.writeLock();
-        wlock.lock();
-
-        long curCon = mContext;
-        // context is considered dead as of this point
-        mContext = 0;
-
-        wlock.unlock();
-        rsnContextDestroy(curCon);
-    }
-    native void rsnContextSetPriority(long con, int p);
-    synchronized void nContextSetPriority(int p) {
-        validate();
-        rsnContextSetPriority(mContext, p);
-    }
-    native void rsnContextDump(long con, int bits);
-    synchronized void nContextDump(int bits) {
-        validate();
-        rsnContextDump(mContext, bits);
-    }
-    native void rsnContextFinish(long con);
-    synchronized void nContextFinish() {
-        validate();
-        rsnContextFinish(mContext);
-    }
-
-    native void rsnContextSendMessage(long con, int id, int[] data);
-    synchronized void nContextSendMessage(int id, int[] data) {
-        validate();
-        rsnContextSendMessage(mContext, id, data);
-    }
-
-    // nObjDestroy is explicitly _not_ synchronous to prevent crashes in finalizers
-    native void rsnObjDestroy(long con, long id);
-    void nObjDestroy(long id) {
-        // There is a race condition here.  The calling code may be run
-        // by the gc while teardown is occuring.  This protects againts
-        // deleting dead objects.
-        if (mContext != 0) {
-            rsnObjDestroy(mContext, id);
-        }
-    }
-
-    native long  rsnElementCreate(long con, long type, int kind, boolean norm, int vecSize);
-    synchronized long nElementCreate(long type, int kind, boolean norm, int vecSize) {
-        validate();
-        return rsnElementCreate(mContext, type, kind, norm, vecSize);
-    }
-    native long  rsnElementCreate2(long con, long[] elements, String[] names, int[] arraySizes);
-    synchronized long nElementCreate2(long[] elements, String[] names, int[] arraySizes) {
-        validate();
-        return rsnElementCreate2(mContext, elements, names, arraySizes);
-    }
-    native void rsnElementGetNativeData(long con, long id, int[] elementData);
-    synchronized void nElementGetNativeData(long id, int[] elementData) {
-        validate();
-        rsnElementGetNativeData(mContext, id, elementData);
-    }
-    native void rsnElementGetSubElements(long con, long id,
-                                         long[] IDs, String[] names, int[] arraySizes);
-    synchronized void nElementGetSubElements(long id, long[] IDs, String[] names, int[] arraySizes) {
-        validate();
-        rsnElementGetSubElements(mContext, id, IDs, names, arraySizes);
-    }
-
-    native long rsnTypeCreate(long con, long eid, int x, int y, int z, boolean mips, boolean faces, int yuv);
-    synchronized long nTypeCreate(long eid, int x, int y, int z, boolean mips, boolean faces, int yuv) {
-        validate();
-        return rsnTypeCreate(mContext, eid, x, y, z, mips, faces, yuv);
-    }
-
-    native void rsnTypeGetNativeData(long con, long id, long[] typeData);
-    synchronized void nTypeGetNativeData(long id, long[] typeData) {
-        validate();
-        rsnTypeGetNativeData(mContext, id, typeData);
-    }
-
-    native long  rsnAllocationCreateTyped(long con, long type, int mip, int usage, long pointer);
-    synchronized long nAllocationCreateTyped(long type, int mip, int usage, long pointer) {
-        validate();
-        return rsnAllocationCreateTyped(mContext, type, mip, usage, pointer);
-    }
-    native long  rsnAllocationCreateFromBitmap(long con, long type, int mip, Bitmap bmp, int usage);
-    synchronized long nAllocationCreateFromBitmap(long type, int mip, Bitmap bmp, int usage) {
-        validate();
-        return rsnAllocationCreateFromBitmap(mContext, type, mip, bmp, usage);
-    }
-
-    native long  rsnAllocationCreateBitmapBackedAllocation(long con, long type, int mip, Bitmap bmp, int usage);
-    synchronized long nAllocationCreateBitmapBackedAllocation(long type, int mip, Bitmap bmp, int usage) {
-        validate();
-        return rsnAllocationCreateBitmapBackedAllocation(mContext, type, mip, bmp, usage);
-    }
-
-
-    native long  rsnAllocationCubeCreateFromBitmap(long con, long type, int mip, Bitmap bmp, int usage);
-    synchronized long nAllocationCubeCreateFromBitmap(long type, int mip, Bitmap bmp, int usage) {
-        validate();
-        return rsnAllocationCubeCreateFromBitmap(mContext, type, mip, bmp, usage);
-    }
-    native long  rsnAllocationCreateBitmapRef(long con, long type, Bitmap bmp);
-    synchronized long nAllocationCreateBitmapRef(long type, Bitmap bmp) {
-        validate();
-        return rsnAllocationCreateBitmapRef(mContext, type, bmp);
-    }
-    native long  rsnAllocationCreateFromAssetStream(long con, int mips, int assetStream, int usage);
-    synchronized long nAllocationCreateFromAssetStream(int mips, int assetStream, int usage) {
-        validate();
-        return rsnAllocationCreateFromAssetStream(mContext, mips, assetStream, usage);
-    }
-
-    native void  rsnAllocationCopyToBitmap(long con, long alloc, Bitmap bmp);
-    synchronized void nAllocationCopyToBitmap(long alloc, Bitmap bmp) {
-        validate();
-        rsnAllocationCopyToBitmap(mContext, alloc, bmp);
-    }
-
-
-    native void rsnAllocationSyncAll(long con, long alloc, int src);
-    synchronized void nAllocationSyncAll(long alloc, int src) {
-        validate();
-        rsnAllocationSyncAll(mContext, alloc, src);
-    }
-
-    native void rsnAllocationSetSurface(long con, long alloc, Surface sur);
-    synchronized void nAllocationSetSurface(long alloc, Surface sur) {
-        validate();
-        rsnAllocationSetSurface(mContext, alloc, sur);
-    }
-
-    native void rsnAllocationIoSend(long con, long alloc);
-    synchronized void nAllocationIoSend(long alloc) {
-        validate();
-        rsnAllocationIoSend(mContext, alloc);
-    }
-    native void rsnAllocationIoReceive(long con, long alloc);
-    synchronized void nAllocationIoReceive(long alloc) {
-        validate();
-        rsnAllocationIoReceive(mContext, alloc);
-    }
-    native ByteBuffer rsnAllocationGetByteBuffer(long con, long alloc, int xBytesSize, int dimY, int dimZ);
-    synchronized ByteBuffer nAllocationGetByteBuffer(long alloc, int xBytesSize, int dimY, int dimZ) {
-        validate();
-        return rsnAllocationGetByteBuffer(mContext, alloc, xBytesSize, dimY, dimZ);
-    }
-    native long rsnAllocationGetStride(long con, long alloc);
-    synchronized long nAllocationGetStride(long alloc) {
-        validate();
-        return rsnAllocationGetStride(mContext, alloc);
-    }
-
-    native void rsnAllocationGenerateMipmaps(long con, long alloc);
-    synchronized void nAllocationGenerateMipmaps(long alloc) {
-        validate();
-        rsnAllocationGenerateMipmaps(mContext, alloc);
-    }
-    native void  rsnAllocationCopyFromBitmap(long con, long alloc, Bitmap bmp);
-    synchronized void nAllocationCopyFromBitmap(long alloc, Bitmap bmp) {
-        validate();
-        rsnAllocationCopyFromBitmap(mContext, alloc, bmp);
-    }
-
-
-    native void rsnAllocationData1D(long con, long id, int off, int mip, int count, Object d, int sizeBytes, int dt,
-                                    int mSize, boolean usePadding);
-    synchronized void nAllocationData1D(long id, int off, int mip, int count, Object d, int sizeBytes, Element.DataType dt,
-                                        int mSize, boolean usePadding) {
-        validate();
-        rsnAllocationData1D(mContext, id, off, mip, count, d, sizeBytes, dt.mID, mSize, usePadding);
-    }
-
-    native void rsnAllocationElementData1D(long con,long id, int xoff, int mip, int compIdx, byte[] d, int sizeBytes);
-    synchronized void nAllocationElementData1D(long id, int xoff, int mip, int compIdx, byte[] d, int sizeBytes) {
-        validate();
-        rsnAllocationElementData1D(mContext, id, xoff, mip, compIdx, d, sizeBytes);
-    }
-    /*
-    native void rsnAllocationElementData(long con,long id, int xoff, int yoff, int zoff, int mip, int compIdx, byte[] d, int sizeBytes);
-    synchronized void nAllocationElementData(long id, int xoff, int yoff, int zoff, int mip, int compIdx, byte[] d, int sizeBytes) {
-        validate();
-        rsnAllocationElementData(mContext, id, xoff, yoff, zoff, mip, compIdx, d, sizeBytes);
-    }
-    */
-
-    native void rsnAllocationData2D(long con,
-                                    long dstAlloc, int dstXoff, int dstYoff,
-                                    int dstMip, int dstFace,
-                                    int width, int height,
-                                    long srcAlloc, int srcXoff, int srcYoff,
-                                    int srcMip, int srcFace);
-    synchronized void nAllocationData2D(long dstAlloc, int dstXoff, int dstYoff,
-                                        int dstMip, int dstFace,
-                                        int width, int height,
-                                        long srcAlloc, int srcXoff, int srcYoff,
-                                        int srcMip, int srcFace) {
-        validate();
-        rsnAllocationData2D(mContext,
-                            dstAlloc, dstXoff, dstYoff,
-                            dstMip, dstFace,
-                            width, height,
-                            srcAlloc, srcXoff, srcYoff,
-                            srcMip, srcFace);
-    }
-
-    native void rsnAllocationData2D(long con, long id, int xoff, int yoff, int mip, int face,
-                                    int w, int h, Object d, int sizeBytes, int dt,
-                                    int mSize, boolean usePadding);
-    synchronized void nAllocationData2D(long id, int xoff, int yoff, int mip, int face,
-                                        int w, int h, Object d, int sizeBytes, Element.DataType dt,
-                                        int mSize, boolean usePadding) {
-        validate();
-        rsnAllocationData2D(mContext, id, xoff, yoff, mip, face, w, h, d, sizeBytes, dt.mID, mSize, usePadding);
-    }
-
-    native void rsnAllocationData2D(long con, long id, int xoff, int yoff, int mip, int face, Bitmap b);
-    synchronized void nAllocationData2D(long id, int xoff, int yoff, int mip, int face, Bitmap b) {
-        validate();
-        rsnAllocationData2D(mContext, id, xoff, yoff, mip, face, b);
-    }
-
-    native void rsnAllocationData3D(long con,
-                                    long dstAlloc, int dstXoff, int dstYoff, int dstZoff,
-                                    int dstMip,
-                                    int width, int height, int depth,
-                                    long srcAlloc, int srcXoff, int srcYoff, int srcZoff,
-                                    int srcMip);
-    synchronized void nAllocationData3D(long dstAlloc, int dstXoff, int dstYoff, int dstZoff,
-                                        int dstMip,
-                                        int width, int height, int depth,
-                                        long srcAlloc, int srcXoff, int srcYoff, int srcZoff,
-                                        int srcMip) {
-        validate();
-        rsnAllocationData3D(mContext,
-                            dstAlloc, dstXoff, dstYoff, dstZoff,
-                            dstMip, width, height, depth,
-                            srcAlloc, srcXoff, srcYoff, srcZoff, srcMip);
-    }
-
-
-    native void rsnAllocationData3D(long con, long id, int xoff, int yoff, int zoff, int mip,
-                                    int w, int h, int depth, Object d, int sizeBytes, int dt,
-                                    int mSize, boolean usePadding);
-    synchronized void nAllocationData3D(long id, int xoff, int yoff, int zoff, int mip,
-                                        int w, int h, int depth, Object d, int sizeBytes, Element.DataType dt,
-                                        int mSize, boolean usePadding) {
-        validate();
-        rsnAllocationData3D(mContext, id, xoff, yoff, zoff, mip, w, h, depth, d, sizeBytes,
-                            dt.mID, mSize, usePadding);
-    }
-
-    native void rsnAllocationRead(long con, long id, Object d, int dt, int mSize, boolean usePadding);
-    synchronized void nAllocationRead(long id, Object d, Element.DataType dt, int mSize, boolean usePadding) {
-        validate();
-        rsnAllocationRead(mContext, id, d, dt.mID, mSize, usePadding);
-    }
-
-    native void rsnAllocationRead1D(long con, long id, int off, int mip, int count, Object d,
-                                    int sizeBytes, int dt, int mSize, boolean usePadding);
-    synchronized void nAllocationRead1D(long id, int off, int mip, int count, Object d,
-                                        int sizeBytes, Element.DataType dt, int mSize, boolean usePadding) {
-        validate();
-        rsnAllocationRead1D(mContext, id, off, mip, count, d, sizeBytes, dt.mID, mSize, usePadding);
-    }
-
-    /*
-    native void rsnAllocationElementRead(long con,long id, int xoff, int yoff, int zoff,
-                                         int mip, int compIdx, byte[] d, int sizeBytes);
-    synchronized void nAllocationElementRead(long id, int xoff, int yoff, int zoff,
-                                             int mip, int compIdx, byte[] d, int sizeBytes) {
-        validate();
-        rsnAllocationElementRead(mContext, id, xoff, yoff, zoff, mip, compIdx, d, sizeBytes);
-    }
-    */
-
-    native void rsnAllocationRead2D(long con, long id, int xoff, int yoff, int mip, int face,
-                                    int w, int h, Object d, int sizeBytes, int dt,
-                                    int mSize, boolean usePadding);
-    synchronized void nAllocationRead2D(long id, int xoff, int yoff, int mip, int face,
-                                        int w, int h, Object d, int sizeBytes, Element.DataType dt,
-                                        int mSize, boolean usePadding) {
-        validate();
-        rsnAllocationRead2D(mContext, id, xoff, yoff, mip, face, w, h, d, sizeBytes, dt.mID, mSize, usePadding);
-    }
-
-    /*
-    native void rsnAllocationRead3D(long con, long id, int xoff, int yoff, int zoff, int mip,
-                                    int w, int h, int depth, Object d, int sizeBytes, int dt,
-                                    int mSize, boolean usePadding);
-    synchronized void nAllocationRead3D(long id, int xoff, int yoff, int zoff, int mip,
-                                        int w, int h, int depth, Object d, int sizeBytes, Element.DataType dt,
-                                        int mSize, boolean usePadding) {
-        validate();
-        rsnAllocationRead3D(mContext, id, xoff, yoff, zoff, mip, w, h, depth, d, sizeBytes, dt.mID, mSize, usePadding);
-    }
-    */
-
-    native long  rsnAllocationGetType(long con, long id);
-    synchronized long nAllocationGetType(long id) {
-        validate();
-        return rsnAllocationGetType(mContext, id);
-    }
-
-    native void rsnAllocationResize1D(long con, long id, int dimX);
-    synchronized void nAllocationResize1D(long id, int dimX) {
-        validate();
-        rsnAllocationResize1D(mContext, id, dimX);
-    }
-    native void rsnAllocationResize2D(long con, long id, int dimX, int dimY);
-    synchronized void nAllocationResize2D(long id, int dimX, int dimY) {
-        validate();
-        rsnAllocationResize2D(mContext, id, dimX, dimY);
-    }
-
-    native void rsnScriptBindAllocation(long con, long script, long alloc, int slot, boolean mUseInc);
-    synchronized void nScriptBindAllocation(long script, long alloc, int slot, boolean mUseInc) {
-        validate();
-        long curCon = mContext;
-        if (mUseInc) {
-            curCon = mIncCon;
-        }
-        rsnScriptBindAllocation(curCon, script, alloc, slot, mUseInc);
-    }
-    native void rsnScriptSetTimeZone(long con, long script, byte[] timeZone, boolean mUseInc);
-    synchronized void nScriptSetTimeZone(long script, byte[] timeZone, boolean mUseInc) {
-        validate();
-        long curCon = mContext;
-        if (mUseInc) {
-            curCon = mIncCon;
-        }
-        rsnScriptSetTimeZone(curCon, script, timeZone, mUseInc);
-    }
-    native void rsnScriptInvoke(long con, long id, int slot, boolean mUseInc);
-    synchronized void nScriptInvoke(long id, int slot, boolean mUseInc) {
-        validate();
-        long curCon = mContext;
-        if (mUseInc) {
-            curCon = mIncCon;
-        }
-        rsnScriptInvoke(curCon, id, slot, mUseInc);
-    }
-    native void rsnScriptForEach(long con, long incCon, long id, int slot, long ain, long aout, byte[] params, boolean mUseInc);
-    native void rsnScriptForEach(long con, long incCon, long id, int slot, long ain, long aout, boolean mUseInc);
-    native void rsnScriptForEachClipped(long con, long incCon, long id, int slot, long ain, long aout, byte[] params,
-                                        int xstart, int xend, int ystart, int yend, int zstart, int zend, boolean mUseInc);
-    native void rsnScriptForEachClipped(long con, long incCon, long id, int slot, long ain, long aout,
-                                        int xstart, int xend, int ystart, int yend, int zstart, int zend, boolean mUseInc);
-    synchronized void nScriptForEach(long id, int slot, long ain, long aout, byte[] params, boolean mUseInc) {
-        validate();
-        if (params == null) {
-            rsnScriptForEach(mContext, mIncCon, id, slot, ain, aout, mUseInc);
-        } else {
-            rsnScriptForEach(mContext, mIncCon, id, slot, ain, aout, params, mUseInc);
-        }
-    }
-
-    synchronized void nScriptForEachClipped(long id, int slot, long ain, long aout, byte[] params,
-                                            int xstart, int xend, int ystart, int yend, int zstart, int zend, boolean mUseInc) {
-        validate();
-        if (params == null) {
-            rsnScriptForEachClipped(mContext, mIncCon, id, slot, ain, aout, xstart, xend, ystart, yend, zstart, zend, mUseInc);
-        } else {
-            rsnScriptForEachClipped(mContext, mIncCon, id, slot, ain, aout, params, xstart, xend, ystart, yend, zstart, zend, mUseInc);
-        }
-    }
-
-    native void rsnScriptForEach(long con, long id, int slot, long[] ains,
-                                 long aout, byte[] params, int[] limits);
-
-    synchronized void nScriptForEach(long id, int slot, long[] ains, long aout,
-                                     byte[] params, int[] limits) {
-        if (!mEnableMultiInput) {
-            Log.e(LOG_TAG, "Multi-input kernels are not supported, please change targetSdkVersion to >= 23");
-            throw new RSRuntimeException("Multi-input kernels are not supported before API 23)");
-        }
-        validate();
-        rsnScriptForEach(mContext, id, slot, ains, aout, params, limits);
-    }
-
-    native void rsnScriptReduce(long con, long id, int slot, long[] ains,
-                                long aout, int[] limits);
-    synchronized void nScriptReduce(long id, int slot, long ains[], long aout,
-                                    int[] limits) {
-        validate();
-        rsnScriptReduce(mContext, id, slot, ains, aout, limits);
-    }
-
-    native void rsnScriptInvokeV(long con, long id, int slot, byte[] params, boolean mUseInc);
-    synchronized void nScriptInvokeV(long id, int slot, byte[] params, boolean mUseInc) {
-        validate();
-        long curCon = mContext;
-        if (mUseInc) {
-            curCon = mIncCon;
-        }
-        rsnScriptInvokeV(curCon, id, slot, params, mUseInc);
-    }
-    native void rsnScriptSetVarI(long con, long id, int slot, int val, boolean mUseInc);
-    synchronized void nScriptSetVarI(long id, int slot, int val, boolean mUseInc) {
-        validate();
-        long curCon = mContext;
-        if (mUseInc) {
-            curCon = mIncCon;
-        }
-        rsnScriptSetVarI(curCon, id, slot, val, mUseInc);
-    }
-    native void rsnScriptSetVarJ(long con, long id, int slot, long val, boolean mUseInc);
-    synchronized void nScriptSetVarJ(long id, int slot, long val, boolean mUseInc) {
-        validate();
-        long curCon = mContext;
-        if (mUseInc) {
-            curCon = mIncCon;
-        }
-        rsnScriptSetVarJ(curCon, id, slot, val, mUseInc);
-    }
-    native void rsnScriptSetVarF(long con, long id, int slot, float val, boolean mUseInc);
-    synchronized void nScriptSetVarF(long id, int slot, float val, boolean mUseInc) {
-        validate();
-        long curCon = mContext;
-        if (mUseInc) {
-            curCon = mIncCon;
-        }
-        rsnScriptSetVarF(curCon, id, slot, val, mUseInc);
-    }
-    native void rsnScriptSetVarD(long con, long id, int slot, double val, boolean mUseInc);
-    synchronized void nScriptSetVarD(long id, int slot, double val, boolean mUseInc) {
-        validate();
-        long curCon = mContext;
-        if (mUseInc) {
-            curCon = mIncCon;
-        }
-        rsnScriptSetVarD(curCon, id, slot, val, mUseInc);
-    }
-    native void rsnScriptSetVarV(long con, long id, int slot, byte[] val, boolean mUseInc);
-    synchronized void nScriptSetVarV(long id, int slot, byte[] val, boolean mUseInc) {
-        validate();
-        long curCon = mContext;
-        if (mUseInc) {
-            curCon = mIncCon;
-        }
-        rsnScriptSetVarV(curCon, id, slot, val, mUseInc);
-    }
-    native void rsnScriptSetVarVE(long con, long id, int slot, byte[] val,
-                                  long e, int[] dims, boolean mUseInc);
-    synchronized void nScriptSetVarVE(long id, int slot, byte[] val,
-                                      long e, int[] dims, boolean mUseInc) {
-        validate();
-        long curCon = mContext;
-        if (mUseInc) {
-            curCon = mIncCon;
-        }
-        rsnScriptSetVarVE(curCon, id, slot, val, e, dims, mUseInc);
-    }
-    native void rsnScriptSetVarObj(long con, long id, int slot, long val, boolean mUseInc);
-    synchronized void nScriptSetVarObj(long id, int slot, long val, boolean mUseInc) {
-        validate();
-        long curCon = mContext;
-        if (mUseInc) {
-            curCon = mIncCon;
-        }
-        rsnScriptSetVarObj(curCon, id, slot, val, mUseInc);
-    }
-
-    native long  rsnScriptCCreate(long con, String resName, String cacheDir,
-                                 byte[] script, int length);
-    synchronized long nScriptCCreate(String resName, String cacheDir, byte[] script, int length) {
-        validate();
-        return rsnScriptCCreate(mContext, resName, cacheDir, script, length);
-    }
-
-    native long  rsnScriptIntrinsicCreate(long con, int id, long eid, boolean mUseInc);
-    synchronized long nScriptIntrinsicCreate(int id, long eid, boolean mUseInc) {
-        validate();
-        if (mUseInc) {
-            if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.LOLLIPOP) {
-                Log.e(LOG_TAG, "Incremental Intrinsics are not supported, please change targetSdkVersion to >= 21");
-                throw new RSRuntimeException("Incremental Intrinsics are not supported before Lollipop (API 21)");
-            }
-
-            if (!mIncLoaded) {
-                try {
-                    System.loadLibrary("RSSupport");
-                } catch (UnsatisfiedLinkError e) {
-                    Log.e(LOG_TAG, "Error loading RS Compat library for Incremental Intrinsic Support: " + e);
-                    throw new RSRuntimeException("Error loading RS Compat library for Incremental Intrinsic Support: " + e);
-                }
-                if (!nIncLoadSO(SUPPORT_LIB_API, mNativeLibDir + "/libRSSupport.so")) {
-                    throw new RSRuntimeException("Error loading libRSSupport library for Incremental Intrinsic Support");
-                }
-                mIncLoaded = true;
-            }
-            if (mIncCon == 0) {
-                //Create a dummy compat context (synchronous).
-                long device = nIncDeviceCreate();
-                mIncCon = nIncContextCreate(device, 0, 0, 0);
-            }
-            return rsnScriptIntrinsicCreate(mIncCon, id, eid, mUseInc);
-        } else {
-            return rsnScriptIntrinsicCreate(mContext, id, eid, mUseInc);
-        }
-    }
-
-    native long  rsnScriptKernelIDCreate(long con, long sid, int slot, int sig, boolean mUseInc);
-    synchronized long nScriptKernelIDCreate(long sid, int slot, int sig, boolean mUseInc) {
-        validate();
-        long curCon = mContext;
-        if (mUseInc) {
-            curCon = mIncCon;
-        }
-        return rsnScriptKernelIDCreate(curCon, sid, slot, sig, mUseInc);
-    }
-
-    native long  rsnScriptInvokeIDCreate(long con, long sid, int slot);
-    synchronized long nScriptInvokeIDCreate(long sid, int slot) {
-        validate();
-        return rsnScriptInvokeIDCreate(mContext, sid, slot);
-    }
-
-    native long  rsnScriptFieldIDCreate(long con, long sid, int slot, boolean mUseInc);
-    synchronized long nScriptFieldIDCreate(long sid, int slot, boolean mUseInc) {
-        validate();
-        long curCon = mContext;
-        if (mUseInc) {
-            curCon = mIncCon;
-        }
-        return rsnScriptFieldIDCreate(curCon, sid, slot, mUseInc);
-    }
-
-    native long  rsnScriptGroupCreate(long con, long[] kernels, long[] src, long[] dstk, long[] dstf, long[] types);
-    synchronized long nScriptGroupCreate(long[] kernels, long[] src, long[] dstk, long[] dstf, long[] types) {
-        validate();
-        return rsnScriptGroupCreate(mContext, kernels, src, dstk, dstf, types);
-    }
-
-    native void rsnScriptGroupSetInput(long con, long group, long kernel, long alloc);
-    synchronized void nScriptGroupSetInput(long group, long kernel, long alloc) {
-        validate();
-        rsnScriptGroupSetInput(mContext, group, kernel, alloc);
-    }
-
-    native void rsnScriptGroupSetOutput(long con, long group, long kernel, long alloc);
-    synchronized void nScriptGroupSetOutput(long group, long kernel, long alloc) {
-        validate();
-        rsnScriptGroupSetOutput(mContext, group, kernel, alloc);
-    }
-
-    native void rsnScriptGroupExecute(long con, long group);
-    synchronized void nScriptGroupExecute(long group) {
-        validate();
-        rsnScriptGroupExecute(mContext, group);
-    }
-
-    native long  rsnSamplerCreate(long con, int magFilter, int minFilter,
-                                 int wrapS, int wrapT, int wrapR, float aniso);
-    synchronized long nSamplerCreate(int magFilter, int minFilter,
-                                 int wrapS, int wrapT, int wrapR, float aniso) {
-        validate();
-        return rsnSamplerCreate(mContext, magFilter, minFilter, wrapS, wrapT, wrapR, aniso);
-    }
-
-// entry points for ScriptGroup2
-    native long rsnClosureCreate(long con, long kernelID, long returnValue,
-        long[] fieldIDs, long[] values, int[] sizes, long[] depClosures,
-        long[] depFieldIDs);
-    synchronized long nClosureCreate(long kernelID, long returnValue,
-        long[] fieldIDs, long[] values, int[] sizes, long[] depClosures,
-        long[] depFieldIDs) {
-      validate();
-      long c = rsnClosureCreate(mContext, kernelID, returnValue, fieldIDs, values,
-          sizes, depClosures, depFieldIDs);
-      if (c == 0) {
-          throw new RSRuntimeException("Failed creating closure.");
-      }
-      return c;
-    }
-
-    native long rsnInvokeClosureCreate(long con, long invokeID, byte[] params,
-        long[] fieldIDs, long[] values, int[] sizes);
-    synchronized long nInvokeClosureCreate(long invokeID, byte[] params,
-        long[] fieldIDs, long[] values, int[] sizes) {
-      validate();
-      long c = rsnInvokeClosureCreate(mContext, invokeID, params, fieldIDs,
-          values, sizes);
-      if (c == 0) {
-          throw new RSRuntimeException("Failed creating closure.");
-      }
-      return c;
-    }
-
-    native void rsnClosureSetArg(long con, long closureID, int index,
-      long value, int size);
-    synchronized void nClosureSetArg(long closureID, int index, long value,
-        int size) {
-      validate();
-      rsnClosureSetArg(mContext, closureID, index, value, size);
-    }
-
-    native void rsnClosureSetGlobal(long con, long closureID, long fieldID,
-        long value, int size);
-    // Does this have to be synchronized?
-    synchronized void nClosureSetGlobal(long closureID, long fieldID,
-        long value, int size) {
-      validate(); // TODO: is this necessary?
-      rsnClosureSetGlobal(mContext, closureID, fieldID, value, size);
-    }
-
-    native long rsnScriptGroup2Create(long con, String name, String cachePath,
-                                      long[] closures);
-    synchronized long nScriptGroup2Create(String name, String cachePath,
-                                          long[] closures) {
-      validate();
-      return rsnScriptGroup2Create(mContext, name, cachePath, closures);
-    }
-
-    native void rsnScriptGroup2Execute(long con, long groupID);
-    synchronized void nScriptGroup2Execute(long groupID) {
-      validate();
-      rsnScriptGroup2Execute(mContext, groupID);
-    }
-
-    native void rsnScriptIntrinsicBLAS_Single(long con, long incCon, long id, int func, int TransA,
-                                              int TransB, int Side, int Uplo, int Diag, int M, int N, int K,
-                                              float alpha, long A, long B, float beta, long C, int incX, int incY,
-                                              int KL, int KU, boolean mUseInc);
-    synchronized void nScriptIntrinsicBLAS_Single(long id, int func, int TransA,
-                                                  int TransB, int Side, int Uplo, int Diag, int M, int N, int K,
-                                                  float alpha, long A, long B, float beta, long C, int incX, int incY,
-                                                  int KL, int KU, boolean mUseInc) {
-        validate();
-        rsnScriptIntrinsicBLAS_Single(mContext, mIncCon, id, func, TransA, TransB, Side, Uplo, Diag, M, N, K, alpha, A, B, beta, C, incX, incY, KL, KU, mUseInc);
-    }
-
-    native void rsnScriptIntrinsicBLAS_Double(long con, long incCon, long id, int func, int TransA,
-                                              int TransB, int Side, int Uplo, int Diag, int M, int N, int K,
-                                              double alpha, long A, long B, double beta, long C, int incX, int incY,
-                                              int KL, int KU, boolean mUseInc);
-    synchronized void nScriptIntrinsicBLAS_Double(long id, int func, int TransA,
-                                                  int TransB, int Side, int Uplo, int Diag, int M, int N, int K,
-                                                  double alpha, long A, long B, double beta, long C, int incX, int incY,
-                                                  int KL, int KU, boolean mUseInc) {
-        validate();
-        rsnScriptIntrinsicBLAS_Double(mContext, mIncCon, id, func, TransA, TransB, Side, Uplo, Diag, M, N, K, alpha, A, B, beta, C, incX, incY, KL, KU, mUseInc);
-    }
-
-    native void rsnScriptIntrinsicBLAS_Complex(long con, long incCon, long id, int func, int TransA,
-                                               int TransB, int Side, int Uplo, int Diag, int M, int N, int K,
-                                               float alphaX, float alphaY, long A, long B, float betaX, float betaY, long C, int incX, int incY,
-                                               int KL, int KU, boolean mUseInc);
-    synchronized void nScriptIntrinsicBLAS_Complex(long id, int func, int TransA,
-                                                   int TransB, int Side, int Uplo, int Diag, int M, int N, int K,
-                                                   float alphaX, float alphaY, long A, long B, float betaX, float betaY, long C, int incX, int incY,
-                                                   int KL, int KU, boolean mUseInc) {
-        validate();
-        rsnScriptIntrinsicBLAS_Complex(mContext, mIncCon, id, func, TransA, TransB, Side, Uplo, Diag, M, N, K, alphaX, alphaY, A, B, betaX, betaY, C, incX, incY, KL, KU, mUseInc);
-    }
-
-    native void rsnScriptIntrinsicBLAS_Z(long con, long incCon, long id, int func, int TransA,
-                                         int TransB, int Side, int Uplo, int Diag, int M, int N, int K,
-                                         double alphaX, double alphaY, long A, long B, double betaX, double betaY, long C, int incX, int incY,
-                                         int KL, int KU, boolean mUseInc);
-    synchronized void nScriptIntrinsicBLAS_Z(long id, int func, int TransA,
-                                             int TransB, int Side, int Uplo, int Diag, int M, int N, int K,
-                                             double alphaX, double alphaY, long A, long B, double betaX, double betaY, long C, int incX, int incY,
-                                             int KL, int KU, boolean mUseInc) {
-        validate();
-        rsnScriptIntrinsicBLAS_Z(mContext, mIncCon, id, func, TransA, TransB, Side, Uplo, Diag, M, N, K, alphaX, alphaY, A, B, betaX, betaY, C, incX, incY, KL, KU, mUseInc);
-    }
-
-    native void rsnScriptIntrinsicBLAS_BNNM(long con, long incCon, long id, int M, int N, int K,
-                                             long A, int a_offset, long B, int b_offset, long C, int c_offset,
-                                             int c_mult_int, boolean mUseInc);
-    synchronized void nScriptIntrinsicBLAS_BNNM(long id, int M, int N, int K,
-                                             long A, int a_offset, long B, int b_offset, long C, int c_offset,
-                                             int c_mult_int, boolean mUseInc) {
-        validate();
-        rsnScriptIntrinsicBLAS_BNNM(mContext, mIncCon, id, M, N, K, A, a_offset, B, b_offset, C, c_offset, c_mult_int, mUseInc);
-    }
-
-// Additional Entry points For inc libRSSupport
-
-    native boolean nIncLoadSO(int deviceApi, String libPath);
-    native long nIncDeviceCreate();
-    native void nIncDeviceDestroy(long dev);
-    // Methods below are wrapped to protect the non-threadsafe
-    // lockless fifo.
-    native long  rsnIncContextCreate(long dev, int ver, int sdkVer, int contextType);
-    synchronized long nIncContextCreate(long dev, int ver, int sdkVer, int contextType) {
-        return rsnIncContextCreate(dev, ver, sdkVer, contextType);
-    }
-    native void rsnIncContextDestroy(long con);
-    synchronized void nIncContextDestroy() {
-        validate();
-
-        // take teardown lock
-        // teardown lock can only be taken when no objects are being destroyed
-        ReentrantReadWriteLock.WriteLock wlock = mRWLock.writeLock();
-        wlock.lock();
-
-        long curCon = mIncCon;
-        // context is considered dead as of this point
-        mIncCon = 0;
-
-        wlock.unlock();
-        rsnIncContextDestroy(curCon);
-    }
-
-    native void rsnIncContextFinish(long con);
-    synchronized void nIncContextFinish() {
-        validate();
-        rsnIncContextFinish(mIncCon);
-    }
-
-    native void rsnIncObjDestroy(long con, long id);
-    void nIncObjDestroy(long id) {
-        // There is a race condition here.  The calling code may be run
-        // by the gc while teardown is occuring.  This protects againts
-        // deleting dead objects.
-        if (mIncCon != 0) {
-            rsnIncObjDestroy(mIncCon, id);
-        }
-    }
-    native long  rsnIncElementCreate(long con, long type, int kind, boolean norm, int vecSize);
-    synchronized long nIncElementCreate(long type, int kind, boolean norm, int vecSize) {
-        validate();
-        return rsnIncElementCreate(mIncCon, type, kind, norm, vecSize);
-    }
-    native long rsnIncTypeCreate(long con, long eid, int x, int y, int z, boolean mips, boolean faces, int yuv);
-    synchronized long nIncTypeCreate(long eid, int x, int y, int z, boolean mips, boolean faces, int yuv) {
-        validate();
-        return rsnIncTypeCreate(mIncCon, eid, x, y, z, mips, faces, yuv);
-    }
-    native long  rsnIncAllocationCreateTyped(long con, long incCon, long alloc, long type, int xBytesSize);
-    synchronized long nIncAllocationCreateTyped(long alloc, long type, int xBytesSize) {
-        validate();
-        return rsnIncAllocationCreateTyped(mContext, mIncCon, alloc, type, xBytesSize);
-    }
-
-    long     mContext;
-    private boolean mDestroyed = false;
-    //Dummy device & context for Inc Support Lib
-    long     mIncCon;
-    //indicator of whether inc support lib has been loaded or not.
-    boolean  mIncLoaded;
-    ReentrantReadWriteLock mRWLock;
-    @SuppressWarnings({"FieldCanBeLocal"})
-    MessageThread mMessageThread;
-
-    Element mElement_U8;
-    Element mElement_I8;
-    Element mElement_U16;
-    Element mElement_I16;
-    Element mElement_U32;
-    Element mElement_I32;
-    Element mElement_U64;
-    Element mElement_I64;
-    Element mElement_F32;
-    Element mElement_F64;
-    Element mElement_BOOLEAN;
-
-    Element mElement_ELEMENT;
-    Element mElement_TYPE;
-    Element mElement_ALLOCATION;
-    Element mElement_SAMPLER;
-    Element mElement_SCRIPT;
-
-    Element mElement_A_8;
-    Element mElement_RGB_565;
-    Element mElement_RGB_888;
-    Element mElement_RGBA_5551;
-    Element mElement_RGBA_4444;
-    Element mElement_RGBA_8888;
-
-    Element mElement_FLOAT_2;
-    Element mElement_FLOAT_3;
-    Element mElement_FLOAT_4;
-
-    Element mElement_DOUBLE_2;
-    Element mElement_DOUBLE_3;
-    Element mElement_DOUBLE_4;
-
-    Element mElement_UCHAR_2;
-    Element mElement_UCHAR_3;
-    Element mElement_UCHAR_4;
-
-    Element mElement_CHAR_2;
-    Element mElement_CHAR_3;
-    Element mElement_CHAR_4;
-
-    Element mElement_USHORT_2;
-    Element mElement_USHORT_3;
-    Element mElement_USHORT_4;
-
-    Element mElement_SHORT_2;
-    Element mElement_SHORT_3;
-    Element mElement_SHORT_4;
-
-    Element mElement_UINT_2;
-    Element mElement_UINT_3;
-    Element mElement_UINT_4;
-
-    Element mElement_INT_2;
-    Element mElement_INT_3;
-    Element mElement_INT_4;
-
-    Element mElement_ULONG_2;
-    Element mElement_ULONG_3;
-    Element mElement_ULONG_4;
-
-    Element mElement_LONG_2;
-    Element mElement_LONG_3;
-    Element mElement_LONG_4;
-
-    Element mElement_MATRIX_4X4;
-    Element mElement_MATRIX_3X3;
-    Element mElement_MATRIX_2X2;
-
-    Sampler mSampler_CLAMP_NEAREST;
-    Sampler mSampler_CLAMP_LINEAR;
-    Sampler mSampler_CLAMP_LINEAR_MIP_LINEAR;
-    Sampler mSampler_WRAP_NEAREST;
-    Sampler mSampler_WRAP_LINEAR;
-    Sampler mSampler_WRAP_LINEAR_MIP_LINEAR;
-    Sampler mSampler_MIRRORED_REPEAT_NEAREST;
-    Sampler mSampler_MIRRORED_REPEAT_LINEAR;
-    Sampler mSampler_MIRRORED_REPEAT_LINEAR_MIP_LINEAR;
-
-
-    ///////////////////////////////////////////////////////////////////////////////////
-    //
-
-    /**
-     * The base class from which an application should derive in order
-     * to receive RS messages from scripts. When a script calls {@code
-     * rsSendToClient}, the data fields will be filled, and the run
-     * method will be called on a separate thread.  This will occur
-     * some time after {@code rsSendToClient} completes in the script,
-     * as {@code rsSendToClient} is asynchronous. Message handlers are
-     * not guaranteed to have completed when {@link
-     * android.support.v8.renderscript.RenderScript#finish} returns.
-     *
-     */
-    public static class RSMessageHandler implements Runnable {
-        protected int[] mData;
-        protected int mID;
-        protected int mLength;
-        public void run() {
-        }
-    }
-    /**
-     * If an application is expecting messages, it should set this
-     * field to an instance of {@link RSMessageHandler}.  This
-     * instance will receive all the user messages sent from {@code
-     * sendToClient} by scripts from this context.
-     *
-     */
-    RSMessageHandler mMessageCallback = null;
-
-    public void setMessageHandler(RSMessageHandler msg) {
-        mMessageCallback = msg;
-    }
-    public RSMessageHandler getMessageHandler() {
-        return mMessageCallback;
-    }
-
-    /**
-     * Place a message into the message queue to be sent back to the message
-     * handler once all previous commands have been executed.
-     *
-     * @param id
-     * @param data
-     */
-    public void sendMessage(int id, int[] data) {
-        nContextSendMessage(id, data);
-    }
-
-    /**
-     * The runtime error handler base class.  An application should derive from this class
-     * if it wishes to install an error handler.  When errors occur at runtime,
-     * the fields in this class will be filled, and the run method will be called.
-     *
-     */
-    public static class RSErrorHandler implements Runnable {
-        protected String mErrorMessage;
-        protected int mErrorNum;
-        public void run() {
-        }
-    }
-
-    /**
-     * Application Error handler.  All runtime errors will be dispatched to the
-     * instance of RSAsyncError set here.  If this field is null a
-     * {@link RSRuntimeException} will instead be thrown with details about the error.
-     * This will cause program termaination.
-     *
-     */
-    RSErrorHandler mErrorCallback = null;
-
-    public void setErrorHandler(RSErrorHandler msg) {
-        mErrorCallback = msg;
-    }
-    public RSErrorHandler getErrorHandler() {
-        return mErrorCallback;
-    }
-
-    /**
-     * RenderScript worker thread priority enumeration.  The default value is
-     * NORMAL.  Applications wishing to do background processing should set
-     * their priority to LOW to avoid starving forground processes.
-     */
-    public enum Priority {
-        LOW (Process.THREAD_PRIORITY_BACKGROUND + (5 * Process.THREAD_PRIORITY_LESS_FAVORABLE)),
-        NORMAL (Process.THREAD_PRIORITY_DISPLAY);
-
-        int mID;
-        Priority(int id) {
-            mID = id;
-        }
-    }
-
-    void validateObject(BaseObj o) {
-        if (o != null) {
-            if (o.mRS != this) {
-                throw new RSIllegalArgumentException("Attempting to use an object across contexts.");
-            }
-        }
-    }
-
-    void validate() {
-        if (mContext == 0) {
-            throw new RSInvalidStateException("Calling RS with no Context active.");
-        }
-    }
-
-    /**
-     * check if IO support lib is available.
-     */
-    boolean usingIO() {
-        return useIOlib;
-    }
-    /**
-     * Change the priority of the worker threads for this context.
-     *
-     * @param p New priority to be set.
-     */
-    public void setPriority(Priority p) {
-        validate();
-        nContextSetPriority(p.mID);
-    }
-
-    static class MessageThread extends Thread {
-        RenderScript mRS;
-        boolean mRun = true;
-        int[] mAuxData = new int[2];
-
-        static final int RS_MESSAGE_TO_CLIENT_NONE = 0;
-        static final int RS_MESSAGE_TO_CLIENT_EXCEPTION = 1;
-        static final int RS_MESSAGE_TO_CLIENT_RESIZE = 2;
-        static final int RS_MESSAGE_TO_CLIENT_ERROR = 3;
-
-        static final int RS_MESSAGE_TO_CLIENT_USER = 4;
-        static final int RS_ERROR_FATAL_UNKNOWN = 0x1000;
-
-        MessageThread(RenderScript rs) {
-            super("RSMessageThread");
-            mRS = rs;
-
-        }
-
-        public void run() {
-            // This function is a temporary solution.  The final solution will
-            // used typed allocations where the message id is the type indicator.
-            int[] rbuf = new int[16];
-            mRS.nContextInitToClient(mRS.mContext);
-            while(mRun) {
-                rbuf[0] = 0;
-                int msg = mRS.nContextPeekMessage(mRS.mContext, mAuxData);
-                int size = mAuxData[1];
-                int subID = mAuxData[0];
-
-                if (msg == RS_MESSAGE_TO_CLIENT_USER) {
-                    if ((size>>2) >= rbuf.length) {
-                        rbuf = new int[(size + 3) >> 2];
-                    }
-                    if (mRS.nContextGetUserMessage(mRS.mContext, rbuf) !=
-                        RS_MESSAGE_TO_CLIENT_USER) {
-                        throw new RSDriverException("Error processing message from RenderScript.");
-                    }
-
-                    if(mRS.mMessageCallback != null) {
-                        mRS.mMessageCallback.mData = rbuf;
-                        mRS.mMessageCallback.mID = subID;
-                        mRS.mMessageCallback.mLength = size;
-                        mRS.mMessageCallback.run();
-                    } else {
-                        throw new RSInvalidStateException("Received a message from the script with no message handler installed.");
-                    }
-                    continue;
-                }
-
-                if (msg == RS_MESSAGE_TO_CLIENT_ERROR) {
-                    String e = mRS.nContextGetErrorMessage(mRS.mContext);
-
-                    if (subID >= RS_ERROR_FATAL_UNKNOWN) {
-                        throw new RSRuntimeException("Fatal error " + subID + ", details: " + e);
-                    }
-
-                    if(mRS.mErrorCallback != null) {
-                        mRS.mErrorCallback.mErrorMessage = e;
-                        mRS.mErrorCallback.mErrorNum = subID;
-                        mRS.mErrorCallback.run();
-                    } else {
-                        android.util.Log.e(LOG_TAG, "non fatal RS error, " + e);
-                        // Do not throw here. In these cases, we do not have
-                        // a fatal error.
-                    }
-                    continue;
-                }
-
-                // 2: teardown.
-                // But we want to avoid starving other threads during
-                // teardown by yielding until the next line in the destructor
-                // can execute to set mRun = false
-                try {
-                    sleep(1, 0);
-                } catch(InterruptedException e) {
-                }
-            }
-            //Log.d(LOG_TAG, "MessageThread exiting.");
-        }
-    }
-
-    RenderScript(Context ctx) {
-        mContextType = ContextType.NORMAL;
-        if (ctx != null) {
-            mApplicationContext = ctx.getApplicationContext();
-            // Only set mNativeLibDir for API 9+.
-            mNativeLibDir = mApplicationContext.getApplicationInfo().nativeLibraryDir;
-        }
-        mIncCon = 0;
-        mIncLoaded = false;
-        mRWLock = new ReentrantReadWriteLock();
-    }
-
-    /**
-     * Gets the application context associated with the RenderScript context.
-     *
-     * @return The application context.
-     */
-    public final Context getApplicationContext() {
-        return mApplicationContext;
-    }
-
-    /**
-     * Create a RenderScript context.
-     *
-     * @param ctx The context.
-     * @return RenderScript
-     */
-    private static RenderScript internalCreate(Context ctx, int sdkVersion, ContextType ct, int flags) {
-        RenderScript rs = new RenderScript(ctx);
-
-        if (sSdkVersion == -1) {
-            sSdkVersion = sdkVersion;
-        } else if (sSdkVersion != sdkVersion) {
-            throw new RSRuntimeException("Can't have two contexts with different SDK versions in support lib");
-        }
-        useNative = setupNative(sSdkVersion, ctx);
-        synchronized(lock) {
-            if (sInitialized == false) {
-                try {
-                    Class<?> vm_runtime = Class.forName("dalvik.system.VMRuntime");
-                    Method get_runtime = vm_runtime.getDeclaredMethod("getRuntime");
-                    sRuntime = get_runtime.invoke(null);
-                    registerNativeAllocation = vm_runtime.getDeclaredMethod("registerNativeAllocation", Integer.TYPE);
-                    registerNativeFree = vm_runtime.getDeclaredMethod("registerNativeFree", Integer.TYPE);
-                    sUseGCHooks = true;
-                } catch (Exception e) {
-                    Log.e(LOG_TAG, "No GC methods");
-                    sUseGCHooks = false;
-                }
-                try {
-                    // For API 9 - 22, always use the absolute path of librsjni.so
-                    // http://b/25226912
-                    if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.M &&
-                        rs.mNativeLibDir != null) {
-                        System.load(rs.mNativeLibDir + "/librsjni.so");
-                    } else {
-                        System.loadLibrary("rsjni");
-                    }
-                    sInitialized = true;
-                    sPointerSize = rsnSystemGetPointerSize();
-                } catch (UnsatisfiedLinkError e) {
-                    Log.e(LOG_TAG, "Error loading RS jni library: " + e);
-                    throw new RSRuntimeException("Error loading RS jni library: " + e + " Support lib API: " + SUPPORT_LIB_VERSION);
-                }
-            }
-        }
-
-        if (useNative) {
-            android.util.Log.v(LOG_TAG, "RS native mode");
-        } else {
-            android.util.Log.v(LOG_TAG, "RS compat mode");
-        }
-
-        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
-            useIOlib = true;
-        }
-
-        // The target API level used to init dispatchTable.
-        int dispatchAPI = sdkVersion;
-        if (sdkVersion < android.os.Build.VERSION.SDK_INT) {
-            // If the device API is higher than target API level, init dispatch table based on device API.
-            dispatchAPI = android.os.Build.VERSION.SDK_INT;
-        }
-
-        String rssupportPath = null;
-        // For API 9 - 22, always use the absolute path of libRSSupport.so
-        // http://b/25226912
-        if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.M &&
-            rs.mNativeLibDir != null) {
-            rssupportPath = rs.mNativeLibDir + "/libRSSupport.so";
-        }
-        if (!rs.nLoadSO(useNative, dispatchAPI, rssupportPath)) {
-            if (useNative) {
-                android.util.Log.v(LOG_TAG, "Unable to load libRS.so, falling back to compat mode");
-                useNative = false;
-            }
-            try {
-                if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.M &&
-                    rs.mNativeLibDir != null) {
-                    System.load(rssupportPath);
-                } else {
-                    System.loadLibrary("RSSupport");
-                }
-            } catch (UnsatisfiedLinkError e) {
-                Log.e(LOG_TAG, "Error loading RS Compat library: " + e + " Support lib version: " + SUPPORT_LIB_VERSION);
-                throw new RSRuntimeException("Error loading RS Compat library: " + e + " Support lib version: " + SUPPORT_LIB_VERSION);
-            }
-            if (!rs.nLoadSO(false, dispatchAPI, rssupportPath)) {
-                Log.e(LOG_TAG, "Error loading RS Compat library: nLoadSO() failed; Support lib version: " + SUPPORT_LIB_VERSION);
-                throw new RSRuntimeException("Error loading libRSSupport library, Support lib version: " + SUPPORT_LIB_VERSION);
-            }
-        }
-
-        if (useIOlib) {
-            try {
-                System.loadLibrary("RSSupportIO");
-            } catch (UnsatisfiedLinkError e) {
-                useIOlib = false;
-            }
-            if (!useIOlib || !rs.nLoadIOSO()) {
-                android.util.Log.v(LOG_TAG, "Unable to load libRSSupportIO.so, USAGE_IO not supported");
-                useIOlib = false;
-            }
-        }
-
-        // For old APIs with dlopen bug, need to load blas lib in Java first.
-        // Only try load to blasV8 when the desired API level includes IntrinsicBLAS.
-        if (dispatchAPI >= 23) {
-            // Enable multi-input kernels only when diapatchAPI is M+.
-            rs.mEnableMultiInput = true;
-            try {
-                System.loadLibrary("blasV8");
-            } catch (UnsatisfiedLinkError e) {
-                Log.v(LOG_TAG, "Unable to load BLAS lib, ONLY BNNM will be supported: " + e);
-            }
-        }
-
-        long device = rs.nDeviceCreate();
-        rs.mContext = rs.nContextCreate(device, 0, sdkVersion, ct.mID, rs.mNativeLibDir);
-        rs.mContextType = ct;
-        rs.mContextFlags = flags;
-        rs.mContextSdkVersion = sdkVersion;
-        rs.mDispatchAPILevel = dispatchAPI;
-        if (rs.mContext == 0) {
-            throw new RSDriverException("Failed to create RS context.");
-        }
-        rs.mMessageThread = new MessageThread(rs);
-        rs.mMessageThread.start();
-        return rs;
-    }
-
-    /**
-     * Create a RenderScript context.
-     *
-     * See documentation for @create for details
-     *
-     * @param ctx The context.
-     * @return RenderScript
-     */
-    public static RenderScript create(Context ctx) {
-        return create(ctx, ContextType.NORMAL);
-    }
-
-    /**
-     * calls create(ctx, ct, CREATE_FLAG_NONE)
-     *
-     * See documentation for @create for details
-     *
-     * @param ctx The context.
-     * @param ct The type of context to be created.
-     * @return RenderScript
-     */
-    public static RenderScript create(Context ctx, ContextType ct) {
-        return create(ctx, ct, CREATE_FLAG_NONE);
-    }
-
-    /**
-     * Gets or creates a RenderScript context of the specified type.
-     *
-     * The returned context will be cached for future reuse within
-     * the process. When an application is finished using
-     * RenderScript it should call releaseAllContexts()
-     *
-     * A process context is a context designed for easy creation and
-     * lifecycle management.  Multiple calls to this function will
-     * return the same object provided they are called with the same
-     * options.  This allows it to be used any time a RenderScript
-     * context is needed.
-     *
-     *
-     * @param ctx The context.
-     * @param ct The type of context to be created.
-     * @param flags The OR of the CREATE_FLAG_* options desired
-     * @return RenderScript
-     */
-    public static RenderScript create(Context ctx, ContextType ct, int flags) {
-        int v = ctx.getApplicationInfo().targetSdkVersion;
-        return create(ctx, v, ct, flags);
-    }
-
-    /**
-     * calls create(ctx, sdkVersion, ContextType.NORMAL, CREATE_FLAG_NONE)
-     *
-     * Used by the RenderScriptThunker to maintain backward compatibility.
-     *
-     * @hide
-     * @param ctx The context.
-     * @param sdkVersion The target SDK Version.
-     * @return RenderScript
-     */
-    public static RenderScript create(Context ctx, int sdkVersion) {
-        return create(ctx, sdkVersion, ContextType.NORMAL, CREATE_FLAG_NONE);
-    }
-
-
-    /**
-     * calls create(ctx, sdkVersion, ct, CREATE_FLAG_NONE)
-     * Create a RenderScript context.
-     *
-     * @hide
-     * @param ctx The context.
-     * @return RenderScript
-     */
-    public static RenderScript create(Context ctx, int sdkVersion, ContextType ct) {
-        return create(ctx, sdkVersion, ct, CREATE_FLAG_NONE);
-    }
-
-     /**
-     * Gets or creates a RenderScript context of the specified type.
-     *
-     * @param ctx The context.
-     * @param ct The type of context to be created.
-     * @param sdkVersion The target SDK Version.
-     * @param flags The OR of the CREATE_FLAG_* options desired
-     * @return RenderScript
-     */
-    public static RenderScript create(Context ctx, int sdkVersion, ContextType ct, int flags) {
-        synchronized (mProcessContextList) {
-            for (RenderScript prs : mProcessContextList) {
-                if ((prs.mContextType == ct) &&
-                    (prs.mContextFlags == flags) &&
-                    (prs.mContextSdkVersion == sdkVersion)) {
-
-                    return prs;
-                }
-            }
-
-            RenderScript prs = internalCreate(ctx, sdkVersion, ct, flags);
-            prs.mIsProcessContext = true;
-            mProcessContextList.add(prs);
-            return prs;
-        }
-    }
-
-    /**
-     *
-     * Releases all the process contexts.  This is the same as
-     * calling .destroy() on each unique context retreived with
-     * create(...). If no contexts have been created this
-     * function does nothing.
-     *
-     * Typically you call this when your application is losing focus
-     * and will not be using a context for some time.
-     *
-     * This has no effect on a context created with
-     * createMultiContext()
-     */
-    public static void releaseAllContexts() {
-        ArrayList<RenderScript> oldList;
-        synchronized (mProcessContextList) {
-            oldList = mProcessContextList;
-            mProcessContextList = new ArrayList<RenderScript>();
-        }
-
-        for (RenderScript prs : oldList) {
-            prs.mIsProcessContext = false;
-            prs.destroy();
-        }
-        oldList.clear();
-    }
-
-
-
-    /**
-     * Create a RenderScript context.
-     *
-     * This is an advanced function intended for applications which
-     * need to create more than one RenderScript context to be used
-     * at the same time.
-     *
-     * If you need a single context please use create()
-     *
-     * @param ctx The context.
-     * @return RenderScript
-     */
-    public static RenderScript createMultiContext(Context ctx, ContextType ct, int flags, int API_number) {
-        return internalCreate(ctx, API_number, ct, flags);
-    }
-
-    /**
-     * Print the currently available debugging information about the state of
-     * the RS context to the log.
-     *
-     */
-    public void contextDump() {
-        validate();
-        nContextDump(0);
-    }
-
-    /**
-     * Wait for any pending asynchronous opeations (such as copies to a RS
-     * allocation or RS script executions) to complete.
-     *
-     */
-    public void finish() {
-        nContextFinish();
-    }
-
-    private void helpDestroy() {
-        boolean shouldDestroy = false;
-        synchronized(this) {
-            if (!mDestroyed) {
-                shouldDestroy = true;
-                mDestroyed = true;
-            }
-        }
-
-        if (shouldDestroy) {
-            nContextFinish();
-            if (mIncCon != 0) {
-                nIncContextFinish();
-                nIncContextDestroy();
-                mIncCon = 0;
-            }
-            nContextDeinitToClient(mContext);
-            mMessageThread.mRun = false;
-            // Interrupt mMessageThread so it gets to see immediately that mRun is false
-            // and exit rightaway.
-            mMessageThread.interrupt();
-
-            // Wait for mMessageThread to join.  Try in a loop, in case this thread gets interrupted
-            // during the wait.  If interrupted, set the "interrupted" status of the current thread.
-            boolean hasJoined = false, interrupted = false;
-            while (!hasJoined) {
-                try {
-                    mMessageThread.join();
-                    hasJoined = true;
-                } catch (InterruptedException e) {
-                    interrupted = true;
-                }
-            }
-            if (interrupted) {
-                Log.v(LOG_TAG, "Interrupted during wait for MessageThread to join");
-                Thread.currentThread().interrupt();
-            }
-
-            nContextDestroy();
-        }
-    }
-
-    @Override
-    protected void finalize() throws Throwable {
-        helpDestroy();
-        super.finalize();
-    }
-
-    /**
-     * Destroys this RenderScript context.  Once this function is called,
-     * using this context or any objects belonging to this context is
-     * illegal.
-     *
-     * This function is a NOP if the context was created
-     * with create().  Please use releaseAllContexts() to clean up
-     * contexts created with the create function.
-     */
-    public void destroy() {
-        if (mIsProcessContext) {
-            // users cannot destroy a process context
-            return;
-        }
-        validate();
-        helpDestroy();
-    }
-
-    boolean isAlive() {
-        return mContext != 0;
-    }
-
-    long safeID(BaseObj o) {
-        if(o != null) {
-            return o.getID(this);
-        }
-        return 0;
-    }
-}
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/Sampler.java b/v8/renderscript/java/src/android/support/v8/renderscript/Sampler.java
deleted file mode 100644
index 7119e8c..0000000
--- a/v8/renderscript/java/src/android/support/v8/renderscript/Sampler.java
+++ /dev/null
@@ -1,346 +0,0 @@
-/*
- * Copyright (C) 2012 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 android.support.v8.renderscript;
-
-
-import java.io.IOException;
-import java.io.InputStream;
-
-import android.content.res.Resources;
-import android.os.Bundle;
-import android.util.Log;
-
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-
-/**
- * Sampler object that defines how Allocations can be read as textures within a
- * kernel. Samplers are used in conjunction with the {@code rsSample} runtime
- * function to return values from normalized coordinates.
- *
- * Any Allocation used with a Sampler must have been created with {@link
- * android.support.v8.renderscript.Allocation#USAGE_GRAPHICS_TEXTURE}; using a
- * Sampler on an {@link android.support.v8.renderscript.Allocation} that was not
- * created with
- * {@link android.support.v8.renderscript.Allocation#USAGE_GRAPHICS_TEXTURE} is
- * undefined.
- **/
-public class Sampler extends BaseObj {
-    public enum Value {
-        NEAREST (0),
-        LINEAR (1),
-        LINEAR_MIP_LINEAR (2),
-        LINEAR_MIP_NEAREST (5),
-        WRAP (3),
-        CLAMP (4),
-        MIRRORED_REPEAT (6);
-
-        int mID;
-        Value(int id) {
-            mID = id;
-        }
-    }
-
-    Value mMin;
-    Value mMag;
-    Value mWrapS;
-    Value mWrapT;
-    Value mWrapR;
-    float mAniso;
-
-    Sampler(long id, RenderScript rs) {
-        super(id, rs);
-    }
-
-    /**
-     * @return minification setting for the sampler
-     */
-    public Value getMinification() {
-        return mMin;
-    }
-
-    /**
-     * @return magnification setting for the sampler
-     */
-    public Value getMagnification() {
-        return mMag;
-    }
-
-    /**
-     * @return S wrapping mode for the sampler
-     */
-    public Value getWrapS() {
-        return mWrapS;
-    }
-
-    /**
-     * @return T wrapping mode for the sampler
-     */
-    public Value getWrapT() {
-        return mWrapT;
-    }
-
-    /**
-     * @return anisotropy setting for the sampler
-     */
-    public float getAnisotropy() {
-        return mAniso;
-    }
-
-    /**
-     * Retrieve a sampler with min and mag set to nearest and wrap modes set to
-     * clamp.
-     *
-     * @param rs Context to which the sampler will belong.
-     *
-     * @return Sampler
-     */
-    public static Sampler CLAMP_NEAREST(RenderScript rs) {
-        if(rs.mSampler_CLAMP_NEAREST == null) {
-            Builder b = new Builder(rs);
-            b.setMinification(Value.NEAREST);
-            b.setMagnification(Value.NEAREST);
-            b.setWrapS(Value.CLAMP);
-            b.setWrapT(Value.CLAMP);
-            rs.mSampler_CLAMP_NEAREST = b.create();
-        }
-        return rs.mSampler_CLAMP_NEAREST;
-    }
-
-    /**
-     * Retrieve a sampler with min and mag set to linear and wrap modes set to
-     * clamp.
-     *
-     * @param rs Context to which the sampler will belong.
-     *
-     * @return Sampler
-     */
-    public static Sampler CLAMP_LINEAR(RenderScript rs) {
-        if(rs.mSampler_CLAMP_LINEAR == null) {
-            Builder b = new Builder(rs);
-            b.setMinification(Value.LINEAR);
-            b.setMagnification(Value.LINEAR);
-            b.setWrapS(Value.CLAMP);
-            b.setWrapT(Value.CLAMP);
-            rs.mSampler_CLAMP_LINEAR = b.create();
-        }
-        return rs.mSampler_CLAMP_LINEAR;
-    }
-
-    /**
-     * Retrieve a sampler with mag set to linear, min linear mipmap linear, and
-     * wrap modes set to clamp.
-     *
-     * @param rs Context to which the sampler will belong.
-     *
-     * @return Sampler
-     */
-    public static Sampler CLAMP_LINEAR_MIP_LINEAR(RenderScript rs) {
-        if(rs.mSampler_CLAMP_LINEAR_MIP_LINEAR == null) {
-            Builder b = new Builder(rs);
-            b.setMinification(Value.LINEAR_MIP_LINEAR);
-            b.setMagnification(Value.LINEAR);
-            b.setWrapS(Value.CLAMP);
-            b.setWrapT(Value.CLAMP);
-            rs.mSampler_CLAMP_LINEAR_MIP_LINEAR = b.create();
-        }
-        return rs.mSampler_CLAMP_LINEAR_MIP_LINEAR;
-    }
-
-    /**
-     * Retrieve a sampler with min and mag set to nearest and wrap modes set to
-     * wrap.
-     *
-     * @param rs Context to which the sampler will belong.
-     *
-     * @return Sampler
-     */
-    public static Sampler WRAP_NEAREST(RenderScript rs) {
-        if(rs.mSampler_WRAP_NEAREST == null) {
-            Builder b = new Builder(rs);
-            b.setMinification(Value.NEAREST);
-            b.setMagnification(Value.NEAREST);
-            b.setWrapS(Value.WRAP);
-            b.setWrapT(Value.WRAP);
-            rs.mSampler_WRAP_NEAREST = b.create();
-        }
-        return rs.mSampler_WRAP_NEAREST;
-    }
-
-    /**
-     * Retrieve a sampler with min and mag set to linear and wrap modes set to
-     * wrap.
-     *
-     * @param rs Context to which the sampler will belong.
-     *
-     * @return Sampler
-     */
-    public static Sampler WRAP_LINEAR(RenderScript rs) {
-        if(rs.mSampler_WRAP_LINEAR == null) {
-            Builder b = new Builder(rs);
-            b.setMinification(Value.LINEAR);
-            b.setMagnification(Value.LINEAR);
-            b.setWrapS(Value.WRAP);
-            b.setWrapT(Value.WRAP);
-            rs.mSampler_WRAP_LINEAR = b.create();
-        }
-        return rs.mSampler_WRAP_LINEAR;
-    }
-
-    /**
-     * Retrieve a sampler with mag set to linear, min linear mipmap linear, and
-     * wrap modes set to wrap.
-     *
-     * @param rs Context to which the sampler will belong.
-     *
-     * @return Sampler
-     */
-    public static Sampler WRAP_LINEAR_MIP_LINEAR(RenderScript rs) {
-        if(rs.mSampler_WRAP_LINEAR_MIP_LINEAR == null) {
-            Builder b = new Builder(rs);
-            b.setMinification(Value.LINEAR_MIP_LINEAR);
-            b.setMagnification(Value.LINEAR);
-            b.setWrapS(Value.WRAP);
-            b.setWrapT(Value.WRAP);
-            rs.mSampler_WRAP_LINEAR_MIP_LINEAR = b.create();
-        }
-        return rs.mSampler_WRAP_LINEAR_MIP_LINEAR;
-    }
-
-    /**
-     * Retrieve a sampler with min and mag set to nearest and wrap modes set to
-     * mirrored repeat.
-     *
-     * @param rs Context to which the sampler will belong.
-     *
-     * @return Sampler
-     */
-    public static Sampler MIRRORED_REPEAT_NEAREST(RenderScript rs) {
-        if(rs.mSampler_MIRRORED_REPEAT_NEAREST == null) {
-            Builder b = new Builder(rs);
-            b.setMinification(Value.NEAREST);
-            b.setMagnification(Value.NEAREST);
-            b.setWrapS(Value.MIRRORED_REPEAT);
-            b.setWrapT(Value.MIRRORED_REPEAT);
-            rs.mSampler_MIRRORED_REPEAT_NEAREST = b.create();
-        }
-        return rs.mSampler_MIRRORED_REPEAT_NEAREST;
-    }
-
-    /**
-     * Retrieve a sampler with min and mag set to linear and wrap modes set to
-     * mirrored repeat.
-     *
-     * @param rs Context to which the sampler will belong.
-     *
-     * @return Sampler
-     */
-    public static Sampler MIRRORED_REPEAT_LINEAR(RenderScript rs) {
-        if(rs.mSampler_MIRRORED_REPEAT_LINEAR == null) {
-            Builder b = new Builder(rs);
-            b.setMinification(Value.LINEAR);
-            b.setMagnification(Value.LINEAR);
-            b.setWrapS(Value.MIRRORED_REPEAT);
-            b.setWrapT(Value.MIRRORED_REPEAT);
-            rs.mSampler_MIRRORED_REPEAT_LINEAR = b.create();
-        }
-        return rs.mSampler_MIRRORED_REPEAT_LINEAR;
-    }
-
-    /**
-     * Builder for creating non-standard samplers.  This is only necessary if
-     * a Sampler with different min and mag modes is desired.
-     */
-    public static class Builder {
-        RenderScript mRS;
-        Value mMin;
-        Value mMag;
-        Value mWrapS;
-        Value mWrapT;
-        Value mWrapR;
-        float mAniso;
-
-        public Builder(RenderScript rs) {
-            mRS = rs;
-            mMin = Value.NEAREST;
-            mMag = Value.NEAREST;
-            mWrapS = Value.WRAP;
-            mWrapT = Value.WRAP;
-            mWrapR = Value.WRAP;
-            mAniso = 1.0f;
-        }
-
-        public void setMinification(Value v) {
-            if (v == Value.NEAREST ||
-                v == Value.LINEAR ||
-                v == Value.LINEAR_MIP_LINEAR ||
-                v == Value.LINEAR_MIP_NEAREST) {
-                mMin = v;
-            } else {
-                throw new IllegalArgumentException("Invalid value");
-            }
-        }
-
-        public void setMagnification(Value v) {
-            if (v == Value.NEAREST || v == Value.LINEAR) {
-                mMag = v;
-            } else {
-                throw new IllegalArgumentException("Invalid value");
-            }
-        }
-
-        public void setWrapS(Value v) {
-            if (v == Value.WRAP || v == Value.CLAMP || v == Value.MIRRORED_REPEAT) {
-                mWrapS = v;
-            } else {
-                throw new IllegalArgumentException("Invalid value");
-            }
-        }
-
-        public void setWrapT(Value v) {
-            if (v == Value.WRAP || v == Value.CLAMP || v == Value.MIRRORED_REPEAT) {
-                mWrapT = v;
-            } else {
-                throw new IllegalArgumentException("Invalid value");
-            }
-        }
-
-        public void setAnisotropy(float v) {
-            if(v >= 0.0f) {
-                mAniso = v;
-            } else {
-                throw new IllegalArgumentException("Invalid value");
-            }
-        }
-
-        public Sampler create() {
-            mRS.validate();
-            long id = mRS.nSamplerCreate(mMag.mID, mMin.mID,
-                                        mWrapS.mID, mWrapT.mID, mWrapR.mID, mAniso);
-            Sampler sampler = new Sampler(id, mRS);
-            sampler.mMin = mMin;
-            sampler.mMag = mMag;
-            sampler.mWrapS = mWrapS;
-            sampler.mWrapT = mWrapT;
-            sampler.mWrapR = mWrapR;
-            sampler.mAniso = mAniso;
-            return sampler;
-        }
-    }
-
-}
-
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/Script.java b/v8/renderscript/java/src/android/support/v8/renderscript/Script.java
deleted file mode 100644
index ec3a7a9..0000000
--- a/v8/renderscript/java/src/android/support/v8/renderscript/Script.java
+++ /dev/null
@@ -1,701 +0,0 @@
-/*
- * Copyright (C) 2012 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 android.support.v8.renderscript;
-
-import android.util.SparseArray;
-
-/**
- * The parent class for all executable scripts. This should not be used by
- * applications.
- **/
-public class Script extends BaseObj {
-    /**
-     * Determine if Incremental Intrinsic Support is needed
-     *
-     */
-    private boolean mUseIncSupp;
-    protected void setIncSupp(boolean useInc) {
-        mUseIncSupp = useInc;
-    }
-    protected boolean isIncSupp() {
-        return mUseIncSupp;
-    }
-    /**
-     * An allocation for the compat context will be created when needed
-     * e.g. foreach(ain, aout), setVar(ain);
-     *
-     */
-    long getDummyAlloc(Allocation ain) {
-        long dInElement = 0;
-        long dInType = 0;
-        long dummyAlloc = 0;
-        if (ain != null) {
-            Type inType = ain.getType();
-            dInElement = inType.getElement().getDummyElement(mRS);
-            dInType = inType.getDummyType(mRS, dInElement);
-            int xBytesSize = inType.getX() * inType.getElement().getBytesSize();
-            dummyAlloc = mRS.nIncAllocationCreateTyped(ain.getID(mRS), dInType, xBytesSize);
-            ain.setIncAllocID(dummyAlloc);
-        }
-
-        return dummyAlloc;
-    }
-    /**
-     * KernelID is an identifier for a Script + root function pair. It is used
-     * as an identifier for ScriptGroup creation.
-     *
-     * This class should not be directly created. Instead use the method in the
-     * reflected or intrinsic code "getKernelID_funcname()".
-     *
-     */
-    public static final class KernelID extends BaseObj {
-        android.renderscript.Script.KernelID mN;
-        Script mScript;
-        int mSlot;
-        int mSig;
-        KernelID(long id, RenderScript rs, Script s, int slot, int sig) {
-            super(id, rs);
-            mScript = s;
-            mSlot = slot;
-            mSig = sig;
-        }
-    }
-
-    private final SparseArray<KernelID> mKIDs = new SparseArray<KernelID>();
-    /**
-     * Only to be used by generated reflected classes.
-     *
-     *
-     * @param slot
-     * @param sig
-     * @param ein
-     * @param eout
-     *
-     * @return KernelID
-     */
-    protected KernelID createKernelID(int slot, int sig, Element ein, Element eout) {
-        KernelID k = mKIDs.get(slot);
-        if (k != null) {
-            return k;
-        }
-
-        long id = mRS.nScriptKernelIDCreate(getID(mRS), slot, sig, mUseIncSupp);
-        if (id == 0) {
-            throw new RSDriverException("Failed to create KernelID");
-        }
-
-        k = new KernelID(id, mRS, this, slot, sig);
-
-        mKIDs.put(slot, k);
-        return k;
-    }
-
-    /**
-     * InvokeID is an identifier for a invoke function. It is used
-     * as an identifier for ScriptGroup creation.
-     *
-     * This class should not be directly created. Instead use the method in the
-     * reflected or intrinsic code "getInvokeID_funcname()".
-     *
-     */
-    public static final class InvokeID extends BaseObj {
-        Script mScript;
-        int mSlot;
-        InvokeID(long id, RenderScript rs, Script s, int slot) {
-            super(id, rs);
-            mScript = s;
-            mSlot = slot;
-        }
-    }
-
-    private final SparseArray<InvokeID> mIIDs = new SparseArray<InvokeID>();
-    /**
-     * Only to be used by generated reflected classes.
-     */
-    protected InvokeID createInvokeID(int slot) {
-        InvokeID i = mIIDs.get(slot);
-        if (i != null) {
-            return i;
-        }
-
-        long id = mRS.nScriptInvokeIDCreate(getID(mRS), slot);
-        if (id == 0) {
-            throw new RSDriverException("Failed to create KernelID");
-        }
-
-        i = new InvokeID(id, mRS, this, slot);
-        mIIDs.put(slot, i);
-        return i;
-    }
-
-    /**
-     * FieldID is an identifier for a Script + exported field pair. It is used
-     * as an identifier for ScriptGroup creation.
-     *
-     * This class should not be directly created. Instead use the method in the
-     * reflected or intrinsic code "getFieldID_funcname()".
-     *
-     */
-    public static final class FieldID extends BaseObj {
-        android.renderscript.Script.FieldID mN;
-        Script mScript;
-        int mSlot;
-        FieldID(long id, RenderScript rs, Script s, int slot) {
-            super(id, rs);
-            mScript = s;
-            mSlot = slot;
-        }
-    }
-
-    private final SparseArray<FieldID> mFIDs = new SparseArray();
-    /**
-     * Only to be used by generated reflected classes.
-     *
-     * @param slot
-     * @param e
-     *
-     * @return FieldID
-     */
-    protected FieldID createFieldID(int slot, Element e) {
-        FieldID f = mFIDs.get(slot);
-        if (f != null) {
-            return f;
-        }
-
-        long id = mRS.nScriptFieldIDCreate(getID(mRS), slot, mUseIncSupp);
-        if (id == 0) {
-            throw new RSDriverException("Failed to create FieldID");
-        }
-
-        f = new FieldID(id, mRS, this, slot);
-        mFIDs.put(slot, f);
-        return f;
-    }
-
-    /**
-     * Only intended for use by generated reflected code.
-     *
-     * @param slot
-     */
-    protected void invoke(int slot) {
-        mRS.nScriptInvoke(getID(mRS), slot, mUseIncSupp);
-    }
-
-    /**
-     * Only intended for use by generated reflected code.
-     *
-     * @param slot
-     * @param v
-     */
-    protected void invoke(int slot, FieldPacker v) {
-        if (v != null) {
-            mRS.nScriptInvokeV(getID(mRS), slot, v.getData(), mUseIncSupp);
-        } else {
-            mRS.nScriptInvoke(getID(mRS), slot, mUseIncSupp);
-        }
-    }
-
-    /**
-     * Only intended for use by generated reflected code.
-     *
-     * @param va
-     * @param slot
-     */
-    public void bindAllocation(Allocation va, int slot) {
-        mRS.validate();
-        if (va != null) {
-            mRS.nScriptBindAllocation(getID(mRS), va.getID(mRS), slot, mUseIncSupp);
-        } else {
-            mRS.nScriptBindAllocation(getID(mRS), 0, slot, mUseIncSupp);
-        }
-    }
-
-    public void setTimeZone(String timeZone) {
-        mRS.validate();
-        try {
-            mRS.nScriptSetTimeZone(getID(mRS), timeZone.getBytes("UTF-8"), mUseIncSupp);
-        } catch (java.io.UnsupportedEncodingException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-
-    /**
-     * Only intended for use by generated reflected code.
-     *
-     * @param slot
-     * @param ain
-     * @param aout
-     * @param v
-     */
-    protected void forEach(int slot, Allocation ain, Allocation aout, FieldPacker v) {
-        if (ain == null && aout == null) {
-            throw new RSIllegalArgumentException(
-                "At least one of ain or aout is required to be non-null.");
-        }
-        long in_id = 0;
-        long out_id = 0;
-        if (ain != null) {
-            in_id = ain.getID(mRS);
-        }
-        if (aout != null) {
-            out_id = aout.getID(mRS);
-        }
-
-        byte[] params = null;
-        if (v != null) {
-            params = v.getData();
-        }
-
-        if (mUseIncSupp) {
-            long ainInc = getDummyAlloc(ain);
-            long aoutInc = getDummyAlloc(aout);
-            mRS.nScriptForEach(getID(mRS), slot, ainInc, aoutInc, params, mUseIncSupp);
-        } else {
-            mRS.nScriptForEach(getID(mRS), slot, in_id, out_id, params, mUseIncSupp);
-        }
-    }
-
-    /**
-     * Only intended for use by generated reflected code.
-     *
-     * @param slot
-     * @param ain
-     * @param aout
-     * @param v
-     * @param sc
-     */
-    protected void forEach(int slot, Allocation ain, Allocation aout, FieldPacker v, LaunchOptions sc) {
-        if (ain == null && aout == null) {
-            throw new RSIllegalArgumentException(
-                "At least one of ain or aout is required to be non-null.");
-        }
-
-        if (sc == null) {
-            forEach(slot, ain, aout, v);
-            return;
-        }
-        long in_id = 0;
-        long out_id = 0;
-        if (ain != null) {
-            in_id = ain.getID(mRS);
-        }
-        if (aout != null) {
-            out_id = aout.getID(mRS);
-        }
-
-        byte[] params = null;
-        if (v != null) {
-            params = v.getData();
-        }
-        if (mUseIncSupp) {
-            long ainInc = getDummyAlloc(ain);
-            long aoutInc = getDummyAlloc(aout);
-            mRS.nScriptForEachClipped(getID(mRS), slot, ainInc, aoutInc, params, sc.xstart, sc.xend, sc.ystart, sc.yend, sc.zstart, sc.zend, mUseIncSupp);        
-        } else {
-            mRS.nScriptForEachClipped(getID(mRS), slot, in_id, out_id, params, sc.xstart, sc.xend, sc.ystart, sc.yend, sc.zstart, sc.zend, mUseIncSupp);
-        }
-    }
-
-    Script(long id, RenderScript rs) {
-        super(id, rs);
-        mUseIncSupp = false;
-    }
-
-    /**
-     * Only intended for use by generated reflected code.
-     *
-     * @hide
-     */
-    protected void forEach(int slot, Allocation[] ains, Allocation aout,
-                           FieldPacker v) {
-        forEach(slot, ains, aout, v, null);
-    }
-
-    /**
-     * Only intended for use by generated reflected code.
-     *
-     * @hide
-     */
-    protected void forEach(int slot, Allocation[] ains, Allocation aout,
-                           FieldPacker v, LaunchOptions sc) {
-        // TODO: Is this necessary if nScriptForEach calls validate as well?
-        mRS.validate();
-        if (ains != null) {
-            for (Allocation ain : ains) {
-                mRS.validateObject(ain);
-            }
-        }
-        mRS.validateObject(aout);
-
-        if (ains == null && aout == null) {
-            throw new RSIllegalArgumentException(
-                "At least one of ain or aout is required to be non-null.");
-        }
-
-        long[] in_ids;
-        if (ains != null) {
-            in_ids = new long[ains.length];
-            for (int index = 0; index < ains.length; ++index) {
-                in_ids[index] = ains[index].getID(mRS);
-            }
-        } else {
-            in_ids = null;
-        }
-
-        long out_id = 0;
-        if (aout != null) {
-            out_id = aout.getID(mRS);
-        }
-
-        byte[] params = null;
-        if (v != null) {
-            params = v.getData();
-        }
-
-        int[] limits = null;
-        if (sc != null) {
-            limits = new int[6];
-
-            limits[0] = sc.xstart;
-            limits[1] = sc.xend;
-            limits[2] = sc.ystart;
-            limits[3] = sc.yend;
-            limits[4] = sc.zstart;
-            limits[5] = sc.zend;
-        }
-
-        mRS.nScriptForEach(getID(mRS), slot, in_ids, out_id, params, limits);
-    }
-
-    /**
-     * Only intended for use by generated reflected code.  (General reduction)
-     *
-     * @hide
-     */
-    protected void reduce(int slot, Allocation[] ains, Allocation aout, LaunchOptions sc) {
-        mRS.validate();
-        if (ains == null || ains.length < 1) {
-            throw new RSIllegalArgumentException(
-                "At least one input is required.");
-        }
-        if (aout == null) {
-            throw new RSIllegalArgumentException(
-                "aout is required to be non-null.");
-        }
-        for (Allocation ain : ains) {
-            mRS.validateObject(ain);
-        }
-
-        long[] in_ids = new long[ains.length];
-        for (int index = 0; index < ains.length; ++index) {
-            in_ids[index] = ains[index].getID(mRS);
-        }
-        long out_id = aout.getID(mRS);
-
-        int[] limits = null;
-        if (sc != null) {
-            limits = new int[6];
-
-            limits[0] = sc.xstart;
-            limits[1] = sc.xend;
-            limits[2] = sc.ystart;
-            limits[3] = sc.yend;
-            limits[4] = sc.zstart;
-            limits[5] = sc.zend;
-        }
-
-        mRS.nScriptReduce(getID(mRS), slot, in_ids, out_id, limits);
-    }
-
-    /**
-     * Only intended for use by generated reflected code.
-     *
-     * @param index
-     * @param v
-     */
-    public void setVar(int index, float v) {
-        mRS.nScriptSetVarF(getID(mRS), index, v, mUseIncSupp);
-    }
-
-    /**
-     * Only intended for use by generated reflected code.
-     *
-     * @param index
-     * @param v
-     */
-    public void setVar(int index, double v) {
-        mRS.nScriptSetVarD(getID(mRS), index, v, mUseIncSupp);
-    }
-
-    /**
-     * Only intended for use by generated reflected code.
-     *
-     * @param index
-     * @param v
-     */
-    public void setVar(int index, int v) {
-        mRS.nScriptSetVarI(getID(mRS), index, v, mUseIncSupp);
-    }
-
-    /**
-     * Only intended for use by generated reflected code.
-     *
-     * @param index
-     * @param v
-     */
-    public void setVar(int index, long v) {
-        mRS.nScriptSetVarJ(getID(mRS), index, v, mUseIncSupp);
-    }
-
-    /**
-     * Only intended for use by generated reflected code.
-     *
-     * @param index
-     * @param v
-     */
-    public void setVar(int index, boolean v) {
-        mRS.nScriptSetVarI(getID(mRS), index, v ? 1 : 0, mUseIncSupp);
-    }
-
-    /**
-     * Only intended for use by generated reflected code.
-     *
-     * @param index
-     * @param o
-     */
-    public void setVar(int index, BaseObj o) {
-        if (mUseIncSupp) {
-            long oInc = getDummyAlloc((Allocation)o);
-            mRS.nScriptSetVarObj(getID(mRS), index, (o == null) ? 0 : oInc, mUseIncSupp);            
-        } else {
-            mRS.nScriptSetVarObj(getID(mRS), index, (o == null) ? 0 : o.getID(mRS), mUseIncSupp);
-        }
-    }
-
-    /**
-     * Only intended for use by generated reflected code.
-     *
-     * @param index
-     * @param v
-     */
-    public void setVar(int index, FieldPacker v) {
-        mRS.nScriptSetVarV(getID(mRS), index, v.getData(), mUseIncSupp);
-    }
-
-    /**
-     * Only intended for use by generated reflected code.
-     *
-     * @param index
-     * @param v
-     * @param e
-     * @param dims
-     */
-    public void setVar(int index, FieldPacker v, Element e, int[] dims) {
-        if (mUseIncSupp) {
-            long dElement = e.getDummyElement(mRS);
-            mRS.nScriptSetVarVE(getID(mRS), index, v.getData(), dElement, dims, mUseIncSupp);
-        } else {
-            mRS.nScriptSetVarVE(getID(mRS), index, v.getData(), e.getID(mRS), dims, mUseIncSupp);
-        }
-    }
-
-    /**
-     * Only intended for use by generated reflected code.
-     *
-     */
-    public static class Builder {
-        RenderScript mRS;
-
-        Builder(RenderScript rs) {
-            mRS = rs;
-        }
-    }
-
-
-    /**
-     * Only intended for use by generated reflected code.
-     *
-     */
-    public static class FieldBase {
-        protected Element mElement;
-        protected Allocation mAllocation;
-
-        protected void init(RenderScript rs, int dimx) {
-            mAllocation = Allocation.createSized(rs, mElement, dimx, Allocation.USAGE_SCRIPT);
-        }
-
-        protected void init(RenderScript rs, int dimx, int usages) {
-            mAllocation = Allocation.createSized(rs, mElement, dimx, Allocation.USAGE_SCRIPT | usages);
-        }
-
-        protected FieldBase() {
-        }
-
-        public Element getElement() {
-            return mElement;
-        }
-
-        public Type getType() {
-            return mAllocation.getType();
-        }
-
-        public Allocation getAllocation() {
-            return mAllocation;
-        }
-
-        //@Override
-        public void updateAllocation() {
-        }
-    }
-
-
-    /**
-     * Class for specifying the specifics about how a kernel will be
-     * launched.
-     *
-     * This class can specify a potential range of cells on which to
-     * run a kernel.  If no set is called for a dimension then this
-     * class will have no impact on that dimension when the kernel
-     * is executed.
-     *
-     * The forEach kernel launch will operate over the intersection of
-     * the dimensions.
-     *
-     * Example:
-     * LaunchOptions with setX(5, 15)
-     * Allocation with dimension X=10, Y=10
-     * The resulting forEach run would execute over:
-     * x = 5 to 9 (inclusive) and
-     * y = 0 to 9 (inclusive).
-     *
-     */
-    public static final class LaunchOptions {
-        private int xstart = 0;
-        private int ystart = 0;
-        private int xend = 0;
-        private int yend = 0;
-        private int zstart = 0;
-        private int zend = 0;
-        private int strategy;
-
-        /**
-         * Set the X range. xstartArg is the lowest coordinate of the range,
-         * and xendArg-1 is the highest coordinate of the range.
-         *
-         * @param xstartArg Must be >= 0
-         * @param xendArg Must be > xstartArg
-         *
-         * @return LaunchOptions
-         */
-        public LaunchOptions setX(int xstartArg, int xendArg) {
-            if (xstartArg < 0 || xendArg <= xstartArg) {
-                throw new RSIllegalArgumentException("Invalid dimensions");
-            }
-            xstart = xstartArg;
-            xend = xendArg;
-            return this;
-        }
-
-        /**
-         * Set the Y range. ystartArg is the lowest coordinate of the range,
-         * and yendArg-1 is the highest coordinate of the range.
-         *
-         * @param ystartArg Must be >= 0
-         * @param yendArg Must be > ystartArg
-         *
-         * @return LaunchOptions
-         */
-        public LaunchOptions setY(int ystartArg, int yendArg) {
-            if (ystartArg < 0 || yendArg <= ystartArg) {
-                throw new RSIllegalArgumentException("Invalid dimensions");
-            }
-            ystart = ystartArg;
-            yend = yendArg;
-            return this;
-        }
-
-        /**
-         * Set the Z range. zstartArg is the lowest coordinate of the range,
-         * and zendArg-1 is the highest coordinate of the range.
-         *
-         * @param zstartArg Must be >= 0
-         * @param zendArg Must be > zstartArg
-         *
-         * @return LaunchOptions
-         */
-        public LaunchOptions setZ(int zstartArg, int zendArg) {
-            if (zstartArg < 0 || zendArg <= zstartArg) {
-                throw new RSIllegalArgumentException("Invalid dimensions");
-            }
-            zstart = zstartArg;
-            zend = zendArg;
-            return this;
-        }
-
-
-        /**
-         * Returns the current X start
-         *
-         * @return int current value
-         */
-        public int getXStart() {
-            return xstart;
-        }
-        /**
-         * Returns the current X end
-         *
-         * @return int current value
-         */
-        public int getXEnd() {
-            return xend;
-        }
-        /**
-         * Returns the current Y start
-         *
-         * @return int current value
-         */
-        public int getYStart() {
-            return ystart;
-        }
-        /**
-         * Returns the current Y end
-         *
-         * @return int current value
-         */
-        public int getYEnd() {
-            return yend;
-        }
-        /**
-         * Returns the current Z start
-         *
-         * @return int current value
-         */
-        public int getZStart() {
-            return zstart;
-        }
-        /**
-         * Returns the current Z end
-         *
-         * @return int current value
-         */
-        public int getZEnd() {
-            return zend;
-        }
-
-    }
-}
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/ScriptC.java b/v8/renderscript/java/src/android/support/v8/renderscript/ScriptC.java
deleted file mode 100644
index 28e9613..0000000
--- a/v8/renderscript/java/src/android/support/v8/renderscript/ScriptC.java
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * Copyright (C) 2012 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 android.support.v8.renderscript;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.util.Log;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Map.Entry;
-import java.util.HashMap;
-
-import java.lang.reflect.Field;
-import java.lang.reflect.Modifier;
-
-/**
- * The superclass for all user-defined scripts. This is only
- * intended to be used by the generated derived classes.
- **/
-public class ScriptC extends Script {
-    private static final String TAG = "ScriptC";
-
-    /**
-     * Only intended for use by the generated derived classes.
-     *
-     * @param id
-     * @param rs
-     */
-    protected ScriptC(long id, RenderScript rs) {
-        super(id, rs);
-    }
-
-    /**
-     * Only intended for use by the generated derived classes.
-     *
-     *
-     * @param rs
-     * @param resources
-     * @param resourceID
-     */
-    protected ScriptC(RenderScript rs, Resources resources, int resourceID) {
-        super(0, rs);
-        long id = internalCreate(rs, resources, resourceID);
-        if (id == 0) {
-            throw new RSRuntimeException("Loading of ScriptC script failed.");
-        }
-        setID(id);
-    }
-
-    /**
-     * Only intended for use by the generated derived classes.
-     *
-     * @param rs
-     * @param resName
-     * @param bitcode32
-     * @param bitcode64
-     */
-    protected ScriptC(RenderScript rs, String resName, byte[] bitcode32, byte[] bitcode64) {
-        super(0, rs);
-        long id = 0;
-        if (RenderScript.sPointerSize == 4) {
-            id = internalStringCreate(rs, resName, bitcode32);
-        } else {
-            id = internalStringCreate(rs, resName, bitcode64);
-        }
-        if (id == 0) {
-            throw new RSRuntimeException("Loading of ScriptC script failed.");
-        }
-        setID(id);
-    }
-
-    private static synchronized long internalCreate(RenderScript rs, Resources resources, int resourceID) {
-        byte[] pgm;
-        int pgmLength;
-        InputStream is = resources.openRawResource(resourceID);
-        try {
-            try {
-                pgm = new byte[1024];
-                pgmLength = 0;
-                while(true) {
-                    int bytesLeft = pgm.length - pgmLength;
-                    if (bytesLeft == 0) {
-                        byte[] buf2 = new byte[pgm.length * 2];
-                        System.arraycopy(pgm, 0, buf2, 0, pgm.length);
-                        pgm = buf2;
-                        bytesLeft = pgm.length - pgmLength;
-                    }
-                    int bytesRead = is.read(pgm, pgmLength, bytesLeft);
-                    if (bytesRead <= 0) {
-                        break;
-                    }
-                    pgmLength += bytesRead;
-                }
-            } finally {
-                is.close();
-            }
-        } catch(IOException e) {
-            throw new Resources.NotFoundException();
-        }
-
-        String resName = resources.getResourceEntryName(resourceID);
-        String cachePath = rs.getApplicationContext().getCacheDir().toString();
-
-        //        Log.v(TAG, "Create script for resource = " + resName + ", " + pgmLength + ", " + pgm);
-        //Log.v(TAG, " path = " + cachePath);
-        return rs.nScriptCCreate(resName, cachePath, pgm, pgmLength);
-    }
-
-    private static synchronized long internalStringCreate(RenderScript rs, String resName, byte[] bitcode) {
-        //        Log.v(TAG, "Create script for resource = " + resName);
-        String cachePath = rs.getApplicationContext().getCacheDir().toString();
-        return rs.nScriptCCreate(resName, cachePath, bitcode, bitcode.length);
-    }
-
-}
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/ScriptGroup.java b/v8/renderscript/java/src/android/support/v8/renderscript/ScriptGroup.java
deleted file mode 100644
index 139fde2..0000000
--- a/v8/renderscript/java/src/android/support/v8/renderscript/ScriptGroup.java
+++ /dev/null
@@ -1,1180 +0,0 @@
-/*
- * Copyright (C) 2012 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 android.support.v8.renderscript;
-
-import android.util.Log;
-import android.util.Pair;
-import java.lang.reflect.Method;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * A group of kernels that are executed
- * together with one execution call as if they were a single kernel
- * <p>
- * In addition to kernels, a script group may contain invocable functions as well.
- * A script group may take inputs and generate outputs, which are consumed and
- * produced by its member kernels.
- * Inside a script group, outputs from one kernel can be passed to another kernel as inputs.
- * The API disallows cyclic dependencies among kernels in a script group,
- * effectively making it a directed acyclic graph (DAG) of kernels.
- * <p>
- * Grouping kernels together allows for more efficient execution. For example,
- * runtime and compiler optimization can be applied to reduce computation and
- * communication overhead, and to make better use of the CPU and the GPU.
- **/
-public final class ScriptGroup extends BaseObj {
-    //FIXME: Change 23 to the codename when that is decided.
-    private static final int MIN_API_VERSION = 23;
-    private static final String TAG = "ScriptGroup";
-    IO mOutputs[];
-    IO mInputs[];
-    private boolean mUseIncSupp = false;
-    private ArrayList<Node> mNodes = new ArrayList<Node>();
-
-    static class IO {
-        Script.KernelID mKID;
-        Allocation mAllocation;
-
-        IO(Script.KernelID s) {
-            mKID = s;
-        }
-    }
-
-    static class ConnectLine {
-        ConnectLine(Type t, Script.KernelID from, Script.KernelID to) {
-            mFrom = from;
-            mToK = to;
-            mAllocationType = t;
-        }
-
-        ConnectLine(Type t, Script.KernelID from, Script.FieldID to) {
-            mFrom = from;
-            mToF = to;
-            mAllocationType = t;
-        }
-
-        Script.FieldID mToF;
-        Script.KernelID mToK;
-        Script.KernelID mFrom;
-        Type mAllocationType;
-        Allocation mAllocation;
-    }
-
-    static class Node {
-        Script mScript;
-        ArrayList<Script.KernelID> mKernels = new ArrayList<Script.KernelID>();
-        ArrayList<ConnectLine> mInputs = new ArrayList<ConnectLine>();
-        ArrayList<ConnectLine> mOutputs = new ArrayList<ConnectLine>();
-        int dagNumber;
-        boolean mSeen;
-        int mOrder;
-
-        Node mNext;
-
-        Node(Script s) {
-            mScript = s;
-        }
-    }
-
-    /**
-     * An opaque class for closures
-     * <p>
-     * A closure represents a function call to a kernel or invocable function,
-     * combined with arguments and values for global variables. A closure is
-     * created using the {@link Builder2#addKernel} or
-     * {@link Builder2#addInvoke}
-     * method.
-     */
-
-    public static final class Closure extends BaseObj {
-        private Object[] mArgs;
-        private Allocation mReturnValue;
-        private Map<Script.FieldID, Object> mBindings;
-
-        private Future mReturnFuture;
-        private Map<Script.FieldID, Future> mGlobalFuture;
-
-        private FieldPacker mFP;
-
-        private static final String TAG = "Closure";
-
-        Closure(long id, RenderScript rs) {
-            super(id, rs);
-        }
-
-        Closure(RenderScript rs, Script.KernelID kernelID, Type returnType,
-                       Object[] args, Map<Script.FieldID, Object> globals) {
-            super(0, rs);
-
-            if (android.os.Build.VERSION.SDK_INT < MIN_API_VERSION && rs.isUseNative()) {
-                throw new RSRuntimeException("ScriptGroup2 not supported in this API level");
-            }
-
-            mArgs = args;
-            mReturnValue = Allocation.createTyped(rs, returnType);
-            mBindings = globals;
-            mGlobalFuture = new HashMap<Script.FieldID, Future>();
-
-            int numValues = args.length + globals.size();
-
-            long[] fieldIDs = new long[numValues];
-            long[] values = new long[numValues];
-            int[] sizes = new int[numValues];
-            long[] depClosures = new long[numValues];
-            long[] depFieldIDs = new long[numValues];
-
-            int i;
-            for (i = 0; i < args.length; i++) {
-                fieldIDs[i] = 0;
-                retrieveValueAndDependenceInfo(rs, i, null, args[i],
-                                               values, sizes, depClosures, depFieldIDs);
-            }
-            for (Map.Entry<Script.FieldID, Object> entry : globals.entrySet()) {
-                Object obj = entry.getValue();
-                Script.FieldID fieldID = entry.getKey();
-                fieldIDs[i] = fieldID.getID(rs);
-                retrieveValueAndDependenceInfo(rs, i, fieldID, obj,
-                                               values, sizes, depClosures, depFieldIDs);
-                i++;
-            }
-
-            long id = rs.nClosureCreate(kernelID.getID(rs), mReturnValue.getID(rs),
-                                        fieldIDs, values, sizes, depClosures, depFieldIDs);
-
-            setID(id);
-        }
-
-        Closure(RenderScript rs, Script.InvokeID invokeID,
-                Object[] args, Map<Script.FieldID, Object> globals) {
-            super(0, rs);
-
-            if (android.os.Build.VERSION.SDK_INT < MIN_API_VERSION && rs.isUseNative()) {
-                throw new RSRuntimeException("ScriptGroup2 not supported in this API level");
-            }
-
-            mFP = FieldPacker.createFromArray(args);
-
-            mArgs = args;
-            mBindings = globals;
-            mGlobalFuture = new HashMap<Script.FieldID, Future>();
-
-            int numValues = globals.size();
-
-            long[] fieldIDs = new long[numValues];
-            long[] values = new long[numValues];
-            int[] sizes = new int[numValues];
-            long[] depClosures = new long[numValues];
-            long[] depFieldIDs = new long[numValues];
-
-            int i = 0;
-            for (Map.Entry<Script.FieldID, Object> entry : globals.entrySet()) {
-                Object obj = entry.getValue();
-                Script.FieldID fieldID = entry.getKey();
-                fieldIDs[i] = fieldID.getID(rs);
-                retrieveValueAndDependenceInfo(rs, i, fieldID, obj, values,
-                                               sizes, depClosures, depFieldIDs);
-                i++;
-            }
-
-            long id = rs.nInvokeClosureCreate(invokeID.getID(rs), mFP.getData(), fieldIDs,
-                                              values, sizes);
-
-            setID(id);
-        }
-
-        private void retrieveValueAndDependenceInfo(RenderScript rs,
-                                                    int index, Script.FieldID fid, Object obj,
-                                                    long[] values, int[] sizes,
-                                                    long[] depClosures,
-                                                    long[] depFieldIDs) {
-
-            if (obj instanceof Future) {
-                Future f = (Future)obj;
-                obj = f.getValue();
-                depClosures[index] = f.getClosure().getID(rs);
-                Script.FieldID fieldID = f.getFieldID();
-                depFieldIDs[index] = fieldID != null ? fieldID.getID(rs) : 0;
-            } else {
-                depClosures[index] = 0;
-                depFieldIDs[index] = 0;
-            }
-
-            if (obj instanceof Input) {
-                Input unbound = (Input)obj;
-                if (index < mArgs.length) {
-                    unbound.addReference(this, index);
-                } else {
-                    unbound.addReference(this, fid);
-                }
-                values[index] = 0;
-                sizes[index] = 0;
-            } else {
-                ValueAndSize vs = new ValueAndSize(rs, obj);
-                values[index] = vs.value;
-                sizes[index] = vs.size;
-            }
-        }
-
-        /**
-         * Returns the future for the return value
-         *
-         * @return a future
-         */
-
-        public Future getReturn() {
-            if (mReturnFuture == null) {
-                mReturnFuture = new Future(this, null, mReturnValue);
-            }
-
-            return mReturnFuture;
-        }
-
-        /**
-         * Returns the future for a global variable
-         *
-         * @param field the field ID for the global variable
-         * @return a future
-         */
-
-        public Future getGlobal(Script.FieldID field) {
-            Future f = mGlobalFuture.get(field);
-
-            if (f == null) {
-                // If the field is not bound to this closure, this will return a future
-                // without an associated value (reference). So this is not working for
-                // cross-module (cross-script) linking in this case where a field not
-                // explicitly bound.
-                Object obj = mBindings.get(field);
-                if (obj instanceof Future) {
-                    obj = ((Future)obj).getValue();
-                }
-                f = new Future(this, field, obj);
-                mGlobalFuture.put(field, f);
-            }
-
-            return f;
-        }
-
-        void setArg(int index, Object obj) {
-            if (obj instanceof Future) {
-                obj = ((Future)obj).getValue();
-            }
-            mArgs[index] = obj;
-            ValueAndSize vs = new ValueAndSize(mRS, obj);
-            mRS.nClosureSetArg(getID(mRS), index, vs.value, vs.size);
-        }
-
-        void setGlobal(Script.FieldID fieldID, Object obj) {
-            if (obj instanceof Future) {
-                obj = ((Future)obj).getValue();
-            }
-            mBindings.put(fieldID, obj);
-            ValueAndSize vs = new ValueAndSize(mRS, obj);
-            mRS.nClosureSetGlobal(getID(mRS), fieldID.getID(mRS), vs.value, vs.size);
-        }
-
-        private static final class ValueAndSize {
-            public ValueAndSize(RenderScript rs, Object obj) {
-                if (obj instanceof Allocation) {
-                    value = ((Allocation)obj).getID(rs);
-                    size = -1;
-                } else if (obj instanceof Boolean) {
-                    value = ((Boolean)obj).booleanValue() ? 1 : 0;
-                    size = 4;
-                } else if (obj instanceof Integer) {
-                    value = ((Integer)obj).longValue();
-                    size = 4;
-                } else if (obj instanceof Long) {
-                    value = ((Long)obj).longValue();
-                    size = 8;
-                } else if (obj instanceof Float) {
-                    value = Float.floatToRawIntBits(((Float)obj).floatValue());
-                    size = 4;
-                } else if (obj instanceof Double) {
-                    value = Double.doubleToRawLongBits(((Double)obj).doubleValue());
-                    size = 8;
-                }
-            }
-            public long value;
-            public int size;
-        }
-    }
-
-    /**
-     * An opaque class for futures
-     * <p>
-     * A future represents an output of a closure, either the return value of
-     * the function, or the value of a global variable written by the function.
-     * A future is created by calling the {@link Closure#getReturn}  or
-     * {@link Closure#getGlobal} method.
-     */
-
-    public static final class Future {
-        Closure mClosure;
-        Script.FieldID mFieldID;
-        Object mValue;
-
-        Future(Closure closure, Script.FieldID fieldID, Object value) {
-            mClosure = closure;
-            mFieldID = fieldID;
-            mValue = value;
-        }
-
-        Closure getClosure() { return mClosure; }
-        Script.FieldID getFieldID() { return mFieldID; }
-        Object getValue() { return mValue; }
-    }
-
-    /**
-     * An opaque class for unbound values (used for script group inputs)
-     * <p>
-     * Created by calling the {@link Builder2#addInput} method. The value
-     * is assigned in {@link ScriptGroup#execute(Object...)} method as
-     * one of its arguments. Arguments to the execute method should be in
-     * the same order as intputs are added using the addInput method.
-     */
-
-    public static final class Input {
-        // Either mFieldID or mArgIndex should be set but not both.
-        List<Pair<Closure, Script.FieldID>> mFieldID;
-        // -1 means unset. Legal values are 0 .. n-1, where n is the number of
-        // arguments for the referencing closure.
-        List<Pair<Closure, Integer>> mArgIndex;
-        Object mValue;
-
-        Input() {
-            mFieldID = new ArrayList<Pair<Closure, Script.FieldID>>();
-            mArgIndex = new ArrayList<Pair<Closure, Integer>>();
-        }
-
-        void addReference(Closure closure, int index) {
-            mArgIndex.add(Pair.create(closure, Integer.valueOf(index)));
-        }
-
-        void addReference(Closure closure, Script.FieldID fieldID) {
-            mFieldID.add(Pair.create(closure, fieldID));
-        }
-
-        void set(Object value) {
-            mValue = value;
-            for (Pair<Closure, Integer> p : mArgIndex) {
-                Closure closure = p.first;
-                int index = p.second.intValue();
-                closure.setArg(index, value);
-            }
-            for (Pair<Closure, Script.FieldID> p : mFieldID) {
-                Closure closure = p.first;
-                Script.FieldID fieldID = p.second;
-                closure.setGlobal(fieldID, value);
-            }
-        }
-
-        Object get() { return mValue; }
-    }
-
-    private String mName;
-    private List<Closure> mClosures;
-    private List<Input> mInputs2;
-    private Future[] mOutputs2;
-
-    ScriptGroup(long id, RenderScript rs) {
-        super(id, rs);
-    }
-
-    ScriptGroup(RenderScript rs, String name, List<Closure> closures,
-                List<Input> inputs, Future[] outputs) {
-        super(0, rs);
-
-        if (android.os.Build.VERSION.SDK_INT < MIN_API_VERSION && rs.isUseNative()) {
-            throw new RSRuntimeException("ScriptGroup2 not supported in this API level");
-        }
-        mName = name;
-        mClosures = closures;
-        mInputs2 = inputs;
-        mOutputs2 = outputs;
-
-        long[] closureIDs = new long[closures.size()];
-        for (int i = 0; i < closureIDs.length; i++) {
-            closureIDs[i] = closures.get(i).getID(rs);
-        }
-        String cachePath = rs.getApplicationContext().getCacheDir().toString();
-        long id = rs.nScriptGroup2Create(name, cachePath, closureIDs);
-        setID(id);
-    }
-
-    /**
-     * Executes a script group
-     *
-     * @param inputs inputs to the script group
-     * @return outputs of the script group as an array of objects
-     */
-
-    public Object[] execute(Object... inputs) {
-        if (inputs.length < mInputs2.size()) {
-            Log.e(TAG, this.toString() + " receives " + inputs.length + " inputs, " +
-                  "less than expected " + mInputs2.size());
-            return null;
-        }
-
-        if (inputs.length > mInputs2.size()) {
-            Log.i(TAG, this.toString() + " receives " + inputs.length + " inputs, " +
-                  "more than expected " + mInputs2.size());
-        }
-
-        for (int i = 0; i < mInputs2.size(); i++) {
-            Object obj = inputs[i];
-            if (obj instanceof Future || obj instanceof Input) {
-                Log.e(TAG, this.toString() + ": input " + i +
-                      " is a future or unbound value");
-                return null;
-            }
-            Input unbound = mInputs2.get(i);
-            unbound.set(obj);
-        }
-
-        mRS.nScriptGroup2Execute(getID(mRS));
-
-        Object[] outputObjs = new Object[mOutputs2.length];
-        int i = 0;
-        for (Future f : mOutputs2) {
-            Object output = f.getValue();
-            if (output instanceof Input) {
-                output = ((Input)output).get();
-            }
-            outputObjs[i++] = output;
-        }
-        return outputObjs;
-    }
-
-    /**
-     * Sets an input of the ScriptGroup. This specifies an
-     * Allocation to be used for kernels that require an input
-     * Allocation provided from outside of the ScriptGroup.
-     *
-     * @deprecated Set arguments to {@link #execute(Object...)} instead.
-     *
-     * @param s The ID of the kernel where the allocation should be
-     *          connected.
-     * @param a The allocation to connect.
-     */
-    @Deprecated
-    public void setInput(Script.KernelID s, Allocation a) {
-        for (int ct=0; ct < mInputs.length; ct++) {
-            if (mInputs[ct].mKID == s) {
-                mInputs[ct].mAllocation = a;
-                if (!mUseIncSupp) {
-                    mRS.nScriptGroupSetInput(getID(mRS), s.getID(mRS), mRS.safeID(a));
-                }
-                return;
-            }
-        }
-        throw new RSIllegalArgumentException("Script not found");
-    }
-
-    /**
-     * Sets an output of the ScriptGroup. This specifies an
-     * Allocation to be used for the kernels that require an output
-     * Allocation visible after the ScriptGroup is executed.
-     *
-     * @deprecated Use return value of {@link #execute(Object...)} instead.
-     *
-     * @param s The ID of the kernel where the allocation should be
-     *          connected.
-     * @param a The allocation to connect.
-     */
-    @Deprecated
-    public void setOutput(Script.KernelID s, Allocation a) {
-        for (int ct=0; ct < mOutputs.length; ct++) {
-            if (mOutputs[ct].mKID == s) {
-                mOutputs[ct].mAllocation = a;
-                if (!mUseIncSupp) {
-                    mRS.nScriptGroupSetOutput(getID(mRS), s.getID(mRS), mRS.safeID(a));
-                }
-                return;
-            }
-        }
-        throw new RSIllegalArgumentException("Script not found");
-    }
-
-    /**
-     * Execute the ScriptGroup.  This will run all the kernels in
-     * the ScriptGroup.  No internal connection results will be visible
-     * after execution of the ScriptGroup.
-     *
-     * If Incremental Support for intrinsics is needed, the execution
-     * will take the naive path: execute kernels one by one in the
-     * correct order.
-     *
-     * @deprecated Use {@link #execute} instead.
-     */
-    @Deprecated
-    public void execute() {
-        if (!mUseIncSupp) {
-            mRS.nScriptGroupExecute(getID(mRS));
-        } else {
-            // setup the allocations.
-            for (int ct=0; ct < mNodes.size(); ct++) {
-                Node n = mNodes.get(ct);
-                for (int ct2=0; ct2 < n.mOutputs.size(); ct2++) {
-                    ConnectLine l = n.mOutputs.get(ct2);
-                    if (l.mAllocation !=null) {
-                        continue;
-                    }
-
-                    //create allocation here
-                    Allocation alloc = Allocation.createTyped(mRS, l.mAllocationType,
-                                                              Allocation.MipmapControl.MIPMAP_NONE,
-                                                              Allocation.USAGE_SCRIPT);
-
-                    l.mAllocation = alloc;
-                    for (int ct3=ct2+1; ct3 < n.mOutputs.size(); ct3++) {
-                        if (n.mOutputs.get(ct3).mFrom == l.mFrom) {
-                            n.mOutputs.get(ct3).mAllocation = alloc;
-                        }
-                    }
-                }
-            }
-            for (Node node : mNodes) {
-                for (Script.KernelID kernel : node.mKernels) {
-                    Allocation ain  = null;
-                    Allocation aout = null;
-
-                    for (ConnectLine nodeInput : node.mInputs) {
-                        if (nodeInput.mToK == kernel) {
-                            ain = nodeInput.mAllocation;
-                        }
-                    }
-
-                    for (IO sgInput : mInputs) {
-                        if (sgInput.mKID == kernel) {
-                            ain = sgInput.mAllocation;
-                        }
-                    }
-
-                    for (ConnectLine nodeOutput : node.mOutputs) {
-                        if (nodeOutput.mFrom == kernel) {
-                            aout = nodeOutput.mAllocation;
-                        }
-                    }
-
-                    for (IO sgOutput : mOutputs) {
-                        if (sgOutput.mKID == kernel) {
-                            aout = sgOutput.mAllocation;
-                        }
-                    }
-
-                    kernel.mScript.forEach(kernel.mSlot, ain, aout, null);
-                }
-            }
-        }
-    }
-
-
-    /**
-     * Helper class to build a ScriptGroup. A ScriptGroup is
-     * created in two steps.
-     * <p>
-     * First, all kernels to be used by the ScriptGroup should be added.
-     * <p>
-     * Second, add connections between kernels. There are two types
-     * of connections: kernel to kernel and kernel to field.
-     * Kernel to kernel allows a kernel's output to be passed to
-     * another kernel as input. Kernel to field allows the output of
-     * one kernel to be bound as a script global. Kernel to kernel is
-     * higher performance and should be used where possible.
-     * <p>
-     * A ScriptGroup must contain a single directed acyclic graph (DAG); it
-     * cannot contain cycles. Currently, all kernels used in a ScriptGroup
-     * must come from different Script objects. Additionally, all kernels
-     * in a ScriptGroup must have at least one input, output, or internal
-     * connection.
-     * <p>
-     * Once all connections are made, a call to {@link #create} will
-     * return the ScriptGroup object.
-     *
-     * @deprecated Use {@link Builder2} instead.
-     *
-     */
-    @Deprecated
-    public static final class Builder {
-        private RenderScript mRS;
-        private ArrayList<Node> mNodes = new ArrayList<Node>();
-        private ArrayList<ConnectLine> mLines = new ArrayList<ConnectLine>();
-        private int mKernelCount;
-        private boolean mUseIncSupp = false;
-
-        /**
-         * Create a Builder for generating a ScriptGroup.
-         *
-         *
-         * @param rs The RenderScript context.
-         */
-        public Builder(RenderScript rs) {
-            mRS = rs;
-        }
-
-        // do a DFS from original node, looking for original node
-        // any cycle that could be created must contain original node
-        private void validateCycle(Node target, Node original) {
-            for (int ct = 0; ct < target.mOutputs.size(); ct++) {
-                final ConnectLine cl = target.mOutputs.get(ct);
-                if (cl.mToK != null) {
-                    Node tn = findNode(cl.mToK.mScript);
-                    if (tn.equals(original)) {
-                        throw new RSInvalidStateException("Loops in group not allowed.");
-                    }
-                    validateCycle(tn, original);
-                }
-                if (cl.mToF != null) {
-                    Node tn = findNode(cl.mToF.mScript);
-                    if (tn.equals(original)) {
-                        throw new RSInvalidStateException("Loops in group not allowed.");
-                    }
-                    validateCycle(tn, original);
-                }
-            }
-        }
-
-        private void mergeDAGs(int valueUsed, int valueKilled) {
-            for (int ct=0; ct < mNodes.size(); ct++) {
-                if (mNodes.get(ct).dagNumber == valueKilled)
-                    mNodes.get(ct).dagNumber = valueUsed;
-            }
-        }
-
-        private void validateDAGRecurse(Node n, int dagNumber) {
-            // combine DAGs if this node has been seen already
-            if (n.dagNumber != 0 && n.dagNumber != dagNumber) {
-                mergeDAGs(n.dagNumber, dagNumber);
-                return;
-            }
-
-            n.dagNumber = dagNumber;
-            for (int ct=0; ct < n.mOutputs.size(); ct++) {
-                final ConnectLine cl = n.mOutputs.get(ct);
-                if (cl.mToK != null) {
-                    Node tn = findNode(cl.mToK.mScript);
-                    validateDAGRecurse(tn, dagNumber);
-                }
-                if (cl.mToF != null) {
-                    Node tn = findNode(cl.mToF.mScript);
-                    validateDAGRecurse(tn, dagNumber);
-                }
-            }
-        }
-
-        private void validateDAG() {
-            for (int ct=0; ct < mNodes.size(); ct++) {
-                Node n = mNodes.get(ct);
-                if (n.mInputs.size() == 0) {
-                    if (n.mOutputs.size() == 0 && mNodes.size() > 1) {
-                        String msg = "Groups cannot contain unconnected scripts";
-                        throw new RSInvalidStateException(msg);
-                    }
-                    validateDAGRecurse(n, ct+1);
-                }
-            }
-            int dagNumber = mNodes.get(0).dagNumber;
-            for (int ct=0; ct < mNodes.size(); ct++) {
-                if (mNodes.get(ct).dagNumber != dagNumber) {
-                    throw new RSInvalidStateException("Multiple DAGs in group not allowed.");
-                }
-            }
-        }
-
-        private Node findNode(Script s) {
-            for (int ct=0; ct < mNodes.size(); ct++) {
-                if (s == mNodes.get(ct).mScript) {
-                    return mNodes.get(ct);
-                }
-            }
-            return null;
-        }
-
-        private Node findNode(Script.KernelID k) {
-            for (int ct=0; ct < mNodes.size(); ct++) {
-                Node n = mNodes.get(ct);
-                for (int ct2=0; ct2 < n.mKernels.size(); ct2++) {
-                    if (k == n.mKernels.get(ct2)) {
-                        return n;
-                    }
-                }
-            }
-            return null;
-        }
-
-        /**
-         * Adds a Kernel to the group.
-         *
-         *
-         * @param k The kernel to add.
-         *
-         * @return Builder Returns this.
-         */
-        public Builder addKernel(Script.KernelID k) {
-            if (mLines.size() != 0) {
-                throw new RSInvalidStateException(
-                    "Kernels may not be added once connections exist.");
-            }
-            if (k.mScript.isIncSupp()) {
-                mUseIncSupp = true;
-            }
-            //android.util.Log.v("RSR", "addKernel 1 k=" + k);
-            if (findNode(k) != null) {
-                return this;
-            }
-            //android.util.Log.v("RSR", "addKernel 2 ");
-            mKernelCount++;
-            Node n = findNode(k.mScript);
-            if (n == null) {
-                //android.util.Log.v("RSR", "addKernel 3 ");
-                n = new Node(k.mScript);
-                mNodes.add(n);
-            }
-            n.mKernels.add(k);
-            return this;
-        }
-
-        /**
-         * Adds a connection to the group.
-         *
-         *
-         * @param t The type of the connection. This is used to
-         *          determine the kernel launch sizes on the source side
-         *          of this connection.
-         * @param from The source for the connection.
-         * @param to The destination of the connection.
-         *
-         * @return Builder Returns this
-         */
-        public Builder addConnection(Type t, Script.KernelID from, Script.FieldID to) {
-            //android.util.Log.v("RSR", "addConnection " + t +", " + from + ", " + to);
-            Node nf = findNode(from);
-            if (nf == null) {
-                throw new RSInvalidStateException("From script not found.");
-            }
-
-            Node nt = findNode(to.mScript);
-            if (nt == null) {
-                throw new RSInvalidStateException("To script not found.");
-            }
-
-            ConnectLine cl = new ConnectLine(t, from, to);
-            mLines.add(new ConnectLine(t, from, to));
-
-            nf.mOutputs.add(cl);
-            nt.mInputs.add(cl);
-
-            validateCycle(nf, nf);
-            return this;
-        }
-
-        /**
-         * Adds a connection to the group.
-         *
-         *
-         * @param t The type of the connection. This is used to
-         *          determine the kernel launch sizes for both sides of
-         *          this connection.
-         * @param from The source for the connection.
-         * @param to The destination of the connection.
-         *
-         * @return Builder Returns this
-         */
-        public Builder addConnection(Type t, Script.KernelID from, Script.KernelID to) {
-            //android.util.Log.v("RSR", "addConnection " + t +", " + from + ", " + to);
-            Node nf = findNode(from);
-            if (nf == null) {
-                throw new RSInvalidStateException("From script not found.");
-            }
-
-            Node nt = findNode(to);
-            if (nt == null) {
-                throw new RSInvalidStateException("To script not found.");
-            }
-
-            ConnectLine cl = new ConnectLine(t, from, to);
-            mLines.add(new ConnectLine(t, from, to));
-
-            nf.mOutputs.add(cl);
-            nt.mInputs.add(cl);
-
-            validateCycle(nf, nf);
-            return this;
-        }
-
-        /**
-         * Calculate the order of each node.
-         *
-         *
-         * @return Success or Fail
-         */
-        private boolean calcOrderRecurse(Node node0, int depth) {
-            node0.mSeen = true;
-            if (node0.mOrder < depth) {
-                node0.mOrder = depth;
-            }
-            boolean ret = true;
-
-            for (ConnectLine link : node0.mOutputs) {
-                Node node1 = null;
-                if (link.mToF != null) {
-                    node1 = findNode(link.mToF.mScript);
-                } else {
-                    node1 = findNode(link.mToK.mScript);
-                }
-                if (node1.mSeen) {
-                    return false;
-                }
-                ret &= calcOrderRecurse(node1, node0.mOrder + 1);
-            }
-
-            return ret;
-        }
-
-        private boolean calcOrder() {
-            boolean ret = true;
-            for (Node n0 : mNodes) {
-                if (n0.mInputs.size() == 0) {
-                    for (Node n1 : mNodes) {
-                        n1.mSeen = false;
-                    }
-                    ret &= calcOrderRecurse(n0, 1);
-                }
-            }
-
-            Collections.sort(mNodes, new Comparator<Node>() {
-                public int compare(Node n1, Node n2) {
-                    return n1.mOrder - n2.mOrder;
-                }
-            });
-
-            return ret;
-        }
-
-        /**
-         * Creates the Script group.
-         *
-         *
-         * @return ScriptGroup The new ScriptGroup
-         */
-        public ScriptGroup create() {
-
-            if (mNodes.size() == 0) {
-                throw new RSInvalidStateException("Empty script groups are not allowed");
-            }
-
-            // reset DAG numbers in case we're building a second group
-            for (int ct=0; ct < mNodes.size(); ct++) {
-                mNodes.get(ct).dagNumber = 0;
-            }
-            validateDAG();
-
-            ArrayList<IO> inputs = new ArrayList<IO>();
-            ArrayList<IO> outputs = new ArrayList<IO>();
-
-            long[] kernels = new long[mKernelCount];
-            int idx = 0;
-            for (int ct=0; ct < mNodes.size(); ct++) {
-                Node n = mNodes.get(ct);
-                for (int ct2=0; ct2 < n.mKernels.size(); ct2++) {
-                    final Script.KernelID kid = n.mKernels.get(ct2);
-                    kernels[idx++] = kid.getID(mRS);
-
-                    boolean hasInput = false;
-                    boolean hasOutput = false;
-                    for (int ct3=0; ct3 < n.mInputs.size(); ct3++) {
-                        if (n.mInputs.get(ct3).mToK == kid) {
-                            hasInput = true;
-                        }
-                    }
-                    for (int ct3=0; ct3 < n.mOutputs.size(); ct3++) {
-                        if (n.mOutputs.get(ct3).mFrom == kid) {
-                            hasOutput = true;
-                        }
-                    }
-                    if (!hasInput) {
-                        inputs.add(new IO(kid));
-                    }
-                    if (!hasOutput) {
-                        outputs.add(new IO(kid));
-                    }
-                }
-            }
-            if (idx != mKernelCount) {
-                throw new RSRuntimeException("Count mismatch, should not happen.");
-            }
-
-            long id = 0;
-            if (!mUseIncSupp) {
-                long[] src = new long[mLines.size()];
-                long[] dstk = new long[mLines.size()];
-                long[] dstf = new long[mLines.size()];
-                long[] types = new long[mLines.size()];
-
-                for (int ct=0; ct < mLines.size(); ct++) {
-                    ConnectLine cl = mLines.get(ct);
-                    src[ct] = cl.mFrom.getID(mRS);
-                    if (cl.mToK != null) {
-                        dstk[ct] = cl.mToK.getID(mRS);
-                    }
-                    if (cl.mToF != null) {
-                        dstf[ct] = cl.mToF.getID(mRS);
-                    }
-                    types[ct] = cl.mAllocationType.getID(mRS);
-                }
-                id = mRS.nScriptGroupCreate(kernels, src, dstk, dstf, types);
-                if (id == 0) {
-                    throw new RSRuntimeException("Object creation error, should not happen.");
-                }
-            } else {
-                //Calculate the order of the DAG so that script can run one after another.
-                calcOrder();
-            }
-
-            ScriptGroup sg = new ScriptGroup(id, mRS);
-            sg.mOutputs = new IO[outputs.size()];
-            for (int ct=0; ct < outputs.size(); ct++) {
-                sg.mOutputs[ct] = outputs.get(ct);
-            }
-
-            sg.mInputs = new IO[inputs.size()];
-            for (int ct=0; ct < inputs.size(); ct++) {
-                sg.mInputs[ct] = inputs.get(ct);
-            }
-            sg.mNodes = mNodes;
-            sg.mUseIncSupp = mUseIncSupp;
-            return sg;
-        }
-
-    }
-
-    /**
-     * Represents a binding of a value to a global variable in a
-     * kernel or invocable function. Used in closure creation.
-     */
-
-    public static final class Binding {
-        private final Script.FieldID mField;
-        private final Object mValue;
-
-        /**
-         * Returns a Binding object that binds value to field
-         *
-         * @param field the Script.FieldID of the global variable
-         * @param value the value
-         */
-
-        public Binding(Script.FieldID field, Object value) {
-            mField = field;
-            mValue = value;
-        }
-
-        /**
-         * Returns the field ID
-         */
-
-        public Script.FieldID getField() { return mField; }
-
-        /**
-         * Returns the value
-         */
-
-        public Object getValue() { return mValue; }
-    }
-
-    /**
-     * The builder class for creating script groups
-     * <p>
-     * A script group is created using closures (see class {@link Closure}).
-     * A closure is a function call to a kernel or
-     * invocable function. Each function argument or global variable accessed inside
-     * the function is bound to 1) a known value, 2) a script group input
-     * (see class {@link Input}), or 3) a
-     * future (see class {@link Future}).
-     * A future is the output of a closure, either the return value of the
-     * function or a global variable written by that function.
-     * <p>
-     * Closures are created using the {@link #addKernel} or {@link #addInvoke}
-     * methods.
-     * When a closure is created, futures from previously created closures
-     * can be used as its inputs.
-     * External script group inputs can be used as inputs to individual closures as well.
-     * An external script group input is created using the {@link #addInput} method.
-     * A script group is created by a call to the {@link #create} method, which
-     * accepts an array of futures as the outputs for the script group.
-     * <p>
-     * Closures in a script group can be evaluated in any order as long as the
-     * following conditions are met:
-     * 1) a closure must be evaluated before any other closures that take its
-     * futures as inputs;
-     * 2) all closures added before an invoke closure must be evaluated
-     * before it;
-     * and 3) all closures added after an invoke closure must be evaluated after
-     * it.
-     * As a special case, the order that the closures are added is a legal
-     * evaluation order. However, other evaluation orders are possible, including
-     * concurrently evaluating independent closures.
-     */
-
-    public static final class Builder2 {
-        RenderScript mRS;
-        List<Closure> mClosures;
-        List<Input> mInputs;
-        private static final String TAG = "ScriptGroup.Builder2";
-
-        /**
-         * Returns a Builder object
-         *
-         * @param rs the RenderScript context
-         */
-        public Builder2(RenderScript rs) {
-            mRS = rs;
-            mClosures = new ArrayList<Closure>();
-            mInputs = new ArrayList<Input>();
-        }
-
-        /**
-         * Adds a closure for a kernel
-         *
-         * @param k Kernel ID for the kernel function
-         * @param returnType Allocation type for the return value
-         * @param args arguments to the kernel function
-         * @param globalBindings bindings for global variables
-         * @return a closure
-         */
-
-        private Closure addKernelInternal(Script.KernelID k, Type returnType, Object[] args,
-                                          Map<Script.FieldID, Object> globalBindings) {
-            Closure c = new Closure(mRS, k, returnType, args, globalBindings);
-            mClosures.add(c);
-            return c;
-        }
-
-        /**
-         * Adds a closure for an invocable function
-         *
-         * @param invoke Invoke ID for the invocable function
-         * @param args arguments to the invocable function
-         * @param globalBindings bindings for global variables
-         * @return a closure
-         */
-
-        private Closure addInvokeInternal(Script.InvokeID invoke, Object[] args,
-                                          Map<Script.FieldID, Object> globalBindings) {
-            Closure c = new Closure(mRS, invoke, args, globalBindings);
-            mClosures.add(c);
-            return c;
-        }
-
-        /**
-         * Adds a script group input
-         *
-         * @return a script group input, which can be used as an argument or a value to
-         *     a global variable for creating closures
-         */
-
-        public Input addInput() {
-            Input unbound = new Input();
-            mInputs.add(unbound);
-            return unbound;
-        }
-
-        /**
-         * Adds a closure for a kernel
-         *
-         * @param k Kernel ID for the kernel function
-         * @param argsAndBindings arguments followed by bindings for global variables
-         * @return a closure
-         */
-
-        public Closure addKernel(Script.KernelID k, Type returnType, Object... argsAndBindings) {
-            ArrayList<Object> args = new ArrayList<Object>();
-            Map<Script.FieldID, Object> bindingMap = new HashMap<Script.FieldID, Object>();
-            if (!seperateArgsAndBindings(argsAndBindings, args, bindingMap)) {
-                return null;
-            }
-            return addKernelInternal(k, returnType, args.toArray(), bindingMap);
-        }
-
-        /**
-         * Adds a closure for an invocable function
-         *
-         * @param invoke Invoke ID for the invocable function
-         * @param argsAndBindings arguments followed by bindings for global variables
-         * @return a closure
-         */
-
-        public Closure addInvoke(Script.InvokeID invoke, Object... argsAndBindings) {
-            ArrayList<Object> args = new ArrayList<Object>();
-            Map<Script.FieldID, Object> bindingMap = new HashMap<Script.FieldID, Object>();
-            if (!seperateArgsAndBindings(argsAndBindings, args, bindingMap)) {
-                return null;
-            }
-            return addInvokeInternal(invoke, args.toArray(), bindingMap);
-        }
-
-        /**
-         * Creates a script group
-         *
-         * @param name name for the script group. Legal names can only contain letters, digits,
-         *        '-', or '_'. The name can be no longer than 100 characters.
-         * @param outputs futures intended as outputs of the script group
-         * @return a script group
-         */
-
-        public ScriptGroup create(String name, Future... outputs) {
-            if (name == null || name.isEmpty() || name.length() > 100 ||
-                !name.equals(name.replaceAll("[^a-zA-Z0-9-]", "_"))) {
-                throw new RSIllegalArgumentException("invalid script group name");
-            }
-            ScriptGroup ret = new ScriptGroup(mRS, name, mClosures, mInputs, outputs);
-            return ret;
-        }
-
-        private boolean seperateArgsAndBindings(Object[] argsAndBindings,
-                                                ArrayList<Object> args,
-                                                Map<Script.FieldID, Object> bindingMap) {
-            int i;
-            for (i = 0; i < argsAndBindings.length; i++) {
-                if (argsAndBindings[i] instanceof Binding) {
-                    break;
-                }
-                args.add(argsAndBindings[i]);
-            }
-
-            for (; i < argsAndBindings.length; i++) {
-                if (!(argsAndBindings[i] instanceof Binding)) {
-                    return false;
-                }
-                Binding b = (Binding)argsAndBindings[i];
-                bindingMap.put(b.getField(), b.getValue());
-            }
-
-            return true;
-        }
-
-    }
-
-}
-
-
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/ScriptIntrinsic.java b/v8/renderscript/java/src/android/support/v8/renderscript/ScriptIntrinsic.java
deleted file mode 100644
index e59cf6d..0000000
--- a/v8/renderscript/java/src/android/support/v8/renderscript/ScriptIntrinsic.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (C) 2012 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 android.support.v8.renderscript;
-
-/**
- * Base class for all Intrinsic scripts. An intrinsic a script
- * which implements a pre-defined function. Intrinsics are
- * provided to provide effecient implemtations of common
- * operations.
- *
- * Not intended for direct use.
- **/
-public abstract class ScriptIntrinsic extends Script {
-    ScriptIntrinsic(long id, RenderScript rs) {
-        super(id, rs);
-        if (id == 0) {
-            throw new RSRuntimeException("Loading of ScriptIntrinsic failed.");
-        }
-    }
-}
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/ScriptIntrinsic3DLUT.java b/v8/renderscript/java/src/android/support/v8/renderscript/ScriptIntrinsic3DLUT.java
deleted file mode 100644
index 7fc71f3..0000000
--- a/v8/renderscript/java/src/android/support/v8/renderscript/ScriptIntrinsic3DLUT.java
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright (C) 2012 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 android.support.v8.renderscript;
-
-import android.util.Log;
-
-/**
- *
- * Intrinsic for converting RGB to RGBA by using a 3D lookup table.  The
- * incoming r,g,b values are use as normalized x,y,z coordinates into a 3D
- * allocation.  The 8 nearest values are sampled and linearly interpolated.  The
- * result is placed in the output.
- *
- **/
-public class ScriptIntrinsic3DLUT extends ScriptIntrinsic {
-    private Allocation mLUT;
-    private Element mElement;
-    // API level for the intrinsic
-    private static final int INTRINSIC_API_LEVEL = 19;
-
-    protected ScriptIntrinsic3DLUT(long id, RenderScript rs, Element e) {
-        super(id, rs);
-        mElement = e;
-    }
-
-    /**
-     * Supported elements types are {@link Element#U8_4}
-     *
-     * The defaults tables are identity.
-     *
-     * @param rs The RenderScript context
-     * @param e Element type for intputs and outputs
-     *
-     * @return ScriptIntrinsic3DLUT
-     */
-    public static ScriptIntrinsic3DLUT create(RenderScript rs, Element e) {
-        if (!e.isCompatible(Element.U8_4(rs))) {
-            throw new RSIllegalArgumentException("Element must be compatible with uchar4.");
-        }
-        long id;
-        boolean mUseIncSupp = rs.isUseNative() &&
-                              android.os.Build.VERSION.SDK_INT < INTRINSIC_API_LEVEL;
-
-        id = rs.nScriptIntrinsicCreate(8, e.getID(rs), mUseIncSupp);
-
-        ScriptIntrinsic3DLUT si = new ScriptIntrinsic3DLUT(id, rs, e);
-        si.setIncSupp(mUseIncSupp);
-        return si;
-    }
-
-    /**
-     * Sets the {@link android.support.v8.renderscript.Allocation} to be used as
-     * the lookup table.
-     *
-     * The lookup table must use the same
-     * {@link android.support.v8.renderscript.Element} as the intrinsic.
-     *
-     */
-
-    public void setLUT(Allocation lut) {
-        final Type t = lut.getType();
-
-        if (t.getZ() == 0) {
-            throw new RSIllegalArgumentException("LUT must be 3d.");
-        }
-
-        if (!t.getElement().isCompatible(mElement)) {
-            throw new RSIllegalArgumentException("LUT element type must match.");
-        }
-
-        mLUT = lut;
-        setVar(0, mLUT);
-    }
-
-
-    /**
-     * Invoke the kernel and apply the lookup to each cell of ain
-     * and copy to aout.
-     *
-     * @param ain Input allocation
-     * @param aout Output allocation
-     */
-    public void forEach(Allocation ain, Allocation aout) {
-        forEach(0, ain, aout, null);
-    }
-
-    /**
-     * Get a KernelID for this intrinsic kernel.
-     *
-     * @return Script.KernelID The KernelID object.
-     */
-    public Script.KernelID getKernelID() {
-        return createKernelID(0, 3, null, null);
-    }
-}
-
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/ScriptIntrinsicBLAS.java b/v8/renderscript/java/src/android/support/v8/renderscript/ScriptIntrinsicBLAS.java
deleted file mode 100644
index fe32989..0000000
--- a/v8/renderscript/java/src/android/support/v8/renderscript/ScriptIntrinsicBLAS.java
+++ /dev/null
@@ -1,4190 +0,0 @@
-/*
- * 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 android.support.v8.renderscript;
-
-import android.support.annotation.IntDef;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- *
- * ScriptIntrinsicBLAS class provides high performance RenderScript APIs to BLAS.
- *
- * The BLAS (Basic Linear Algebra Subprograms) are routines that provide standard
- * building blocks for performing basic vector and matrix operations.
- *
- * For detailed description of BLAS, please refer to http://www.netlib.org/blas/
- *
- **/
-public final class ScriptIntrinsicBLAS extends ScriptIntrinsic {
-    private Allocation mLUT;
-    private static final int INTRINSIC_API_LEVEL = 23;
-
-    private ScriptIntrinsicBLAS(long id, RenderScript rs) {
-        super(id, rs);
-    }
-
-    private static final int RsBlas_sdsdot = 1;
-    private static final int RsBlas_dsdot = 2;
-    private static final int RsBlas_sdot = 3;
-    private static final int RsBlas_ddot = 4;
-    private static final int RsBlas_cdotu_sub = 5;
-    private static final int RsBlas_cdotc_sub = 6;
-    private static final int RsBlas_zdotu_sub = 7;
-    private static final int RsBlas_zdotc_sub = 8;
-    private static final int RsBlas_snrm2 = 9;
-    private static final int RsBlas_sasum = 10;
-    private static final int RsBlas_dnrm2 = 11;
-    private static final int RsBlas_dasum = 12;
-    private static final int RsBlas_scnrm2 = 13;
-    private static final int RsBlas_scasum = 14;
-    private static final int RsBlas_dznrm2 = 15;
-    private static final int RsBlas_dzasum = 16;
-    private static final int RsBlas_isamax = 17;
-    private static final int RsBlas_idamax = 18;
-    private static final int RsBlas_icamax = 19;
-    private static final int RsBlas_izamax = 20;
-    private static final int RsBlas_sswap = 21;
-    private static final int RsBlas_scopy = 22;
-    private static final int RsBlas_saxpy = 23;
-    private static final int RsBlas_dswap = 24;
-    private static final int RsBlas_dcopy = 25;
-    private static final int RsBlas_daxpy = 26;
-    private static final int RsBlas_cswap = 27;
-    private static final int RsBlas_ccopy = 28;
-    private static final int RsBlas_caxpy = 29;
-    private static final int RsBlas_zswap = 30;
-    private static final int RsBlas_zcopy = 31;
-    private static final int RsBlas_zaxpy = 32;
-    private static final int RsBlas_srotg = 33;
-    private static final int RsBlas_srotmg = 34;
-    private static final int RsBlas_srot = 35;
-    private static final int RsBlas_srotm = 36;
-    private static final int RsBlas_drotg = 37;
-    private static final int RsBlas_drotmg = 38;
-    private static final int RsBlas_drot = 39;
-    private static final int RsBlas_drotm = 40;
-    private static final int RsBlas_sscal = 41;
-    private static final int RsBlas_dscal = 42;
-    private static final int RsBlas_cscal = 43;
-    private static final int RsBlas_zscal = 44;
-    private static final int RsBlas_csscal = 45;
-    private static final int RsBlas_zdscal = 46;
-    private static final int RsBlas_sgemv = 47;
-    private static final int RsBlas_sgbmv = 48;
-    private static final int RsBlas_strmv = 49;
-    private static final int RsBlas_stbmv = 50;
-    private static final int RsBlas_stpmv = 51;
-    private static final int RsBlas_strsv = 52;
-    private static final int RsBlas_stbsv = 53;
-    private static final int RsBlas_stpsv = 54;
-    private static final int RsBlas_dgemv = 55;
-    private static final int RsBlas_dgbmv = 56;
-    private static final int RsBlas_dtrmv = 57;
-    private static final int RsBlas_dtbmv = 58;
-    private static final int RsBlas_dtpmv = 59;
-    private static final int RsBlas_dtrsv = 60;
-    private static final int RsBlas_dtbsv = 61;
-    private static final int RsBlas_dtpsv = 62;
-    private static final int RsBlas_cgemv = 63;
-    private static final int RsBlas_cgbmv = 64;
-    private static final int RsBlas_ctrmv = 65;
-    private static final int RsBlas_ctbmv = 66;
-    private static final int RsBlas_ctpmv = 67;
-    private static final int RsBlas_ctrsv = 68;
-    private static final int RsBlas_ctbsv = 69;
-    private static final int RsBlas_ctpsv = 70;
-    private static final int RsBlas_zgemv = 71;
-    private static final int RsBlas_zgbmv = 72;
-    private static final int RsBlas_ztrmv = 73;
-    private static final int RsBlas_ztbmv = 74;
-    private static final int RsBlas_ztpmv = 75;
-    private static final int RsBlas_ztrsv = 76;
-    private static final int RsBlas_ztbsv = 77;
-    private static final int RsBlas_ztpsv = 78;
-    private static final int RsBlas_ssymv = 79;
-    private static final int RsBlas_ssbmv = 80;
-    private static final int RsBlas_sspmv = 81;
-    private static final int RsBlas_sger = 82;
-    private static final int RsBlas_ssyr = 83;
-    private static final int RsBlas_sspr = 84;
-    private static final int RsBlas_ssyr2 = 85;
-    private static final int RsBlas_sspr2 = 86;
-    private static final int RsBlas_dsymv = 87;
-    private static final int RsBlas_dsbmv = 88;
-    private static final int RsBlas_dspmv = 89;
-    private static final int RsBlas_dger = 90;
-    private static final int RsBlas_dsyr = 91;
-    private static final int RsBlas_dspr = 92;
-    private static final int RsBlas_dsyr2 = 93;
-    private static final int RsBlas_dspr2 = 94;
-    private static final int RsBlas_chemv = 95;
-    private static final int RsBlas_chbmv = 96;
-    private static final int RsBlas_chpmv = 97;
-    private static final int RsBlas_cgeru = 98;
-    private static final int RsBlas_cgerc = 99;
-    private static final int RsBlas_cher = 100;
-    private static final int RsBlas_chpr = 101;
-    private static final int RsBlas_cher2 = 102;
-    private static final int RsBlas_chpr2 = 103;
-    private static final int RsBlas_zhemv = 104;
-    private static final int RsBlas_zhbmv = 105;
-    private static final int RsBlas_zhpmv = 106;
-    private static final int RsBlas_zgeru = 107;
-    private static final int RsBlas_zgerc = 108;
-    private static final int RsBlas_zher = 109;
-    private static final int RsBlas_zhpr = 110;
-    private static final int RsBlas_zher2 = 111;
-    private static final int RsBlas_zhpr2 = 112;
-    private static final int RsBlas_sgemm = 113;
-    private static final int RsBlas_ssymm = 114;
-    private static final int RsBlas_ssyrk = 115;
-    private static final int RsBlas_ssyr2k = 116;
-    private static final int RsBlas_strmm = 117;
-    private static final int RsBlas_strsm = 118;
-    private static final int RsBlas_dgemm = 119;
-    private static final int RsBlas_dsymm = 120;
-    private static final int RsBlas_dsyrk = 121;
-    private static final int RsBlas_dsyr2k = 122;
-    private static final int RsBlas_dtrmm = 123;
-    private static final int RsBlas_dtrsm = 124;
-    private static final int RsBlas_cgemm = 125;
-    private static final int RsBlas_csymm = 126;
-    private static final int RsBlas_csyrk = 127;
-    private static final int RsBlas_csyr2k = 128;
-    private static final int RsBlas_ctrmm = 129;
-    private static final int RsBlas_ctrsm = 130;
-    private static final int RsBlas_zgemm = 131;
-    private static final int RsBlas_zsymm = 132;
-    private static final int RsBlas_zsyrk = 133;
-    private static final int RsBlas_zsyr2k = 134;
-    private static final int RsBlas_ztrmm = 135;
-    private static final int RsBlas_ztrsm = 136;
-    private static final int RsBlas_chemm = 137;
-    private static final int RsBlas_cherk = 138;
-    private static final int RsBlas_cher2k = 139;
-    private static final int RsBlas_zhemm = 140;
-    private static final int RsBlas_zherk = 141;
-    private static final int RsBlas_zher2k = 142;
-
-    // BLAS extensions start here
-    private static final int RsBlas_bnnm = 1000;
-
-    /**
-     * Create an intrinsic to access BLAS subroutines.
-     *
-     * @param rs The RenderScript context
-     * @return ScriptIntrinsicBLAS
-     */
-    public static ScriptIntrinsicBLAS create(RenderScript rs) {
-        long id;
-        boolean mUseIncSupp = rs.isUseNative() &&
-                              android.os.Build.VERSION.SDK_INT < INTRINSIC_API_LEVEL;
-
-        id = rs.nScriptIntrinsicCreate(13, Element.U32(rs).getID(rs), mUseIncSupp);
-        ScriptIntrinsicBLAS si = new ScriptIntrinsicBLAS(id, rs);
-        si.setIncSupp(mUseIncSupp);
-        return si;
-    }
-
-    /**
-     * @hide
-     */
-    @IntDef({NO_TRANSPOSE, TRANSPOSE, CONJ_TRANSPOSE})
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface Transpose {}
-
-    /**
-     * @hide
-     */
-    @IntDef({UPPER, LOWER})
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface Uplo {}
-
-    /**
-     * @hide
-     */
-    @IntDef({NON_UNIT, UNIT})
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface Diag {}
-
-    /**
-     * @hide
-     */
-    @IntDef({LEFT, RIGHT})
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface Side {}
-
-    public static final int NO_TRANSPOSE = 111;
-    public static final int TRANSPOSE = 112;
-    public static final int CONJ_TRANSPOSE = 113;
-
-    public static final int UPPER = 121;
-    public static final int LOWER = 122;
-
-    public static final int NON_UNIT = 131;
-    public static final int UNIT = 132;
-
-    public static final int LEFT = 141;
-    public static final int RIGHT = 142;
-
-    static void validateSide(@Side int Side) {
-        if (Side != LEFT && Side != RIGHT) {
-            throw new RSRuntimeException("Invalid side passed to BLAS");
-        }
-    }
-
-    static void validateTranspose(@Transpose int Trans) {
-        if (Trans != NO_TRANSPOSE && Trans != TRANSPOSE &&
-            Trans != CONJ_TRANSPOSE) {
-            throw new RSRuntimeException("Invalid transpose passed to BLAS");
-        }
-    }
-
-    static void validateConjTranspose(@Transpose int Trans) {
-        if (Trans != NO_TRANSPOSE &&
-            Trans != CONJ_TRANSPOSE) {
-            throw new RSRuntimeException("Invalid transpose passed to BLAS");
-        }
-    }
-
-    static void validateDiag(@Diag int Diag) {
-        if (Diag != NON_UNIT && Diag != UNIT) {
-            throw new RSRuntimeException("Invalid diag passed to BLAS");
-        }
-    }
-
-    static void validateUplo(@Uplo int Uplo) {
-        if (Uplo != UPPER && Uplo != LOWER) {
-            throw new RSRuntimeException("Invalid uplo passed to BLAS");
-        }
-    }
-
-
-    /**
-     * Level 2 BLAS
-     */
-
-    static void validateGEMV(Element e, int TransA, Allocation A, Allocation X, int incX, Allocation Y, int incY) {
-        validateTranspose(TransA);
-        int M = A.getType().getY();
-        int N = A.getType().getX();
-        if (!A.getType().getElement().isCompatible(e) ||
-            !X.getType().getElement().isCompatible(e) ||
-            !Y.getType().getElement().isCompatible(e)) {
-            throw new RSRuntimeException("Called BLAS with wrong Element type");
-        }
-        if (X.getType().getY() > 1 || Y.getType().getY() > 1) {
-            throw new RSRuntimeException("BLAS vectors must have Y dimension of 0 or 1");
-        }
-
-        if (incX <= 0 || incY <= 0) {
-            throw new RSRuntimeException("Vector increments must be greater than 0");
-        }
-        int expectedXDim = -1, expectedYDim = -1;
-        if (TransA == NO_TRANSPOSE) {
-            expectedXDim = 1 + (N - 1) * incX;
-            expectedYDim = 1 + (M - 1) * incY;
-        } else {
-            expectedXDim = 1 + (M - 1) * incX;
-            expectedYDim = 1 + (N - 1) * incY;
-        }
-        if (X.getType().getX() != expectedXDim ||
-            Y.getType().getX() != expectedYDim) {
-            throw new RSRuntimeException("Incorrect vector dimensions for GEMV");
-        }
-    }
-
-    /**
-     * SGEMV performs one of the matrix-vector operations
-     * y := alpha*A*x + beta*y   or   y := alpha*A**T*x + beta*y
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/db/d58/sgemv_8f.html
-     *
-     * @param TransA The type of transpose applied to matrix A.
-     * @param alpha The scalar alpha.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32}.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F32}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     * @param beta The scalar beta.
-     * @param Y The input allocation contains vector y, supported elements type {@link Element#F32}.
-     * @param incY The increment for the elements of vector y, must be larger than zero.
-     */
-    public void SGEMV(@Transpose int TransA, float alpha, Allocation A, Allocation X, int incX, float beta, Allocation Y, int incY) {
-        validateGEMV(Element.F32(mRS), TransA, A, X, incX, Y, incY);
-        int M = A.getType().getY();
-        int N = A.getType().getX();
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long xID = X.getID(mRS);
-        long yID = Y.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            xID = getDummyAlloc(X);
-            yID = getDummyAlloc(Y);
-        }
-        mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_sgemv, TransA, 0, 0, 0, 0, M, N, 0, alpha, aID, xID, beta, yID, incX, incY, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * DGEMV performs one of the matrix-vector operations
-     * y := alpha*A*x + beta*y   or   y := alpha*A**T*x + beta*y
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/dc/da8/dgemv_8f.html
-     *
-     * @param TransA The type of transpose applied to matrix A.
-     * @param alpha The scalar alpha.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64}.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F64}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     * @param beta The scalar beta.
-     * @param Y The input allocation contains vector y, supported elements type {@link Element#F64}.
-     * @param incY The increment for the elements of vector y, must be larger than zero.
-     */
-    public void DGEMV(@Transpose int TransA, double alpha, Allocation A, Allocation X, int incX, double beta, Allocation Y, int incY) {
-        validateGEMV(Element.F64(mRS), TransA, A, X, incX, Y, incY);
-        int M = A.getType().getY();
-        int N = A.getType().getX();
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long xID = X.getID(mRS);
-        long yID = Y.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            xID = getDummyAlloc(X);
-            yID = getDummyAlloc(Y);
-        }
-        mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dgemv, TransA, 0, 0, 0, 0, M, N, 0, alpha, aID, xID, beta, yID, incX, incY, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * CGEMV performs one of the matrix-vector operations
-     * y := alpha*A*x + beta*y   or   y := alpha*A**T*x + beta*y   or   y := alpha*A**H*x + beta*y
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d4/d8a/cgemv_8f.html
-     *
-     * @param TransA The type of transpose applied to matrix A.
-     * @param alpha The scalar alpha.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32_2}.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F32_2}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     * @param beta The scalar beta.
-     * @param Y The input allocation contains vector y, supported elements type {@link Element#F32_2}.
-     * @param incY The increment for the elements of vector y, must be larger than zero.
-     */
-    public void CGEMV(@Transpose int TransA, Float2 alpha, Allocation A, Allocation X, int incX, Float2 beta, Allocation Y, int incY) {
-        validateGEMV(Element.F32_2(mRS), TransA, A, X, incX, Y, incY);
-        int M = A.getType().getY();
-        int N = A.getType().getX();
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long xID = X.getID(mRS);
-        long yID = Y.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            xID = getDummyAlloc(X);
-            yID = getDummyAlloc(Y);
-        }
-        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_cgemv, TransA, 0, 0, 0, 0, M, N, 0, alpha.x, alpha.y, aID, xID, beta.x, beta.y, yID, incX, incY, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * ZGEMV performs one of the matrix-vector operations
-     * y := alpha*A*x + beta*y   or   y := alpha*A**T*x + beta*y   or   y := alpha*A**H*x + beta*y
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/db/d40/zgemv_8f.html
-     *
-     * @param TransA The type of transpose applied to matrix A.
-     * @param alpha The scalar alpha.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64_2}.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F64_2}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     * @param beta The scalar beta.
-     * @param Y The input allocation contains vector y, supported elements type {@link Element#F64_2}.
-     * @param incY The increment for the elements of vector y, must be larger than zero.
-     */
-    public void ZGEMV(@Transpose int TransA, Double2 alpha, Allocation A, Allocation X, int incX, Double2 beta, Allocation Y, int incY) {
-        validateGEMV(Element.F64_2(mRS), TransA, A, X, incX, Y, incY);
-        int M = A.getType().getY();
-        int N = A.getType().getX();
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long xID = X.getID(mRS);
-        long yID = Y.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            xID = getDummyAlloc(X);
-            yID = getDummyAlloc(Y);
-        }
-        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_zgemv, TransA, 0, 0, 0, 0, M, N, 0, alpha.x, alpha.y, aID, xID, beta.x, beta.y, yID, incX, incY, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * SGBMV performs one of the matrix-vector operations
-     * y := alpha*A*x + beta*y   or   y := alpha*A**T*x + beta*y
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d6/d46/sgbmv_8f.html
-     *
-     * Note: For a M*N matrix, the input Allocation should also be of size M*N (dimY = M, dimX = N),
-     *       but only the region M*(KL+KU+1) will be referenced. The following subroutine can is an
-     *       example showing how to convert the original matrix 'a' to row-based band matrix 'b'.
-     *           for i in range(0, m):
-     *              for j in range(max(0, i-kl), min(i+ku+1, n)):
-     *                  b[i, j-i+kl] = a[i, j]
-     *
-     * @param TransA The type of transpose applied to matrix A.
-     * @param KL The number of sub-diagonals of the matrix A.
-     * @param KU The number of super-diagonals of the matrix A.
-     * @param alpha The scalar alpha.
-     * @param A The input allocation contains the band matrix A, supported elements type {@link Element#F32}.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F32}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     * @param beta The scalar beta.
-     * @param Y The input allocation contains vector y, supported elements type {@link Element#F32}.
-     * @param incY The increment for the elements of vector y, must be larger than zero.
-     */
-    public void SGBMV(@Transpose int TransA, int KL, int KU, float alpha, Allocation A, Allocation X, int incX, float beta, Allocation Y, int incY) {
-        // GBMV has the same validation requirements as GEMV + KL and KU >= 0
-        validateGEMV(Element.F32(mRS), TransA, A, X, incX, Y, incY);
-        if (KL < 0 || KU < 0) {
-            throw new RSRuntimeException("KL and KU must be greater than or equal to 0");
-        }
-        int M = A.getType().getY();
-        int N = A.getType().getX();
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long xID = X.getID(mRS);
-        long yID = Y.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            xID = getDummyAlloc(X);
-            yID = getDummyAlloc(Y);
-        }
-        mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_sgbmv, TransA, 0, 0, 0, 0, M, N, 0, alpha, aID, xID, beta, yID, incX, incY, KL, KU, mUseIncSupp);
-    }
-
-    /**
-     * DGBMV performs one of the matrix-vector operations
-     * y := alpha*A*x + beta*y   or   y := alpha*A**T*x + beta*y
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d2/d3f/dgbmv_8f.html
-     *
-     * Note: For a M*N matrix, the input Allocation should also be of size M*N (dimY = M, dimX = N),
-     *       but only the region M*(KL+KU+1) will be referenced. The following subroutine can is an
-     *       example showing how to convert the original matrix 'a' to row-based band matrix 'b'.
-     *           for i in range(0, m):
-     *              for j in range(max(0, i-kl), min(i+ku+1, n)):
-     *                  b[i, j-i+kl] = a[i, j]
-     *
-     * @param TransA The type of transpose applied to matrix A.
-     * @param KL The number of sub-diagonals of the matrix A.
-     * @param KU The number of super-diagonals of the matrix A.
-     * @param alpha The scalar alpha.
-     * @param A The input allocation contains the band matrix A, supported elements type {@link Element#F64}.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F64}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     * @param beta The scalar beta.
-     * @param Y The input allocation contains vector y, supported elements type {@link Element#F64}.
-     * @param incY The increment for the elements of vector y, must be larger than zero.
-     */
-    public void DGBMV(@Transpose int TransA, int KL, int KU, double alpha, Allocation A, Allocation X, int incX, double beta, Allocation Y, int incY) {
-        // GBMV has the same validation requirements as GEMV + KL and KU >= 0
-        validateGEMV(Element.F64(mRS), TransA, A, X, incX, Y, incY);
-        if (KL < 0 || KU < 0) {
-            throw new RSRuntimeException("KL and KU must be greater than or equal to 0");
-        }
-        int M = A.getType().getY();
-        int N = A.getType().getX();
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long xID = X.getID(mRS);
-        long yID = Y.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            xID = getDummyAlloc(X);
-            yID = getDummyAlloc(Y);
-        }
-        mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dgbmv, TransA, 0, 0, 0, 0, M, N, 0, alpha, aID, xID, beta, yID, incX, incY, KL, KU, mUseIncSupp);
-    }
-
-    /**
-     * CGBMV performs one of the matrix-vector operations
-     * y := alpha*A*x + beta*y   or   y := alpha*A**T*x + beta*y   or   y := alpha*A**H*x + beta*y
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d0/d75/cgbmv_8f.html
-     *
-     * Note: For a M*N matrix, the input Allocation should also be of size M*N (dimY = M, dimX = N),
-     *       but only the region M*(KL+KU+1) will be referenced. The following subroutine can is an
-     *       example showing how to convert the original matrix 'a' to row-based band matrix 'b'.
-     *           for i in range(0, m):
-     *              for j in range(max(0, i-kl), min(i+ku+1, n)):
-     *                  b[i, j-i+kl] = a[i, j]
-     *
-     * @param TransA The type of transpose applied to matrix A.
-     * @param KL The number of sub-diagonals of the matrix A.
-     * @param KU The number of super-diagonals of the matrix A.
-     * @param alpha The scalar alpha.
-     * @param A The input allocation contains the band matrix A, supported elements type {@link Element#F32_2}.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F32_2}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     * @param beta The scalar beta.
-     * @param Y The input allocation contains vector y, supported elements type {@link Element#F32_2}.
-     * @param incY The increment for the elements of vector y, must be larger than zero.
-     */
-    public void CGBMV(@Transpose int TransA, int KL, int KU, Float2 alpha, Allocation A, Allocation X, int incX, Float2 beta, Allocation Y, int incY) {
-        // GBMV has the same validation requirements as GEMV + KL and KU >= 0
-        validateGEMV(Element.F32_2(mRS), TransA, A, X, incX, Y, incY);
-        if (KL < 0 || KU < 0) {
-            throw new RSRuntimeException("KL and KU must be greater than or equal to 0");
-        }
-        int M = A.getType().getY();
-        int N = A.getType().getX();
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long xID = X.getID(mRS);
-        long yID = Y.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            xID = getDummyAlloc(X);
-            yID = getDummyAlloc(Y);
-        }
-        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_cgbmv, TransA, 0, 0, 0, 0, M, N, 0, alpha.x, alpha.y, aID, xID, beta.x, beta.y, yID, incX, incY, KL, KU, mUseIncSupp);
-    }
-
-    /**
-     * ZGBMV performs one of the matrix-vector operations
-     * y := alpha*A*x + beta*y   or   y := alpha*A**T*x + beta*y   or   y := alpha*A**H*x + beta*y
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d9/d46/zgbmv_8f.html
-     *
-     * Note: For a M*N matrix, the input Allocation should also be of size M*N (dimY = M, dimX = N),
-     *       but only the region M*(KL+KU+1) will be referenced. The following subroutine can is an
-     *       example showing how to convert the original matrix 'a' to row-based band matrix 'b'.
-     *           for i in range(0, m):
-     *              for j in range(max(0, i-kl), min(i+ku+1, n)):
-     *                  b[i, j-i+kl] = a[i, j]
-     *
-     * @param TransA The type of transpose applied to matrix A.
-     * @param KL The number of sub-diagonals of the matrix A.
-     * @param KU The number of super-diagonals of the matrix A.
-     * @param alpha The scalar alpha.
-     * @param A The input allocation contains the band matrix A, supported elements type {@link Element#F64_2}.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F64_2}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     * @param beta The scalar beta.
-     * @param Y The input allocation contains vector y, supported elements type {@link Element#F64_2}.
-     * @param incY The increment for the elements of vector y, must be larger than zero.
-     */
-    public void ZGBMV(@Transpose int TransA, int KL, int KU, Double2 alpha, Allocation A, Allocation X, int incX, Double2 beta, Allocation Y, int incY) {
-        // GBMV has the same validation requirements as GEMV + KL and KU >= 0
-        validateGEMV(Element.F64_2(mRS), TransA, A, X, incX, Y, incY);
-        if (KL < 0 || KU < 0) {
-            throw new RSRuntimeException("KL and KU must be greater than or equal to 0");
-        }
-        int M = A.getType().getY();
-        int N = A.getType().getX();
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long xID = X.getID(mRS);
-        long yID = Y.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            xID = getDummyAlloc(X);
-            yID = getDummyAlloc(Y);
-        }
-        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_zgbmv, TransA, 0, 0, 0, 0, M, N, 0, alpha.x, alpha.y, aID, xID, beta.x, beta.y, yID, incX, incY, KL, KU, mUseIncSupp);
-    }
-
-    static void validateTRMV(Element e, @Uplo int Uplo, @Transpose int TransA, @Diag int Diag, Allocation A, Allocation X, int incX) {
-        validateTranspose(TransA);
-        validateUplo(Uplo);
-        validateDiag(Diag);
-        int N = A.getType().getY();
-        if (A.getType().getX() != N) {
-            throw new RSRuntimeException("A must be a square matrix for TRMV");
-        }
-        if (!A.getType().getElement().isCompatible(e) ||
-            !X.getType().getElement().isCompatible(e)) {
-            throw new RSRuntimeException("Called BLAS with wrong Element type");
-        }
-        if (X.getType().getY() > 1) {
-            throw new RSRuntimeException("BLAS vectors must have Y dimension of 0 or 1");
-        }
-
-        if (incX <= 0) {
-            throw new RSRuntimeException("Vector increments must be greater than 0");
-        }
-        int expectedXDim = 1 + (N - 1) * incX;
-        if (X.getType().getX() != expectedXDim) {
-            throw new RSRuntimeException("Incorrect vector dimensions for TRMV");
-        }
-    }
-
-    static int validateTPMV(Element e, @Uplo int Uplo, @Transpose int TransA, @Diag int Diag, Allocation Ap, Allocation X, int incX) {
-        validateTranspose(TransA);
-        validateUplo(Uplo);
-        validateDiag(Diag);
-        if (!Ap.getType().getElement().isCompatible(e) ||
-            !X.getType().getElement().isCompatible(e)) {
-            throw new RSRuntimeException("Called BLAS with wrong Element type");
-        }
-        if (X.getType().getY() > 1) {
-            throw new RSRuntimeException("BLAS vectors must have Y dimension of 0 or 1");
-        }
-
-        if (Ap.getType().getY() > 1) {
-            throw new RSRuntimeException("Ap must have a Y dimension of 0 or 1");
-        }
-
-        int N = (int)Math.sqrt((double)Ap.getType().getX() * 2);
-        //is it really doing anything?
-        if (Ap.getType().getX() != ((N * (N+1)) / 2)) {
-            throw new RSRuntimeException("Invalid dimension for Ap");
-        }
-        if (incX <= 0) {
-            throw new RSRuntimeException("Vector increments must be greater than 0");
-        }
-        int expectedXDim = 1 + (N - 1) * incX;
-        if (X.getType().getX() != expectedXDim) {
-            throw new RSRuntimeException("Incorrect vector dimensions for TPMV");
-        }
-
-        return N;
-    }
-
-    /**
-     * STRMV performs one of the matrix-vector operations
-     * x := A*x   or   x := A**T*x
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/de/d45/strmv_8f.html
-     *
-     * @param Uplo Specifies whether the matrix is an upper or lower triangular matrix.
-     * @param TransA The type of transpose applied to matrix A.
-     * @param Diag Specifies whether or not A is unit triangular.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32}.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F32}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     */
-    public void STRMV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag, Allocation A, Allocation X, int incX) {
-        validateTRMV(Element.F32(mRS), Uplo, TransA, Diag, A, X, incX);
-        int N = A.getType().getY();
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long xID = X.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            xID = getDummyAlloc(X);
-        }
-        mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_strmv, TransA, 0, 0, Uplo, Diag, 0, N, 0, 0, aID, xID, 0, 0, incX, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * DTRMV performs one of the matrix-vector operations
-     * x := A*x   or   x := A**T*x
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/dc/d7e/dtrmv_8f.html
-     *
-     * @param Uplo Specifies whether the matrix is an upper or lower triangular matrix.
-     * @param TransA The type of transpose applied to matrix A.
-     * @param Diag Specifies whether or not A is unit triangular.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64}.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F64}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     */
-    public void DTRMV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag, Allocation A, Allocation X, int incX) {
-        validateTRMV(Element.F64(mRS), Uplo, TransA, Diag, A, X, incX);
-        int N = A.getType().getY();
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long xID = X.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            xID = getDummyAlloc(X);
-        }
-        mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dtrmv, TransA, 0, 0, Uplo, Diag, 0, N, 0, 0, aID, xID, 0, 0, incX, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * CTRMV performs one of the matrix-vector operations
-     * x := A*x   or   x := A**T*x   or   x := A**H*x
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/df/d78/ctrmv_8f.html
-     *
-     * @param Uplo Specifies whether the matrix is an upper or lower triangular matrix.
-     * @param TransA The type of transpose applied to matrix A.
-     * @param Diag Specifies whether or not A is unit triangular.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32_2}.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F32_2}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     */
-    public void CTRMV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag, Allocation A, Allocation X, int incX) {
-        validateTRMV(Element.F32_2(mRS), Uplo, TransA, Diag, A, X, incX);
-        int N = A.getType().getY();
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long xID = X.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            xID = getDummyAlloc(X);
-        }
-        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_ctrmv, TransA, 0, 0, Uplo, Diag, 0, N, 0, 0, 0, aID, xID, 0, 0, 0, incX, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * ZTRMV performs one of the matrix-vector operations
-     * x := A*x   or   x := A**T*x   or   x := A**H*x
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d0/dd1/ztrmv_8f.html
-     *
-     * @param Uplo Specifies whether the matrix is an upper or lower triangular matrix.
-     * @param TransA The type of transpose applied to matrix A.
-     * @param Diag Specifies whether or not A is unit triangular.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64_2}.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F64_2}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     */
-    public void ZTRMV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag, Allocation A, Allocation X, int incX) {
-        validateTRMV(Element.F64_2(mRS), Uplo, TransA, Diag, A, X, incX);
-        int N = A.getType().getY();
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long xID = X.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            xID = getDummyAlloc(X);
-        }
-        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_ztrmv, TransA, 0, 0, Uplo, Diag, 0, N, 0, 0, 0, aID, xID, 0, 0, 0, incX, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * STBMV performs one of the matrix-vector operations
-     * x := A*x   or   x := A**T*x
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d6/d7d/stbmv_8f.html
-     *
-     * Note: For a N*N matrix, the input Allocation should also be of size N*N (dimY = N, dimX = N),
-     *       but only the region N*(K+1) will be referenced. The following subroutine can is an
-     *       example showing how to convert a UPPER trianglar matrix 'a' to row-based band matrix 'b'.
-     *           for i in range(0, n):
-     *              for j in range(i, min(i+k+1, n)):
-     *                  b[i, j-i] = a[i, j]
-     *
-     * @param Uplo Specifies whether the matrix is an upper or lower triangular matrix.
-     * @param TransA The type of transpose applied to matrix A.
-     * @param Diag Specifies whether or not A is unit triangular.
-     * @param K The number of off-diagonals of the matrix A
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32}.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F32}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     */
-    public void STBMV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  int K, Allocation A,  Allocation X,  int incX) {
-        // TBMV has the same requirements as TRMV + K >= 0
-        if (K < 0) {
-            throw new RSRuntimeException("K must be greater than or equal to 0");
-        }
-        validateTRMV(Element.F32(mRS), Uplo, TransA, Diag, A, X, incX);
-        int N = A.getType().getY();
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long xID = X.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            xID = getDummyAlloc(X);
-        }
-        mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_stbmv, TransA, 0, 0, Uplo, Diag, 0, N, K, 0, aID, xID, 0, 0, incX, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * DTBMV performs one of the matrix-vector operations
-     * x := A*x   or   x := A**T*x
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/df/d29/dtbmv_8f.html
-     *
-     * Note: For a N*N matrix, the input Allocation should also be of size N*N (dimY = N, dimX = N),
-     *       but only the region N*(K+1) will be referenced. The following subroutine can is an
-     *       example showing how to convert a UPPER trianglar matrix 'a' to row-based band matrix 'b'.
-     *           for i in range(0, n):
-     *              for j in range(i, min(i+k+1, n)):
-     *                  b[i, j-i] = a[i, j]
-     *
-     * @param Uplo Specifies whether the matrix is an upper or lower triangular matrix.
-     * @param TransA The type of transpose applied to matrix A.
-     * @param Diag Specifies whether or not A is unit triangular.
-     * @param K The number of off-diagonals of the matrix A
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64}.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F64}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     */
-    public void DTBMV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  int K, Allocation A,  Allocation X,  int incX) {
-        // TBMV has the same requirements as TRMV + K >= 0
-        if (K < 0) {
-            throw new RSRuntimeException("K must be greater than or equal to 0");
-        }
-        validateTRMV(Element.F64(mRS), Uplo, TransA, Diag, A, X, incX);
-        int N = A.getType().getY();
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long xID = X.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            xID = getDummyAlloc(X);
-        }
-        mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dtbmv, TransA, 0, 0, Uplo, Diag, 0, N, K, 0, aID, xID, 0, 0, incX, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * CTBMV performs one of the matrix-vector operations
-     * x := A*x   or   x := A**T*x   or   x := A**H*x
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d3/dcd/ctbmv_8f.html
-     *
-     * Note: For a N*N matrix, the input Allocation should also be of size N*N (dimY = N, dimX = N),
-     *       but only the region N*(K+1) will be referenced. The following subroutine can is an
-     *       example showing how to convert a UPPER trianglar matrix 'a' to row-based band matrix 'b'.
-     *           for i in range(0, n):
-     *              for j in range(i, min(i+k+1, n)):
-     *                  b[i, j-i] = a[i, j]
-     *
-     * @param Uplo Specifies whether the matrix is an upper or lower triangular matrix.
-     * @param TransA The type of transpose applied to matrix A.
-     * @param Diag Specifies whether or not A is unit triangular.
-     * @param K The number of off-diagonals of the matrix A
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32_2}.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F32_2}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     */
-    public void CTBMV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  int K, Allocation A,  Allocation X,  int incX) {
-        // TBMV has the same requirements as TRMV + K >= 0
-        if (K < 0) {
-            throw new RSRuntimeException("K must be greater than or equal to 0");
-        }
-        validateTRMV(Element.F32_2(mRS), Uplo, TransA, Diag, A, X, incX);
-        int N = A.getType().getY();
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long xID = X.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            xID = getDummyAlloc(X);
-        }
-        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_ctbmv, TransA, 0, 0, Uplo, Diag, 0, N, K, 0, 0, aID, xID, 0, 0, 0, incX, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * ZTBMV performs one of the matrix-vector operations
-     * x := A*x   or   x := A**T*x   or   x := A**H*x
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d3/d39/ztbmv_8f.html
-     *
-     * Note: For a N*N matrix, the input Allocation should also be of size N*N (dimY = N, dimX = N),
-     *       but only the region N*(K+1) will be referenced. The following subroutine can is an
-     *       example showing how to convert a UPPER trianglar matrix 'a' to row-based band matrix 'b'.
-     *           for i in range(0, n):
-     *              for j in range(i, min(i+k+1, n)):
-     *                  b[i, j-i] = a[i, j]
-     *
-     * @param Uplo Specifies whether the matrix is an upper or lower triangular matrix.
-     * @param TransA The type of transpose applied to matrix A.
-     * @param Diag Specifies whether or not A is unit triangular.
-     * @param K The number of off-diagonals of the matrix A
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64_2}.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F64_2}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     */
-    public void ZTBMV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  int K, Allocation A,  Allocation X,  int incX) {
-        // TBMV has the same requirements as TRMV + K >= 0
-        if (K < 0) {
-            throw new RSRuntimeException("K must be greater than or equal to 0");
-        }
-        validateTRMV(Element.F64_2(mRS), Uplo, TransA, Diag, A, X, incX);
-        int N = A.getType().getY();
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long xID = X.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            xID = getDummyAlloc(X);
-        }
-        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_ztbmv, TransA, 0, 0, Uplo, Diag, 0, N, K, 0, 0, aID, xID, 0, 0, 0, incX, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * STPMV performs one of the matrix-vector operations
-     * x := A*x   or   x := A**T*x
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/db/db1/stpmv_8f.html
-     *
-     * Note: For a N*N matrix, the input Allocation should be a 1D allocation of size dimX = N*(N+1)/2,
-     *       The following subroutine can is an example showing how to convert a UPPER trianglar matrix
-     *       'a' to packed matrix 'b'.
-     *           k = 0
-     *           for i in range(0, n):
-     *              for j in range(i, n):
-     *                  b[k++] = a[i, j]
-     *
-     * @param Uplo Specifies whether the matrix is an upper or lower triangular matrix.
-     * @param TransA The type of transpose applied to matrix A.
-     * @param Diag Specifies whether or not A is unit triangular.
-     * @param Ap The input allocation contains packed matrix A, supported elements type {@link Element#F32}.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F32}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     */
-    public void STPMV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  Allocation Ap,  Allocation X,  int incX) {
-        int N = validateTPMV(Element.F32(mRS), Uplo, TransA, Diag, Ap, X, incX);
-
-        boolean mUseIncSupp = isIncSupp();
-        long apID = Ap.getID(mRS);
-        long xID = X.getID(mRS);
-        if (mUseIncSupp) {
-            apID = getDummyAlloc(Ap);
-            xID = getDummyAlloc(X);
-        }
-        mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_stpmv, TransA, 0, 0, Uplo, Diag, 0, N, 0, 0, apID, xID, 0, 0, incX, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * DTPMV performs one of the matrix-vector operations
-     * x := A*x   or   x := A**T*x
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/dc/dcd/dtpmv_8f.html
-     *
-     * Note: For a N*N matrix, the input Allocation should be a 1D allocation of size dimX = N*(N+1)/2,
-     *       The following subroutine can is an example showing how to convert a UPPER trianglar matrix
-     *       'a' to packed matrix 'b'.
-     *           k = 0
-     *           for i in range(0, n):
-     *              for j in range(i, n):
-     *                  b[k++] = a[i, j]
-     *
-     * @param Uplo Specifies whether the matrix is an upper or lower triangular matrix.
-     * @param TransA The type of transpose applied to matrix A.
-     * @param Diag Specifies whether or not A is unit triangular.
-     * @param Ap The input allocation contains packed matrix A, supported elements type {@link Element#F64}.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F64}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     */
-    public void DTPMV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  Allocation Ap,  Allocation X,  int incX) {
-        int N = validateTPMV(Element.F64(mRS), Uplo, TransA, Diag, Ap, X, incX);
-
-        boolean mUseIncSupp = isIncSupp();
-        long apID = Ap.getID(mRS);
-        long xID = X.getID(mRS);
-        if (mUseIncSupp) {
-            apID = getDummyAlloc(Ap);
-            xID = getDummyAlloc(X);
-        }
-        mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dtpmv, TransA, 0, 0, Uplo, Diag, 0, N, 0, 0, apID, xID, 0, 0, incX, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * CTPMV performs one of the matrix-vector operations
-     * x := A*x   or   x := A**T*x   or   x := A**H*x
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d4/dbb/ctpmv_8f.html
-     *
-     * Note: For a N*N matrix, the input Allocation should be a 1D allocation of size dimX = N*(N+1)/2,
-     *       The following subroutine can is an example showing how to convert a UPPER trianglar matrix
-     *       'a' to packed matrix 'b'.
-     *           k = 0
-     *           for i in range(0, n):
-     *              for j in range(i, n):
-     *                  b[k++] = a[i, j]
-     *
-     * @param Uplo Specifies whether the matrix is an upper or lower triangular matrix.
-     * @param TransA The type of transpose applied to matrix A.
-     * @param Diag Specifies whether or not A is unit triangular.
-     * @param Ap The input allocation contains packed matrix A, supported elements type {@link Element#F32_2}.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F32_2}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     */
-    public void CTPMV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  Allocation Ap,  Allocation X,  int incX) {
-        int N = validateTPMV(Element.F32_2(mRS), Uplo, TransA, Diag, Ap, X, incX);
-
-        boolean mUseIncSupp = isIncSupp();
-        long apID = Ap.getID(mRS);
-        long xID = X.getID(mRS);
-        if (mUseIncSupp) {
-            apID = getDummyAlloc(Ap);
-            xID = getDummyAlloc(X);
-        }
-        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_ctpmv, TransA, 0, 0, Uplo, Diag, 0, N, 0, 0, 0, apID, xID, 0, 0, 0, incX, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * ZTPMV performs one of the matrix-vector operations
-     * x := A*x   or   x := A**T*x   or   x := A**H*x
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d2/d9e/ztpmv_8f.html
-     *
-     * Note: For a N*N matrix, the input Allocation should be a 1D allocation of size dimX = N*(N+1)/2,
-     *       The following subroutine can is an example showing how to convert a UPPER trianglar matrix
-     *       'a' to packed matrix 'b'.
-     *           k = 0
-     *           for i in range(0, n):
-     *              for j in range(i, n):
-     *                  b[k++] = a[i, j]
-     *
-     * @param Uplo Specifies whether the matrix is an upper or lower triangular matrix.
-     * @param TransA The type of transpose applied to matrix A.
-     * @param Diag Specifies whether or not A is unit triangular.
-     * @param Ap The input allocation contains packed matrix A, supported elements type {@link Element#F64_2}.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F64_2}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     */
-    public void ZTPMV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  Allocation Ap,  Allocation X,  int incX) {
-        int N = validateTPMV(Element.F64_2(mRS), Uplo, TransA, Diag, Ap, X, incX);
-
-        boolean mUseIncSupp = isIncSupp();
-        long apID = Ap.getID(mRS);
-        long xID = X.getID(mRS);
-        if (mUseIncSupp) {
-            apID = getDummyAlloc(Ap);
-            xID = getDummyAlloc(X);
-        }
-        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_ztpmv, TransA, 0, 0, Uplo, Diag, 0, N, 0, 0, 0, apID, xID, 0, 0, 0, incX, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * STRSV solves one of the systems of equations
-     * A*x = b   or   A**T*x = b
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d0/d2a/strsv_8f.html
-     *
-     * @param Uplo Specifies whether the matrix is an upper or lower triangular matrix.
-     * @param TransA The type of transpose applied to matrix A.
-     * @param Diag Specifies whether or not A is unit triangular.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32}.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F32}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     */
-    public void STRSV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  Allocation A,  Allocation X,  int incX) {
-        // TRSV is the same as TRMV
-        validateTRMV(Element.F32(mRS), Uplo, TransA, Diag, A, X, incX);
-        int N = A.getType().getY();
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long xID = X.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            xID = getDummyAlloc(X);
-        }
-        mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_strsv, TransA, 0, 0, Uplo, Diag, 0, N, 0, 0, aID, xID, 0, 0, incX, 0, 0, 0, mUseIncSupp);
-
-    }
-
-    /**
-     * DTRSV solves one of the systems of equations
-     * A*x = b   or   A**T*x = b
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d6/d96/dtrsv_8f.html
-     *
-     * @param Uplo Specifies whether the matrix is an upper or lower triangular matrix.
-     * @param TransA The type of transpose applied to matrix A.
-     * @param Diag Specifies whether or not A is unit triangular.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64}.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F64}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     */
-    public void DTRSV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  Allocation A,  Allocation X,  int incX) {
-        // TRSV is the same as TRMV
-        validateTRMV(Element.F64(mRS), Uplo, TransA, Diag, A, X, incX);
-        int N = A.getType().getY();
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long xID = X.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            xID = getDummyAlloc(X);
-        }
-        mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dtrsv, TransA, 0, 0, Uplo, Diag, 0, N, 0, 0, aID, xID, 0, 0, incX, 0, 0, 0, mUseIncSupp);
-
-    }
-
-    /**
-     * CTRSV solves one of the systems of equations
-     * A*x = b   or   A**T*x = b   or   A**H*x = b
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d4/dc8/ctrsv_8f.html
-     *
-     * @param Uplo Specifies whether the matrix is an upper or lower triangular matrix.
-     * @param TransA The type of transpose applied to matrix A.
-     * @param Diag Specifies whether or not A is unit triangular.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32_2}.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F32_2}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     */
-    public void CTRSV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  Allocation A,  Allocation X,  int incX) {
-        // TRSV is the same as TRMV
-        validateTRMV(Element.F32_2(mRS), Uplo, TransA, Diag, A, X, incX);
-        int N = A.getType().getY();
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long xID = X.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            xID = getDummyAlloc(X);
-        }
-        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_ctrsv, TransA, 0, 0, Uplo, Diag, 0, N, 0, 0, 0, aID, xID, 0, 0, 0, incX, 0, 0, 0, mUseIncSupp);
-
-    }
-
-    /**
-     * ZTRSV solves one of the systems of equations
-     * A*x = b   or   A**T*x = b   or   A**H*x = b
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d1/d2f/ztrsv_8f.html
-     *
-     * @param Uplo Specifies whether the matrix is an upper or lower triangular matrix.
-     * @param TransA The type of transpose applied to matrix A.
-     * @param Diag Specifies whether or not A is unit triangular.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64_2}.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F64_2}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     */
-    public void ZTRSV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  Allocation A,  Allocation X,  int incX) {
-        // TRSV is the same as TRMV
-        validateTRMV(Element.F64_2(mRS), Uplo, TransA, Diag, A, X, incX);
-        int N = A.getType().getY();
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long xID = X.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            xID = getDummyAlloc(X);
-        }
-        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_ztrsv, TransA, 0, 0, Uplo, Diag, 0, N, 0, 0, 0, aID, xID, 0, 0, 0, incX, 0, 0, 0, mUseIncSupp);
-
-    }
-
-    /**
-     * STBSV solves one of the systems of equations
-     * A*x = b   or   A**T*x = b
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d0/d1f/stbsv_8f.html
-     *
-     * Note: For a N*N matrix, the input Allocation should also be of size N*N (dimY = N, dimX = N),
-     *       but only the region N*(K+1) will be referenced. The following subroutine can is an
-     *       example showing how to convert a UPPER trianglar matrix 'a' to row-based band matrix 'b'.
-     *           for i in range(0, n):
-     *              for j in range(i, min(i+k+1, n)):
-     *                  b[i, j-i] = a[i, j]
-     *
-     * @param Uplo Specifies whether the matrix is an upper or lower triangular matrix.
-     * @param TransA The type of transpose applied to matrix A.
-     * @param Diag Specifies whether or not A is unit triangular.
-     * @param K The number of off-diagonals of the matrix A
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32}.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F32}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     */
-    public void STBSV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  int K, Allocation A,  Allocation X,  int incX) {
-        // TBSV is the same as TRMV + K >= 0
-        validateTRMV(Element.F32(mRS), Uplo, TransA, Diag, A, X, incX);
-        int N = A.getType().getY();
-        if (K < 0) {
-            throw new RSRuntimeException("Number of diagonals must be positive");
-        }
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long xID = X.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            xID = getDummyAlloc(X);
-        }
-        mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_stbsv, TransA, 0, 0, Uplo, Diag, 0, N, K, 0, aID, xID, 0, 0, incX, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * DTBSV solves one of the systems of equations
-     * A*x = b   or   A**T*x = b
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d4/dcf/dtbsv_8f.html
-     *
-     * Note: For a N*N matrix, the input Allocation should also be of size N*N (dimY = N, dimX = N),
-     *       but only the region N*(K+1) will be referenced. The following subroutine can is an
-     *       example showing how to convert a UPPER trianglar matrix 'a' to row-based band matrix 'b'.
-     *           for i in range(0, n):
-     *              for j in range(i, min(i+k+1, n)):
-     *                  b[i, j-i] = a[i, j]
-     *
-     * @param Uplo Specifies whether the matrix is an upper or lower triangular matrix.
-     * @param TransA The type of transpose applied to matrix A.
-     * @param Diag Specifies whether or not A is unit triangular.
-     * @param K The number of off-diagonals of the matrix A
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64}.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F64}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     */
-    public void DTBSV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  int K, Allocation A,  Allocation X,  int incX) {
-        // TBSV is the same as TRMV + K >= 0
-        validateTRMV(Element.F64(mRS), Uplo, TransA, Diag, A, X, incX);
-        int N = A.getType().getY();
-        if (K < 0) {
-            throw new RSRuntimeException("Number of diagonals must be positive");
-        }
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long xID = X.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            xID = getDummyAlloc(X);
-        }
-        mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dtbsv, TransA, 0, 0, Uplo, Diag, 0, N, K, 0, aID, xID, 0, 0, incX, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * CTBSV solves one of the systems of equations
-     * A*x = b   or   A**T*x = b   or   A**H*x = b
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d9/d5f/ctbsv_8f.html
-     *
-     * Note: For a N*N matrix, the input Allocation should also be of size N*N (dimY = N, dimX = N),
-     *       but only the region N*(K+1) will be referenced. The following subroutine can is an
-     *       example showing how to convert a UPPER trianglar matrix 'a' to row-based band matrix 'b'.
-     *           for i in range(0, n):
-     *              for j in range(i, min(i+k+1, n)):
-     *                  b[i, j-i] = a[i, j]
-     *
-     * @param Uplo Specifies whether the matrix is an upper or lower triangular matrix.
-     * @param TransA The type of transpose applied to matrix A.
-     * @param Diag Specifies whether or not A is unit triangular.
-     * @param K The number of off-diagonals of the matrix A
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32_2}.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F32_2}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     */
-    public void CTBSV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  int K, Allocation A,  Allocation X,  int incX) {
-        // TBSV is the same as TRMV + K >= 0
-        validateTRMV(Element.F32_2(mRS), Uplo, TransA, Diag, A, X, incX);
-        int N = A.getType().getY();
-        if (K < 0) {
-            throw new RSRuntimeException("Number of diagonals must be positive");
-        }
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long xID = X.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            xID = getDummyAlloc(X);
-        }
-        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_ctbsv, TransA, 0, 0, Uplo, Diag, 0, N, K, 0, 0, aID, xID, 0, 0, 0, incX, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * ZTBSV solves one of the systems of equations
-     * A*x = b   or   A**T*x = b   or   A**H*x = b
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d4/d5a/ztbsv_8f.html
-     *
-     * Note: For a N*N matrix, the input Allocation should also be of size N*N (dimY = N, dimX = N),
-     *       but only the region N*(K+1) will be referenced. The following subroutine can is an
-     *       example showing how to convert a UPPER trianglar matrix 'a' to row-based band matrix 'b'.
-     *           for i in range(0, n):
-     *              for j in range(i, min(i+k+1, n)):
-     *                  b[i, j-i] = a[i, j]
-     *
-     * @param Uplo Specifies whether the matrix is an upper or lower triangular matrix.
-     * @param TransA The type of transpose applied to matrix A.
-     * @param Diag Specifies whether or not A is unit triangular.
-     * @param K The number of off-diagonals of the matrix A
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64_2}.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F64_2}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     */
-    public void ZTBSV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  int K, Allocation A,  Allocation X,  int incX) {
-        // TBSV is the same as TRMV + K >= 0
-        validateTRMV(Element.F64_2(mRS), Uplo, TransA, Diag, A, X, incX);
-        int N = A.getType().getY();
-        if (K < 0) {
-            throw new RSRuntimeException("Number of diagonals must be positive");
-        }
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long xID = X.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            xID = getDummyAlloc(X);
-        }
-        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_ztbsv, TransA, 0, 0, Uplo, Diag, 0, N, K, 0, 0, aID, xID, 0, 0, 0, incX, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * STPSV solves one of the systems of equations
-     * A*x = b   or   A**T*x = b
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d0/d7c/stpsv_8f.html
-     *
-     * Note: For a N*N matrix, the input Allocation should be a 1D allocation of size dimX = N*(N+1)/2,
-     *       The following subroutine can is an example showing how to convert a UPPER trianglar matrix
-     *       'a' to packed matrix 'b'.
-     *           k = 0
-     *           for i in range(0, n):
-     *              for j in range(i, n):
-     *                  b[k++] = a[i, j]
-     *
-     * @param Uplo Specifies whether the matrix is an upper or lower triangular matrix.
-     * @param TransA The type of transpose applied to matrix A.
-     * @param Diag Specifies whether or not A is unit triangular.
-     * @param Ap The input allocation contains packed matrix A, supported elements type {@link Element#F32}.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F32}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     */
-    public void STPSV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  Allocation Ap,  Allocation X,  int incX) {
-        // TPSV is same as TPMV
-        int N = validateTPMV(Element.F32(mRS), Uplo, TransA, Diag, Ap, X, incX);
-
-        boolean mUseIncSupp = isIncSupp();
-        long apID = Ap.getID(mRS);
-        long xID = X.getID(mRS);
-        if (mUseIncSupp) {
-            apID = getDummyAlloc(Ap);
-            xID = getDummyAlloc(X);
-        }
-        mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_stpsv, TransA, 0, 0, Uplo, Diag, 0, N, 0, 0, apID, xID, 0, 0, incX, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * DTPSV solves one of the systems of equations
-     * A*x = b   or   A**T*x = b
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d9/d84/dtpsv_8f.html
-     *
-     * Note: For a N*N matrix, the input Allocation should be a 1D allocation of size dimX = N*(N+1)/2,
-     *       The following subroutine can is an example showing how to convert a UPPER trianglar matrix
-     *       'a' to packed matrix 'b'.
-     *           k = 0
-     *           for i in range(0, n):
-     *              for j in range(i, n):
-     *                  b[k++] = a[i, j]
-     *
-     * @param Uplo Specifies whether the matrix is an upper or lower triangular matrix.
-     * @param TransA The type of transpose applied to matrix A.
-     * @param Diag Specifies whether or not A is unit triangular.
-     * @param Ap The input allocation contains packed matrix A, supported elements type {@link Element#F64}.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F64}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     */
-    public void DTPSV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  Allocation Ap,  Allocation X,  int incX) {
-        // TPSV is same as TPMV
-        int N = validateTPMV(Element.F64(mRS), Uplo, TransA, Diag, Ap, X, incX);
-
-        boolean mUseIncSupp = isIncSupp();
-        long apID = Ap.getID(mRS);
-        long xID = X.getID(mRS);
-        if (mUseIncSupp) {
-            apID = getDummyAlloc(Ap);
-            xID = getDummyAlloc(X);
-        }
-        mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dtpsv, TransA, 0, 0, Uplo, Diag, 0, N, 0, 0, apID, xID, 0, 0, incX, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * CTPSV solves one of the systems of equations
-     * A*x = b   or   A**T*x = b   or   A**H*x = b
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d8/d56/ctpsv_8f.html
-     *
-     * Note: For a N*N matrix, the input Allocation should be a 1D allocation of size dimX = N*(N+1)/2,
-     *       The following subroutine can is an example showing how to convert a UPPER trianglar matrix
-     *       'a' to packed matrix 'b'.
-     *           k = 0
-     *           for i in range(0, n):
-     *              for j in range(i, n):
-     *                  b[k++] = a[i, j]
-     *
-     * @param Uplo Specifies whether the matrix is an upper or lower triangular matrix.
-     * @param TransA The type of transpose applied to matrix A.
-     * @param Diag Specifies whether or not A is unit triangular.
-     * @param Ap The input allocation contains packed matrix A, supported elements type {@link Element#F32_2}.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F32_2}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     */
-    public void CTPSV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  Allocation Ap,  Allocation X,  int incX) {
-        // TPSV is same as TPMV
-        int N = validateTPMV(Element.F32_2(mRS), Uplo, TransA, Diag, Ap, X, incX);
-
-        boolean mUseIncSupp = isIncSupp();
-        long apID = Ap.getID(mRS);
-        long xID = X.getID(mRS);
-        if (mUseIncSupp) {
-            apID = getDummyAlloc(Ap);
-            xID = getDummyAlloc(X);
-        }
-        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_ctpsv, TransA, 0, 0, Uplo, Diag, 0, N, 0, 0, 0, apID, xID, 0, 0, 0, incX, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * ZTPSV solves one of the systems of equations
-     * A*x = b   or   A**T*x = b   or   A**H*x = b
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/da/d57/ztpsv_8f.html
-     *
-     * Note: For a N*N matrix, the input Allocation should be a 1D allocation of size dimX = N*(N+1)/2,
-     *       The following subroutine can is an example showing how to convert a UPPER trianglar matrix
-     *       'a' to packed matrix 'b'.
-     *           k = 0
-     *           for i in range(0, n):
-     *              for j in range(i, n):
-     *                  b[k++] = a[i, j]
-     *
-     * @param Uplo Specifies whether the matrix is an upper or lower triangular matrix.
-     * @param TransA The type of transpose applied to matrix A.
-     * @param Diag Specifies whether or not A is unit triangular.
-     * @param Ap The input allocation contains packed matrix A, supported elements type {@link Element#F64_2}.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F64_2}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     */
-    public void ZTPSV(@Uplo int Uplo, @Transpose int TransA, @Diag int Diag,  Allocation Ap,  Allocation X,  int incX) {
-        // TPSV is same as TPMV
-        int N = validateTPMV(Element.F64_2(mRS), Uplo, TransA, Diag, Ap, X, incX);
-
-        boolean mUseIncSupp = isIncSupp();
-        long apID = Ap.getID(mRS);
-        long xID = X.getID(mRS);
-        if (mUseIncSupp) {
-            apID = getDummyAlloc(Ap);
-            xID = getDummyAlloc(X);
-        }
-        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_ztpsv, TransA, 0, 0, Uplo, Diag, 0, N, 0, 0, 0, apID, xID, 0, 0, 0, incX, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * Level 2, S and D only
-     */
-    static int validateSYMV(Element e, @Uplo int Uplo, Allocation A, Allocation X, Allocation Y, int incX, int incY) {
-        validateUplo(Uplo);
-        int N = A.getType().getY();
-        if (A.getType().getX() != N) {
-            throw new RSRuntimeException("A must be a square matrix for SYMV");
-        }
-        if (!A.getType().getElement().isCompatible(e) ||
-            !X.getType().getElement().isCompatible(e) ||
-            !Y.getType().getElement().isCompatible(e) ) {
-            throw new RSRuntimeException("Called BLAS with wrong Element type");
-        }
-        if (X.getType().getY() > 1 || Y.getType().getY() > 1) {
-            throw new RSRuntimeException("BLAS vectors must have Y dimension of 0 or 1");
-        }
-
-        if (incX <= 0 || incY <= 0) {
-            throw new RSRuntimeException("Vector increments must be greater than 0");
-        }
-        int expectedXDim = 1 + (N - 1) * incX;
-        if (X.getType().getX() != expectedXDim) {
-            throw new RSRuntimeException("Incorrect vector dimensions for SYMV");
-        }
-        int expectedYDim = 1 + (N - 1) * incY;
-        if (Y.getType().getX() != expectedYDim) {
-            throw new RSRuntimeException("Incorrect vector dimensions for SYMV");
-        }
-        return N;
-    }
-    static int validateSPMV(Element e, @Uplo int Uplo, Allocation Ap, Allocation X, int incX, Allocation Y, int incY) {
-        validateUplo(Uplo);
-        if (!Ap.getType().getElement().isCompatible(e) ||
-            !X.getType().getElement().isCompatible(e) ||
-            !Y.getType().getElement().isCompatible(e)) {
-            throw new RSRuntimeException("Called BLAS with wrong Element type");
-        }
-        if (X.getType().getY() > 1 || Y.getType().getY() > 1) {
-            throw new RSRuntimeException("BLAS vectors must have Y dimension of 0 or 1");
-        }
-
-        if (Ap.getType().getY() > 1) {
-            throw new RSRuntimeException("Ap must have a Y dimension of 0 or 1");
-        }
-
-        int N = (int)Math.sqrt((double)Ap.getType().getX() * 2);
-        if (Ap.getType().getX() != ((N * (N+1)) / 2)) {
-            throw new RSRuntimeException("Invalid dimension for Ap");
-        }
-        if (incX <= 0 || incY <= 0) {
-            throw new RSRuntimeException("Vector increments must be greater than 0");
-        }
-        int expectedXDim = 1 + (N - 1) * incX;
-        if (X.getType().getX() != expectedXDim) {
-            throw new RSRuntimeException("Incorrect vector dimensions for SPMV");
-        }
-        int expectedYDim = 1 + (N - 1) * incY;
-        if (Y.getType().getX() != expectedYDim) {
-            throw new RSRuntimeException("Incorrect vector dimensions for SPMV");
-        }
-
-        return N;
-    }
-    static void validateGER(Element e, Allocation X, int incX, Allocation Y, int incY, Allocation A) {
-        if (!A.getType().getElement().isCompatible(e) ||
-            !X.getType().getElement().isCompatible(e) ||
-            !Y.getType().getElement().isCompatible(e) ) {
-            throw new RSRuntimeException("Called BLAS with wrong Element type");
-        }
-
-        if (X.getType().getY() > 1 || Y.getType().getY() > 1) {
-            throw new RSRuntimeException("BLAS vectors must have Y dimension of 0 or 1");
-        }
-
-        int M = A.getType().getY();
-        int N = A.getType().getX();
-
-        if (N < 1 || M < 1) {
-            throw new RSRuntimeException("M and N must be 1 or greater for GER");
-        }
-        if (incX <= 0 || incY <= 0) {
-            throw new RSRuntimeException("Vector increments must be greater than 0");
-        }
-        int expectedXDim = 1 + (M - 1) * incX;
-        if (X.getType().getX() != expectedXDim) {
-            throw new RSRuntimeException("Incorrect vector dimensions for GER");
-        }
-        int expectedYDim = 1 + (N - 1) * incY;
-        if (Y.getType().getX() != expectedYDim) {
-            throw new RSRuntimeException("Incorrect vector dimensions for GER");
-        }
-
-
-    }
-    static int validateSYR(Element e, @Uplo int Uplo, Allocation X, int incX, Allocation A) {
-        validateUplo(Uplo);
-        if (!A.getType().getElement().isCompatible(e) ||
-            !X.getType().getElement().isCompatible(e)) {
-            throw new RSRuntimeException("Called BLAS with wrong Element type");
-        }
-
-        int N = A.getType().getX();
-
-        if (X.getType().getY() > 1) {
-            throw new RSRuntimeException("BLAS vectors must have Y dimension of 0 or 1");
-        }
-        if (N != A.getType().getY()) {
-            throw new RSRuntimeException("A must be a symmetric matrix");
-        }
-        if (incX <= 0) {
-            throw new RSRuntimeException("Vector increments must be greater than 0");
-        }
-        int expectedXDim = 1 + (N - 1) * incX;
-        if (X.getType().getX() != expectedXDim) {
-            throw new RSRuntimeException("Incorrect vector dimensions for SYR");
-        }
-        return N;
-    }
-    static int validateSPR(Element e, @Uplo int Uplo, Allocation X, int incX, Allocation Ap) {
-        validateUplo(Uplo);
-        if (!Ap.getType().getElement().isCompatible(e) ||
-            !X.getType().getElement().isCompatible(e)) {
-            throw new RSRuntimeException("Called BLAS with wrong Element type");
-        }
-        if (X.getType().getY() > 1) {
-            throw new RSRuntimeException("BLAS vectors must have Y dimension of 0 or 1");
-        }
-
-        if (Ap.getType().getY() > 1) {
-            throw new RSRuntimeException("Ap must have a Y dimension of 0 or 1");
-        }
-
-        int N = (int)Math.sqrt((double)Ap.getType().getX() * 2);
-        if (Ap.getType().getX() != ((N * (N+1)) / 2)) {
-            throw new RSRuntimeException("Invalid dimension for Ap");
-        }
-        if (incX <= 0) {
-            throw new RSRuntimeException("Vector increments must be greater than 0");
-        }
-        int expectedXDim = 1 + (N - 1) * incX;
-        if (X.getType().getX() != expectedXDim) {
-            throw new RSRuntimeException("Incorrect vector dimensions for SPR");
-        }
-
-        return N;
-    }
-
-    static int validateSYR2(Element e, @Uplo int Uplo, Allocation X, int incX, Allocation Y, int incY, Allocation A) {
-        validateUplo(Uplo);
-        if (!A.getType().getElement().isCompatible(e) ||
-            !X.getType().getElement().isCompatible(e) ||
-            !Y.getType().getElement().isCompatible(e)) {
-            throw new RSRuntimeException("Called BLAS with wrong Element type");
-        }
-
-        if (X.getType().getY() > 1 || Y.getType().getY() > 1) {
-            throw new RSRuntimeException("BLAS vectors must have Y dimension of 0 or 1");
-        }
-
-        int N = A.getType().getX();
-
-        if (N != A.getType().getY()) {
-            throw new RSRuntimeException("A must be a symmetric matrix");
-        }
-        if (incX <= 0 || incY <= 0) {
-            throw new RSRuntimeException("Vector increments must be greater than 0");
-        }
-        int expectedXDim = 1 + (N - 1) * incX;
-        int expectedYDim = 1 + (N - 1) * incY;
-        if (X.getType().getX() != expectedXDim || Y.getType().getX() != expectedYDim) {
-            throw new RSRuntimeException("Incorrect vector dimensions for SYR");
-        }
-        return N;
-
-    }
-    static int validateSPR2(Element e, @Uplo int Uplo, Allocation X, int incX, Allocation Y, int incY, Allocation Ap) {
-        validateUplo(Uplo);
-        if (!Ap.getType().getElement().isCompatible(e) ||
-            !X.getType().getElement().isCompatible(e) ||
-            !Y.getType().getElement().isCompatible(e)) {
-            throw new RSRuntimeException("Called BLAS with wrong Element type");
-        }
-        if (X.getType().getY() > 1 || Y.getType().getY() > 1) {
-            throw new RSRuntimeException("BLAS vectors must have Y dimension of 0 or 1");
-        }
-
-        if (Ap.getType().getY() > 1) {
-            throw new RSRuntimeException("Ap must have a Y dimension of 0 or 1");
-        }
-
-        int N = (int)Math.sqrt((double)Ap.getType().getX() * 2);
-        if (Ap.getType().getX() != ((N * (N+1)) / 2)) {
-            throw new RSRuntimeException("Invalid dimension for Ap");
-        }
-        if (incX <= 0 || incY <= 0) {
-            throw new RSRuntimeException("Vector increments must be greater than 0");
-        }
-        int expectedXDim = 1 + (N - 1) * incX;
-        int expectedYDim = 1 + (N - 1) * incY;
-        if (X.getType().getX() != expectedXDim || Y.getType().getX() != expectedYDim) {
-            throw new RSRuntimeException("Incorrect vector dimensions for SPR2");
-        }
-
-        return N;
-    }
-
-    /**
-     * SSYMV performs the matrix-vector operation
-     * y := alpha*A*x + beta*y
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d2/d94/ssymv_8f.html
-     *
-     * @param Uplo Specifies whether the upper or lower triangular part is to be referenced.
-     * @param alpha The scalar alpha.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32}.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F32}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     * @param beta The scalar beta.
-     * @param Y The input allocation contains vector y, supported elements type {@link Element#F32}.
-     * @param incY The increment for the elements of vector y, must be larger than zero.
-     */
-    public void SSYMV(@Uplo int Uplo, float alpha, Allocation A, Allocation X, int incX, float beta, Allocation Y, int incY) {
-        int N = validateSYMV(Element.F32(mRS), Uplo, A, X, Y, incX, incY);
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long xID = X.getID(mRS);
-        long yID = Y.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            xID = getDummyAlloc(X);
-            yID = getDummyAlloc(Y);
-        }
-        mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_ssymv, 0, 0, 0, Uplo, 0, 0, N, 0, alpha, aID, xID, beta, yID, incX, incY, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * SSBMV performs the matrix-vector operation
-     * y := alpha*A*x + beta*y
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d3/da1/ssbmv_8f.html
-     *
-     * Note: For a N*N matrix, the input Allocation should also be of size N*N (dimY = N, dimX = N),
-     *       but only the region N*(K+1) will be referenced. The following subroutine can is an
-     *       example showing how to convert a UPPER trianglar matrix 'a' to row-based band matrix 'b'.
-     *           for i in range(0, n):
-     *              for j in range(i, min(i+k+1, n)):
-     *                  b[i, j-i] = a[i, j]
-     *
-     * @param Uplo Specifies whether the upper or lower triangular part of the band matrix A is being supplied.
-     * @param K The number of off-diagonals of the matrix A
-     * @param alpha The scalar alpha.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32}.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F32}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     * @param beta The scalar beta.
-     * @param Y The input allocation contains vector y, supported elements type {@link Element#F32}.
-     * @param incY The increment for the elements of vector y, must be larger than zero.
-     */
-    public void SSBMV(@Uplo int Uplo, int K, float alpha, Allocation A, Allocation X, int incX, float beta, Allocation Y, int incY) {
-        // SBMV is the same as SYMV + K >= 0
-        if (K < 0) {
-            throw new RSRuntimeException("K must be greater than or equal to 0");
-        }
-        int N = validateSYMV(Element.F32(mRS), Uplo, A, X, Y, incX, incY);
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long xID = X.getID(mRS);
-        long yID = Y.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            xID = getDummyAlloc(X);
-            yID = getDummyAlloc(Y);
-        }
-        mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_ssbmv, 0, 0, 0, Uplo, 0, 0, N, K, alpha, aID, xID, beta, yID, incX, incY, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * SSPMV performs the matrix-vector operation
-     * y := alpha*A*x + beta*y
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d8/d68/sspmv_8f.html
-     *
-     * Note: For a N*N matrix, the input Allocation should be a 1D allocation of size dimX = N*(N+1)/2,
-     *       The following subroutine can is an example showing how to convert a UPPER trianglar matrix
-     *       'a' to packed matrix 'b'.
-     *           k = 0
-     *           for i in range(0, n):
-     *              for j in range(i, n):
-     *                  b[k++] = a[i, j]
-     *
-     * @param Uplo Specifies whether the upper or lower triangular part of the matrix A is supplied in packed form.
-     * @param alpha The scalar alpha.
-     * @param Ap The input allocation contains matrix A, supported elements type {@link Element#F32}.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F32}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     * @param beta The scalar beta.
-     * @param Y The input allocation contains vector y, supported elements type {@link Element#F32}.
-     * @param incY The increment for the elements of vector y, must be larger than zero.
-     */
-    public void SSPMV(@Uplo int Uplo, float alpha, Allocation Ap, Allocation X, int incX, float beta, Allocation Y, int incY) {
-        int N = validateSPMV(Element.F32(mRS), Uplo, Ap, X, incX, Y, incY);
-
-        boolean mUseIncSupp = isIncSupp();
-        long apID = Ap.getID(mRS);
-        long xID = X.getID(mRS);
-        long yID = Y.getID(mRS);
-        if (mUseIncSupp) {
-            apID = getDummyAlloc(Ap);
-            xID = getDummyAlloc(X);
-            yID = getDummyAlloc(Y);
-        }
-        mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_sspmv, 0, 0, 0, Uplo, 0, 0, N, 0, alpha, apID, xID, beta, yID, incX, incY, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * SGER performs the rank 1 operation
-     * A := alpha*x*y**T + A
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/db/d5c/sger_8f.html
-     *
-     * @param alpha The scalar alpha.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F32}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     * @param Y The input allocation contains vector y, supported elements type {@link Element#F32}.
-     * @param incY The increment for the elements of vector y, must be larger than zero.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32}.
-     */
-    public void SGER(float alpha, Allocation X, int incX, Allocation Y, int incY, Allocation A) {
-        int M = A.getType().getY();
-        int N = A.getType().getX();
-        validateGER(Element.F32(mRS), X, incX, Y, incY, A);
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long xID = X.getID(mRS);
-        long yID = Y.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            xID = getDummyAlloc(X);
-            yID = getDummyAlloc(Y);
-        }
-        mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_sger, 0, 0, 0, 0, 0, M, N, 0, alpha, xID, yID, 0.f, aID, incX, incY, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * SSYR performs the rank 1 operation
-     * A := alpha*x*x**T + A
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d6/dac/ssyr_8f.html
-     *
-     * @param Uplo Specifies whether the upper or lower triangular part is to be referenced.
-     * @param alpha The scalar alpha.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F32}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32}.
-     */
-    public void SSYR(@Uplo int Uplo, float alpha, Allocation X, int incX, Allocation A) {
-        int N = validateSYR(Element.F32(mRS), Uplo, X, incX, A);
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long xID = X.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            xID = getDummyAlloc(X);
-        }
-        mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_ssyr, 0, 0, 0, Uplo, 0, 0, N, 0, alpha, xID, aID, 0.f, 0, incX, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * SSPR performs the rank 1 operation
-     * A := alpha*x*x**T + A
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d2/d9b/sspr_8f.html
-     *
-     * Note: For a N*N matrix, the input Allocation should be a 1D allocation of size dimX = N*(N+1)/2,
-     *       The following subroutine can is an example showing how to convert a UPPER trianglar matrix
-     *       'a' to packed matrix 'b'.
-     *           k = 0
-     *           for i in range(0, n):
-     *              for j in range(i, n):
-     *                  b[k++] = a[i, j]
-     *
-     * @param Uplo Specifies whether the upper or lower triangular part is to be supplied in the packed form.
-     * @param alpha The scalar alpha.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F32}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     * @param Ap The input allocation contains matrix A, supported elements type {@link Element#F32}.
-     */
-    public void SSPR(@Uplo int Uplo, float alpha, Allocation X, int incX, Allocation Ap) {
-        int N = validateSPR(Element.F32(mRS), Uplo, X, incX, Ap);
-
-        boolean mUseIncSupp = isIncSupp();
-        long apID = Ap.getID(mRS);
-        long xID = X.getID(mRS);
-        if (mUseIncSupp) {
-            apID = getDummyAlloc(Ap);
-            xID = getDummyAlloc(X);
-        }
-        mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_sspr, 0, 0, 0, Uplo, 0, 0, N, 0, alpha, xID, apID, 0.f, 0, incX, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * SSYR2 performs the symmetric rank 2 operation
-     * A := alpha*x*y**T + alpha*y*x**T + A
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/db/d99/ssyr2_8f.html
-     *
-     * @param Uplo Specifies whether the upper or lower triangular part is to be referenced.
-     * @param alpha The scalar alpha.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F32}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     * @param Y The input allocation contains vector y, supported elements type {@link Element#F32}.
-     * @param incY The increment for the elements of vector y, must be larger than zero.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32}.
-     */
-    public void SSYR2(@Uplo int Uplo, float alpha, Allocation X, int incX, Allocation Y, int incY, Allocation A) {
-        int N = validateSYR2(Element.F32(mRS), Uplo, X, incX, Y, incY, A);
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long xID = X.getID(mRS);
-        long yID = Y.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            xID = getDummyAlloc(X);
-            yID = getDummyAlloc(Y);
-        }
-        mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_ssyr2, 0, 0, 0, Uplo, 0, 0, N, 0, alpha, xID, yID, 0, aID, incX, incY, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * SSPR2 performs the symmetric rank 2 operation
-     * A := alpha*x*y**T + alpha*y*x**T + A
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/db/d3e/sspr2_8f.html
-     *
-     * Note: For a N*N matrix, the input Allocation should be a 1D allocation of size dimX = N*(N+1)/2,
-     *       The following subroutine can is an example showing how to convert a UPPER trianglar matrix
-     *       'a' to packed matrix 'b'.
-     *           k = 0
-     *           for i in range(0, n):
-     *              for j in range(i, n):
-     *                  b[k++] = a[i, j]
-     *
-     * @param Uplo Specifies whether the upper or lower triangular part is to be supplied in the packed form.
-     * @param alpha The scalar alpha.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F32}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     * @param Y The input allocation contains vector y, supported elements type {@link Element#F32}.
-     * @param incY The increment for the elements of vector y, must be larger than zero.
-     * @param Ap The input allocation contains matrix A, supported elements type {@link Element#F32}.
-     */
-    public void SSPR2(@Uplo int Uplo, float alpha, Allocation X, int incX, Allocation Y, int incY, Allocation Ap) {
-        int N = validateSPR2(Element.F32(mRS), Uplo, X, incX, Y, incY, Ap);
-
-        boolean mUseIncSupp = isIncSupp();
-        long apID = Ap.getID(mRS);
-        long xID = X.getID(mRS);
-        long yID = Y.getID(mRS);
-        if (mUseIncSupp) {
-            apID = getDummyAlloc(Ap);
-            xID = getDummyAlloc(X);
-            yID = getDummyAlloc(Y);
-        }
-        mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_sspr2, 0, 0, 0, Uplo, 0, 0, N, 0, alpha, xID, yID, 0, apID, incX, incY, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * DSYMV performs the matrix-vector operation
-     * y := alpha*A*x + beta*y
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d8/dbe/dsymv_8f.html
-     *
-     * @param Uplo Specifies whether the upper or lower triangular part is to be referenced.
-     * @param alpha The scalar alpha.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64}.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F64}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     * @param beta The scalar beta.
-     * @param Y The input allocation contains vector y, supported elements type {@link Element#F64}.
-     * @param incY The increment for the elements of vector y, must be larger than zero.
-     */
-    public void DSYMV(@Uplo int Uplo, double alpha, Allocation A, Allocation X, int incX, double beta, Allocation Y, int incY) {
-        int N = validateSYMV(Element.F64(mRS), Uplo, A, X, Y, incX, incY);
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long xID = X.getID(mRS);
-        long yID = Y.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            xID = getDummyAlloc(X);
-            yID = getDummyAlloc(Y);
-        }
-        mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dsymv, 0, 0, 0, Uplo, 0, 0, N, 0, alpha, aID, xID, beta, yID, incX, incY, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * DSBMV performs the matrix-vector operation
-     * y := alpha*A*x + beta*y
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d8/d1e/dsbmv_8f.html
-     *
-     * Note: For a N*N matrix, the input Allocation should also be of size N*N (dimY = N, dimX = N),
-     *       but only the region N*(K+1) will be referenced. The following subroutine can is an
-     *       example showing how to convert a UPPER trianglar matrix 'a' to row-based band matrix 'b'.
-     *           for i in range(0, n):
-     *              for j in range(i, min(i+k+1, n)):
-     *                  b[i, j-i] = a[i, j]
-     *
-     * @param Uplo Specifies whether the upper or lower triangular part of the band matrix A is being supplied.
-     * @param K The number of off-diagonals of the matrix A
-     * @param alpha The scalar alpha.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64}.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F64}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     * @param beta The scalar beta.
-     * @param Y The input allocation contains vector y, supported elements type {@link Element#F64}.
-     * @param incY The increment for the elements of vector y, must be larger than zero.
-     */
-    public void DSBMV(@Uplo int Uplo, int K, double alpha, Allocation A, Allocation X, int incX, double beta, Allocation Y, int incY) {
-        // SBMV is the same as SYMV + K >= 0
-        if (K < 0) {
-            throw new RSRuntimeException("K must be greater than or equal to 0");
-        }
-        int N = validateSYMV(Element.F64(mRS), Uplo, A, X, Y, incX, incY);
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long xID = X.getID(mRS);
-        long yID = Y.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            xID = getDummyAlloc(X);
-            yID = getDummyAlloc(Y);
-        }
-        mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dsbmv, 0, 0, 0, Uplo, 0, 0, N, K, alpha, aID, xID, beta, yID, incX, incY, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * DSPMV performs the matrix-vector operation
-     * y := alpha*A*x + beta*y
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d4/d85/dspmv_8f.html
-     *
-     * Note: For a N*N matrix, the input Allocation should be a 1D allocation of size dimX = N*(N+1)/2,
-     *       The following subroutine can is an example showing how to convert a UPPER trianglar matrix
-     *       'a' to packed matrix 'b'.
-     *           k = 0
-     *           for i in range(0, n):
-     *              for j in range(i, n):
-     *                  b[k++] = a[i, j]
-     *
-     * @param Uplo Specifies whether the upper or lower triangular part of the matrix A is supplied in packed form.
-     * @param alpha The scalar alpha.
-     * @param Ap The input allocation contains matrix A, supported elements type {@link Element#F64}.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F64}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     * @param beta The scalar beta.
-     * @param Y The input allocation contains vector y, supported elements type {@link Element#F64}.
-     * @param incY The increment for the elements of vector y, must be larger than zero.
-     */
-    public void DSPMV(@Uplo int Uplo, double alpha, Allocation Ap, Allocation X, int incX, double beta, Allocation Y, int incY) {
-        int N = validateSPMV(Element.F64(mRS), Uplo, Ap, X, incX, Y, incY);
-
-        boolean mUseIncSupp = isIncSupp();
-        long apID = Ap.getID(mRS);
-        long xID = X.getID(mRS);
-        long yID = Y.getID(mRS);
-        if (mUseIncSupp) {
-            apID = getDummyAlloc(Ap);
-            xID = getDummyAlloc(X);
-            yID = getDummyAlloc(Y);
-        }
-        mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dspmv, 0, 0, 0, Uplo, 0, 0, N, 0, alpha, apID, xID, beta, yID, incX, incY, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * DGER performs the rank 1 operation
-     * A := alpha*x*y**T + A
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/dc/da8/dger_8f.html
-     *
-     * @param alpha The scalar alpha.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F64}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     * @param Y The input allocation contains vector y, supported elements type {@link Element#F64}.
-     * @param incY The increment for the elements of vector y, must be larger than zero.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64}.
-     */
-    public void DGER(double alpha, Allocation X, int incX, Allocation Y, int incY, Allocation A) {
-        int M = A.getType().getY();
-        int N = A.getType().getX();
-        validateGER(Element.F64(mRS), X, incX, Y, incY, A);
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long xID = X.getID(mRS);
-        long yID = Y.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            xID = getDummyAlloc(X);
-            yID = getDummyAlloc(Y);
-        }
-        mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dger, 0, 0, 0, 0, 0, M, N, 0, alpha, xID, yID, 0.f, aID, incX, incY, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * DSYR performs the rank 1 operation
-     * A := alpha*x*x**T + A
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d3/d60/dsyr_8f.html
-     *
-     * @param Uplo Specifies whether the upper or lower triangular part is to be referenced.
-     * @param alpha The scalar alpha.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F64}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64}.
-     */
-    public void DSYR(@Uplo int Uplo, double alpha, Allocation X, int incX, Allocation A) {
-        int N = validateSYR(Element.F64(mRS), Uplo, X, incX, A);
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long xID = X.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            xID = getDummyAlloc(X);
-        }
-        mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dsyr, 0, 0, 0, Uplo, 0, 0, N, 0, alpha, xID, aID, 0.f, 0, incX, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * DSPR performs the rank 1 operation
-     * A := alpha*x*x**T + A
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/dd/dba/dspr_8f.html
-     *
-     * Note: For a N*N matrix, the input Allocation should be a 1D allocation of size dimX = N*(N+1)/2,
-     *       The following subroutine can is an example showing how to convert a UPPER trianglar matrix
-     *       'a' to packed matrix 'b'.
-     *           k = 0
-     *           for i in range(0, n):
-     *              for j in range(i, n):
-     *                  b[k++] = a[i, j]
-     *
-     * @param Uplo Specifies whether the upper or lower triangular part is to be supplied in the packed form.
-     * @param alpha The scalar alpha.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F64}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     * @param Ap The input allocation contains matrix A, supported elements type {@link Element#F64}.
-     */
-    public void DSPR(@Uplo int Uplo, double alpha, Allocation X, int incX, Allocation Ap) {
-        int N = validateSPR(Element.F64(mRS), Uplo, X, incX, Ap);
-
-        boolean mUseIncSupp = isIncSupp();
-        long apID = Ap.getID(mRS);
-        long xID = X.getID(mRS);
-        if (mUseIncSupp) {
-            apID = getDummyAlloc(Ap);
-            xID = getDummyAlloc(X);
-        }
-        mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dspr, 0, 0, 0, Uplo, 0, 0, N, 0, alpha, xID, apID, 0.f, 0, incX, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * DSYR2 performs the symmetric rank 2 operation
-     * A := alpha*x*y**T + alpha*y*x**T + A
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/de/d41/dsyr2_8f.html
-     *
-     * @param Uplo Specifies whether the upper or lower triangular part is to be referenced.
-     * @param alpha The scalar alpha.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F64}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     * @param Y The input allocation contains vector y, supported elements type {@link Element#F64}.
-     * @param incY The increment for the elements of vector y, must be larger than zero.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64}.
-     */
-    public void DSYR2(@Uplo int Uplo, double alpha, Allocation X, int incX, Allocation Y, int incY, Allocation A) {
-        int N = validateSYR2(Element.F64(mRS), Uplo, X, incX, Y, incY, A);
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long xID = X.getID(mRS);
-        long yID = Y.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            xID = getDummyAlloc(X);
-            yID = getDummyAlloc(Y);
-        }
-        mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dsyr2, 0, 0, 0, Uplo, 0, 0, N, 0, alpha, xID, yID, 0, aID, incX, incY, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * DSPR2 performs the symmetric rank 2 operation
-     * A := alpha*x*y**T + alpha*y*x**T + A
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/dd/d9e/dspr2_8f.html
-     *
-     * Note: For a N*N matrix, the input Allocation should be a 1D allocation of size dimX = N*(N+1)/2,
-     *       The following subroutine can is an example showing how to convert a UPPER trianglar matrix
-     *       'a' to packed matrix 'b'.
-     *           k = 0
-     *           for i in range(0, n):
-     *              for j in range(i, n):
-     *                  b[k++] = a[i, j]
-     *
-     * @param Uplo Specifies whether the upper or lower triangular part is to be supplied in the packed form.
-     * @param alpha The scalar alpha.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F64}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     * @param Y The input allocation contains vector y, supported elements type {@link Element#F64}.
-     * @param incY The increment for the elements of vector y, must be larger than zero.
-     * @param Ap The input allocation contains matrix A, supported elements type {@link Element#F64}.
-     */
-    public void DSPR2(@Uplo int Uplo, double alpha, Allocation X, int incX, Allocation Y, int incY, Allocation Ap) {
-        int N = validateSPR2(Element.F64(mRS), Uplo, X, incX, Y, incY, Ap);
-
-        boolean mUseIncSupp = isIncSupp();
-        long apID = Ap.getID(mRS);
-        long xID = X.getID(mRS);
-        long yID = Y.getID(mRS);
-        if (mUseIncSupp) {
-            apID = getDummyAlloc(Ap);
-            xID = getDummyAlloc(X);
-            yID = getDummyAlloc(Y);
-        }
-        mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dspr2, 0, 0, 0, Uplo, 0, 0, N, 0, alpha, xID, yID, 0, apID, incX, incY, 0, 0, mUseIncSupp);
-    }
-
-
-    /**
-     * Level 2, C and Z only
-     */
-
-    static void validateGERU(Element e, Allocation X, int incX, Allocation Y, int incY, Allocation A) {
-        if (!A.getType().getElement().isCompatible(e) ||
-            !X.getType().getElement().isCompatible(e) ||
-            !Y.getType().getElement().isCompatible(e)) {
-            throw new RSRuntimeException("Called BLAS with wrong Element type");
-        }
-        if (X.getType().getY() > 1 || Y.getType().getY() > 1) {
-            throw new RSRuntimeException("BLAS vectors must have Y dimension of 0 or 1");
-        }
-
-        int M = A.getType().getY();
-        int N = A.getType().getX();
-        if (incX <= 0 || incY <= 0) {
-            throw new RSRuntimeException("Vector increments must be greater than 0");
-        }
-        int expectedXDim = 1 + (M - 1) * incX;
-        if (X.getType().getX() != expectedXDim) {
-            throw new RSRuntimeException("Incorrect vector dimensions for GERU");
-        }
-        int expectedYDim = 1 + (N - 1) * incY;
-        if (Y.getType().getX() != expectedYDim) {
-            throw new RSRuntimeException("Incorrect vector dimensions for GERU");
-        }
-
-    }
-
-    /**
-     * CHEMV performs the matrix-vector operation
-     * y := alpha*A*x + beta*y
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d7/d51/chemv_8f.html
-     *
-     * @param Uplo Specifies whether the upper or lower triangular part is to be referenced.
-     * @param alpha The scalar alpha.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32_2}.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F32_2}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     * @param beta The scalar beta.
-     * @param Y The input allocation contains vector y, supported elements type {@link Element#F32_2}.
-     * @param incY The increment for the elements of vector y, must be larger than zero.
-     */
-    public void CHEMV(@Uplo int Uplo, Float2 alpha, Allocation A, Allocation X, int incX, Float2 beta, Allocation Y, int incY) {
-        // HEMV is the same as SYR2 validation-wise
-        int N = validateSYR2(Element.F32_2(mRS), Uplo, X, incX, Y, incY, A);
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long xID = X.getID(mRS);
-        long yID = Y.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            xID = getDummyAlloc(X);
-            yID = getDummyAlloc(Y);
-        }
-        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_chemv, 0, 0, 0, Uplo, 0, 0, N, 0, alpha.x, alpha.y, aID, xID, beta.x, beta.y, yID, incX, incY, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * CHBMV performs the matrix-vector operation
-     * y := alpha*A*x + beta*y
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/db/dc2/chbmv_8f.html
-     *
-     * Note: For a N*N matrix, the input Allocation should also be of size N*N (dimY = N, dimX = N),
-     *       but only the region N*(K+1) will be referenced. The following subroutine can is an
-     *       example showing how to convert a UPPER trianglar matrix 'a' to row-based band matrix 'b'.
-     *           for i in range(0, n):
-     *              for j in range(i, min(i+k+1, n)):
-     *                  b[i, j-i] = a[i, j]
-     *
-     * @param Uplo Specifies whether the upper or lower triangular part of the band matrix A is being supplied.
-     * @param K The number of off-diagonals of the matrix A
-     * @param alpha The scalar alpha.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32_2}.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F32_2}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     * @param beta The scalar beta.
-     * @param Y The input allocation contains vector y, supported elements type {@link Element#F32_2}.
-     * @param incY The increment for the elements of vector y, must be larger than zero.
-     */
-    public void CHBMV(@Uplo int Uplo, int K, Float2 alpha, Allocation A, Allocation X, int incX, Float2 beta, Allocation Y, int incY) {
-        // HBMV is the same as SYR2 validation-wise
-        int N = validateSYR2(Element.F32_2(mRS), Uplo, X, incX, Y, incY, A);
-        if (K < 0) {
-            throw new RSRuntimeException("K must be 0 or greater for HBMV");
-        }
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long xID = X.getID(mRS);
-        long yID = Y.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            xID = getDummyAlloc(X);
-            yID = getDummyAlloc(Y);
-        }
-        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_chbmv, 0, 0, 0, Uplo, 0, 0, N, K, alpha.x, alpha.y, aID, xID, beta.x, beta.y, yID, incX, incY, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * CHPMV performs the matrix-vector operation
-     * y := alpha*A*x + beta*y
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d2/d06/chpmv_8f.html
-     *
-     * Note: For a N*N matrix, the input Allocation should be a 1D allocation of size dimX = N*(N+1)/2,
-     *       The following subroutine can is an example showing how to convert a UPPER trianglar matrix
-     *       'a' to packed matrix 'b'.
-     *           k = 0
-     *           for i in range(0, n):
-     *              for j in range(i, n):
-     *                  b[k++] = a[i, j]
-     *
-     * @param Uplo Specifies whether the upper or lower triangular part of the matrix A is supplied in packed form.
-     * @param alpha The scalar alpha.
-     * @param Ap The input allocation contains matrix A, supported elements type {@link Element#F32_2}.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F32_2}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     * @param beta The scalar beta.
-     * @param Y The input allocation contains vector y, supported elements type {@link Element#F32_2}.
-     * @param incY The increment for the elements of vector y, must be larger than zero.
-     */
-    public void CHPMV(@Uplo int Uplo, Float2 alpha, Allocation Ap, Allocation X, int incX, Float2 beta, Allocation Y, int incY) {
-        // HPMV is the same as SPR2
-        int N = validateSPR2(Element.F32_2(mRS), Uplo, X, incX, Y, incY, Ap);
-
-        boolean mUseIncSupp = isIncSupp();
-        long apID = Ap.getID(mRS);
-        long xID = X.getID(mRS);
-        long yID = Y.getID(mRS);
-        if (mUseIncSupp) {
-            apID = getDummyAlloc(Ap);
-            xID = getDummyAlloc(X);
-            yID = getDummyAlloc(Y);
-        }
-        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_chpmv, 0, 0, 0, Uplo, 0, 0, N, 0, alpha.x, alpha.y, apID, xID, beta.x, beta.y, yID, incX, incY, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * CGERU performs the rank 1 operation
-     * A := alpha*x*y**T + A
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/db/d5f/cgeru_8f.html
-     *
-     * @param alpha The scalar alpha.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F32_2}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     * @param Y The input allocation contains vector y, supported elements type {@link Element#F32_2}.
-     * @param incY The increment for the elements of vector y, must be larger than zero.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32_2}.
-     */
-    public void CGERU(Float2 alpha, Allocation X, int incX, Allocation Y, int incY, Allocation A) {
-        validateGERU(Element.F32_2(mRS), X, incX, Y, incY, A);
-        int M = A.getType().getY();
-        int N = A.getType().getX();
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long xID = X.getID(mRS);
-        long yID = Y.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            xID = getDummyAlloc(X);
-            yID = getDummyAlloc(Y);
-        }
-        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_cgeru, 0, 0, 0, 0, 0, M, N, 0, alpha.x, alpha.y, xID, yID, 0, 0, aID, incX, incY, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * CGERC performs the rank 1 operation
-     * A := alpha*x*y**H + A
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/dd/d84/cgerc_8f.html
-     *
-     * @param alpha The scalar alpha.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F32_2}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     * @param Y The input allocation contains vector y, supported elements type {@link Element#F32_2}.
-     * @param incY The increment for the elements of vector y, must be larger than zero.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32_2}.
-     */
-    public void CGERC(Float2 alpha, Allocation X, int incX, Allocation Y, int incY, Allocation A) {
-        // same as GERU
-        validateGERU(Element.F32_2(mRS), X, incX, Y, incY, A);
-        int M = A.getType().getY();
-        int N = A.getType().getX();
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long xID = X.getID(mRS);
-        long yID = Y.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            xID = getDummyAlloc(X);
-            yID = getDummyAlloc(Y);
-        }
-        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_cgerc, 0, 0, 0, 0, 0, M, N, 0, alpha.x, alpha.y, xID, yID, 0, 0, aID, incX, incY, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * CHER performs the rank 1 operation
-     * A := alpha*x*x**H + A
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d3/d6d/cher_8f.html
-     *
-     * @param Uplo Specifies whether the upper or lower triangular part is to be referenced.
-     * @param alpha The scalar alpha.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F32_2}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32_2}.
-     */
-    public void CHER(@Uplo int Uplo, float alpha, Allocation X, int incX, Allocation A) {
-        // same as SYR
-        int N = validateSYR(Element.F32_2(mRS), Uplo, X, incX, A);
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long xID = X.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            xID = getDummyAlloc(X);
-        }
-        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_cher, 0, 0, 0, Uplo, 0, 0, N, 0, alpha, 0, xID, 0, 0, 0, aID, incX, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * CHPR performs the rank 1 operation
-     * A := alpha*x*x**H + A
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/db/dcd/chpr_8f.html
-     *
-     * Note: For a N*N matrix, the input Allocation should be a 1D allocation of size dimX = N*(N+1)/2,
-     *       The following subroutine can is an example showing how to convert a UPPER trianglar matrix
-     *       'a' to packed matrix 'b'.
-     *           k = 0
-     *           for i in range(0, n):
-     *              for j in range(i, n):
-     *                  b[k++] = a[i, j]
-     *
-     * @param Uplo Specifies whether the upper or lower triangular part is to be supplied in the packed form.
-     * @param alpha The scalar alpha.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F32_2}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     * @param Ap The input allocation contains matrix A, supported elements type {@link Element#F32_2}.
-     */
-    public void CHPR(@Uplo int Uplo, float alpha, Allocation X, int incX, Allocation Ap) {
-        // equivalent to SPR for validation
-        int N = validateSPR(Element.F32_2(mRS), Uplo, X, incX, Ap);
-
-        boolean mUseIncSupp = isIncSupp();
-        long apID = Ap.getID(mRS);
-        long xID = X.getID(mRS);
-        if (mUseIncSupp) {
-            apID = getDummyAlloc(Ap);
-            xID = getDummyAlloc(X);
-        }
-        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_chpr, 0, 0, 0, Uplo, 0, 0, N, 0, alpha, 0, xID, 0, 0, 0, apID, incX, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * CHER2 performs the symmetric rank 2 operation
-     * A := alpha*x*y**H + alpha*y*x**H + A
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/db/d87/cher2_8f.html
-     *
-     * @param Uplo Specifies whether the upper or lower triangular part is to be referenced.
-     * @param alpha The scalar alpha.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F32_2}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     * @param Y The input allocation contains vector y, supported elements type {@link Element#F32_2}.
-     * @param incY The increment for the elements of vector y, must be larger than zero.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32_2}.
-     */
-    public void CHER2(@Uplo int Uplo, Float2 alpha, Allocation X, int incX, Allocation Y, int incY, Allocation A) {
-        // same as SYR2
-        int N = validateSYR2(Element.F32_2(mRS), Uplo, X, incX, Y, incY, A);
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long xID = X.getID(mRS);
-        long yID = Y.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            xID = getDummyAlloc(X);
-            yID = getDummyAlloc(Y);
-        }
-        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_cher2, 0, 0, 0, Uplo, 0, 0, N, 0, alpha.x, alpha.y, xID, yID, 0, 0, aID, incX, incY, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * CHPR2 performs the symmetric rank 2 operation
-     * A := alpha*x*y**H + alpha*y*x**H + A
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d6/d44/chpr2_8f.html
-     *
-     * Note: For a N*N matrix, the input Allocation should be a 1D allocation of size dimX = N*(N+1)/2,
-     *       The following subroutine can is an example showing how to convert a UPPER trianglar matrix
-     *       'a' to packed matrix 'b'.
-     *           k = 0
-     *           for i in range(0, n):
-     *              for j in range(i, n):
-     *                  b[k++] = a[i, j]
-     *
-     * @param Uplo Specifies whether the upper or lower triangular part is to be supplied in the packed form.
-     * @param alpha The scalar alpha.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F32_2}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     * @param Y The input allocation contains vector y, supported elements type {@link Element#F32_2}.
-     * @param incY The increment for the elements of vector y, must be larger than zero.
-     * @param Ap The input allocation contains matrix A, supported elements type {@link Element#F32_2}.
-     */
-    public void CHPR2(@Uplo int Uplo, Float2 alpha, Allocation X, int incX, Allocation Y, int incY, Allocation Ap) {
-        // same as SPR2
-        int N = validateSPR2(Element.F32_2(mRS), Uplo, X, incX, Y, incY, Ap);
-
-        boolean mUseIncSupp = isIncSupp();
-        long apID = Ap.getID(mRS);
-        long xID = X.getID(mRS);
-        long yID = Y.getID(mRS);
-        if (mUseIncSupp) {
-            apID = getDummyAlloc(Ap);
-            xID = getDummyAlloc(X);
-            yID = getDummyAlloc(Y);
-        }
-        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_chpr2, 0, 0, 0, Uplo, 0, 0, N, 0, alpha.x, alpha.y, xID, yID, 0, 0, apID, incX, incY, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * ZHEMV performs the matrix-vector operation
-     * y := alpha*A*x + beta*y
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d0/ddd/zhemv_8f.html
-     *
-     * @param Uplo Specifies whether the upper or lower triangular part is to be referenced.
-     * @param alpha The scalar alpha.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64_2}.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F64_2}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     * @param beta The scalar beta.
-     * @param Y The input allocation contains vector y, supported elements type {@link Element#F64_2}.
-     * @param incY The increment for the elements of vector y, must be larger than zero.
-     */
-    public void ZHEMV(@Uplo int Uplo, Double2 alpha, Allocation A, Allocation X, int incX, Double2 beta, Allocation Y, int incY) {
-        // HEMV is the same as SYR2 validation-wise
-        int N = validateSYR2(Element.F64_2(mRS), Uplo, X, incX, Y, incY, A);
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long xID = X.getID(mRS);
-        long yID = Y.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            xID = getDummyAlloc(X);
-            yID = getDummyAlloc(Y);
-        }
-        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_zhemv, 0, 0, 0, Uplo, 0, 0, N, 0, alpha.x, alpha.y, aID, xID, beta.x, beta.y, yID, incX, incY, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * ZHBMV performs the matrix-vector operation
-     * y := alpha*A*x + beta*y
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d3/d1a/zhbmv_8f.html
-     *
-     * Note: For a N*N matrix, the input Allocation should also be of size N*N (dimY = N, dimX = N),
-     *       but only the region N*(K+1) will be referenced. The following subroutine can is an
-     *       example showing how to convert a UPPER trianglar matrix 'a' to row-based band matrix 'b'.
-     *           for i in range(0, n):
-     *              for j in range(i, min(i+k+1, n)):
-     *                  b[i, j-i] = a[i, j]
-     *
-     * @param Uplo Specifies whether the upper or lower triangular part of the band matrix A is being supplied.
-     * @param K The number of off-diagonals of the matrix A
-     * @param alpha The scalar alpha.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64_2}.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F64_2}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     * @param beta The scalar beta.
-     * @param Y The input allocation contains vector y, supported elements type {@link Element#F64_2}.
-     * @param incY The increment for the elements of vector y, must be larger than zero.
-     */
-    public void ZHBMV(@Uplo int Uplo, int K, Double2 alpha, Allocation A, Allocation X, int incX, Double2 beta, Allocation Y, int incY) {
-        // HBMV is the same as SYR2 validation-wise
-        int N = validateSYR2(Element.F64_2(mRS), Uplo, X, incX, Y, incY, A);
-        if (K < 0) {
-            throw new RSRuntimeException("K must be 0 or greater for HBMV");
-        }
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long xID = X.getID(mRS);
-        long yID = Y.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            xID = getDummyAlloc(X);
-            yID = getDummyAlloc(Y);
-        }
-        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_zhbmv, 0, 0, 0, Uplo, 0, 0, N, K, alpha.x, alpha.y, aID, xID, beta.x, beta.y, yID, incX, incY, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * ZHPMV performs the matrix-vector operation
-     * y := alpha*A*x + beta*y
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d0/d60/zhpmv_8f.html
-     *
-     * Note: For a N*N matrix, the input Allocation should be a 1D allocation of size dimX = N*(N+1)/2,
-     *       The following subroutine can is an example showing how to convert a UPPER trianglar matrix
-     *       'a' to packed matrix 'b'.
-     *           k = 0
-     *           for i in range(0, n):
-     *              for j in range(i, n):
-     *                  b[k++] = a[i, j]
-     *
-     * @param Uplo Specifies whether the upper or lower triangular part of the matrix A is supplied in packed form.
-     * @param alpha The scalar alpha.
-     * @param Ap The input allocation contains matrix A, supported elements type {@link Element#F64_2}.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F64_2}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     * @param beta The scalar beta.
-     * @param Y The input allocation contains vector y, supported elements type {@link Element#F64_2}.
-     * @param incY The increment for the elements of vector y, must be larger than zero.
-     */
-    public void ZHPMV(@Uplo int Uplo, Double2 alpha, Allocation Ap, Allocation X, int incX, Double2 beta, Allocation Y, int incY) {
-        // HPMV is the same as SPR2
-        int N = validateSPR2(Element.F64_2(mRS), Uplo, X, incX, Y, incY, Ap);
-
-        boolean mUseIncSupp = isIncSupp();
-        long apID = Ap.getID(mRS);
-        long xID = X.getID(mRS);
-        long yID = Y.getID(mRS);
-        if (mUseIncSupp) {
-            apID = getDummyAlloc(Ap);
-            xID = getDummyAlloc(X);
-            yID = getDummyAlloc(Y);
-        }
-        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_zhpmv, 0, 0, 0, Uplo, 0, 0, N, 0, alpha.x, alpha.y, apID, xID, beta.x, beta.y, yID, incX, incY, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * ZGERU performs the rank 1 operation
-     * A := alpha*x*y**T + A
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d7/d12/zgeru_8f.html
-     *
-     * @param alpha The scalar alpha.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F64_2}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     * @param Y The input allocation contains vector y, supported elements type {@link Element#F64_2}.
-     * @param incY The increment for the elements of vector y, must be larger than zero.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64_2}.
-     */
-    public void ZGERU(Double2 alpha, Allocation X, int incX, Allocation Y, int incY, Allocation A) {
-        validateGERU(Element.F64_2(mRS), X, incX, Y, incY, A);
-        int M = A.getType().getY();
-        int N = A.getType().getX();
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long xID = X.getID(mRS);
-        long yID = Y.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            xID = getDummyAlloc(X);
-            yID = getDummyAlloc(Y);
-        }
-        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_zgeru, 0, 0, 0, 0, 0, M, N, 0, alpha.x, alpha.y, xID, yID, 0, 0, aID, incX, incY, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * ZGERC performs the rank 1 operation
-     * A := alpha*x*y**H + A
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d3/dad/zgerc_8f.html
-     *
-     * @param alpha The scalar alpha.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F64_2}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     * @param Y The input allocation contains vector y, supported elements type {@link Element#F64_2}.
-     * @param incY The increment for the elements of vector y, must be larger than zero.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64_2}.
-     */
-    public void ZGERC(Double2 alpha, Allocation X, int incX, Allocation Y, int incY, Allocation A) {
-        // same as GERU
-        validateGERU(Element.F64_2(mRS), X, incX, Y, incY, A);
-        int M = A.getType().getY();
-        int N = A.getType().getX();
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long xID = X.getID(mRS);
-        long yID = Y.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            xID = getDummyAlloc(X);
-            yID = getDummyAlloc(Y);
-        }
-        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_zgerc, 0, 0, 0, 0, 0, M, N, 0, alpha.x, alpha.y, xID, yID, 0, 0, aID, incX, incY, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * ZHER performs the rank 1 operation
-     * A := alpha*x*x**H + A
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/de/d0e/zher_8f.html
-     *
-     * @param Uplo Specifies whether the upper or lower triangular part is to be referenced.
-     * @param alpha The scalar alpha.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F64_2}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64_2}.
-     */
-    public void ZHER(@Uplo int Uplo, double alpha, Allocation X, int incX, Allocation A) {
-        // same as SYR
-        int N = validateSYR(Element.F64_2(mRS), Uplo, X, incX, A);
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long xID = X.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            xID = getDummyAlloc(X);
-        }
-        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_zher, 0, 0, 0, Uplo, 0, 0, N, 0, alpha, 0, xID, 0, 0, 0, aID, incX, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * ZHPR performs the rank 1 operation
-     * A := alpha*x*x**H + A
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/de/de1/zhpr_8f.html
-     *
-     * Note: For a N*N matrix, the input Allocation should be a 1D allocation of size dimX = N*(N+1)/2,
-     *       The following subroutine can is an example showing how to convert a UPPER trianglar matrix
-     *       'a' to packed matrix 'b'.
-     *           k = 0
-     *           for i in range(0, n):
-     *              for j in range(i, n):
-     *                  b[k++] = a[i, j]
-     *
-     * @param Uplo Specifies whether the upper or lower triangular part is to be supplied in the packed form.
-     * @param alpha The scalar alpha.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F64_2}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     * @param Ap The input allocation contains matrix A, supported elements type {@link Element#F64_2}.
-     */
-    public void ZHPR(@Uplo int Uplo, double alpha, Allocation X, int incX, Allocation Ap) {
-        // equivalent to SPR for validation
-        int N = validateSPR(Element.F64_2(mRS), Uplo, X, incX, Ap);
-
-        boolean mUseIncSupp = isIncSupp();
-        long apID = Ap.getID(mRS);
-        long xID = X.getID(mRS);
-        if (mUseIncSupp) {
-            apID = getDummyAlloc(Ap);
-            xID = getDummyAlloc(X);
-        }
-        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_zhpr, 0, 0, 0, Uplo, 0, 0, N, 0, alpha, 0, xID, 0, 0, 0, apID, incX, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * ZHER2 performs the symmetric rank 2 operation
-     * A := alpha*x*y**H + alpha*y*x**H + A
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/da/d8a/zher2_8f.html
-     *
-     * @param Uplo Specifies whether the upper or lower triangular part is to be referenced.
-     * @param alpha The scalar alpha.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F64_2}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     * @param Y The input allocation contains vector y, supported elements type {@link Element#F64_2}.
-     * @param incY The increment for the elements of vector y, must be larger than zero.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64_2}.
-     */
-    public void ZHER2(@Uplo int Uplo, Double2 alpha, Allocation X, int incX, Allocation Y, int incY, Allocation A) {
-        // same as SYR2
-        int N = validateSYR2(Element.F64_2(mRS), Uplo, X, incX, Y, incY, A);
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long xID = X.getID(mRS);
-        long yID = Y.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            xID = getDummyAlloc(X);
-            yID = getDummyAlloc(Y);
-        }
-        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_zher2, 0, 0, 0, Uplo, 0, 0, N, 0, alpha.x, alpha.y, xID, yID, 0, 0, aID, incX, incY, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * ZHPR2 performs the symmetric rank 2 operation
-     * A := alpha*x*y**H + alpha*y*x**H + A
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d5/d52/zhpr2_8f.html
-     *
-     * Note: For a N*N matrix, the input Allocation should be a 1D allocation of size dimX = N*(N+1)/2,
-     *       The following subroutine can is an example showing how to convert a UPPER trianglar matrix
-     *       'a' to packed matrix 'b'.
-     *           k = 0
-     *           for i in range(0, n):
-     *              for j in range(i, n):
-     *                  b[k++] = a[i, j]
-     *
-     * @param Uplo Specifies whether the upper or lower triangular part is to be supplied in the packed form.
-     * @param alpha The scalar alpha.
-     * @param X The input allocation contains vector x, supported elements type {@link Element#F64_2}.
-     * @param incX The increment for the elements of vector x, must be larger than zero.
-     * @param Y The input allocation contains vector y, supported elements type {@link Element#F64_2}.
-     * @param incY The increment for the elements of vector y, must be larger than zero.
-     * @param Ap The input allocation contains matrix A, supported elements type {@link Element#F64_2}.
-     */
-    public void ZHPR2(@Uplo int Uplo, Double2 alpha, Allocation X, int incX, Allocation Y, int incY, Allocation Ap) {
-        // same as SPR2
-        int N = validateSPR2(Element.F64_2(mRS), Uplo, X, incX, Y, incY, Ap);
-
-        boolean mUseIncSupp = isIncSupp();
-        long apID = Ap.getID(mRS);
-        long xID = X.getID(mRS);
-        long yID = Y.getID(mRS);
-        if (mUseIncSupp) {
-            apID = getDummyAlloc(Ap);
-            xID = getDummyAlloc(X);
-            yID = getDummyAlloc(Y);
-        }
-        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_zhpr2, 0, 0, 0, Uplo, 0, 0, N, 0, alpha.x, alpha.y, xID, yID, 0, 0, apID, incX, incY, 0, 0, mUseIncSupp);
-    }
-
-
-    /**
-     * Level 3 BLAS
-     */
-
-    static void validateL3(Element e, int TransA, int TransB, int Side, Allocation A, Allocation B, Allocation C) {
-        int aM = -1, aN = -1, bM = -1, bN = -1, cM = -1, cN = -1;
-        if ((A != null && !A.getType().getElement().isCompatible(e)) ||
-            (B != null && !B.getType().getElement().isCompatible(e)) ||
-            (C != null && !C.getType().getElement().isCompatible(e))) {
-            throw new RSRuntimeException("Called BLAS with wrong Element type");
-        }
-        if (C == null) {
-            //since matrix C is used to store the result, it cannot be null.
-            throw new RSRuntimeException("Allocation C cannot be null");
-        }
-        cM = C.getType().getY();
-        cN = C.getType().getX();
-
-        if (Side == RIGHT) {
-            if ((A == null && B != null) || (A != null && B == null)) {
-                throw new RSRuntimeException("Provided Matrix A without Matrix B, or vice versa");
-            }
-            if (B != null) {
-                bM = A.getType().getY();
-                bN = A.getType().getX();
-            }
-            if (A != null) {
-                aM = B.getType().getY();
-                aN = B.getType().getX();
-            }
-        } else {
-            if (A != null) {
-                if (TransA == TRANSPOSE || TransA == CONJ_TRANSPOSE) {
-                    aN = A.getType().getY();
-                    aM = A.getType().getX();
-                } else {
-                    aM = A.getType().getY();
-                    aN = A.getType().getX();
-                }
-            }
-            if (B != null) {
-                if (TransB == TRANSPOSE || TransB == CONJ_TRANSPOSE) {
-                    bN = B.getType().getY();
-                    bM = B.getType().getX();
-                } else {
-                    bM = B.getType().getY();
-                    bN = B.getType().getX();
-                }
-            }
-        }
-        if (A != null && B != null && C != null) {
-            if (aN != bM || aM != cM || bN != cN) {
-                throw new RSRuntimeException("Called BLAS with invalid dimensions");
-            }
-        } else if (A != null && C != null) {
-            // A and C only, for SYRK
-            if (cM != cN) {
-                throw new RSRuntimeException("Matrix C is not symmetric");
-            }
-            if (aM != cM) {
-                throw new RSRuntimeException("Called BLAS with invalid dimensions");
-            }
-        } else if (A != null && B != null) {
-            // A and B only
-            if (aN != bM) {
-                throw new RSRuntimeException("Called BLAS with invalid dimensions");
-            }
-        }
-
-    }
-
-    /**
-     * SGEMM performs one of the matrix-matrix operations
-     * C := alpha*op(A)*op(B) + beta*C   where op(X) is one of op(X) = X  or  op(X) = X**T
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d4/de2/sgemm_8f.html
-     *
-     * @param TransA The type of transpose applied to matrix A.
-     * @param TransB The type of transpose applied to matrix B.
-     * @param alpha The scalar alpha.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32}.
-     * @param B The input allocation contains matrix B, supported elements type {@link Element#F32}.
-     * @param beta The scalar beta.
-     * @param C The input allocation contains matrix C, supported elements type {@link Element#F32}.
-     */
-    public void SGEMM(@Transpose int TransA, @Transpose int TransB, float alpha, Allocation A,
-                      Allocation B, float beta, Allocation C) {
-        validateTranspose(TransA);
-        validateTranspose(TransB);
-        validateL3(Element.F32(mRS), TransA, TransB, 0, A, B, C);
-
-        int M = -1, N = -1, K = -1;
-        if (TransA != NO_TRANSPOSE) {
-            M = A.getType().getX();
-            K = A.getType().getY();
-        } else {
-            M = A.getType().getY();
-            K = A.getType().getX();
-        }
-        if (TransB != NO_TRANSPOSE) {
-            N = B.getType().getY();
-        } else {
-            N = B.getType().getX();
-        }
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long bID = B.getID(mRS);
-        long cID = C.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            bID = getDummyAlloc(B);
-            cID = getDummyAlloc(C);
-        }
-        mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_sgemm, TransA, TransB, 0, 0, 0, M, N, K,  alpha, aID, bID,
-                                        beta, cID, 0, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * DGEMM performs one of the matrix-matrix operations
-     * C := alpha*op(A)*op(B) + beta*C   where op(X) is one of op(X) = X  or  op(X) = X**T
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d7/d2b/dgemm_8f.html
-     *
-     * @param TransA The type of transpose applied to matrix A.
-     * @param TransB The type of transpose applied to matrix B.
-     * @param alpha The scalar alpha.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64}.
-     * @param B The input allocation contains matrix B, supported elements type {@link Element#F64}.
-     * @param beta The scalar beta.
-     * @param C The input allocation contains matrix C, supported elements type {@link Element#F64}.
-     */
-    public void DGEMM(@Transpose int TransA, @Transpose int TransB, double alpha, Allocation A,
-                      Allocation B, double beta, Allocation C) {
-        validateTranspose(TransA);
-        validateTranspose(TransB);
-        validateL3(Element.F64(mRS), TransA, TransB, 0, A, B, C);
-        int M = -1, N = -1, K = -1;
-        if (TransA != NO_TRANSPOSE) {
-            M = A.getType().getX();
-            K = A.getType().getY();
-        } else {
-            M = A.getType().getY();
-            K = A.getType().getX();
-        }
-        if (TransB != NO_TRANSPOSE) {
-            N = B.getType().getY();
-        } else {
-            N = B.getType().getX();
-        }
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long bID = B.getID(mRS);
-        long cID = C.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            bID = getDummyAlloc(B);
-            cID = getDummyAlloc(C);
-        }
-        mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dgemm, TransA, TransB, 0, 0, 0, M, N, K,  alpha, aID, bID,
-                                        beta, cID, 0, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * CGEMM performs one of the matrix-matrix operations
-     * C := alpha*op(A)*op(B) + beta*C   where op(X) is one of op(X) = X  or  op(X) = X**T  or  op(X) = X**H
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d6/d5b/cgemm_8f.html
-     *
-     * @param TransA The type of transpose applied to matrix A.
-     * @param TransB The type of transpose applied to matrix B.
-     * @param alpha The scalar alpha.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32_2}.
-     * @param B The input allocation contains matrix B, supported elements type {@link Element#F32_2}.
-     * @param beta The scalar beta.
-     * @param C The input allocation contains matrix C, supported elements type {@link Element#F32_2}.
-     */
-    public void CGEMM(@Transpose int TransA, @Transpose int TransB, Float2 alpha, Allocation A,
-                      Allocation B, Float2 beta, Allocation C) {
-        validateTranspose(TransA);
-        validateTranspose(TransB);
-        validateL3(Element.F32_2(mRS), TransA, TransB, 0, A, B, C);
-        int M = -1, N = -1, K = -1;
-        if (TransA != NO_TRANSPOSE) {
-            M = A.getType().getX();
-            K = A.getType().getY();
-        } else {
-            M = A.getType().getY();
-            K = A.getType().getX();
-        }
-        if (TransB != NO_TRANSPOSE) {
-            N = B.getType().getY();
-        } else {
-            N = B.getType().getX();
-        }
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long bID = B.getID(mRS);
-        long cID = C.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            bID = getDummyAlloc(B);
-            cID = getDummyAlloc(C);
-        }
-        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_cgemm, TransA, TransB, 0, 0, 0, M, N, K,  alpha.x, alpha.y, aID, bID,
-                                         beta.x, beta.y, cID, 0, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * ZGEMM performs one of the matrix-matrix operations
-     * C := alpha*op(A)*op(B) + beta*C   where op(X) is one of op(X) = X  or  op(X) = X**T  or  op(X) = X**H
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d7/d76/zgemm_8f.html
-     *
-     * @param TransA The type of transpose applied to matrix A.
-     * @param TransB The type of transpose applied to matrix B.
-     * @param alpha The scalar alpha.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64_2
-     * @param B The input allocation contains matrix B, supported elements type {@link Element#F64_2
-     * @param beta The scalar beta.
-     * @param C The input allocation contains matrix C, supported elements type {@link Element#F64_2
-     */
-    public void ZGEMM(@Transpose int TransA, @Transpose int TransB, Double2 alpha, Allocation A,
-                      Allocation B, Double2 beta, Allocation C) {
-        validateTranspose(TransA);
-        validateTranspose(TransB);
-        validateL3(Element.F64_2(mRS), TransA, TransB, 0, A, B, C);
-        int M = -1, N = -1, K = -1;
-        if (TransA != NO_TRANSPOSE) {
-            M = A.getType().getX();
-            K = A.getType().getY();
-        } else {
-            M = A.getType().getY();
-            K = A.getType().getX();
-        }
-        if (TransB != NO_TRANSPOSE) {
-            N = B.getType().getY();
-        } else {
-            N = B.getType().getX();
-        }
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long bID = B.getID(mRS);
-        long cID = C.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            bID = getDummyAlloc(B);
-            cID = getDummyAlloc(C);
-        }
-        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_zgemm, TransA, TransB, 0, 0, 0, M, N, K,  alpha.x, alpha.y, aID, bID,
-                                   beta.x, beta.y, cID, 0, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * SSYMM performs one of the matrix-matrix operations
-     * C := alpha*A*B + beta*C   or   C := alpha*B*A + beta*C
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d7/d42/ssymm_8f.html
-     *
-     * @param Side Specifies whether the symmetric matrix A appears on the left or right.
-     * @param Uplo Specifies whether the upper or lower triangular part is to be referenced.
-     * @param alpha The scalar alpha.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32}.
-     * @param B The input allocation contains matrix B, supported elements type {@link Element#F32}.
-     * @param beta The scalar beta.
-     * @param C The input allocation contains matrix C, supported elements type {@link Element#F32}.
-     */
-    public void SSYMM(@Side int Side, @Uplo int Uplo, float alpha, Allocation A,
-                      Allocation B, float beta, Allocation C) {
-        validateSide(Side);
-        validateUplo(Uplo);
-        //For SYMM, Matrix A should be symmetric
-        if (A.getType().getX() != A.getType().getY()) {
-            throw new RSRuntimeException("Matrix A is not symmetric");
-        }
-        validateL3(Element.F32(mRS), 0, 0, Side, A, B, C);
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long bID = B.getID(mRS);
-        long cID = C.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            bID = getDummyAlloc(B);
-            cID = getDummyAlloc(C);
-        }
-        mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_ssymm, 0, 0, Side, Uplo, 0, C.getType().getY(), C.getType().getX(), 0, alpha, aID, bID,
-                                        beta, cID, 0, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * DSYMM performs one of the matrix-matrix operations
-     * C := alpha*A*B + beta*C   or   C := alpha*B*A + beta*C
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d8/db0/dsymm_8f.html
-     *
-     * @param Side Specifies whether the symmetric matrix A appears on the left or right.
-     * @param Uplo Specifies whether the upper or lower triangular part is to be referenced.
-     * @param alpha The scalar alpha.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64}.
-     * @param B The input allocation contains matrix B, supported elements type {@link Element#F64}.
-     * @param beta The scalar beta.
-     * @param C The input allocation contains matrix C, supported elements type {@link Element#F64}.
-     */
-    public void DSYMM(@Side int Side, @Uplo int Uplo, double alpha, Allocation A,
-                      Allocation B, double beta, Allocation C) {
-        validateSide(Side);
-        validateUplo(Uplo);
-        if (A.getType().getX() != A.getType().getY()) {
-            throw new RSRuntimeException("Matrix A is not symmetric");
-        }
-        validateL3(Element.F64(mRS), 0, 0, Side, A, B, C);
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long bID = B.getID(mRS);
-        long cID = C.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            bID = getDummyAlloc(B);
-            cID = getDummyAlloc(C);
-        }
-        mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dsymm, 0, 0, Side, Uplo, 0, C.getType().getY(), C.getType().getX(), 0, alpha, aID, bID,
-                                        beta, cID, 0, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * CSYMM performs one of the matrix-matrix operations
-     * C := alpha*A*B + beta*C   or   C := alpha*B*A + beta*C
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/db/d59/csymm_8f.html
-     *
-     * @param Side Specifies whether the symmetric matrix A appears on the left or right.
-     * @param Uplo Specifies whether the upper or lower triangular part is to be referenced.
-     * @param alpha The scalar alpha.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32_2}.
-     * @param B The input allocation contains matrix B, supported elements type {@link Element#F32_2}.
-     * @param beta The scalar beta.
-     * @param C The input allocation contains matrix C, supported elements type {@link Element#F32_2}.
-     */
-    public void CSYMM(@Side int Side, @Uplo int Uplo, Float2 alpha, Allocation A,
-                      Allocation B, Float2 beta, Allocation C) {
-        validateSide(Side);
-        validateUplo(Uplo);
-        if (A.getType().getX() != A.getType().getY()) {
-            throw new RSRuntimeException("Matrix A is not symmetric");
-        }
-        validateL3(Element.F32_2(mRS), 0, 0, Side, A, B, C);
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long bID = B.getID(mRS);
-        long cID = C.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            bID = getDummyAlloc(B);
-            cID = getDummyAlloc(C);
-        }
-        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_csymm, 0, 0, Side, Uplo, 0, C.getType().getY(), C.getType().getX(), 0, alpha.x, alpha.y, aID, bID,
-                                         beta.x, beta.y, cID, 0, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * ZSYMM performs one of the matrix-matrix operations
-     * C := alpha*A*B + beta*C   or   C := alpha*B*A + beta*C
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/df/d51/zsymm_8f.html
-     *
-     * @param Side Specifies whether the symmetric matrix A appears on the left or right.
-     * @param Uplo Specifies whether the upper or lower triangular part is to be referenced.
-     * @param alpha The scalar alpha.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64_2}.
-     * @param B The input allocation contains matrix B, supported elements type {@link Element#F64_2}.
-     * @param beta The scalar beta.
-     * @param C The input allocation contains matrix C, supported elements type {@link Element#F64_2}.
-     */
-    public void ZSYMM(@Side int Side, @Uplo int Uplo, Double2 alpha, Allocation A,
-                      Allocation B, Double2 beta, Allocation C) {
-        validateSide(Side);
-        validateUplo(Uplo);
-        if (A.getType().getX() != A.getType().getY()) {
-            throw new RSRuntimeException("Matrix A is not symmetric");
-        }
-        validateL3(Element.F64_2(mRS), 0, 0, Side, A, B, C);
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long bID = B.getID(mRS);
-        long cID = C.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            bID = getDummyAlloc(B);
-            cID = getDummyAlloc(C);
-        }
-        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_zsymm, 0, 0, Side, Uplo, 0, C.getType().getY(), C.getType().getX(), 0, alpha.x, alpha.y, aID, bID,
-                                   beta.x, beta.y, cID, 0, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * SSYRK performs one of the symmetric rank k operations
-     * C := alpha*A*A**T + beta*C   or   C := alpha*A**T*A + beta*C
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d0/d40/ssyrk_8f.html
-     *
-     * @param Uplo Specifies whether the upper or lower triangular part of C is to be referenced.
-     * @param Trans The type of transpose applied to the operation.
-     * @param alpha The scalar alpha.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32}.
-     * @param beta The scalar beta.
-     * @param C The input allocation contains matrix C, supported elements type {@link Element#F32}.
-     */
-    public void SSYRK(@Uplo int Uplo, @Transpose int Trans, float alpha, Allocation A, float beta, Allocation C) {
-        validateTranspose(Trans);
-        validateUplo(Uplo);
-        validateL3(Element.F32(mRS), Trans, 0, 0, A, null, C);
-        int K = -1;
-        if (Trans != NO_TRANSPOSE) {
-            K = A.getType().getY();
-        } else {
-            K = A.getType().getX();
-        }
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long cID = C.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            cID = getDummyAlloc(C);
-        }
-        mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_ssyrk, Trans, 0, 0, Uplo, 0, 0, C.getType().getX(), K, alpha, aID, 0, beta, cID, 0, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * DSYRK performs one of the symmetric rank k operations
-     * C := alpha*A*A**T + beta*C   or   C := alpha*A**T*A + beta*C
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/dc/d05/dsyrk_8f.html
-     *
-     * @param Uplo Specifies whether the upper or lower triangular part of C is to be referenced.
-     * @param Trans The type of transpose applied to the operation.
-     * @param alpha The scalar alpha.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64}.
-     * @param beta The scalar beta.
-     * @param C The input allocation contains matrix C, supported elements type {@link Element#F64}.
-     */
-    public void DSYRK(@Uplo int Uplo, @Transpose int Trans, double alpha, Allocation A, double beta, Allocation C) {
-        validateTranspose(Trans);
-        validateUplo(Uplo);
-        validateL3(Element.F64(mRS), Trans, 0, 0, A, null, C);
-        int K = -1;
-        if (Trans != NO_TRANSPOSE) {
-            K = A.getType().getY();
-        } else {
-            K = A.getType().getX();
-        }
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long cID = C.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            cID = getDummyAlloc(C);
-        }
-        mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dsyrk, Trans, 0, 0, Uplo, 0, 0, C.getType().getX(), K, alpha, aID, 0, beta, cID, 0, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * CSYRK performs one of the symmetric rank k operations
-     * C := alpha*A*A**T + beta*C   or   C := alpha*A**T*A + beta*C
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d3/d6a/csyrk_8f.html
-     *
-     * @param Uplo Specifies whether the upper or lower triangular part of C is to be referenced.
-     * @param Trans The type of transpose applied to the operation.
-     * @param alpha The scalar alpha.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32_2}.
-     * @param beta The scalar beta.
-     * @param C The input allocation contains matrix C, supported elements type {@link Element#F32_2}.
-     */
-    public void CSYRK(@Uplo int Uplo, @Transpose int Trans, Float2 alpha, Allocation A, Float2 beta, Allocation C) {
-        validateTranspose(Trans);
-        validateUplo(Uplo);
-        validateL3(Element.F32_2(mRS), Trans, 0, 0, A, null, C);
-        int K = -1;
-        if (Trans != NO_TRANSPOSE) {
-            K = A.getType().getY();
-        } else {
-            K = A.getType().getX();
-        }
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long cID = C.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            cID = getDummyAlloc(C);
-        }
-        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_csyrk, Trans, 0, 0, Uplo, 0, 0, C.getType().getX(), K, alpha.x, alpha.y, aID, 0, beta.x, beta.y,
-                                         C.getID(mRS), 0, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * ZSYRK performs one of the symmetric rank k operations
-     * C := alpha*A*A**T + beta*C   or   C := alpha*A**T*A + beta*C
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/de/d54/zsyrk_8f.html
-     *
-     * @param Uplo Specifies whether the upper or lower triangular part of C is to be referenced.
-     * @param Trans The type of transpose applied to the operation.
-     * @param alpha The scalar alpha.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64_2}.
-     * @param beta The scalar beta.
-     * @param C The input allocation contains matrix C, supported elements type {@link Element#F64_2}.
-     */
-    public void ZSYRK(@Uplo int Uplo, @Transpose int Trans, Double2 alpha, Allocation A, Double2 beta, Allocation C) {
-        validateTranspose(Trans);
-        validateUplo(Uplo);
-        validateL3(Element.F64_2(mRS), Trans, 0, 0, A, null, C);
-        int K = -1;
-        if (Trans != NO_TRANSPOSE) {
-            K = A.getType().getY();
-        } else {
-            K = A.getType().getX();
-        }
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long cID = C.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            cID = getDummyAlloc(C);
-        }
-        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_zsyrk, Trans, 0, 0, Uplo, 0, 0, C.getType().getX(), K, alpha.x, alpha.y, aID, 0, beta.x, beta.y,
-                                   C.getID(mRS), 0, 0, 0, 0, mUseIncSupp);
-    }
-
-    static void validateSYR2K(Element e, @Transpose int Trans, Allocation A, Allocation B, Allocation C) {
-        validateTranspose(Trans);
-        if (!A.getType().getElement().isCompatible(e) ||
-            !B.getType().getElement().isCompatible(e) ||
-            !C.getType().getElement().isCompatible(e)) {
-            throw new RSRuntimeException("Called BLAS with wrong Element type");
-        }
-        int Cdim = -1;
-        // A is n x k if no transpose, k x n if transpose
-        // C is n x n
-        if (Trans == TRANSPOSE) {
-            // check columns versus C
-            Cdim = A.getType().getX();
-        } else {
-            // check rows versus C
-            Cdim = A.getType().getY();
-        }
-        if (C.getType().getX() != Cdim || C.getType().getY() != Cdim) {
-            throw new RSRuntimeException("Invalid symmetric matrix in SYR2K");
-        }
-        // A dims == B dims
-        if (A.getType().getX() != B.getType().getX() || A.getType().getY() != B.getType().getY()) {
-            throw new RSRuntimeException("Invalid A and B in SYR2K");
-        }
-    }
-
-    /**
-     * SSYR2K performs one of the symmetric rank 2k operations
-     * C := alpha*A*B**T + alpha*B*A**T + beta*C   or   C := alpha*A**T*B + alpha*B**T*A + beta*C
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/df/d3d/ssyr2k_8f.html
-     *
-     * @param Uplo Specifies whether the upper or lower triangular part of C is to be referenced.
-     * @param Trans The type of transpose applied to the operation.
-     * @param alpha The scalar alpha.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32}.
-     * @param B The input allocation contains matrix B, supported elements type {@link Element#F32}.
-     * @param beta The scalar beta.
-     * @param C The input allocation contains matrix C, supported elements type {@link Element#F32}.
-     */
-    public void SSYR2K(@Uplo int Uplo, @Transpose int Trans, float alpha, Allocation A, Allocation B, float beta, Allocation C) {
-        validateUplo(Uplo);
-        validateSYR2K(Element.F32(mRS), Trans, A, B, C);
-        int K = -1;
-        if (Trans != NO_TRANSPOSE) {
-            K = A.getType().getY();
-        } else {
-            K = A.getType().getX();
-        }
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long bID = B.getID(mRS);
-        long cID = C.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            bID = getDummyAlloc(B);
-            cID = getDummyAlloc(C);
-        }
-        mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_ssyr2k, Trans, 0, 0, Uplo, 0, 0, C.getType().getX(), K, alpha, aID, bID, beta, cID, 0, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * DSYR2K performs one of the symmetric rank 2k operations
-     * C := alpha*A*B**T + alpha*B*A**T + beta*C   or   C := alpha*A**T*B + alpha*B**T*A + beta*C
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d1/dec/dsyr2k_8f.html
-     *
-     * @param Uplo Specifies whether the upper or lower triangular part of C is to be referenced.
-     * @param Trans The type of transpose applied to the operation.
-     * @param alpha The scalar alpha.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64}.
-     * @param B The input allocation contains matrix B, supported elements type {@link Element#F64}.
-     * @param beta The scalar beta.
-     * @param C The input allocation contains matrix C, supported elements type {@link Element#F64}.
-     */
-    public void DSYR2K(@Uplo int Uplo, @Transpose int Trans, double alpha, Allocation A, Allocation B, double beta, Allocation C) {
-        validateUplo(Uplo);
-        validateSYR2K(Element.F64(mRS), Trans, A, B, C);
-        int K = -1;
-        if (Trans != NO_TRANSPOSE) {
-            K = A.getType().getY();
-        } else {
-            K = A.getType().getX();
-        }
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long bID = B.getID(mRS);
-        long cID = C.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            bID = getDummyAlloc(B);
-            cID = getDummyAlloc(C);
-        }
-        mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dsyr2k, Trans, 0, 0, Uplo, 0, 0, C.getType().getX(), K, alpha, aID, bID, beta, cID, 0, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * CSYR2K performs one of the symmetric rank 2k operations
-     * C := alpha*A*B**T + alpha*B*A**T + beta*C   or   C := alpha*A**T*B + alpha*B**T*A + beta*C
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/de/d7e/csyr2k_8f.html
-     *
-     * @param Uplo Specifies whether the upper or lower triangular part of C is to be referenced.
-     * @param Trans The type of transpose applied to the operation.
-     * @param alpha The scalar alpha.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32_2}.
-     * @param B The input allocation contains matrix B, supported elements type {@link Element#F32_2}.
-     * @param beta The scalar beta.
-     * @param C The input allocation contains matrix C, supported elements type {@link Element#F32_2}.
-     */
-    public void CSYR2K(@Uplo int Uplo, @Transpose int Trans, Float2 alpha, Allocation A, Allocation B, Float2 beta, Allocation C) {
-        validateUplo(Uplo);
-        validateSYR2K(Element.F32_2(mRS), Trans, A, B, C);
-        int K = -1;
-        if (Trans != NO_TRANSPOSE) {
-            K = A.getType().getY();
-        } else {
-            K = A.getType().getX();
-        }
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long bID = B.getID(mRS);
-        long cID = C.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            bID = getDummyAlloc(B);
-            cID = getDummyAlloc(C);
-        }
-        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_csyr2k, Trans, 0, 0, Uplo, 0, 0, C.getType().getX(), K, alpha.x, alpha.y, aID, bID, beta.x, beta.y, cID, 0, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * ZSYR2K performs one of the symmetric rank 2k operations
-     * C := alpha*A*B**T + alpha*B*A**T + beta*C   or   C := alpha*A**T*B + alpha*B**T*A + beta*C
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/df/d20/zsyr2k_8f.html
-     *
-     * @param Uplo Specifies whether the upper or lower triangular part of C is to be referenced.
-     * @param Trans The type of transpose applied to the operation.
-     * @param alpha The scalar alpha.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64_2}.
-     * @param B The input allocation contains matrix B, supported elements type {@link Element#F64_2}.
-     * @param beta The scalar beta.
-     * @param C The input allocation contains matrix C, supported elements type {@link Element#F64_2}.
-     */
-    public void ZSYR2K(@Uplo int Uplo, @Transpose int Trans, Double2 alpha, Allocation A, Allocation B, Double2 beta, Allocation C) {
-        validateUplo(Uplo);
-        validateSYR2K(Element.F64_2(mRS), Trans, A, B, C);
-        int K = -1;
-        if (Trans != NO_TRANSPOSE) {
-            K = A.getType().getY();
-        } else {
-            K = A.getType().getX();
-        }
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long bID = B.getID(mRS);
-        long cID = C.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            bID = getDummyAlloc(B);
-            cID = getDummyAlloc(C);
-        }
-        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_zsyr2k, Trans, 0, 0, Uplo, 0, 0, C.getType().getX(), K, alpha.x, alpha.y, aID, bID, beta.x, beta.y, cID, 0, 0, 0, 0, mUseIncSupp);
-    }
-
-    static void validateTRMM(Element e, @Side int Side, @Transpose int TransA, Allocation A, Allocation B) {
-        validateSide(Side);
-        validateTranspose(TransA);
-        int aM = -1, aN = -1, bM = -1, bN = -1;
-        if (!A.getType().getElement().isCompatible(e) ||
-            !B.getType().getElement().isCompatible(e)) {
-            throw new RSRuntimeException("Called BLAS with wrong Element type");
-        }
-
-        aM = A.getType().getY();
-        aN = A.getType().getX();
-        if (aM != aN) {
-            throw new RSRuntimeException("Called TRMM with a non-symmetric matrix A");
-        }
-
-        bM = B.getType().getY();
-        bN = B.getType().getX();
-        if (Side == LEFT) {
-            if (aN != bM) {
-                throw new RSRuntimeException("Called TRMM with invalid matrices");
-            }
-        } else {
-            if (bN != aM) {
-                throw new RSRuntimeException("Called TRMM with invalid matrices");
-            }
-        }
-    }
-
-    /**
-     * STRMM performs one of the matrix-matrix operations
-     * B := alpha*op(A)*B   or   B := alpha*B*op(A)
-     * op(A) is one of  op(A) = A  or  op(A) = A**T
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/df/d01/strmm_8f.html
-     *
-     * @param Side Specifies whether the symmetric matrix A appears on the left or right.
-     * @param Uplo Specifies whether matrix A is upper or lower triangular.
-     * @param TransA The type of transpose applied to matrix A.
-     * @param Diag Specifies whether or not A is unit triangular.
-     * @param alpha The scalar alpha.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32}.
-     * @param B The input allocation contains matrix B, supported elements type {@link Element#F32}.
-     */
-    public void STRMM(@Side int Side, @Uplo int Uplo, @Transpose int TransA, @Diag int Diag, float alpha, Allocation A, Allocation B) {
-        validateUplo(Uplo);
-        validateDiag(Diag);
-        validateTRMM(Element.F32(mRS), Side, TransA, A, B);
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long bID = B.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            bID = getDummyAlloc(B);
-        }
-        mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_strmm, TransA, 0, Side, Uplo, Diag, B.getType().getY(), B.getType().getX(), 0,
-                                        alpha, aID, bID, 0.f, 0, 0, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * DTRMM performs one of the matrix-matrix operations
-     * B := alpha*op(A)*B   or   B := alpha*B*op(A)
-     * op(A) is one of  op(A) = A  or  op(A) = A**T
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/dd/d19/dtrmm_8f.html
-     *
-     * @param Side Specifies whether the symmetric matrix A appears on the left or right.
-     * @param Uplo Specifies whether matrix A is upper or lower triangular.
-     * @param TransA The type of transpose applied to matrix A.
-     * @param Diag Specifies whether or not A is unit triangular.
-     * @param alpha The scalar alpha.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64}.
-     * @param B The input allocation contains matrix B, supported elements type {@link Element#F64}.
-     */
-    public void DTRMM(@Side int Side, @Uplo int Uplo, @Transpose int TransA, @Diag int Diag, double alpha, Allocation A, Allocation B) {
-        validateUplo(Uplo);
-        validateDiag(Diag);
-        validateTRMM(Element.F64(mRS), Side, TransA, A, B);
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long bID = B.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            bID = getDummyAlloc(B);
-        }
-        mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dtrmm, TransA, 0, Side, Uplo, Diag, B.getType().getY(), B.getType().getX(), 0,
-                                        alpha, aID, bID, 0, 0, 0, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * CTRMM performs one of the matrix-matrix operations
-     * B := alpha*op(A)*B   or   B := alpha*B*op(A)
-     * op(A) is one of  op(A) = A  or  op(A) = A**T  or  op(A) = A**H
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d4/d9b/ctrmm_8f.html
-     *
-     * @param Side Specifies whether the symmetric matrix A appears on the left or right.
-     * @param Uplo Specifies whether matrix A is upper or lower triangular.
-     * @param TransA The type of transpose applied to matrix A.
-     * @param Diag Specifies whether or not A is unit triangular.
-     * @param alpha The scalar alpha.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32_2}.
-     * @param B The input allocation contains matrix B, supported elements type {@link Element#F32_2}.
-     */
-    public void CTRMM(@Side int Side, @Uplo int Uplo, @Transpose int TransA, @Diag int Diag, Float2 alpha, Allocation A, Allocation B) {
-        validateUplo(Uplo);
-        validateDiag(Diag);
-        validateTRMM(Element.F32_2(mRS), Side, TransA, A, B);
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long bID = B.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            bID = getDummyAlloc(B);
-        }
-        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_ctrmm, TransA, 0, Side, Uplo, Diag, B.getType().getY(), B.getType().getX(), 0,
-                                         alpha.x, alpha.y, aID, bID, 0, 0, 0, 0, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * ZTRMM performs one of the matrix-matrix operations
-     * B := alpha*op(A)*B   or   B := alpha*B*op(A)
-     * op(A) is one of  op(A) = A  or  op(A) = A**T  or  op(A) = A**H
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d8/de1/ztrmm_8f.html
-     *
-     * @param Side Specifies whether the symmetric matrix A appears on the left or right.
-     * @param Uplo Specifies whether matrix A is upper or lower triangular.
-     * @param TransA The type of transpose applied to matrix A.
-     * @param Diag Specifies whether or not A is unit triangular.
-     * @param alpha The scalar alpha.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64_2}.
-     * @param B The input allocation contains matrix B, supported elements type {@link Element#F64_2}.
-     */
-    public void ZTRMM(@Side int Side, @Uplo int Uplo, @Transpose int TransA, @Diag int Diag, Double2 alpha, Allocation A, Allocation B) {
-        validateUplo(Uplo);
-        validateDiag(Diag);
-        validateTRMM(Element.F64_2(mRS), Side, TransA, A, B);
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long bID = B.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            bID = getDummyAlloc(B);
-        }
-        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_ztrmm, TransA, 0, Side, Uplo, Diag, B.getType().getY(), B.getType().getX(), 0,
-                                   alpha.x, alpha.y, aID, bID, 0, 0, 0, 0, 0, 0, 0, mUseIncSupp);
-    }
-
-    static void validateTRSM(Element e, @Side int Side, @Transpose int TransA, Allocation A, Allocation B) {
-        int adim = -1, bM = -1, bN = -1;
-        validateSide(Side);
-        validateTranspose(TransA);
-        if (!A.getType().getElement().isCompatible(e) ||
-            !B.getType().getElement().isCompatible(e)) {
-            throw new RSRuntimeException("Called BLAS with wrong Element type");
-        }
-        adim = A.getType().getX();
-        if (adim != A.getType().getY()) {
-            // this may be unnecessary, the restriction could potentially be relaxed
-            // A needs to contain at least that symmetric matrix but could theoretically be larger
-            // for now we assume adapters are sufficient, will reevaluate in the future
-            throw new RSRuntimeException("Called TRSM with a non-symmetric matrix A");
-        }
-        bM = B.getType().getY();
-        bN = B.getType().getX();
-        if (Side == LEFT) {
-            // A is M*M
-            if (adim != bM) {
-                throw new RSRuntimeException("Called TRSM with invalid matrix dimensions");
-            }
-        } else {
-            // A is N*N
-            if (adim != bN) {
-                throw new RSRuntimeException("Called TRSM with invalid matrix dimensions");
-            }
-        }
-    }
-
-    /**
-     * STRSM solves one of the matrix equations
-     * op(A)*X := alpha*B   or   X*op(A) := alpha*B
-     * op(A) is one of  op(A) = A  or  op(A) = A**T
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d2/d8b/strsm_8f.html
-     *
-     * @param Side Specifies whether the symmetric matrix A appears on the left or right.
-     * @param Uplo Specifies whether matrix A is upper or lower triangular.
-     * @param TransA The type of transpose applied to matrix A.
-     * @param Diag Specifies whether or not A is unit triangular.
-     * @param alpha The scalar alpha.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32}.
-     * @param B The input allocation contains matrix B, supported elements type {@link Element#F32}.
-     */
-    public void STRSM(@Side int Side, @Uplo int Uplo, @Transpose int TransA, @Diag int Diag, float alpha, Allocation A, Allocation B) {
-        validateUplo(Uplo);
-        validateDiag(Diag);
-        validateTRSM(Element.F32(mRS), Side, TransA, A, B);
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long bID = B.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            bID = getDummyAlloc(B);
-        }
-        mRS.nScriptIntrinsicBLAS_Single(getID(mRS), RsBlas_strsm, TransA, 0, Side, Uplo, Diag, B.getType().getY(), B.getType().getX(), 0,
-                                        alpha, aID, bID, 0, 0, 0, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * DTRSM solves one of the matrix equations
-     * op(A)*X := alpha*B   or   X*op(A) := alpha*B
-     * op(A) is one of  op(A) = A  or  op(A) = A**T
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/de/da7/dtrsm_8f.html
-     *
-     * @param Side Specifies whether the symmetric matrix A appears on the left or right.
-     * @param Uplo Specifies whether matrix A is upper or lower triangular.
-     * @param TransA The type of transpose applied to matrix A.
-     * @param Diag Specifies whether or not A is unit triangular.
-     * @param alpha The scalar alpha.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64}.
-     * @param B The input allocation contains matrix B, supported elements type {@link Element#F64}.
-     */
-    public void DTRSM(@Side int Side, @Uplo int Uplo, @Transpose int TransA, @Diag int Diag, double alpha, Allocation A, Allocation B) {
-        validateUplo(Uplo);
-        validateDiag(Diag);
-        validateTRSM(Element.F64(mRS), Side, TransA, A, B);
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long bID = B.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            bID = getDummyAlloc(B);
-        }
-        mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dtrsm, TransA, 0, Side, Uplo, Diag, B.getType().getY(), B.getType().getX(), 0,
-                                        alpha, aID, bID, 0, 0, 0, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * CTRSM solves one of the matrix equations
-     * op(A)*X := alpha*B   or   X*op(A) := alpha*B
-     * op(A) is one of  op(A) = A  or  op(A) = A**T  or  op(A) = A**H
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/de/d30/ctrsm_8f.html
-     *
-     * @param Side Specifies whether the symmetric matrix A appears on the left or right.
-     * @param Uplo Specifies whether matrix A is upper or lower triangular.
-     * @param TransA The type of transpose applied to matrix A.
-     * @param Diag Specifies whether or not A is unit triangular.
-     * @param alpha The scalar alpha.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32_2}.
-     * @param B The input allocation contains matrix B, supported elements type {@link Element#F32_2}.
-     */
-    public void CTRSM(@Side int Side, @Uplo int Uplo, @Transpose int TransA, @Diag int Diag, Float2 alpha, Allocation A, Allocation B) {
-        validateUplo(Uplo);
-        validateDiag(Diag);
-        validateTRSM(Element.F32_2(mRS), Side, TransA, A, B);
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long bID = B.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            bID = getDummyAlloc(B);
-        }
-        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_ctrsm, TransA, 0, Side, Uplo, Diag, B.getType().getY(), B.getType().getX(), 0,
-                                         alpha.x, alpha.y, aID, bID, 0, 0, 0, 0, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * ZTRSM solves one of the matrix equations
-     * op(A)*X := alpha*B   or   X*op(A) := alpha*B
-     * op(A) is one of  op(A) = A  or  op(A) = A**T  or  op(A) = A**H
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d1/d39/ztrsm_8f.html
-     *
-     * @param Side Specifies whether the symmetric matrix A appears on the left or right.
-     * @param Uplo Specifies whether matrix A is upper or lower triangular.
-     * @param TransA The type of transpose applied to matrix A.
-     * @param Diag Specifies whether or not A is unit triangular.
-     * @param alpha The scalar alpha.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64_2}.
-     * @param B The input allocation contains matrix B, supported elements type {@link Element#F64_2}.
-     */
-    public void ZTRSM(@Side int Side, @Uplo int Uplo, @Transpose int TransA, @Diag int Diag, Double2 alpha, Allocation A, Allocation B) {
-        validateUplo(Uplo);
-        validateDiag(Diag);
-        validateTRSM(Element.F64_2(mRS), Side, TransA, A, B);
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long bID = B.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            bID = getDummyAlloc(B);
-        }
-        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_ztrsm, TransA, 0, Side, Uplo, Diag, B.getType().getY(), B.getType().getX(), 0,
-                                   alpha.x, alpha.y, aID, bID, 0, 0, 0, 0, 0, 0, 0, mUseIncSupp);
-    }
-
-    static void validateHEMM(Element e, @Side int Side, Allocation A, Allocation B, Allocation C) {
-        validateSide(Side);
-
-        if (!A.getType().getElement().isCompatible(e) ||
-            !B.getType().getElement().isCompatible(e) ||
-            !C.getType().getElement().isCompatible(e)) {
-            throw new RSRuntimeException("Called BLAS with wrong Element type");
-        }
-
-        // A must be square; can potentially be relaxed similar to TRSM
-        int adim = A.getType().getX();
-        if (adim != A.getType().getY()) {
-            throw new RSRuntimeException("Called HEMM with non-square A");
-        }
-        if ((Side == LEFT && adim != B.getType().getY()) ||
-            (Side == RIGHT && adim != B.getType().getX())) {
-            throw new RSRuntimeException("Called HEMM with invalid B");
-        }
-        if (B.getType().getX() != C.getType().getX() ||
-            B.getType().getY() != C.getType().getY()) {
-            throw new RSRuntimeException("Called HEMM with mismatched B and C");
-        }
-    }
-
-    /**
-     * CHEMM performs one of the matrix-matrix operations
-     * C := alpha*A*B + beta*C   or   C := alpha*B*A + beta*C
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d3/d66/chemm_8f.html
-     *
-     * @param Side Specifies whether the symmetric matrix A appears on the left or right.
-     * @param Uplo Specifies whether the upper or lower triangular part is to be referenced.
-     * @param alpha The scalar alpha.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32_2}.
-     * @param B The input allocation contains matrix B, supported elements type {@link Element#F32_2}.
-     * @param beta The scalar beta.
-     * @param C The input allocation contains matrix C, supported elements type {@link Element#F32_2}.
-     */
-    public void CHEMM(@Side int Side, @Uplo int Uplo, Float2 alpha, Allocation A, Allocation B, Float2 beta, Allocation C) {
-        validateUplo(Uplo);
-        validateHEMM(Element.F32_2(mRS), Side, A, B, C);
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long bID = B.getID(mRS);
-        long cID = C.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            bID = getDummyAlloc(B);
-            cID = getDummyAlloc(C);
-        }
-        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_chemm, 0, 0, Side, Uplo, 0, C.getType().getY(), C.getType().getX(), 0,
-                                         alpha.x, alpha.y, aID, bID, beta.x, beta.y, cID, 0, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * ZHEMM performs one of the matrix-matrix operations
-     * C := alpha*A*B + beta*C   or   C := alpha*B*A + beta*C
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d6/d3e/zhemm_8f.html
-     *
-     * @param Side Specifies whether the symmetric matrix A appears on the left or right.
-     * @param Uplo Specifies whether the upper or lower triangular part is to be referenced.
-     * @param alpha The scalar alpha.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64_2}.
-     * @param B The input allocation contains matrix B, supported elements type {@link Element#F64_2}.
-     * @param beta The scalar beta.
-     * @param C The input allocation contains matrix C, supported elements type {@link Element#F64_2}.
-     */
-    public void ZHEMM(@Side int Side, @Uplo int Uplo, Double2 alpha, Allocation A, Allocation B, Double2 beta, Allocation C) {
-        validateUplo(Uplo);
-        validateHEMM(Element.F64_2(mRS), Side, A, B, C);
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long bID = B.getID(mRS);
-        long cID = C.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            bID = getDummyAlloc(B);
-            cID = getDummyAlloc(C);
-        }
-        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_zhemm, 0, 0, Side, Uplo, 0, C.getType().getY(), C.getType().getX(), 0,
-                                   alpha.x, alpha.y, aID, bID, beta.x, beta.y, cID, 0, 0, 0, 0, mUseIncSupp);
-    }
-
-    static void validateHERK(Element e, @Transpose int Trans, Allocation A, Allocation C) {
-        if (!A.getType().getElement().isCompatible(e) ||
-            !C.getType().getElement().isCompatible(e)) {
-            throw new RSRuntimeException("Called BLAS with wrong Element type");
-        }
-        validateConjTranspose(Trans);
-        int cdim = C.getType().getX();
-        if (cdim != C.getType().getY()) {
-            throw new RSRuntimeException("Called HERK with non-square C");
-        }
-        if (Trans == NO_TRANSPOSE) {
-            if (cdim != A.getType().getY()) {
-                throw new RSRuntimeException("Called HERK with invalid A");
-            }
-        } else {
-            if (cdim != A.getType().getX()) {
-                throw new RSRuntimeException("Called HERK with invalid A");
-            }
-        }
-    }
-
-    /**
-     * CHERK performs one of the hermitian rank k operations
-     * C := alpha*A*A**H + beta*C   or   C := alpha*A**H*A + beta*C
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d8/d52/cherk_8f.html
-     *
-     * @param Uplo Specifies whether the upper or lower triangular part of C is to be referenced.
-     * @param Trans The type of transpose applied to the operation.
-     * @param alpha The scalar alpha.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32_2}.
-     * @param beta The scalar beta.
-     * @param C The input allocation contains matrix C, supported elements type {@link Element#F32_2}.
-     */
-    public void CHERK(@Uplo int Uplo, @Transpose int Trans, float alpha, Allocation A, float beta, Allocation C) {
-        validateUplo(Uplo);
-        validateHERK(Element.F32_2(mRS), Trans, A, C);
-        int k = 0;
-        if (Trans == CONJ_TRANSPOSE) {
-            k = A.getType().getY();
-        } else {
-            k = A.getType().getX();
-        }
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long cID = C.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            cID = getDummyAlloc(C);
-        }
-        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_cherk, Trans, 0, 0, Uplo, 0, 0, C.getType().getX(), k,
-                                         alpha, 0, aID, 0, beta, 0, cID, 0, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * ZHERK performs one of the hermitian rank k operations
-     * C := alpha*A*A**H + beta*C   or   C := alpha*A**H*A + beta*C
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d1/db1/zherk_8f.html
-     *
-     * @param Uplo Specifies whether the upper or lower triangular part of C is to be referenced.
-     * @param Trans The type of transpose applied to the operation.
-     * @param alpha The scalar alpha.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64_2}.
-     * @param beta The scalar beta.
-     * @param C The input allocation contains matrix C, supported elements type {@link Element#F64_2}.
-     */
-    public void ZHERK(@Uplo int Uplo, @Transpose int Trans, double alpha, Allocation A, double beta, Allocation C) {
-        validateUplo(Uplo);
-        validateHERK(Element.F64_2(mRS), Trans, A, C);
-        int k = 0;
-        if (Trans == CONJ_TRANSPOSE) {
-            k = A.getType().getY();
-        } else {
-            k = A.getType().getX();
-        }
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long cID = C.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            cID = getDummyAlloc(C);
-        }
-        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_zherk, Trans, 0, 0, Uplo, 0, 0, C.getType().getX(), k,
-                                   alpha, 0, aID, 0, beta, 0, cID, 0, 0, 0, 0, mUseIncSupp);
-    }
-
-    static void validateHER2K(Element e, @Transpose int Trans, Allocation A, Allocation B, Allocation C) {
-        if (!A.getType().getElement().isCompatible(e) ||
-            !B.getType().getElement().isCompatible(e) ||
-            !C.getType().getElement().isCompatible(e)) {
-            throw new RSRuntimeException("Called BLAS with wrong Element type");
-        }
-        validateConjTranspose(Trans);
-        int cdim = C.getType().getX();
-        if (cdim != C.getType().getY()) {
-            throw new RSRuntimeException("Called HER2K with non-square C");
-        }
-        if (Trans == NO_TRANSPOSE) {
-            if (A.getType().getY() != cdim) {
-                throw new RSRuntimeException("Called HER2K with invalid matrices");
-            }
-        } else {
-            if (A.getType().getX() != cdim) {
-                throw new RSRuntimeException("Called HER2K with invalid matrices");
-            }
-        }
-        if (A.getType().getX() != B.getType().getX() || A.getType().getY() != B.getType().getY()) {
-            throw new RSRuntimeException("Called HER2K with invalid A and B matrices");
-        }
-    }
-
-    /**
-     * CHER2K performs one of the hermitian rank 2k operations
-     * C := alpha*A*B**H + conjg( alpha )*B*A**H + beta*C   or   C := alpha*A**H*B + conjg( alpha )*B**H*A + beta*C
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d1/d82/cher2k_8f.html
-     *
-     * @param Uplo Specifies whether the upper or lower triangular part of C is to be referenced.
-     * @param Trans The type of transpose applied to the operation.
-     * @param alpha The scalar alpha.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F32_2}.
-     * @param B The input allocation contains matrix B, supported elements type {@link Element#F32_2}.
-     * @param beta The scalar beta.
-     * @param C The input allocation contains matrix C, supported elements type {@link Element#F32_2}.
-     */
-    public void CHER2K(@Uplo int Uplo, @Transpose int Trans, Float2 alpha, Allocation A, Allocation B, float beta, Allocation C) {
-        validateUplo(Uplo);
-        validateHER2K(Element.F32_2(mRS), Trans, A, B, C);
-        int k = 0;
-        if (Trans == NO_TRANSPOSE) {
-            k = A.getType().getX();
-        } else {
-            k = A.getType().getY();
-        }
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long bID = B.getID(mRS);
-        long cID = C.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            bID = getDummyAlloc(B);
-            cID = getDummyAlloc(C);
-        }
-        mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_cher2k, Trans, 0, 0, Uplo, 0, 0, C.getType().getX(), k, alpha.x, alpha.y,
-                                         A.getID(mRS), bID, beta, 0, cID, 0, 0, 0, 0, mUseIncSupp);
-    }
-
-    /**
-     * ZHER2K performs one of the hermitian rank 2k operations
-     * C := alpha*A*B**H + conjg( alpha )*B*A**H + beta*C   or   C := alpha*A**H*B + conjg( alpha )*B**H*A + beta*C
-     *
-     * Details: http://www.netlib.org/lapack/explore-html/d7/dfa/zher2k_8f.html
-     *
-     * @param Uplo Specifies whether the upper or lower triangular part of C is to be referenced.
-     * @param Trans The type of transpose applied to the operation.
-     * @param alpha The scalar alpha.
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#F64_2}.
-     * @param B The input allocation contains matrix B, supported elements type {@link Element#F64_2}.
-     * @param beta The scalar beta.
-     * @param C The input allocation contains matrix C, supported elements type {@link Element#F64_2}.
-     */
-    public void ZHER2K(@Uplo int Uplo, @Transpose int Trans, Double2 alpha, Allocation A, Allocation B, double beta, Allocation C) {
-        validateUplo(Uplo);
-        validateHER2K(Element.F64_2(mRS), Trans, A, B, C);
-        int k = 0;
-        if (Trans == NO_TRANSPOSE) {
-            k = A.getType().getX();
-        } else {
-            k = A.getType().getY();
-        }
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long bID = B.getID(mRS);
-        long cID = C.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            bID = getDummyAlloc(B);
-            cID = getDummyAlloc(C);
-        }
-        mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_zher2k, Trans, 0, 0, Uplo, 0, 0, C.getType().getX(), k, alpha.x, alpha.y,
-                                   A.getID(mRS), bID, beta, 0, cID, 0, 0, 0, 0, mUseIncSupp);
-    }
-
-
-    /**
-     * 8-bit GEMM-like operation for neural networks: C = A * Transpose(B)
-     * Calculations are done in 1.10.21 fixed-point format for the final output,
-     * just before there's a shift down to drop the fractional parts. The output
-     * values are gated to 0 to 255 to fit in a byte, but the 10-bit format
-     * gives some headroom to avoid wrapping around on small overflows.
-     *
-     * @param A The input allocation contains matrix A, supported elements type {@link Element#U8}.
-     * @param a_offset The offset for all values in matrix A, e.g A[i,j] = A[i,j] - a_offset. Value should be from 0 to 255.
-     * @param B The input allocation contains matrix B, supported elements type {@link Element#U8}.
-     * @param b_offset The offset for all values in matrix B, e.g B[i,j] = B[i,j] - b_offset. Value should be from 0 to 255.
-     * @param C The input allocation contains matrix C, supported elements type {@link Element#U8}.
-     * @param c_offset The offset for all values in matrix C.
-     * @param c_mult The multiplier for all values in matrix C, e.g C[i,j] = (C[i,j] + c_offset) * c_mult.
-     **/
-    public void BNNM(Allocation A, int a_offset, Allocation B, int b_offset, Allocation C, int c_offset, int c_mult) {
-        validateL3(Element.U8(mRS), NO_TRANSPOSE, TRANSPOSE, 0, A, B, C);
-
-        if (a_offset < 0 || a_offset > 255) {
-            throw new RSRuntimeException("Invalid a_offset passed to BNNM");
-        }
-        if (b_offset < 0 || b_offset > 255) {
-            throw new RSRuntimeException("Invalid b_offset passed to BNNM");
-        }
-        int M = -1, N = -1, K = -1;
-        M = A.getType().getY();
-        N = B.getType().getY();
-        K = A.getType().getX();
-
-        boolean mUseIncSupp = isIncSupp();
-        long aID = A.getID(mRS);
-        long bID = B.getID(mRS);
-        long cID = C.getID(mRS);
-        if (mUseIncSupp) {
-            aID = getDummyAlloc(A);
-            bID = getDummyAlloc(B);
-            cID = getDummyAlloc(C);
-        }
-        mRS.nScriptIntrinsicBLAS_BNNM(getID(mRS), M, N, K, aID, a_offset, bID, b_offset, cID, c_offset, c_mult, mUseIncSupp);
-
-    }
-
-}
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/ScriptIntrinsicBlend.java b/v8/renderscript/java/src/android/support/v8/renderscript/ScriptIntrinsicBlend.java
deleted file mode 100644
index eef581e..0000000
--- a/v8/renderscript/java/src/android/support/v8/renderscript/ScriptIntrinsicBlend.java
+++ /dev/null
@@ -1,477 +0,0 @@
-/*
- * Copyright (C) 2012 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 android.support.v8.renderscript;
-
-
-/**
- * Intrinsic kernels for blending two
- * {@link android.support.v8.renderscript.Allocation} objects.
- **/
-public class ScriptIntrinsicBlend extends ScriptIntrinsic {
-    // API level for the intrinsic
-    private static final int INTRINSIC_API_LEVEL = 19;
-
-    ScriptIntrinsicBlend(long id, RenderScript rs) {
-        super(id, rs);
-    }
-
-    /**
-     * Supported elements types are {@link Element#U8_4}
-     *
-     * @param rs The RenderScript context
-     * @param e Element type for inputs and outputs
-     *
-     * @return ScriptIntrinsicBlend
-     */
-    public static ScriptIntrinsicBlend create(RenderScript rs, Element e) {
-        // 7 comes from RS_SCRIPT_INTRINSIC_ID_BLEND in rsDefines.h
-        long id;
-        boolean mUseIncSupp = rs.isUseNative() &&
-                              android.os.Build.VERSION.SDK_INT < INTRINSIC_API_LEVEL;
-
-        id = rs.nScriptIntrinsicCreate(7, e.getID(rs), mUseIncSupp);
-
-        ScriptIntrinsicBlend si = new ScriptIntrinsicBlend(id, rs);
-        si.setIncSupp(mUseIncSupp);
-        return si;
-
-    }
-
-    private void blend(int id, Allocation ain, Allocation aout) {
-        if (!ain.getElement().isCompatible(Element.U8_4(mRS))) {
-            throw new RSIllegalArgumentException("Input is not of expected format.");
-        }
-        if (!aout.getElement().isCompatible(Element.U8_4(mRS))) {
-            throw new RSIllegalArgumentException("Output is not of expected format.");
-        }
-        forEach(id, ain, aout, null);
-    }
-
-    /**
-     * Sets dst = {0, 0, 0, 0}
-     *
-     * @param ain The source buffer
-     * @param aout The destination buffer
-     */
-    public void forEachClear(Allocation ain, Allocation aout) {
-        blend(0, ain, aout);
-    }
-
-    /**
-     * Get a KernelID for the Clear kernel.
-     *
-     * @return Script.KernelID The KernelID object.
-     */
-    public Script.KernelID getKernelIDClear() {
-        return createKernelID(0, 3, null, null);
-    }
-
-
-    /**
-     * Sets dst = src
-     *
-     * @param ain The source buffer
-     * @param aout The destination buffer
-     */
-    public void forEachSrc(Allocation ain, Allocation aout) {
-        blend(1, ain, aout);
-    }
-
-    /**
-     * Get a KernelID for the Src kernel.
-     *
-     * @return Script.KernelID The KernelID object.
-     */
-    public Script.KernelID getKernelIDSrc() {
-        return createKernelID(1, 3, null, null);
-    }
-
-    /**
-     * Sets dst = dst
-     *
-     * This is a NOP.
-     *
-     * @param ain The source buffer
-     * @param aout The destination buffer
-     */
-    public void forEachDst(Allocation ain, Allocation aout) {
-        // NOP
-    }
-
-    /**
-     * Get a KernelID for the Dst kernel.
-     *
-     * @return Script.KernelID The KernelID object.
-     */
-    public Script.KernelID getKernelIDDst() {
-        return createKernelID(2, 3, null, null);
-    }
-
-    /**
-     * Sets dst = src + dst * (1.0 - src.a)
-     *
-     * @param ain The source buffer
-     * @param aout The destination buffer
-     */
-    public void forEachSrcOver(Allocation ain, Allocation aout) {
-        blend(3, ain, aout);
-    }
-
-    /**
-     * Get a KernelID for the SrcOver kernel.
-     *
-     * @return Script.KernelID The KernelID object.
-     */
-    public Script.KernelID getKernelIDSrcOver() {
-        return createKernelID(3, 3, null, null);
-    }
-
-    /**
-     * Sets dst = dst + src * (1.0 - dst.a)
-     *
-     * @param ain The source buffer
-     * @param aout The destination buffer
-     */
-    public void forEachDstOver(Allocation ain, Allocation aout) {
-        blend(4, ain, aout);
-    }
-
-    /**
-     * Get a KernelID for the DstOver kernel.
-     *
-     * @return Script.KernelID The KernelID object.
-     */
-    public Script.KernelID getKernelIDDstOver() {
-        return createKernelID(4, 3, null, null);
-    }
-
-    /**
-     * Sets dst = src * dst.a
-     *
-     * @param ain The source buffer
-     * @param aout The destination buffer
-     */
-    public void forEachSrcIn(Allocation ain, Allocation aout) {
-        blend(5, ain, aout);
-    }
-
-    /**
-     * Get a KernelID for the SrcIn kernel.
-     *
-     * @return Script.KernelID The KernelID object.
-     */
-    public Script.KernelID getKernelIDSrcIn() {
-        return createKernelID(5, 3, null, null);
-    }
-
-    /**
-     * Sets dst = dst * src.a
-     *
-     * @param ain The source buffer
-     * @param aout The destination buffer
-     */
-    public void forEachDstIn(Allocation ain, Allocation aout) {
-        blend(6, ain, aout);
-    }
-
-    /**
-     * Get a KernelID for the DstIn kernel.
-     *
-     * @return Script.KernelID The KernelID object.
-     */
-    public Script.KernelID getKernelIDDstIn() {
-        return createKernelID(6, 3, null, null);
-    }
-
-    /**
-     * Sets dst = src * (1.0 - dst.a)
-     *
-     * @param ain The source buffer
-     * @param aout The destination buffer
-     */
-    public void forEachSrcOut(Allocation ain, Allocation aout) {
-        blend(7, ain, aout);
-    }
-
-    /**
-     * Get a KernelID for the SrcOut kernel.
-     *
-     * @return Script.KernelID The KernelID object.
-     */
-    public Script.KernelID getKernelIDSrcOut() {
-        return createKernelID(7, 3, null, null);
-    }
-
-    /**
-     * Sets dst = dst * (1.0 - src.a)
-     *
-     * @param ain The source buffer
-     * @param aout The destination buffer
-     */
-    public void forEachDstOut(Allocation ain, Allocation aout) {
-        blend(8, ain, aout);
-    }
-
-    /**
-     * Get a KernelID for the DstOut kernel.
-     *
-     * @return Script.KernelID The KernelID object.
-     */
-    public Script.KernelID getKernelIDDstOut() {
-        return createKernelID(8, 3, null, null);
-    }
-
-    /**
-     * dst.rgb = src.rgb * dst.a + (1.0 - src.a) * dst.rgb
-     * dst.a = dst.a
-     *
-     * @param ain The source buffer
-     * @param aout The destination buffer
-     */
-    public void forEachSrcAtop(Allocation ain, Allocation aout) {
-        blend(9, ain, aout);
-    }
-
-    /**
-     * Get a KernelID for the SrcAtop kernel.
-     *
-     * @return Script.KernelID The KernelID object.
-     */
-    public Script.KernelID getKernelIDSrcAtop() {
-        return createKernelID(9, 3, null, null);
-    }
-
-    /**
-     * dst = dst.rgb * src.a + (1.0 - dst.a) * src.rgb
-     * dst.a = src.a
-     * Note: Before API 23, the alpha channel was not correctly set.
-     *       Please use with caution when targeting older APIs.
-     *
-     * @param ain The source buffer
-     * @param aout The destination buffer
-     */
-    public void forEachDstAtop(Allocation ain, Allocation aout) {
-        blend(10, ain, aout);
-    }
-
-    /**
-     * Get a KernelID for the DstAtop kernel.
-     *
-     * @return Script.KernelID The KernelID object.
-     */
-    public Script.KernelID getKernelIDDstAtop() {
-        return createKernelID(10, 3, null, null);
-    }
-
-    /**
-     * Sets dst = {src.r ^ dst.r, src.g ^ dst.g, src.b ^ dst.b, src.a ^ dst.a}
-     *
-     * @param ain The source buffer
-     * @param aout The destination buffer
-     */
-    public void forEachXor(Allocation ain, Allocation aout) {
-        blend(11, ain, aout);
-    }
-
-    /**
-     * Get a KernelID for the Xor kernel.
-     *
-     * @return Script.KernelID The KernelID object.
-     */
-    public Script.KernelID getKernelIDXor() {
-        return createKernelID(11, 3, null, null);
-    }
-
-    ////////
-/*
-    public void forEachNormal(Allocation ain, Allocation aout) {
-        blend(12, ain, aout);
-    }
-
-    public void forEachAverage(Allocation ain, Allocation aout) {
-        blend(13, ain, aout);
-    }
-*/
-    /**
-     * Sets dst = src * dst
-     *
-     * @param ain The source buffer
-     * @param aout The destination buffer
-     */
-    public void forEachMultiply(Allocation ain, Allocation aout) {
-        blend(14, ain, aout);
-    }
-
-    /**
-     * Get a KernelID for the Multiply kernel.
-     *
-     * @return Script.KernelID The KernelID object.
-     */
-    public Script.KernelID getKernelIDMultiply() {
-        return createKernelID(14, 3, null, null);
-    }
-
-/*
-    public void forEachScreen(Allocation ain, Allocation aout) {
-        blend(15, ain, aout);
-    }
-
-    public void forEachDarken(Allocation ain, Allocation aout) {
-        blend(16, ain, aout);
-    }
-
-    public void forEachLighten(Allocation ain, Allocation aout) {
-        blend(17, ain, aout);
-    }
-
-    public void forEachOverlay(Allocation ain, Allocation aout) {
-        blend(18, ain, aout);
-    }
-
-    public void forEachHardlight(Allocation ain, Allocation aout) {
-        blend(19, ain, aout);
-    }
-
-    public void forEachSoftlight(Allocation ain, Allocation aout) {
-        blend(20, ain, aout);
-    }
-
-    public void forEachDifference(Allocation ain, Allocation aout) {
-        blend(21, ain, aout);
-    }
-
-    public void forEachNegation(Allocation ain, Allocation aout) {
-        blend(22, ain, aout);
-    }
-
-    public void forEachExclusion(Allocation ain, Allocation aout) {
-        blend(23, ain, aout);
-    }
-
-    public void forEachColorDodge(Allocation ain, Allocation aout) {
-        blend(24, ain, aout);
-    }
-
-    public void forEachInverseColorDodge(Allocation ain, Allocation aout) {
-        blend(25, ain, aout);
-    }
-
-    public void forEachSoftDodge(Allocation ain, Allocation aout) {
-        blend(26, ain, aout);
-    }
-
-    public void forEachColorBurn(Allocation ain, Allocation aout) {
-        blend(27, ain, aout);
-    }
-
-    public void forEachInverseColorBurn(Allocation ain, Allocation aout) {
-        blend(28, ain, aout);
-    }
-
-    public void forEachSoftBurn(Allocation ain, Allocation aout) {
-        blend(29, ain, aout);
-    }
-
-    public void forEachReflect(Allocation ain, Allocation aout) {
-        blend(30, ain, aout);
-    }
-
-    public void forEachGlow(Allocation ain, Allocation aout) {
-        blend(31, ain, aout);
-    }
-
-    public void forEachFreeze(Allocation ain, Allocation aout) {
-        blend(32, ain, aout);
-    }
-
-    public void forEachHeat(Allocation ain, Allocation aout) {
-        blend(33, ain, aout);
-    }
-*/
-    /**
-     * Sets dst = min(src + dst, 1.0)
-     *
-     * @param ain The source buffer
-     * @param aout The destination buffer
-     */
-    public void forEachAdd(Allocation ain, Allocation aout) {
-        blend(34, ain, aout);
-    }
-
-    /**
-     * Get a KernelID for the Add kernel.
-     *
-     * @return Script.KernelID The KernelID object.
-     */
-    public Script.KernelID getKernelIDAdd() {
-        return createKernelID(34, 3, null, null);
-    }
-
-    /**
-     * Sets dst = max(dst - src, 0.0)
-     *
-     * @param ain The source buffer
-     * @param aout The destination buffer
-     */
-    public void forEachSubtract(Allocation ain, Allocation aout) {
-        blend(35, ain, aout);
-    }
-
-    /**
-     * Get a KernelID for the Subtract kernel.
-     *
-     * @return Script.KernelID The KernelID object.
-     */
-    public Script.KernelID getKernelIDSubtract() {
-        return createKernelID(35, 3, null, null);
-    }
-
-/*
-    public void forEachStamp(Allocation ain, Allocation aout) {
-        blend(36, ain, aout);
-    }
-
-    public void forEachRed(Allocation ain, Allocation aout) {
-        blend(37, ain, aout);
-    }
-
-    public void forEachGreen(Allocation ain, Allocation aout) {
-        blend(38, ain, aout);
-    }
-
-    public void forEachBlue(Allocation ain, Allocation aout) {
-        blend(39, ain, aout);
-    }
-
-    public void forEachHue(Allocation ain, Allocation aout) {
-        blend(40, ain, aout);
-    }
-
-    public void forEachSaturation(Allocation ain, Allocation aout) {
-        blend(41, ain, aout);
-    }
-
-    public void forEachColor(Allocation ain, Allocation aout) {
-        blend(42, ain, aout);
-    }
-
-    public void forEachLuminosity(Allocation ain, Allocation aout) {
-        blend(43, ain, aout);
-    }
-*/
-}
-
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/ScriptIntrinsicBlur.java b/v8/renderscript/java/src/android/support/v8/renderscript/ScriptIntrinsicBlur.java
deleted file mode 100644
index e1a134a..0000000
--- a/v8/renderscript/java/src/android/support/v8/renderscript/ScriptIntrinsicBlur.java
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright (C) 2012 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 android.support.v8.renderscript;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.util.Log;
-
-/**
- * Intrinsic Gausian blur filter. Applies a gaussian blur of the
- * specified radius to all elements of an allocation.
- *
- *
- **/
-public class ScriptIntrinsicBlur extends ScriptIntrinsic {
-    private final float[] mValues = new float[9];
-    private Allocation mInput;
-    // API level for the intrinsic
-    private static final int INTRINSIC_API_LEVEL = 19;
-
-    protected ScriptIntrinsicBlur(long id, RenderScript rs) {
-        super(id, rs);
-    }
-
-    /**
-     * Create an intrinsic for applying a blur to an allocation. The
-     * default radius is 5.0.
-     *
-     * Supported elements types are {@link Element#U8},
-     * {@link Element#U8_4}.
-     *
-     * @param rs The RenderScript context
-     * @param e Element type for inputs and outputs
-     *
-     * @return ScriptIntrinsicBlur
-     */
-    public static ScriptIntrinsicBlur create(RenderScript rs, Element e) {
-        if ((!e.isCompatible(Element.U8_4(rs))) && (!e.isCompatible(Element.U8(rs)))) {
-            throw new RSIllegalArgumentException("Unsupported element type.");
-        }
-        long id;
-        boolean mUseIncSupp = rs.isUseNative() &&
-                              android.os.Build.VERSION.SDK_INT < INTRINSIC_API_LEVEL;
-
-        id = rs.nScriptIntrinsicCreate(5, e.getID(rs), mUseIncSupp);
-
-        ScriptIntrinsicBlur si = new ScriptIntrinsicBlur(id, rs);
-        si.setIncSupp(mUseIncSupp);
-        si.setRadius(5.f);
-
-        return si;
-    }
-
-    /**
-     * Set the input of the blur.
-     * Must match the element type supplied during create.
-     *
-     * @param ain The input allocation
-     */
-    public void setInput(Allocation ain) {
-        mInput = ain;
-        setVar(1, ain);
-    }
-
-    /**
-     * Set the radius of the Blur.
-     *
-     * Supported range 0 < radius <= 25
-     *
-     * @param radius The radius of the blur
-     */
-    public void setRadius(float radius) {
-        if (radius <= 0 || radius > 25) {
-            throw new RSIllegalArgumentException("Radius out of range (0 < r <= 25).");
-        }
-        setVar(0, radius);
-    }
-
-    /**
-     * Apply the filter to the input and save to the specified
-     * allocation.
-     *
-     * @param aout Output allocation. Must match creation element
-     *             type.
-     */
-    public void forEach(Allocation aout) {
-        forEach(0, (Allocation) null, aout, null);
-    }
-
-    /**
-     * Get a KernelID for this intrinsic kernel.
-     *
-     * @return Script.KernelID The KernelID object.
-     */
-    public Script.KernelID getKernelID() {
-        return createKernelID(0, 2, null, null);
-    }
-
-    /**
-     * Get a FieldID for the input field of this intrinsic.
-     *
-     * @return Script.FieldID The FieldID object.
-     */
-    public Script.FieldID getFieldID_Input() {
-        return createFieldID(1, null);
-    }
-}
-
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/ScriptIntrinsicColorMatrix.java b/v8/renderscript/java/src/android/support/v8/renderscript/ScriptIntrinsicColorMatrix.java
deleted file mode 100644
index f03526e..0000000
--- a/v8/renderscript/java/src/android/support/v8/renderscript/ScriptIntrinsicColorMatrix.java
+++ /dev/null
@@ -1,262 +0,0 @@
-/*
- * Copyright (C) 2012 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 android.support.v8.renderscript;
-
-import android.util.Log;
-
-/**
- * Intrinsic for applying a color matrix to allocations.
- *
- * This has the same effect as loading each element and
- * converting it to a {@link Element#F32_4}, multiplying the
- * result by the 4x4 color matrix as performed by
- * rsMatrixMultiply() and writing it to the output after
- * conversion back to {@link Element#U8_4}.
- **/
-public class ScriptIntrinsicColorMatrix extends ScriptIntrinsic {
-    private final Matrix4f mMatrix = new Matrix4f();
-    private final Float4 mAdd = new Float4();
-    private Allocation mInput;
-    // API level for the intrinsic
-    private static final int INTRINSIC_API_LEVEL = 19;
-
-    protected ScriptIntrinsicColorMatrix(long id, RenderScript rs) {
-        super(id, rs);
-    }
-
-    /**
-     * Create an intrinsic for applying a color matrix to an
-     * allocation.
-     *
-     * Supported elements types are {@link Element#U8_4}
-     *
-     * @param rs The RenderScript context
-     * @param e Element type for intputs and outputs
-     *
-     * @return ScriptIntrinsicColorMatrix
-     */
-    public static ScriptIntrinsicColorMatrix create(RenderScript rs, Element e) {
-        if (!e.isCompatible(Element.U8_4(rs))) {
-            throw new RSIllegalArgumentException("Unsupported element type.");
-        }
-        long id;
-        boolean mUseIncSupp = rs.isUseNative() &&
-                              android.os.Build.VERSION.SDK_INT < INTRINSIC_API_LEVEL;
-
-        id = rs.nScriptIntrinsicCreate(2, e.getID(rs), mUseIncSupp);
-
-        ScriptIntrinsicColorMatrix si = new ScriptIntrinsicColorMatrix(id, rs);
-        si.setIncSupp(mUseIncSupp);
-        return si;
-
-    }
-
-    private void setMatrix() {
-        FieldPacker fp = new FieldPacker(16*4);
-        fp.addMatrix(mMatrix);
-        setVar(0, fp);
-    }
-
-    /**
-     * Set the color matrix which will be applied to each cell of
-     * the image.
-     *
-     * @param m The 4x4 matrix to set.
-     */
-    public void setColorMatrix(Matrix4f m) {
-        mMatrix.load(m);
-        setMatrix();
-    }
-
-    /**
-     * Set the color matrix which will be applied to each cell of the image.
-     * This will set the alpha channel to be a copy.
-     *
-     * @param m The 3x3 matrix to set.
-     */
-    public void setColorMatrix(Matrix3f m) {
-        mMatrix.load(m);
-        setMatrix();
-    }
-
-    /**
-     * Set the value to be added after the color matrix has been
-     * applied. The default value is {0, 0, 0, 0}
-     *
-     * @param f The float4 value to be added.
-     */
-    public void setAdd(Float4 f) {
-        mAdd.x = f.x;
-        mAdd.y = f.y;
-        mAdd.z = f.z;
-        mAdd.w = f.w;
-
-        FieldPacker fp = new FieldPacker(4*4);
-        fp.addF32(f.x);
-        fp.addF32(f.y);
-        fp.addF32(f.z);
-        fp.addF32(f.w);
-        setVar(1, fp);
-    }
-
-    /**
-     * Set the value to be added after the color matrix has been
-     * applied. The default value is {0, 0, 0, 0}
-     *
-     * @param r The red add value.
-     * @param g The green add value.
-     * @param b The blue add value.
-     * @param a The alpha add value.
-     */
-    public void setAdd(float r, float g, float b, float a) {
-        mAdd.x = r;
-        mAdd.y = g;
-        mAdd.z = b;
-        mAdd.w = a;
-
-        FieldPacker fp = new FieldPacker(4*4);
-        fp.addF32(mAdd.x);
-        fp.addF32(mAdd.y);
-        fp.addF32(mAdd.z);
-        fp.addF32(mAdd.w);
-        setVar(1, fp);
-    }
-
-    /**
-     * Set a color matrix to convert from RGB to luminance. The alpha channel
-     * will be a copy.
-     *
-     */
-    public void setGreyscale() {
-        mMatrix.loadIdentity();
-        mMatrix.set(0, 0, 0.299f);
-        mMatrix.set(1, 0, 0.587f);
-        mMatrix.set(2, 0, 0.114f);
-        mMatrix.set(0, 1, 0.299f);
-        mMatrix.set(1, 1, 0.587f);
-        mMatrix.set(2, 1, 0.114f);
-        mMatrix.set(0, 2, 0.299f);
-        mMatrix.set(1, 2, 0.587f);
-        mMatrix.set(2, 2, 0.114f);
-        setMatrix();
-    }
-
-    /**
-     * Set the matrix to convert from YUV to RGB with a direct copy of the 4th
-     * channel.
-     *
-     */
-    public void setYUVtoRGB() {
-        mMatrix.loadIdentity();
-        mMatrix.set(0, 0, 1.f);
-        mMatrix.set(1, 0, 0.f);
-        mMatrix.set(2, 0, 1.13983f);
-        mMatrix.set(0, 1, 1.f);
-        mMatrix.set(1, 1, -0.39465f);
-        mMatrix.set(2, 1, -0.5806f);
-        mMatrix.set(0, 2, 1.f);
-        mMatrix.set(1, 2, 2.03211f);
-        mMatrix.set(2, 2, 0.f);
-        setMatrix();
-    }
-
-    /**
-     * Set the matrix to convert from RGB to YUV with a direct copy of the 4th
-     * channel.
-     *
-     */
-    public void setRGBtoYUV() {
-        mMatrix.loadIdentity();
-        mMatrix.set(0, 0, 0.299f);
-        mMatrix.set(1, 0, 0.587f);
-        mMatrix.set(2, 0, 0.114f);
-        mMatrix.set(0, 1, -0.14713f);
-        mMatrix.set(1, 1, -0.28886f);
-        mMatrix.set(2, 1, 0.436f);
-        mMatrix.set(0, 2, 0.615f);
-        mMatrix.set(1, 2, -0.51499f);
-        mMatrix.set(2, 2, -0.10001f);
-        setMatrix();
-    }
-
-
-    /**
-     * Invoke the kernel and apply the matrix to each cell of ain and copy to
-     * aout.
-     *
-     * @param ain Input allocation
-     * @param aout Output allocation
-     */
-    public void forEach(Allocation ain, Allocation aout) {
-        forEach(0, ain, aout, null);
-    }
-
-    /**
-     * Invoke the kernel and apply the matrix to each cell of input
-     * {@link Allocation} and copy to the output {@link Allocation}.
-     *
-     * If the vector size of the input is less than four, the
-     * remaining components are treated as zero for the matrix
-     * multiply.
-     *
-     * If the output vector size is less than four, the unused
-     * vector components are discarded.
-     *
-     *
-     * @param ain Input allocation
-     * @param aout Output allocation
-     * @param opt LaunchOptions for clipping
-     */
-    public void forEach(Allocation ain, Allocation aout, Script.LaunchOptions opt) {
-        if (!ain.getElement().isCompatible(Element.U8(mRS)) &&
-            !ain.getElement().isCompatible(Element.U8_2(mRS)) &&
-            !ain.getElement().isCompatible(Element.U8_3(mRS)) &&
-            !ain.getElement().isCompatible(Element.U8_4(mRS)) &&
-            !ain.getElement().isCompatible(Element.F32(mRS)) &&
-            !ain.getElement().isCompatible(Element.F32_2(mRS)) &&
-            !ain.getElement().isCompatible(Element.F32_3(mRS)) &&
-            !ain.getElement().isCompatible(Element.F32_4(mRS))) {
-
-            throw new RSIllegalArgumentException("Unsupported element type.");
-        }
-
-        if (!aout.getElement().isCompatible(Element.U8(mRS)) &&
-            !aout.getElement().isCompatible(Element.U8_2(mRS)) &&
-            !aout.getElement().isCompatible(Element.U8_3(mRS)) &&
-            !aout.getElement().isCompatible(Element.U8_4(mRS)) &&
-            !aout.getElement().isCompatible(Element.F32(mRS)) &&
-            !aout.getElement().isCompatible(Element.F32_2(mRS)) &&
-            !aout.getElement().isCompatible(Element.F32_3(mRS)) &&
-            !aout.getElement().isCompatible(Element.F32_4(mRS))) {
-
-            throw new RSIllegalArgumentException("Unsupported element type.");
-        }
-
-        forEach(0, ain, aout, null, opt);
-    }
-
-    /**
-     * Get a KernelID for this intrinsic kernel.
-     *
-     * @return Script.KernelID The KernelID object.
-     */
-    public Script.KernelID getKernelID() {
-        return createKernelID(0, 3, null, null);
-    }
-
-}
-
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/ScriptIntrinsicConvolve3x3.java b/v8/renderscript/java/src/android/support/v8/renderscript/ScriptIntrinsicConvolve3x3.java
deleted file mode 100644
index 17889aa..0000000
--- a/v8/renderscript/java/src/android/support/v8/renderscript/ScriptIntrinsicConvolve3x3.java
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * Copyright (C) 2012 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 android.support.v8.renderscript;
-
-import android.util.Log;
-
-/**
- * Intrinsic for applying a 3x3 convolve to an allocation.
- *
- **/
-public class ScriptIntrinsicConvolve3x3 extends ScriptIntrinsic {
-    private final float[] mValues = new float[9];
-    private Allocation mInput;
-    // API level for the intrinsic
-    private static final int INTRINSIC_API_LEVEL = 19;
-
-    ScriptIntrinsicConvolve3x3(long id, RenderScript rs) {
-        super(id, rs);
-    }
-
-    /**
-     * Supported elements types are {@link Element#U8}, {@link
-     * Element#U8_2}, {@link Element#U8_3}, {@link Element#U8_4},
-     * {@link Element#F32}, {@link Element#F32_2}, {@link
-     * Element#F32_3}, and {@link Element#F32_4}.
-     *
-     * <p> The default coefficients are:
-     * <code>
-     * <p> [ 0,  0,  0 ]
-     * <p> [ 0,  1,  0 ]
-     * <p> [ 0,  0,  0 ]
-     * </code>
-     *
-     * @param rs The RenderScript context
-     * @param e Element type for intputs and outputs
-     *
-     * @return ScriptIntrinsicConvolve3x3
-     */
-    public static ScriptIntrinsicConvolve3x3 create(RenderScript rs, Element e) {
-        float f[] = { 0, 0, 0, 0, 1, 0, 0, 0, 0};
-        if (!e.isCompatible(Element.U8(rs)) &&
-            !e.isCompatible(Element.U8_2(rs)) &&
-            !e.isCompatible(Element.U8_3(rs)) &&
-            !e.isCompatible(Element.U8_4(rs)) &&
-            !e.isCompatible(Element.F32(rs)) &&
-            !e.isCompatible(Element.F32_2(rs)) &&
-            !e.isCompatible(Element.F32_3(rs)) &&
-            !e.isCompatible(Element.F32_4(rs))) {
-            throw new RSIllegalArgumentException("Unsupported element type.");
-        }
-        long id;
-        boolean mUseIncSupp = rs.isUseNative() &&
-                              android.os.Build.VERSION.SDK_INT < INTRINSIC_API_LEVEL;
-
-        id = rs.nScriptIntrinsicCreate(1, e.getID(rs), mUseIncSupp);
-
-        ScriptIntrinsicConvolve3x3 si = new ScriptIntrinsicConvolve3x3(id, rs);
-        si.setIncSupp(mUseIncSupp);
-        si.setCoefficients(f);
-        return si;
-    }
-
-    /**
-     * Set the input of the 3x3 convolve.
-     * Must match the element type supplied during create.
-     *
-     * @param ain The input allocation.
-     */
-    public void setInput(Allocation ain) {
-        mInput = ain;
-        setVar(1, ain);
-    }
-
-    /**
-     * Set the coefficients for the convolve.
-     *
-     * <p> The convolve layout is:
-     * <code>
-     * <p> [ 0,  1,  2 ]
-     * <p> [ 3,  4,  5 ]
-     * <p> [ 6,  7,  8 ]
-     * </code>
-     *
-     * @param v The array of coefficients to set
-     */
-    public void setCoefficients(float v[]) {
-        FieldPacker fp = new FieldPacker(9*4);
-        for (int ct=0; ct < mValues.length; ct++) {
-            mValues[ct] = v[ct];
-            fp.addF32(mValues[ct]);
-        }
-        setVar(0, fp);
-    }
-
-    /**
-     * Apply the filter to the input and save to the specified
-     * allocation.
-     *
-     * @param aout Output allocation. Must match creation element
-     *             type.
-     */
-    public void forEach(Allocation aout) {
-        forEach(0, (Allocation) null, aout, null);
-    }
-
-    /**
-     * Apply the filter to the input and save to the specified
-     * allocation.
-     *
-     * @param aout Output allocation. Must match creation element
-     *             type.
-     * @param opt LaunchOptions for clipping
-     */
-    public void forEach(Allocation aout, Script.LaunchOptions opt) {
-        forEach(0, (Allocation) null, aout, null, opt);
-    }
-
-    /**
-     * Get a KernelID for this intrinsic kernel.
-     *
-     * @return Script.KernelID The KernelID object.
-     */
-    public Script.KernelID getKernelID() {
-        return createKernelID(0, 2, null, null);
-    }
-
-    /**
-     * Get a FieldID for the input field of this intrinsic.
-     *
-     * @return Script.FieldID The FieldID object.
-     */
-    public Script.FieldID getFieldID_Input() {
-        return createFieldID(1, null);
-    }
-
-}
-
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/ScriptIntrinsicConvolve5x5.java b/v8/renderscript/java/src/android/support/v8/renderscript/ScriptIntrinsicConvolve5x5.java
deleted file mode 100644
index 2c591ba..0000000
--- a/v8/renderscript/java/src/android/support/v8/renderscript/ScriptIntrinsicConvolve5x5.java
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * Copyright (C) 2012 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 android.support.v8.renderscript;
-
-import android.util.Log;
-
-/**
- * Intrinsic for applying a 5x5 convolve to an allocation.
- *
- **/
-public class ScriptIntrinsicConvolve5x5 extends ScriptIntrinsic {
-    private final float[] mValues = new float[25];
-    private Allocation mInput;
-    // API level for the intrinsic
-    private static final int INTRINSIC_API_LEVEL = 19;
-
-    ScriptIntrinsicConvolve5x5(long id, RenderScript rs) {
-        super(id, rs);
-    }
-
-    /**
-     * Supported elements types are {@link Element#U8}, {@link
-     * Element#U8_2}, {@link Element#U8_3}, {@link Element#U8_4},
-     * {@link Element#F32}, {@link Element#F32_2}, {@link
-     * Element#F32_3}, and {@link Element#F32_4}.
-     *
-     * <p> The default coefficients are:
-     * <code>
-     * <p> [ 0,  0,  0,  0,  0  ]
-     * <p> [ 0,  0,  0,  0,  0  ]
-     * <p> [ 0,  0,  1,  0,  0  ]
-     * <p> [ 0,  0,  0,  0,  0  ]
-     * <p> [ 0,  0,  0,  0,  0  ]
-     * </code>
-     *
-     * @param rs The RenderScript context
-     * @param e Element type for intputs and outputs
-     *
-     * @return ScriptIntrinsicConvolve5x5
-     */
-    public static ScriptIntrinsicConvolve5x5 create(RenderScript rs, Element e) {
-        if (!e.isCompatible(Element.U8(rs)) &&
-            !e.isCompatible(Element.U8_2(rs)) &&
-            !e.isCompatible(Element.U8_3(rs)) &&
-            !e.isCompatible(Element.U8_4(rs)) &&
-            !e.isCompatible(Element.F32(rs)) &&
-            !e.isCompatible(Element.F32_2(rs)) &&
-            !e.isCompatible(Element.F32_3(rs)) &&
-            !e.isCompatible(Element.F32_4(rs))) {
-            throw new RSIllegalArgumentException("Unsupported element type.");
-        }
-        long id;
-        boolean mUseIncSupp = rs.isUseNative() &&
-                              android.os.Build.VERSION.SDK_INT < INTRINSIC_API_LEVEL;
-
-        id = rs.nScriptIntrinsicCreate(4, e.getID(rs), mUseIncSupp);
-
-        ScriptIntrinsicConvolve5x5 si = new ScriptIntrinsicConvolve5x5(id, rs);
-        si.setIncSupp(mUseIncSupp);
-        return si;
-
-    }
-
-    /**
-     * Set the input of the 5x5 convolve.
-     * Must match the element type supplied during create.
-     *
-     * @param ain The input allocation.
-     */
-    public void setInput(Allocation ain) {
-        mInput = ain;
-        setVar(1, ain);
-    }
-
-    /**
-    * Set the coefficients for the convolve.
-    *
-    * <p> The convolve layout is:
-    * <code>
-    * <p> [ 0,  1,  2,  3,  4  ]
-    * <p> [ 5,  6,  7,  8,  9  ]
-    * <p> [ 10, 11, 12, 13, 14 ]
-    * <p> [ 15, 16, 17, 18, 19 ]
-    * <p> [ 20, 21, 22, 23, 24 ]
-    * </code>
-    *
-    * @param v The array of coefficients to set
-    */
-    public void setCoefficients(float v[]) {
-        FieldPacker fp = new FieldPacker(25*4);
-        for (int ct=0; ct < mValues.length; ct++) {
-            mValues[ct] = v[ct];
-            fp.addF32(mValues[ct]);
-        }
-        setVar(0, fp);
-    }
-
-    /**
-     * Apply the filter to the input and save to the specified
-     * allocation.
-     *
-     * @param aout Output allocation. Must match creation element
-     *             type.
-     */
-    public void forEach(Allocation aout) {
-        forEach(0, (Allocation) null, aout, null);
-    }
-
-    /**
-     * Apply the filter to the input and save to the specified
-     * allocation.
-     *
-     * @param aout Output allocation. Must match creation element
-     *             type.
-     * @param opt LaunchOptions for clipping
-     */
-    public void forEach(Allocation aout, Script.LaunchOptions opt) {
-        forEach(0, (Allocation) null, aout, null, opt);
-    }
-
-
-    /**
-     * Get a KernelID for this intrinsic kernel.
-     *
-     * @return Script.KernelID The KernelID object.
-     */
-    public Script.KernelID getKernelID() {
-        return createKernelID(0, 2, null, null);
-    }
-
-    /**
-     * Get a FieldID for the input field of this intrinsic.
-     *
-     * @return Script.FieldID The FieldID object.
-     */
-    public Script.FieldID getFieldID_Input() {
-        return createFieldID(1, null);
-    }
-}
-
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/ScriptIntrinsicHistogram.java b/v8/renderscript/java/src/android/support/v8/renderscript/ScriptIntrinsicHistogram.java
deleted file mode 100644
index e3e6406..0000000
--- a/v8/renderscript/java/src/android/support/v8/renderscript/ScriptIntrinsicHistogram.java
+++ /dev/null
@@ -1,232 +0,0 @@
-/*
- * 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 android.support.v8.renderscript;
-
-import android.util.Log;
-
-/**
- * Intrinsic Histogram filter.
- *
- *
- **/
-public class ScriptIntrinsicHistogram extends ScriptIntrinsic {
-    private Allocation mOut;
-    // API level for the intrinsic
-    private static final int INTRINSIC_API_LEVEL = 19;
-
-    protected ScriptIntrinsicHistogram(long id, RenderScript rs) {
-        super(id, rs);
-    }
-
-    /**
-     * Create an intrinsic for calculating the histogram of an uchar
-     * or uchar4 image.
-     *
-     * Supported elements types are
-     * {@link Element#U8_4}, {@link Element#U8_3},
-     * {@link Element#U8_2}, {@link Element#U8}
-     *
-     * @param rs The RenderScript context
-     * @param e Element type for inputs
-     *
-     * @return ScriptIntrinsicHistogram
-     */
-    public static ScriptIntrinsicHistogram create(RenderScript rs, Element e) {
-        if ((!e.isCompatible(Element.U8_4(rs))) &&
-            (!e.isCompatible(Element.U8_3(rs))) &&
-            (!e.isCompatible(Element.U8_2(rs))) &&
-            (!e.isCompatible(Element.U8(rs)))) {
-            throw new RSIllegalArgumentException("Unsupported element type.");
-        }
-        long id;
-        boolean mUseIncSupp = rs.isUseNative() &&
-                              android.os.Build.VERSION.SDK_INT < INTRINSIC_API_LEVEL;
-
-        id = rs.nScriptIntrinsicCreate(9, e.getID(rs), mUseIncSupp);
-
-        ScriptIntrinsicHistogram si = new ScriptIntrinsicHistogram(id, rs);
-        si.setIncSupp(mUseIncSupp);
-        return si;
-    }
-
-    /**
-     * Process an input buffer and place the histogram into the
-     * output allocation. The output allocation may be a narrower
-     * vector size than the input. In this case the vector size of
-     * the output is used to determine how many of the input
-     * channels are used in the computation. This is useful if you
-     * have an RGBA input buffer but only want the histogram for
-     * RGB.
-     *
-     * 1D and 2D input allocations are supported.
-     *
-     * @param ain The input image
-     */
-    public void forEach(Allocation ain) {
-        forEach(ain, null);
-    }
-
-    /**
-     * Process an input buffer and place the histogram into the
-     * output allocation. The output allocation may be a narrower
-     * vector size than the input. In this case the vector size of
-     * the output is used to determine how many of the input
-     * channels are used in the computation. This is useful if you
-     * have an RGBA input buffer but only want the histogram for
-     * RGB.
-     *
-     * 1D and 2D input allocations are supported.
-     *
-     * @param ain The input image
-     * @param opt LaunchOptions for clipping
-     */
-    public void forEach(Allocation ain, Script.LaunchOptions opt) {
-        if (ain.getType().getElement().getVectorSize() <
-            mOut.getType().getElement().getVectorSize()) {
-
-            throw new RSIllegalArgumentException(
-                "Input vector size must be >= output vector size.");
-        }
-        if (!ain.getType().getElement().isCompatible(Element.U8(mRS)) &&
-            !ain.getType().getElement().isCompatible(Element.U8_2(mRS)) &&
-            !ain.getType().getElement().isCompatible(Element.U8_3(mRS)) &&
-            !ain.getType().getElement().isCompatible(Element.U8_4(mRS))) {
-            throw new RSIllegalArgumentException("Input type must be U8, U8_1, U8_2 or U8_4.");
-        }
-
-        forEach(0, ain, null, null, opt);
-    }
-
-
-
-    /**
-     * Set the coefficients used for the RGBA to Luminocity
-     * calculation. The default is {0.299f, 0.587f, 0.114f, 0.f}.
-     *
-     * Coefficients must be >= 0 and sum to 1.0 or less.
-     *
-     * @param r Red coefficient
-     * @param g Green coefficient
-     * @param b Blue coefficient
-     * @param a Alpha coefficient
-     */
-    public void setDotCoefficients(float r, float g, float b, float a) {
-        if ((r < 0.f) || (g < 0.f) || (b < 0.f) || (a < 0.f)) {
-            throw new RSIllegalArgumentException("Coefficient may not be negative.");
-        }
-        if ((r + g + b + a) > 1.f) {
-            throw new RSIllegalArgumentException("Sum of coefficients must be 1.0 or less.");
-        }
-
-        FieldPacker fp = new FieldPacker(16);
-        fp.addF32(r);
-        fp.addF32(g);
-        fp.addF32(b);
-        fp.addF32(a);
-        setVar(0, fp);
-    }
-
-    /**
-     * Set the output of the histogram.  32 bit integer types are
-     * supported.
-     *
-     * @param aout The output allocation
-     */
-    public void setOutput(Allocation aout) {
-        mOut = aout;
-        if (mOut.getType().getElement() != Element.U32(mRS) &&
-            mOut.getType().getElement() != Element.U32_2(mRS) &&
-            mOut.getType().getElement() != Element.U32_3(mRS) &&
-            mOut.getType().getElement() != Element.U32_4(mRS) &&
-            mOut.getType().getElement() != Element.I32(mRS) &&
-            mOut.getType().getElement() != Element.I32_2(mRS) &&
-            mOut.getType().getElement() != Element.I32_3(mRS) &&
-            mOut.getType().getElement() != Element.I32_4(mRS)) {
-
-            throw new RSIllegalArgumentException("Output type must be U32 or I32.");
-        }
-        if ((mOut.getType().getX() != 256) ||
-            (mOut.getType().getY() != 0) ||
-            mOut.getType().hasMipmaps() ||
-            (mOut.getType().getYuv() != 0)) {
-
-            throw new RSIllegalArgumentException("Output must be 1D, 256 elements.");
-        }
-        setVar(1, aout);
-    }
-
-
-    /**
-     * Process an input buffer and place the histogram into the
-     * output allocation. The dot product of the input channel and
-     * the coefficients from 'setDotCoefficients' are used to
-     * calculate the output values.
-     *
-     * 1D and 2D input allocations are supported.
-     *
-     * @param ain The input image
-     */
-    public void forEach_Dot(Allocation ain) {
-        forEach_Dot(ain, null);
-    }
-
-    /**
-     * Process an input buffer and place the histogram into the
-     * output allocation. The dot product of the input channel and
-     * the coefficients from 'setDotCoefficients' are used to
-     * calculate the output values.
-     *
-     * 1D and 2D input allocations are supported.
-     *
-     * @param ain The input image
-     * @param opt LaunchOptions for clipping
-     */
-    public void forEach_Dot(Allocation ain, Script.LaunchOptions opt) {
-        if (mOut.getType().getElement().getVectorSize() != 1) {
-            throw new RSIllegalArgumentException("Output vector size must be one.");
-        }
-        if (!ain.getType().getElement().isCompatible(Element.U8(mRS)) &&
-            !ain.getType().getElement().isCompatible(Element.U8_2(mRS)) &&
-            !ain.getType().getElement().isCompatible(Element.U8_3(mRS)) &&
-            !ain.getType().getElement().isCompatible(Element.U8_4(mRS))) {
-            throw new RSIllegalArgumentException("Input type must be U8, U8_1, U8_2 or U8_4.");
-        }
-
-        forEach(1, ain, null, null, opt);
-    }
-
-
-
-    /**
-     * Get a KernelID for this intrinsic kernel.
-     *
-     * @return Script.KernelID The KernelID object.
-     */
-    public Script.KernelID getKernelID_Separate() {
-        return createKernelID(0, 3, null, null);
-    }
-
-    /**
-     * Get a FieldID for the input field of this intrinsic.
-     *
-     * @return Script.FieldID The FieldID object.
-     */
-    public Script.FieldID getFieldID_Input() {
-        return createFieldID(1, null);
-    }
-}
-
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/ScriptIntrinsicLUT.java b/v8/renderscript/java/src/android/support/v8/renderscript/ScriptIntrinsicLUT.java
deleted file mode 100644
index 0b905ba..0000000
--- a/v8/renderscript/java/src/android/support/v8/renderscript/ScriptIntrinsicLUT.java
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * Copyright (C) 2012 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 android.support.v8.renderscript;
-
-import android.util.Log;
-
-/**
- * Intrinsic for applying a per-channel lookup table. Each
- * channel of the input has an independant lookup table. The
- * tables are 256 entries in size and can cover the full value
- * range of {@link Element#U8_4}.
- **/
-public class ScriptIntrinsicLUT extends ScriptIntrinsic {
-    private final Matrix4f mMatrix = new Matrix4f();
-    private Allocation mTables;
-    private final byte mCache[] = new byte[1024];
-    private boolean mDirty = true;
-    // API level for the intrinsic
-    private static final int INTRINSIC_API_LEVEL = 19;
-
-    protected ScriptIntrinsicLUT(long id, RenderScript rs) {
-        super(id, rs);
-    }
-
-    /**
-     * Supported elements types are {@link Element#U8_4}
-     *
-     * The defaults tables are identity.
-     *
-     * @param rs The RenderScript context
-     * @param e Element type for intputs and outputs
-     *
-     * @return ScriptIntrinsicLUT
-     */
-    public static ScriptIntrinsicLUT create(RenderScript rs, Element e) {
-        long id;
-        boolean mUseIncSupp = rs.isUseNative() &&
-                              android.os.Build.VERSION.SDK_INT < INTRINSIC_API_LEVEL;
-
-        id = rs.nScriptIntrinsicCreate(3, e.getID(rs), mUseIncSupp);
-
-        ScriptIntrinsicLUT si = new ScriptIntrinsicLUT(id, rs);
-        si.setIncSupp(mUseIncSupp);
-        si.mTables = Allocation.createSized(rs, Element.U8(rs), 1024);
-        for (int ct=0; ct < 256; ct++) {
-            si.mCache[ct] = (byte)ct;
-            si.mCache[ct + 256] = (byte)ct;
-            si.mCache[ct + 512] = (byte)ct;
-            si.mCache[ct + 768] = (byte)ct;
-        }
-        si.setVar(0, si.mTables);
-        return si;
-    }
-
-
-    private void validate(int index, int value) {
-        if (index < 0 || index > 255) {
-            throw new RSIllegalArgumentException("Index out of range (0-255).");
-        }
-        if (value < 0 || value > 255) {
-            throw new RSIllegalArgumentException("Value out of range (0-255).");
-        }
-    }
-
-    /**
-     * Set an entry in the red channel lookup table
-     *
-     * @param index Must be 0-255
-     * @param value Must be 0-255
-     */
-    public void setRed(int index, int value) {
-        validate(index, value);
-        mCache[index] = (byte)value;
-        mDirty = true;
-    }
-
-    /**
-     * Set an entry in the green channel lookup table
-     *
-     * @param index Must be 0-255
-     * @param value Must be 0-255
-     */
-    public void setGreen(int index, int value) {
-        validate(index, value);
-        mCache[index+256] = (byte)value;
-        mDirty = true;
-    }
-
-    /**
-     * Set an entry in the blue channel lookup table
-     *
-     * @param index Must be 0-255
-     * @param value Must be 0-255
-     */
-    public void setBlue(int index, int value) {
-        validate(index, value);
-        mCache[index+512] = (byte)value;
-        mDirty = true;
-    }
-
-    /**
-     * Set an entry in the alpha channel lookup table
-     *
-     * @param index Must be 0-255
-     * @param value Must be 0-255
-     */
-    public void setAlpha(int index, int value) {
-        validate(index, value);
-        mCache[index+768] = (byte)value;
-        mDirty = true;
-    }
-
-
-    /**
-     * Invoke the kernel and apply the lookup to each cell of ain
-     * and copy to aout.
-     *
-     * @param ain Input allocation
-     * @param aout Output allocation
-     */
-    public void forEach(Allocation ain, Allocation aout) {
-        if (mDirty) {
-            mDirty = false;
-            mTables.copyFromUnchecked(mCache);
-        }
-        forEach(0, ain, aout, null);
-    }
-
-    /**
-     * Get a KernelID for this intrinsic kernel.
-     *
-     * @return Script.KernelID The KernelID object.
-     */
-    public Script.KernelID getKernelID() {
-        return createKernelID(0, 3, null, null);
-    }
-}
-
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/ScriptIntrinsicResize.java b/v8/renderscript/java/src/android/support/v8/renderscript/ScriptIntrinsicResize.java
deleted file mode 100644
index 61c169c..0000000
--- a/v8/renderscript/java/src/android/support/v8/renderscript/ScriptIntrinsicResize.java
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * 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 android.support.v8.renderscript;
-
-import android.util.Log;
-
-/**
- * Intrinsic for performing a resize of a 2D allocation.
- */
-public class ScriptIntrinsicResize extends ScriptIntrinsic {
-    private Allocation mInput;
-    // API level for the intrinsic
-    private static final int INTRINSIC_API_LEVEL = 21;
-
-    protected ScriptIntrinsicResize(long id, RenderScript rs) {
-        super(id, rs);
-    }
-
-    /**
-     * Supported elements types are {@link Element#U8}, {@link
-     * Element#U8_2}, {@link Element#U8_3}, {@link Element#U8_4}
-     * {@link Element#F32}, {@link Element#F32_2}, {@link
-     * Element#F32_3}, {@link Element#F32_4}
-     *
-     * @param rs The RenderScript context
-     *
-     * @return ScriptIntrinsicResize
-     */
-    public static ScriptIntrinsicResize create(RenderScript rs) {
-        long id;
-        boolean mUseIncSupp = rs.isUseNative() &&
-                              android.os.Build.VERSION.SDK_INT < INTRINSIC_API_LEVEL;
-
-        id = rs.nScriptIntrinsicCreate(12, 0, mUseIncSupp);
-
-        ScriptIntrinsicResize si = new ScriptIntrinsicResize(id, rs);
-        si.setIncSupp(mUseIncSupp);
-        return si;
-
-    }
-
-    /**
-     * Set the input of the resize.
-     * Must match the element type supplied during create.
-     *
-     * @param ain The input allocation.
-     */
-    public void setInput(Allocation ain) {
-        Element e = ain.getElement();
-        if (!e.isCompatible(Element.U8(mRS)) &&
-            !e.isCompatible(Element.U8_2(mRS)) &&
-            !e.isCompatible(Element.U8_3(mRS)) &&
-            !e.isCompatible(Element.U8_4(mRS)) &&
-            !e.isCompatible(Element.F32(mRS)) &&
-            !e.isCompatible(Element.F32_2(mRS)) &&
-            !e.isCompatible(Element.F32_3(mRS)) &&
-            !e.isCompatible(Element.F32_4(mRS))) {
-            throw new RSIllegalArgumentException("Unsupported element type.");
-        }
-
-        mInput = ain;
-        setVar(0, ain);
-    }
-
-    /**
-     * Get a FieldID for the input field of this intrinsic.
-     *
-     * @return Script.FieldID The FieldID object.
-     */
-    public Script.FieldID getFieldID_Input() {
-        return createFieldID(0, null);
-    }
-
-
-    /**
-     * Resize copy the input allocation to the output specified. The
-     * Allocation is rescaled if necessary using bi-cubic
-     * interpolation.
-     *
-     * @param aout Output allocation. Element type must match
-     *             current input.  Must not be same as input.
-     */
-    public void forEach_bicubic(Allocation aout) {
-        if (aout == mInput) {
-            throw new RSIllegalArgumentException("Output cannot be same as Input.");
-        }
-        forEach_bicubic(aout, null);
-    }
-
-    /**
-     * Resize copy the input allocation to the output specified. The
-     * Allocation is rescaled if necessary using bi-cubic
-     * interpolation.
-     *
-     * @param aout Output allocation. Element type must match
-     *             current input.
-     * @param opt LaunchOptions for clipping
-     */
-    public void forEach_bicubic(Allocation aout, Script.LaunchOptions opt) {
-        forEach(0, (Allocation) null, aout, null, opt);
-    }
-
-    /**
-     * Get a KernelID for this intrinsic kernel.
-     *
-     * @return Script.KernelID The KernelID object.
-     */
-    public Script.KernelID getKernelID_bicubic() {
-        return createKernelID(0, 2, null, null);
-    }
-
-
-}
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/ScriptIntrinsicYuvToRGB.java b/v8/renderscript/java/src/android/support/v8/renderscript/ScriptIntrinsicYuvToRGB.java
deleted file mode 100644
index 6c84020..0000000
--- a/v8/renderscript/java/src/android/support/v8/renderscript/ScriptIntrinsicYuvToRGB.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright (C) 2012 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 android.support.v8.renderscript;
-
-
-/**
- * Intrinsic for converting an Android YUV buffer to RGB.
- *
- * The input allocation is supplied in NV21 format as a U8
- * element type. The output is RGBA, the alpha channel will be
- * set to 255.
- */
-public class ScriptIntrinsicYuvToRGB extends ScriptIntrinsic {
-    private Allocation mInput;
-    // API level for the intrinsic
-    private static final int INTRINSIC_API_LEVEL = 19;
-
-    ScriptIntrinsicYuvToRGB(long id, RenderScript rs) {
-        super(id, rs);
-    }
-
-    /**
-     * Create an intrinsic for converting YUV to RGB.
-     *
-     * Supported elements types are {@link Element#U8_4}
-     *
-     * @param rs The RenderScript context
-     * @param e Element type for output
-     *
-     * @return ScriptIntrinsicYuvToRGB
-     */
-    public static ScriptIntrinsicYuvToRGB create(RenderScript rs, Element e) {
-        // 6 comes from RS_SCRIPT_INTRINSIC_YUV_TO_RGB in rsDefines.h
-        long id;
-        boolean mUseIncSupp = rs.isUseNative() &&
-                              android.os.Build.VERSION.SDK_INT < INTRINSIC_API_LEVEL;
-
-        id = rs.nScriptIntrinsicCreate(6, e.getID(rs), mUseIncSupp);
-
-        ScriptIntrinsicYuvToRGB si = new ScriptIntrinsicYuvToRGB(id, rs);
-        si.setIncSupp(mUseIncSupp);
-        return si;
-    }
-
-
-    /**
-     * Set the input yuv allocation, must be {@link Element#U8}.
-     *
-     * @param ain The input allocation.
-     */
-    public void setInput(Allocation ain) {
-        mInput = ain;
-        setVar(0, ain);
-    }
-
-    /**
-     * Convert the image to RGB.
-     *
-     * @param aout Output allocation. Must match creation element
-     *             type.
-     */
-    public void forEach(Allocation aout) {
-        forEach(0, (Allocation) null, aout, null);
-    }
-
-    /**
-     * Get a KernelID for this intrinsic kernel.
-     *
-     * @return Script.KernelID The KernelID object.
-     */
-    public Script.KernelID getKernelID() {
-        return createKernelID(0, 2, null, null);
-    }
-
-    /**
-     * Get a FieldID for the input field of this intrinsic.
-     *
-     * @return Script.FieldID The FieldID object.
-     */
-    public Script.FieldID getFieldID_Input() {
-        return createFieldID(0, null);
-    }
-}
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/Short2.java b/v8/renderscript/java/src/android/support/v8/renderscript/Short2.java
deleted file mode 100644
index 365b319..0000000
--- a/v8/renderscript/java/src/android/support/v8/renderscript/Short2.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2009 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 android.support.v8.renderscript;
-
-import java.lang.Math;
-import android.util.Log;
-
-
-/**
- * Class for exposing the native RenderScript Short2 type back to the Android system.
- *
- **/
-public class Short2 {
-    public Short2() {
-    }
-
-    public Short2(short initX, short initY) {
-        x = initX;
-        y = initY;
-    }
-
-    public short x;
-    public short y;
-}
-
-
-
-
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/Short3.java b/v8/renderscript/java/src/android/support/v8/renderscript/Short3.java
deleted file mode 100644
index abf8196..0000000
--- a/v8/renderscript/java/src/android/support/v8/renderscript/Short3.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2009 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 android.support.v8.renderscript;
-
-import java.lang.Math;
-import android.util.Log;
-
-
-/**
- * Class for exposing the native RenderScript short3 type back to the Android system.
- *
- **/
-public class Short3 {
-    public Short3() {
-    }
-
-    public Short3(short initX, short initY, short initZ) {
-        x = initX;
-        y = initY;
-        z = initZ;
-    }
-
-    public short x;
-    public short y;
-    public short z;
-}
-
-
-
-
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/Short4.java b/v8/renderscript/java/src/android/support/v8/renderscript/Short4.java
deleted file mode 100644
index d2108e4..0000000
--- a/v8/renderscript/java/src/android/support/v8/renderscript/Short4.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2009 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 android.support.v8.renderscript;
-
-import java.lang.Math;
-import android.util.Log;
-
-
-/**
- * Class for exposing the native RenderScript short4 type back to the Android system.
- *
- **/
-public class Short4 {
-    public Short4() {
-    }
-
-    public Short4(short initX, short initY, short initZ, short initW) {
-        x = initX;
-        y = initY;
-        z = initZ;
-        w = initW;
-    }
-
-    public short x;
-    public short y;
-    public short z;
-    public short w;
-}
-
-
-
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/Type.java b/v8/renderscript/java/src/android/support/v8/renderscript/Type.java
deleted file mode 100644
index 6aeb9ea..0000000
--- a/v8/renderscript/java/src/android/support/v8/renderscript/Type.java
+++ /dev/null
@@ -1,411 +0,0 @@
-/*
- * Copyright (C) 2013 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 android.support.v8.renderscript;
-
-
-import java.lang.reflect.Field;
-
-import android.graphics.ImageFormat;
-import android.util.Log;
-
-/**
- * <p>A Type describes the {@link android.support.v8.renderscript.Element} and
- * dimensions used for an {@link android.support.v8.renderscript.Allocation} or
- * a parallel operation. Types are created through
- * {@link android.support.v8.renderscript.Type.Builder}.</p>
- *
- * <p>A Type always includes an {@link android.support.v8.renderscript.Element}
- * and an X dimension. A Type may be multidimensional, up to three dimensions.
- * A nonzero value in the Y or Z dimensions indicates that the dimension is
- * present. Note that a Type with only a given X dimension and a Type with the
- * same X dimension but Y = 1 are not equivalent.</p>
- *
- * <p>A Type also supports inclusion of level of detail (LOD) or cube map
- * faces. LOD and cube map faces are booleans to indicate present or not
- * present. </p>
- *
- * <p>A Type also supports YUV format information to support an {@link
- * android.support.v8.renderscript.Allocation} in a YUV format. The YUV formats
- * supported are {@link android.graphics.ImageFormat#YV12} and {@link
- * android.graphics.ImageFormat#NV21}.</p>
- *
- * <div class="special reference">
- * <h3>Developer Guides</h3>
- * <p>For more information about creating an application that uses RenderScript,
- * read the
- * <a href="{@docRoot}guide/topics/renderscript/index.html">RenderScript</a>
- * developer guide.</p>
- * </div>
- **/
-public class Type extends BaseObj {
-    int mDimX;
-    int mDimY;
-    int mDimZ;
-    boolean mDimMipmaps;
-    boolean mDimFaces;
-    int mDimYuv;
-    int mElementCount;
-    Element mElement;
-
-    public enum CubemapFace {
-        POSITIVE_X (0),
-        NEGATIVE_X (1),
-        POSITIVE_Y (2),
-        NEGATIVE_Y (3),
-        POSITIVE_Z (4),
-        NEGATIVE_Z (5);
-
-        int mID;
-        CubemapFace(int id) {
-            mID = id;
-        }
-    }
-
-    /**
-     * Return the element associated with this Type.
-     *
-     * @return Element
-     */
-    public Element getElement() {
-        return mElement;
-    }
-
-    /**
-     * Return the value of the X dimension.
-     *
-     * @return int
-     */
-    public int getX() {
-        return mDimX;
-    }
-
-    /**
-     * Return the value of the Y dimension or 0 for a 1D allocation.
-     *
-     * @return int
-     */
-    public int getY() {
-        return mDimY;
-    }
-
-    /**
-     * Return the value of the Z dimension or 0 for a 1D or 2D allocation.
-     *
-     * @return int
-     */
-    public int getZ() {
-        return mDimZ;
-    }
-
-    /**
-     * Get the YUV format
-     *
-     * @return int
-     */
-    public int getYuv() {
-        return mDimYuv;
-    }
-
-    /**
-     * Return if the Type has a mipmap chain.
-     *
-     * @return boolean
-     */
-    public boolean hasMipmaps() {
-        return mDimMipmaps;
-    }
-
-    /**
-     * Return if the Type is a cube map.
-     *
-     * @return boolean
-     */
-    public boolean hasFaces() {
-        return mDimFaces;
-    }
-
-    /**
-     * Return the total number of accessable cells in the Type.
-     *
-     * @return int
-     */
-    public int getCount() {
-        return mElementCount;
-    }
-
-    void calcElementCount() {
-        boolean hasLod = hasMipmaps();
-        int x = getX();
-        int y = getY();
-        int z = getZ();
-        int faces = 1;
-        if (hasFaces()) {
-            faces = 6;
-        }
-        if (x == 0) {
-            x = 1;
-        }
-        if (y == 0) {
-            y = 1;
-        }
-        if (z == 0) {
-            z = 1;
-        }
-
-        int count = x * y * z * faces;
-
-        while (hasLod && ((x > 1) || (y > 1) || (z > 1))) {
-            if(x > 1) {
-                x >>= 1;
-            }
-            if(y > 1) {
-                y >>= 1;
-            }
-            if(z > 1) {
-                z >>= 1;
-            }
-
-            count += x * y * z * faces;
-        }
-        mElementCount = count;
-    }
-
-
-    Type(long id, RenderScript rs) {
-        super(id, rs);
-    }
-
-    /*
-     * Get an identical dummy Type for Compat Context
-     *
-     */
-    public long getDummyType(RenderScript mRS, long eid) {
-        return mRS.nIncTypeCreate(eid, mDimX, mDimY, mDimZ, mDimMipmaps, mDimFaces, mDimYuv);
-    }
-
-    /**
-     * Utility function for creating basic 1D types. The type is
-     * created without mipmaps enabled.
-     *
-     * @param rs The RenderScript context
-     * @param e The Element for the Type
-     * @param dimX The X dimension, must be > 0
-     *
-     * @return Type
-     */
-    static public Type createX(RenderScript rs, Element e, int dimX) {
-        if (dimX < 1) {
-            throw new RSInvalidStateException("Dimension must be >= 1.");
-        }
-
-        long id = rs.nTypeCreate(e.getID(rs), dimX, 0, 0, false, false, 0);
-        Type t = new Type(id, rs);
-        t.mElement = e;
-        t.mDimX = dimX;
-        t.calcElementCount();
-        return t;
-    }
-
-    /**
-     * Utility function for creating basic 2D types. The type is
-     * created without mipmaps or cubemaps.
-     *
-     * @param rs The RenderScript context
-     * @param e The Element for the Type
-     * @param dimX The X dimension, must be > 0
-     * @param dimY The Y dimension, must be > 0
-     *
-     * @return Type
-     */
-    static public Type createXY(RenderScript rs, Element e, int dimX, int dimY) {
-        if ((dimX < 1) || (dimY < 1)) {
-            throw new RSInvalidStateException("Dimension must be >= 1.");
-        }
-
-        long id = rs.nTypeCreate(e.getID(rs), dimX, dimY, 0, false, false, 0);
-        Type t = new Type(id, rs);
-        t.mElement = e;
-        t.mDimX = dimX;
-        t.mDimY = dimY;
-        t.calcElementCount();
-        return t;
-    }
-
-    /**
-     * Utility function for creating basic 3D types. The type is
-     * created without mipmaps.
-     *
-     * @param rs The RenderScript context
-     * @param e The Element for the Type
-     * @param dimX The X dimension, must be > 0
-     * @param dimY The Y dimension, must be > 0
-     * @param dimZ The Z dimension, must be > 0
-     *
-     * @return Type
-     */
-    static public Type createXYZ(RenderScript rs, Element e, int dimX, int dimY, int dimZ) {
-        if ((dimX < 1) || (dimY < 1) || (dimZ < 1)) {
-            throw new RSInvalidStateException("Dimension must be >= 1.");
-        }
-
-        long id = rs.nTypeCreate(e.getID(rs), dimX, dimY, dimZ, false, false, 0);
-        Type t = new Type(id, rs);
-        t.mElement = e;
-        t.mDimX = dimX;
-        t.mDimY = dimY;
-        t.mDimZ = dimZ;
-        t.calcElementCount();
-        return t;
-    }
-
-    /**
-     * Builder class for Type.
-     *
-     */
-    public static class Builder {
-        RenderScript mRS;
-        int mDimX = 1;
-        int mDimY;
-        int mDimZ;
-        boolean mDimMipmaps;
-        boolean mDimFaces;
-        int mYuv;
-
-        Element mElement;
-
-        /**
-         * Create a new builder object.
-         *
-         * @param rs
-         * @param e The element for the type to be created.
-         */
-        public Builder(RenderScript rs, Element e) {
-            e.checkValid();
-            mRS = rs;
-            mElement = e;
-        }
-
-        /**
-         * Add a dimension to the Type.
-         *
-         *
-         * @param value
-         */
-        public Builder setX(int value) {
-            if(value < 1) {
-                throw new RSIllegalArgumentException("Values of less than 1 for Dimension X are not valid.");
-            }
-            mDimX = value;
-            return this;
-        }
-
-        public Builder setY(int value) {
-            if(value < 1) {
-                throw new RSIllegalArgumentException("Values of less than 1 for Dimension Y are not valid.");
-            }
-            mDimY = value;
-            return this;
-        }
-
-        public Builder setZ(int value) {
-            if(value < 1) {
-                throw new RSIllegalArgumentException("Values of less than 1 for Dimension Z are not valid.");
-            }
-            mDimZ = value;
-            return this;
-        }
-
-        public Builder setMipmaps(boolean value) {
-            mDimMipmaps = value;
-            return this;
-        }
-
-        public Builder setFaces(boolean value) {
-            mDimFaces = value;
-            return this;
-        }
-
-        /**
-         * Set the YUV layout for a Type.
-         *
-         * @param yuvFormat {@link android.graphics.ImageFormat#YV12} or {@link android.graphics.ImageFormat#NV21}
-         */
-        public Builder setYuvFormat(int yuvFormat) {
-            switch (yuvFormat) {
-            case android.graphics.ImageFormat.NV21:
-            case android.graphics.ImageFormat.YV12:
-                break;
-
-            default:
-                throw new RSIllegalArgumentException("Only NV21 and YV12 are supported..");
-            }
-
-            mYuv = yuvFormat;
-            return this;
-        }
-
-
-        /**
-         * Validate structure and create a new Type.
-         *
-         * @return Type
-         */
-        public Type create() {
-            if (mDimZ > 0) {
-                if ((mDimX < 1) || (mDimY < 1)) {
-                    throw new RSInvalidStateException("Both X and Y dimension required when Z is present.");
-                }
-                if (mDimFaces) {
-                    throw new RSInvalidStateException("Cube maps not supported with 3D types.");
-                }
-            }
-            if (mDimY > 0) {
-                if (mDimX < 1) {
-                    throw new RSInvalidStateException("X dimension required when Y is present.");
-                }
-            }
-            if (mDimFaces) {
-                if (mDimY < 1) {
-                    throw new RSInvalidStateException("Cube maps require 2D Types.");
-                }
-            }
-
-            if (mYuv != 0) {
-                if ((mDimZ != 0) || mDimFaces || mDimMipmaps) {
-                    throw new RSInvalidStateException("YUV only supports basic 2D.");
-                }
-            }
-
-            Type t;
-            long id = mRS.nTypeCreate(mElement.getID(mRS),
-                                     mDimX, mDimY, mDimZ, mDimMipmaps, mDimFaces, mYuv);
-            t = new Type(id, mRS);
-
-            t.mElement = mElement;
-            t.mDimX = mDimX;
-            t.mDimY = mDimY;
-            t.mDimZ = mDimZ;
-            t.mDimMipmaps = mDimMipmaps;
-            t.mDimFaces = mDimFaces;
-            t.mDimYuv = mYuv;
-
-            t.calcElementCount();
-            return t;
-        }
-    }
-
-}
diff --git a/v8/renderscript/jni/Android.mk b/v8/renderscript/jni/Android.mk
deleted file mode 100644
index d6a800d..0000000
--- a/v8/renderscript/jni/Android.mk
+++ /dev/null
@@ -1,56 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_CLANG := true
-LOCAL_SDK_VERSION := 14
-
-LOCAL_SRC_FILES:= \
-    android_rscompat_usage_io.cpp \
-    android_rscompat_usage_io_driver.cpp
-
-LOCAL_C_INCLUDES += \
-	$(JNI_H_INCLUDE) \
-	frameworks/rs \
-	frameworks/rs/cpp \
-	frameworks/rs/driver
-
-LOCAL_CFLAGS += -Wno-unused-parameter -Werror
-LOCAL_CFLAGS += -DRS_COMPATIBILITY_LIB -std=c++11
-
-LOCAL_MODULE:= libRSSupportIO
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_LDLIBS += -landroid
-LOCAL_LDFLAGS += -ldl -Wl,--exclude-libs,libc++_static.a
-LOCAL_NDK_STL_VARIANT := c++_static
-include $(BUILD_SHARED_LIBRARY)
-
-include $(CLEAR_VARS)
-
-LOCAL_CLANG := true
-LOCAL_SDK_VERSION := 9
-
-LOCAL_SRC_FILES:= \
-    android_renderscript_RenderScript.cpp
-
-LOCAL_SHARED_LIBRARIES := \
-        libjnigraphics
-
-LOCAL_STATIC_LIBRARIES := \
-        libRSDispatch
-
-LOCAL_C_INCLUDES += \
-	$(JNI_H_INCLUDE) \
-	frameworks/rs \
-	frameworks/rs/cpp
-
-LOCAL_CFLAGS += -Wno-unused-parameter -Werror -std=c++11
-
-LOCAL_MODULE:= librsjni
-LOCAL_MODULE_TAGS := optional
-LOCAL_REQUIRED_MODULES := libRSSupport
-
-LOCAL_LDFLAGS += -ldl -llog -Wl,--exclude-libs,libc++_static.a
-LOCAL_NDK_STL_VARIANT := c++_static
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/v8/renderscript/jni/android_renderscript_RenderScript.cpp b/v8/renderscript/jni/android_renderscript_RenderScript.cpp
deleted file mode 100644
index 5642835..0000000
--- a/v8/renderscript/jni/android_renderscript_RenderScript.cpp
+++ /dev/null
@@ -1,2431 +0,0 @@
-/*
- * Copyright (C) 2011-2012 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.
- */
-
-#define LOG_TAG "libRS_jni"
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <math.h>
-#include <android/bitmap.h>
-#include <android/log.h>
-
-#include <rsEnv.h>
-#include "rsDispatch.h"
-#include <dlfcn.h>
-
-//#define LOG_API ALOG
-#define LOG_API(...)
-#define LOG_ERR(...) __android_log_print(ANDROID_LOG_ERROR, "RenderScript JNI", __VA_ARGS__);
-#define RS_JNI_VERSION 2301
-
-#define NELEM(m) (sizeof(m) / sizeof((m)[0]))
-
-template <typename... T>
-void UNUSED(T... t) {}
-#define PER_ARRAY_TYPE(flag, fnc, readonly, ...) {                                      \
-    jint len = 0;                                                                       \
-    void *ptr = nullptr;                                                                \
-    void *srcPtr = nullptr;                                                             \
-    size_t typeBytes = 0;                                                               \
-    jint relFlag = 0;                                                                   \
-    if (readonly) {                                                                     \
-        /* The on-release mode should only be JNI_ABORT for read-only accesses. */      \
-        /* readonly = true, also indicates we are copying to the allocation   . */      \
-        relFlag = JNI_ABORT;                                                            \
-    }                                                                                   \
-    switch(dataType) {                                                                  \
-    case RS_TYPE_FLOAT_32:                                                              \
-        len = _env->GetArrayLength((jfloatArray)data);                                  \
-        ptr = _env->GetFloatArrayElements((jfloatArray)data, flag);                     \
-        typeBytes = 4;                                                                  \
-        if (usePadding) {                                                               \
-            srcPtr = ptr;                                                               \
-            len = len / 3 * 4;                                                          \
-            if (count == 0) {                                                           \
-                count = len / 4;                                                        \
-            }                                                                           \
-            ptr = malloc (len * typeBytes);                                             \
-            if (readonly) {                                                             \
-                copyWithPadding(ptr, srcPtr, mSize, count);                             \
-                fnc(__VA_ARGS__);                                                       \
-            } else {                                                                    \
-                fnc(__VA_ARGS__);                                                       \
-                copyWithUnPadding(srcPtr, ptr, mSize, count);                           \
-            }                                                                           \
-            free(ptr);                                                                  \
-            ptr = srcPtr;                                                               \
-        } else {                                                                        \
-            fnc(__VA_ARGS__);                                                           \
-        }                                                                               \
-        _env->ReleaseFloatArrayElements((jfloatArray)data, (jfloat *)ptr, relFlag);     \
-        return;                                                                         \
-    case RS_TYPE_FLOAT_64:                                                              \
-        len = _env->GetArrayLength((jdoubleArray)data);                                 \
-        ptr = _env->GetDoubleArrayElements((jdoubleArray)data, flag);                   \
-        typeBytes = 8;                                                                  \
-        if (usePadding) {                                                               \
-            srcPtr = ptr;                                                               \
-            len = len / 3 * 4;                                                          \
-            if (count == 0) {                                                           \
-                count = len / 4;                                                        \
-            }                                                                           \
-            ptr = malloc (len * typeBytes);                                             \
-            if (readonly) {                                                             \
-                copyWithPadding(ptr, srcPtr, mSize, count);                             \
-                fnc(__VA_ARGS__);                                                       \
-            } else {                                                                    \
-                fnc(__VA_ARGS__);                                                       \
-                copyWithUnPadding(srcPtr, ptr, mSize, count);                           \
-            }                                                                           \
-            free(ptr);                                                                  \
-            ptr = srcPtr;                                                               \
-        } else {                                                                        \
-            fnc(__VA_ARGS__);                                                           \
-        }                                                                               \
-        _env->ReleaseDoubleArrayElements((jdoubleArray)data, (jdouble *)ptr, relFlag);  \
-        return;                                                                         \
-    case RS_TYPE_SIGNED_8:                                                              \
-    case RS_TYPE_UNSIGNED_8:                                                            \
-        len = _env->GetArrayLength((jbyteArray)data);                                   \
-        ptr = _env->GetByteArrayElements((jbyteArray)data, flag);                       \
-        typeBytes = 1;                                                                  \
-        if (usePadding) {                                                               \
-            srcPtr = ptr;                                                               \
-            len = len / 3 * 4;                                                          \
-            if (count == 0) {                                                           \
-                count = len / 4;                                                        \
-            }                                                                           \
-            ptr = malloc (len * typeBytes);                                             \
-            if (readonly) {                                                             \
-                copyWithPadding(ptr, srcPtr, mSize, count);                             \
-                fnc(__VA_ARGS__);                                                       \
-            } else {                                                                    \
-                fnc(__VA_ARGS__);                                                       \
-                copyWithUnPadding(srcPtr, ptr, mSize, count);                           \
-            }                                                                           \
-            free(ptr);                                                                  \
-            ptr = srcPtr;                                                               \
-        } else {                                                                        \
-            fnc(__VA_ARGS__);                                                           \
-        }                                                                               \
-        _env->ReleaseByteArrayElements((jbyteArray)data, (jbyte*)ptr, relFlag);         \
-        return;                                                                         \
-    case RS_TYPE_SIGNED_16:                                                             \
-    case RS_TYPE_UNSIGNED_16:                                                           \
-        len = _env->GetArrayLength((jshortArray)data);                                  \
-        ptr = _env->GetShortArrayElements((jshortArray)data, flag);                     \
-        typeBytes = 2;                                                                  \
-        if (usePadding) {                                                               \
-            srcPtr = ptr;                                                               \
-            len = len / 3 * 4;                                                          \
-            if (count == 0) {                                                           \
-                count = len / 4;                                                        \
-            }                                                                           \
-            ptr = malloc (len * typeBytes);                                             \
-            if (readonly) {                                                             \
-                copyWithPadding(ptr, srcPtr, mSize, count);                             \
-                fnc(__VA_ARGS__);                                                       \
-            } else {                                                                    \
-                fnc(__VA_ARGS__);                                                       \
-                copyWithUnPadding(srcPtr, ptr, mSize, count);                           \
-            }                                                                           \
-            free(ptr);                                                                  \
-            ptr = srcPtr;                                                               \
-        } else {                                                                        \
-            fnc(__VA_ARGS__);                                                           \
-        }                                                                               \
-        _env->ReleaseShortArrayElements((jshortArray)data, (jshort *)ptr, relFlag);     \
-        return;                                                                         \
-    case RS_TYPE_SIGNED_32:                                                             \
-    case RS_TYPE_UNSIGNED_32:                                                           \
-        len = _env->GetArrayLength((jintArray)data);                                    \
-        ptr = _env->GetIntArrayElements((jintArray)data, flag);                         \
-        typeBytes = 4;                                                                  \
-        if (usePadding) {                                                               \
-            srcPtr = ptr;                                                               \
-            len = len / 3 * 4;                                                          \
-            if (count == 0) {                                                           \
-                count = len / 4;                                                        \
-            }                                                                           \
-            ptr = malloc (len * typeBytes);                                             \
-            if (readonly) {                                                             \
-                copyWithPadding(ptr, srcPtr, mSize, count);                             \
-                fnc(__VA_ARGS__);                                                       \
-            } else {                                                                    \
-                fnc(__VA_ARGS__);                                                       \
-                copyWithUnPadding(srcPtr, ptr, mSize, count);                           \
-            }                                                                           \
-            free(ptr);                                                                  \
-            ptr = srcPtr;                                                               \
-        } else {                                                                        \
-            fnc(__VA_ARGS__);                                                           \
-        }                                                                               \
-        _env->ReleaseIntArrayElements((jintArray)data, (jint *)ptr, relFlag);           \
-        return;                                                                         \
-    case RS_TYPE_SIGNED_64:                                                             \
-    case RS_TYPE_UNSIGNED_64:                                                           \
-        len = _env->GetArrayLength((jlongArray)data);                                   \
-        ptr = _env->GetLongArrayElements((jlongArray)data, flag);                       \
-        typeBytes = 8;                                                                  \
-        if (usePadding) {                                                               \
-            srcPtr = ptr;                                                               \
-            len = len / 3 * 4;                                                          \
-            if (count == 0) {                                                           \
-                count = len / 4;                                                        \
-            }                                                                           \
-            ptr = malloc (len * typeBytes);                                             \
-            if (readonly) {                                                             \
-                copyWithPadding(ptr, srcPtr, mSize, count);                             \
-                fnc(__VA_ARGS__);                                                       \
-            } else {                                                                    \
-                fnc(__VA_ARGS__);                                                       \
-                copyWithUnPadding(srcPtr, ptr, mSize, count);                           \
-            }                                                                           \
-            free(ptr);                                                                  \
-            ptr = srcPtr;                                                               \
-        } else {                                                                        \
-            fnc(__VA_ARGS__);                                                           \
-        }                                                                               \
-        _env->ReleaseLongArrayElements((jlongArray)data, (jlong *)ptr, relFlag);        \
-        return;                                                                         \
-    default:                                                                            \
-        break;                                                                          \
-    }                                                                                   \
-    UNUSED(len, ptr, srcPtr, typeBytes, relFlag);                                       \
-}
-
-
-class AutoJavaStringToUTF8 {
-public:
-    AutoJavaStringToUTF8(JNIEnv* env, jstring str) : fEnv(env), fJStr(str) {
-        fCStr = env->GetStringUTFChars(str, NULL);
-        fLength = env->GetStringUTFLength(str);
-    }
-    ~AutoJavaStringToUTF8() {
-        fEnv->ReleaseStringUTFChars(fJStr, fCStr);
-    }
-    const char* c_str() const { return fCStr; }
-    jsize length() const { return fLength; }
-
-private:
-    JNIEnv*     fEnv;
-    jstring     fJStr;
-    const char* fCStr;
-    jsize       fLength;
-};
-
-class AutoJavaStringArrayToUTF8 {
-public:
-    AutoJavaStringArrayToUTF8(JNIEnv* env, jobjectArray strings, jsize stringsLength)
-    : mEnv(env), mStrings(strings), mStringsLength(stringsLength) {
-        mCStrings = NULL;
-        mSizeArray = NULL;
-        if (stringsLength > 0) {
-            mCStrings = (const char **)calloc(stringsLength, sizeof(char *));
-            mSizeArray = (size_t*)calloc(stringsLength, sizeof(size_t));
-            for (jsize ct = 0; ct < stringsLength; ct ++) {
-                jstring s = (jstring)mEnv->GetObjectArrayElement(mStrings, ct);
-                mCStrings[ct] = mEnv->GetStringUTFChars(s, NULL);
-                mSizeArray[ct] = mEnv->GetStringUTFLength(s);
-            }
-        }
-    }
-    ~AutoJavaStringArrayToUTF8() {
-        for (jsize ct=0; ct < mStringsLength; ct++) {
-            jstring s = (jstring)mEnv->GetObjectArrayElement(mStrings, ct);
-            mEnv->ReleaseStringUTFChars(s, mCStrings[ct]);
-        }
-        free(mCStrings);
-        free(mSizeArray);
-    }
-    const char **c_str() const { return mCStrings; }
-    size_t *c_str_len() const { return mSizeArray; }
-    jsize length() const { return mStringsLength; }
-
-private:
-    JNIEnv      *mEnv;
-    jobjectArray mStrings;
-    const char **mCStrings;
-    size_t      *mSizeArray;
-    jsize        mStringsLength;
-};
-
-
-// ---------------------------------------------------------------------------
-static dispatchTable dispatchTab;
-// Incremental Support lib
-static dispatchTable dispatchTabInc;
-
-static jboolean nLoadSO(JNIEnv *_env, jobject _this, jboolean useNative, jint targetApi, jstring libPath) {
-    void* handle = NULL;
-    if (useNative) {
-        handle = dlopen("libRS.so", RTLD_LAZY | RTLD_LOCAL);
-    } else {
-        // For API 9+, dlopen the full path of libRSSupport.
-        if (libPath != NULL) {
-            const char * libPathJni = _env->GetStringUTFChars(libPath, JNI_FALSE);
-            handle = dlopen(libPathJni, RTLD_LAZY | RTLD_LOCAL);
-            _env->ReleaseStringUTFChars(libPath, libPathJni);
-        } else {
-            handle = dlopen("libRSSupport.so", RTLD_LAZY | RTLD_LOCAL);
-        }
-    }
-    if (handle == NULL) {
-        LOG_ERR("couldn't dlopen %s; librsjni version: %d", dlerror(), RS_JNI_VERSION);
-        return false;
-    }
-
-    if (loadSymbols(handle, dispatchTab, targetApi) == false) {
-        LOG_ERR("Dispatch table init failed! librsjni version: %d", RS_JNI_VERSION);
-        dlclose(handle);
-        return false;
-    }
-    LOG_API("Successfully loaded runtime");
-    return true;
-}
-
-static ioSuppDT ioDispatch;
-static jboolean nLoadIOSO(JNIEnv *_env, jobject _this) {
-    void* handleIO = NULL;
-    handleIO = dlopen("libRSSupportIO.so", RTLD_LAZY | RTLD_LOCAL);
-    if (handleIO == NULL) {
-        LOG_ERR("Couldn't load libRSSupportIO.so, librsjni version: %d", RS_JNI_VERSION);
-        return false;
-    }
-    if (loadIOSuppSyms(handleIO, ioDispatch) == false) {
-        LOG_ERR("libRSSupportIO init failed! librsjni version: %d", RS_JNI_VERSION);
-        return false;
-    }
-    return true;
-}
-
-// ---------------------------------------------------------------------------
-
-static void copyWithPadding(void* ptr, void* srcPtr, int mSize, int count) {
-    int sizeBytesPad = mSize * 4;
-    int sizeBytes = mSize * 3;
-    uint8_t *dst = static_cast<uint8_t *>(ptr);
-    uint8_t *src = static_cast<uint8_t *>(srcPtr);
-    for (int i = 0; i < count; i++) {
-        memcpy(dst, src, sizeBytes);
-        dst += sizeBytesPad;
-        src += sizeBytes;
-    }
-}
-
-static void copyWithUnPadding(void* ptr, void* srcPtr, int mSize, int count) {
-    int sizeBytesPad = mSize * 4;
-    int sizeBytes = mSize * 3;
-    uint8_t *dst = static_cast<uint8_t *>(ptr);
-    uint8_t *src = static_cast<uint8_t *>(srcPtr);
-    for (int i = 0; i < count; i++) {
-        memcpy(dst, src, sizeBytes);
-        dst += sizeBytes;
-        src += sizeBytesPad;
-    }
-}
-
-
-// ---------------------------------------------------------------------------
-
-static void
-nContextFinish(JNIEnv *_env, jobject _this, jlong con)
-{
-    LOG_API("nContextFinish, con(%p)", (RsContext)con);
-    dispatchTab.ContextFinish((RsContext)con);
-}
-
-static jlong
-nClosureCreate(JNIEnv *_env, jobject _this, jlong con, jlong kernelID,
-               jlong returnValue, jlongArray fieldIDArray,
-               jlongArray valueArray, jintArray sizeArray,
-               jlongArray depClosureArray, jlongArray depFieldIDArray) {
-  jlong ret = 0;
-
-  jlong* jFieldIDs = _env->GetLongArrayElements(fieldIDArray, nullptr);
-  jsize fieldIDs_length = _env->GetArrayLength(fieldIDArray);
-  jlong* jValues = _env->GetLongArrayElements(valueArray, nullptr);
-  jsize values_length = _env->GetArrayLength(valueArray);
-  jint* jSizes = _env->GetIntArrayElements(sizeArray, nullptr);
-  jsize sizes_length = _env->GetArrayLength(sizeArray);
-  jlong* jDepClosures =
-      _env->GetLongArrayElements(depClosureArray, nullptr);
-  jsize depClosures_length = _env->GetArrayLength(depClosureArray);
-  jlong* jDepFieldIDs =
-      _env->GetLongArrayElements(depFieldIDArray, nullptr);
-  jsize depFieldIDs_length = _env->GetArrayLength(depFieldIDArray);
-
-  size_t numValues, numDependencies;
-  RsScriptFieldID* fieldIDs;
-  RsClosure* depClosures;
-  RsScriptFieldID* depFieldIDs;
-
-  if (fieldIDs_length != values_length || values_length != sizes_length) {
-      LOG_ERR("Unmatched field IDs, values, and sizes in closure creation.");
-      goto exit;
-  }
-
-  numValues = (size_t)fieldIDs_length;
-
-  if (depClosures_length != depFieldIDs_length) {
-      LOG_ERR("Unmatched closures and field IDs for dependencies in closure creation.");
-      goto exit;
-  }
-
-  numDependencies = (size_t)depClosures_length;
-
-  if (numDependencies > numValues) {
-      LOG_ERR("Unexpected number of dependencies in closure creation");
-      goto exit;
-  }
-
-  if (numValues > RS_CLOSURE_MAX_NUMBER_ARGS_AND_BINDINGS) {
-      LOG_ERR("Too many arguments or globals in closure creation");
-      goto exit;
-  }
-
-  if (numValues > 0) {
-      fieldIDs = (RsScriptFieldID*)alloca(sizeof(RsScriptFieldID) * numValues);
-      if (fieldIDs == nullptr) {
-          goto exit;
-      }
-  } else {
-      // numValues == 0
-      // alloca(0) implementation is platform dependent
-      fieldIDs = nullptr;
-  }
-
-  for (size_t i = 0; i < numValues; i++) {
-    fieldIDs[i] = (RsScriptFieldID)jFieldIDs[i];
-  }
-
-  if (numDependencies > 0) {
-      depClosures = (RsClosure*)alloca(sizeof(RsClosure) * numDependencies);
-      if (depClosures == nullptr) {
-          goto exit;
-      }
-
-      for (size_t i = 0; i < numDependencies; i++) {
-          depClosures[i] = (RsClosure)jDepClosures[i];
-      }
-
-      depFieldIDs = (RsScriptFieldID*)alloca(sizeof(RsScriptFieldID) * numDependencies);
-      if (depFieldIDs == nullptr) {
-          goto exit;
-      }
-
-      for (size_t i = 0; i < numDependencies; i++) {
-          depFieldIDs[i] = (RsClosure)jDepFieldIDs[i];
-      }
-  } else {
-      // numDependencies == 0
-      // alloca(0) implementation is platform dependent
-      depClosures = nullptr;
-      depFieldIDs = nullptr;
-  }
-
-  ret = (jlong)(uintptr_t)dispatchTab.ClosureCreate(
-      (RsContext)con, (RsScriptKernelID)kernelID, (RsAllocation)returnValue,
-      fieldIDs, numValues, jValues, numValues,
-      (int*)jSizes, numValues,
-      depClosures, numDependencies,
-      depFieldIDs, numDependencies);
-
-exit:
-
-  _env->ReleaseLongArrayElements(depFieldIDArray, jDepFieldIDs, JNI_ABORT);
-  _env->ReleaseLongArrayElements(depClosureArray, jDepClosures, JNI_ABORT);
-  _env->ReleaseIntArrayElements (sizeArray,       jSizes,       JNI_ABORT);
-  _env->ReleaseLongArrayElements(valueArray,      jValues,      JNI_ABORT);
-  _env->ReleaseLongArrayElements(fieldIDArray,    jFieldIDs,    JNI_ABORT);
-
-  return ret;
-}
-
-static jlong
-nInvokeClosureCreate(JNIEnv *_env, jobject _this, jlong con, jlong invokeID,
-                     jbyteArray paramArray, jlongArray fieldIDArray, jlongArray valueArray,
-                     jintArray sizeArray) {
-  jlong ret = 0;
-
-  jbyte* jParams = _env->GetByteArrayElements(paramArray, nullptr);
-  jsize jParamLength = _env->GetArrayLength(paramArray);
-  jlong* jFieldIDs = _env->GetLongArrayElements(fieldIDArray, nullptr);
-  jsize fieldIDs_length = _env->GetArrayLength(fieldIDArray);
-  jlong* jValues = _env->GetLongArrayElements(valueArray, nullptr);
-  jsize values_length = _env->GetArrayLength(valueArray);
-  jint* jSizes = _env->GetIntArrayElements(sizeArray, nullptr);
-  jsize sizes_length = _env->GetArrayLength(sizeArray);
-
-  size_t numValues;
-  RsScriptFieldID* fieldIDs;
-
-  if (fieldIDs_length != values_length || values_length != sizes_length) {
-      LOG_ERR("Unmatched field IDs, values, and sizes in closure creation.");
-      goto exit;
-  }
-
-  numValues = (size_t) fieldIDs_length;
-
-  if (numValues > RS_CLOSURE_MAX_NUMBER_ARGS_AND_BINDINGS) {
-      LOG_ERR("Too many arguments or globals in closure creation");
-      goto exit;
-  }
-
-  fieldIDs = (RsScriptFieldID*)alloca(sizeof(RsScriptFieldID) * numValues);
-  if (fieldIDs == nullptr) {
-      goto exit;
-  }
-
-  for (size_t i = 0; i < numValues; i++) {
-    fieldIDs[i] = (RsScriptFieldID)jFieldIDs[i];
-  }
-
-  ret = (jlong)(uintptr_t)dispatchTab.InvokeClosureCreate(
-      (RsContext)con, (RsScriptInvokeID)invokeID, jParams, jParamLength,
-      fieldIDs, numValues, jValues, numValues,
-      (int*)jSizes, numValues);
-
-exit:
-
-  _env->ReleaseIntArrayElements (sizeArray,       jSizes,       JNI_ABORT);
-  _env->ReleaseLongArrayElements(valueArray,      jValues,      JNI_ABORT);
-  _env->ReleaseLongArrayElements(fieldIDArray,    jFieldIDs,    JNI_ABORT);
-  _env->ReleaseByteArrayElements(paramArray,      jParams,      JNI_ABORT);
-
-  return ret;
-}
-
-static void
-nClosureSetArg(JNIEnv *_env, jobject _this, jlong con, jlong closureID,
-               jint index, jlong value, jint size) {
-  // Size is signed with -1 indicating the values is an Allocation
-  dispatchTab.ClosureSetArg((RsContext)con, (RsClosure)closureID, (uint32_t)index,
-                  (uintptr_t)value, size);
-}
-
-static void
-nClosureSetGlobal(JNIEnv *_env, jobject _this, jlong con, jlong closureID,
-                  jlong fieldID, jlong value, jint size) {
-  // Size is signed with -1 indicating the values is an Allocation
-  dispatchTab.ClosureSetGlobal((RsContext)con, (RsClosure)closureID,
-                     (RsScriptFieldID)fieldID, (int64_t)value, size);
-}
-
-static long
-nScriptGroup2Create(JNIEnv *_env, jobject _this, jlong con, jstring name,
-                    jstring cacheDir, jlongArray closureArray) {
-  jlong ret = 0;
-
-  AutoJavaStringToUTF8 nameUTF(_env, name);
-  AutoJavaStringToUTF8 cacheDirUTF(_env, cacheDir);
-
-  jlong* jClosures = _env->GetLongArrayElements(closureArray, nullptr);
-  jsize numClosures = _env->GetArrayLength(closureArray);
-
-  RsClosure* closures;
-
-  if (numClosures > (jsize) RS_SCRIPT_GROUP_MAX_NUMBER_CLOSURES) {
-    LOG_ERR("Too many closures in script group");
-    goto exit;
-  }
-
-  closures = (RsClosure*)alloca(sizeof(RsClosure) * numClosures);
-  if (closures == nullptr) {
-      goto exit;
-  }
-
-  for (int i = 0; i < numClosures; i++) {
-    closures[i] = (RsClosure)jClosures[i];
-  }
-
-  ret = (jlong)(uintptr_t)dispatchTab.ScriptGroup2Create(
-      (RsContext)con, nameUTF.c_str(), nameUTF.length(),
-      cacheDirUTF.c_str(), cacheDirUTF.length(),
-      closures, numClosures);
-
-exit:
-
-  _env->ReleaseLongArrayElements(closureArray, jClosures, JNI_ABORT);
-
-  return ret;
-}
-
-static void
-nScriptGroup2Execute(JNIEnv *_env, jobject _this, jlong con, jlong groupID) {
-  dispatchTab.ScriptGroupExecute((RsContext)con, (RsScriptGroup2)groupID);
-}
-
-static void
-nObjDestroy(JNIEnv *_env, jobject _this, jlong con, jlong obj)
-{
-    LOG_API("nObjDestroy, con(%p) obj(%p)", (RsContext)con, (void *)obj);
-    dispatchTab.ObjDestroy((RsContext)con, (void *)obj);
-}
-
-
-static void
-nScriptIntrinsicBLAS_Single(JNIEnv *_env, jobject _this, jlong con, jlong incCon, jlong id, jint func, jint TransA,
-                            jint TransB, jint Side, jint Uplo, jint Diag, jint M, jint N, jint K,
-                            jfloat alpha, jlong A, jlong B, jfloat beta, jlong C, jint incX, jint incY,
-                            jint KL, jint KU, jboolean mUseInc) {
-    RsBlasCall call;
-    memset(&call, 0, sizeof(call));
-    call.func = (RsBlasFunction)func;
-    call.transA = (RsBlasTranspose)TransA;
-    call.transB = (RsBlasTranspose)TransB;
-    call.side = (RsBlasSide)Side;
-    call.uplo = (RsBlasUplo)Uplo;
-    call.diag = (RsBlasDiag)Diag;
-    call.M = M;
-    call.N = N;
-    call.K = K;
-    call.alpha.f = alpha;
-    call.beta.f = beta;
-    call.incX = incX;
-    call.incY = incY;
-    call.KL = KL;
-    call.KU = KU;
-
-    RsAllocation in_allocs[3];
-    in_allocs[0] = (RsAllocation)A;
-    in_allocs[1] = (RsAllocation)B;
-    in_allocs[2] = (RsAllocation)C;
-
-    if (mUseInc) {
-        dispatchTab.ContextFinish((RsContext)con);
-        dispatchTabInc.ScriptForEachMulti((RsContext)incCon, (RsScript)id, 0,
-                                          in_allocs, NELEM(in_allocs), nullptr,
-                                          &call, sizeof(call), nullptr, 0);
-    } else {
-        dispatchTab.ScriptForEachMulti((RsContext)con, (RsScript)id, 0,
-                                       in_allocs, NELEM(in_allocs), nullptr,
-                                       &call, sizeof(call), nullptr, 0);
-    }
-}
-
-static void
-nScriptIntrinsicBLAS_Double(JNIEnv *_env, jobject _this, jlong con, jlong incCon, jlong id, jint func, jint TransA,
-                            jint TransB, jint Side, jint Uplo, jint Diag, jint M, jint N, jint K,
-                            jdouble alpha, jlong A, jlong B, jdouble beta, jlong C, jint incX, jint incY,
-                            jint KL, jint KU, jboolean mUseInc) {
-    RsBlasCall call;
-    memset(&call, 0, sizeof(call));
-    call.func = (RsBlasFunction)func;
-    call.transA = (RsBlasTranspose)TransA;
-    call.transB = (RsBlasTranspose)TransB;
-    call.side = (RsBlasSide)Side;
-    call.uplo = (RsBlasUplo)Uplo;
-    call.diag = (RsBlasDiag)Diag;
-    call.M = M;
-    call.N = N;
-    call.K = K;
-    call.alpha.d = alpha;
-    call.beta.d = beta;
-    call.incX = incX;
-    call.incY = incY;
-    call.KL = KL;
-    call.KU = KU;
-
-    RsAllocation in_allocs[3];
-    in_allocs[0] = (RsAllocation)A;
-    in_allocs[1] = (RsAllocation)B;
-    in_allocs[2] = (RsAllocation)C;
-
-    if (mUseInc) {
-        dispatchTab.ContextFinish((RsContext)con);
-        dispatchTabInc.ScriptForEachMulti((RsContext)incCon, (RsScript)id, 0,
-                                          in_allocs, NELEM(in_allocs), nullptr,
-                                          &call, sizeof(call), nullptr, 0);
-    } else {
-        dispatchTab.ScriptForEachMulti((RsContext)con, (RsScript)id, 0,
-                                        in_allocs, NELEM(in_allocs), nullptr,
-                                        &call, sizeof(call), nullptr, 0);
-    }
-}
-
-static void
-nScriptIntrinsicBLAS_Complex(JNIEnv *_env, jobject _this, jlong con, jlong incCon, jlong id, jint func, jint TransA,
-                             jint TransB, jint Side, jint Uplo, jint Diag, jint M, jint N, jint K,
-                             jfloat alphaX, jfloat alphaY, jlong A, jlong B, jfloat betaX,
-                             jfloat betaY, jlong C, jint incX, jint incY, jint KL, jint KU, jboolean mUseInc) {
-    RsBlasCall call;
-    memset(&call, 0, sizeof(call));
-    call.func = (RsBlasFunction)func;
-    call.transA = (RsBlasTranspose)TransA;
-    call.transB = (RsBlasTranspose)TransB;
-    call.side = (RsBlasSide)Side;
-    call.uplo = (RsBlasUplo)Uplo;
-    call.diag = (RsBlasDiag)Diag;
-    call.M = M;
-    call.N = N;
-    call.K = K;
-    call.alpha.c.r = alphaX;
-    call.alpha.c.i = alphaY;
-    call.beta.c.r = betaX;
-    call.beta.c.i = betaY;
-    call.incX = incX;
-    call.incY = incY;
-    call.KL = KL;
-    call.KU = KU;
-
-    RsAllocation in_allocs[3];
-    in_allocs[0] = (RsAllocation)A;
-    in_allocs[1] = (RsAllocation)B;
-    in_allocs[2] = (RsAllocation)C;
-
-
-    if (mUseInc) {
-        dispatchTab.ContextFinish((RsContext)con);
-        dispatchTabInc.ScriptForEachMulti((RsContext)incCon, (RsScript)id, 0,
-                                          in_allocs, NELEM(in_allocs), nullptr,
-                                          &call, sizeof(call), nullptr, 0);
-    } else {
-        dispatchTab.ScriptForEachMulti((RsContext)con, (RsScript)id, 0,
-                                       in_allocs, NELEM(in_allocs), nullptr,
-                                       &call, sizeof(call), nullptr, 0);
-    }
-}
-
-static void
-nScriptIntrinsicBLAS_Z(JNIEnv *_env, jobject _this, jlong con, jlong incCon, jlong id, jint func, jint TransA,
-                       jint TransB, jint Side, jint Uplo, jint Diag, jint M, jint N, jint K,
-                       jdouble alphaX, jdouble alphaY, jlong A, jlong B, jdouble betaX,
-                       jdouble betaY, jlong C, jint incX, jint incY, jint KL, jint KU, jboolean mUseInc) {
-    RsBlasCall call;
-    memset(&call, 0, sizeof(call));
-    call.func = (RsBlasFunction)func;
-    call.transA = (RsBlasTranspose)TransA;
-    call.transB = (RsBlasTranspose)TransB;
-    call.side = (RsBlasSide)Side;
-    call.uplo = (RsBlasUplo)Uplo;
-    call.diag = (RsBlasDiag)Diag;
-    call.M = M;
-    call.N = N;
-    call.K = K;
-    call.alpha.z.r = alphaX;
-    call.alpha.z.i = alphaY;
-    call.beta.z.r = betaX;
-    call.beta.z.i = betaY;
-    call.incX = incX;
-    call.incY = incY;
-    call.KL = KL;
-    call.KU = KU;
-
-    RsAllocation in_allocs[3];
-    in_allocs[0] = (RsAllocation)A;
-    in_allocs[1] = (RsAllocation)B;
-    in_allocs[2] = (RsAllocation)C;
-
-
-    if (mUseInc) {
-        dispatchTab.ContextFinish((RsContext)con);
-        dispatchTabInc.ScriptForEachMulti((RsContext)incCon, (RsScript)id, 0,
-                                          in_allocs, NELEM(in_allocs), nullptr,
-                                          &call, sizeof(call), nullptr, 0);
-    } else {
-        dispatchTab.ScriptForEachMulti((RsContext)con, (RsScript)id, 0,
-                                        in_allocs, NELEM(in_allocs), nullptr,
-                                        &call, sizeof(call), nullptr, 0);
-    }
-}
-
-
-static void
-nScriptIntrinsicBLAS_BNNM(JNIEnv *_env, jobject _this, jlong con, jlong incCon, jlong id, jint M, jint N, jint K,
-                          jlong A, jint a_offset, jlong B, jint b_offset, jlong C, jint c_offset,
-                          jint c_mult_int, jboolean mUseInc) {
-    RsBlasCall call;
-    memset(&call, 0, sizeof(call));
-    call.func = RsBlas_bnnm;
-    call.M = M;
-    call.N = N;
-    call.K = K;
-    call.a_offset = a_offset & 0xFF;
-    call.b_offset = b_offset & 0xFF;
-    call.c_offset = c_offset;
-    call.c_mult_int = c_mult_int;
-
-    RsAllocation in_allocs[3];
-    in_allocs[0] = (RsAllocation)A;
-    in_allocs[1] = (RsAllocation)B;
-    in_allocs[2] = (RsAllocation)C;
-
-    if (mUseInc) {
-        dispatchTab.ContextFinish((RsContext)con);
-        dispatchTabInc.ScriptForEachMulti((RsContext)incCon, (RsScript)id, 0,
-                                          in_allocs, NELEM(in_allocs), nullptr,
-                                          &call, sizeof(call), nullptr, 0);
-    } else {
-        dispatchTab.ScriptForEachMulti((RsContext)con, (RsScript)id, 0,
-                                        in_allocs, NELEM(in_allocs), nullptr,
-                                        &call, sizeof(call), nullptr, 0);
-    }
-}
-// ---------------------------------------------------------------------------
-static jlong
-nDeviceCreate(JNIEnv *_env, jobject _this)
-{
-    LOG_API("nDeviceCreate");
-    return (jlong)(uintptr_t)dispatchTab.DeviceCreate();
-}
-
-static void
-nDeviceDestroy(JNIEnv *_env, jobject _this, jlong dev)
-{
-    LOG_API("nDeviceDestroy");
-    return dispatchTab.DeviceDestroy((RsDevice)dev);
-}
-
-static void
-nDeviceSetConfig(JNIEnv *_env, jobject _this, jlong dev, jint p, jint value)
-{
-    LOG_API("nDeviceSetConfig  dev(%p), param(%i), value(%i)", (void *)dev, p, value);
-    return dispatchTab.DeviceSetConfig((RsDevice)dev, (RsDeviceParam)p, value);
-}
-
-static jlong
-nContextCreate(JNIEnv *_env, jobject _this, jlong dev, jint ver, jint sdkVer,
-               jint ct, jstring nativeLibDirJava)
-{
-    LOG_API("nContextCreate");
-    // Access the NativeLibDir in the Java Context.
-    const char * nativeLibDir = _env->GetStringUTFChars(nativeLibDirJava, JNI_FALSE);
-    size_t length = (size_t)_env->GetStringUTFLength(nativeLibDirJava);
-
-    jlong id = (jlong)(uintptr_t)dispatchTab.ContextCreate((RsDevice)dev, ver,
-                                                           sdkVer,
-                                                           (RsContextType)ct, 0);
-    if (dispatchTab.SetNativeLibDir) {
-        dispatchTab.SetNativeLibDir((RsContext)id, nativeLibDir, length);
-    }
-
-    _env->ReleaseStringUTFChars(nativeLibDirJava, nativeLibDir);
-    return id;
-}
-
-
-static void
-nContextSetPriority(JNIEnv *_env, jobject _this, jlong con, jint p)
-{
-    LOG_API("ContextSetPriority, con(%p), priority(%i)", (RsContext)con, p);
-    dispatchTab.ContextSetPriority((RsContext)con, p);
-}
-
-
-
-static void
-nContextDestroy(JNIEnv *_env, jobject _this, jlong con)
-{
-    LOG_API("nContextDestroy, con(%p)", (RsContext)con);
-    dispatchTab.ContextDestroy((RsContext)con);
-}
-
-static void
-nContextDump(JNIEnv *_env, jobject _this, jlong con, jint bits)
-{
-    LOG_API("nContextDump, con(%p)  bits(%i)", (RsContext)con, bits);
-    dispatchTab.ContextDump((RsContext)con, bits);
-}
-
-
-static jstring
-nContextGetErrorMessage(JNIEnv *_env, jobject _this, jlong con)
-{
-    LOG_API("nContextGetErrorMessage, con(%p)", (RsContext)con);
-    char buf[1024];
-
-    size_t receiveLen;
-    uint32_t subID;
-    int id = dispatchTab.ContextGetMessage((RsContext)con,
-                                           buf, sizeof(buf),
-                                           &receiveLen, sizeof(receiveLen),
-                                           &subID, sizeof(subID));
-    if (!id && receiveLen) {
-        //        __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG,
-        //            "message receive buffer too small.  %zu", receiveLen);
-    }
-    return _env->NewStringUTF(buf);
-}
-
-static jint
-nContextGetUserMessage(JNIEnv *_env, jobject _this, jlong con, jintArray data)
-{
-    jint len = _env->GetArrayLength(data);
-    LOG_API("nContextGetMessage, con(%p), len(%i)", (RsContext)con, len);
-    jint *ptr = _env->GetIntArrayElements(data, NULL);
-    size_t receiveLen;
-    uint32_t subID;
-    int id = dispatchTab.ContextGetMessage((RsContext)con,
-                                           ptr, len * 4,
-                                           &receiveLen, sizeof(receiveLen),
-                                           &subID, sizeof(subID));
-    if (!id && receiveLen) {
-        //        __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG,
-        //            "message receive buffer too small.  %zu", receiveLen);
-    }
-    _env->ReleaseIntArrayElements(data, ptr, 0);
-    return (jint)id;
-}
-
-static jint
-nContextPeekMessage(JNIEnv *_env, jobject _this, jlong con, jintArray auxData)
-{
-    LOG_API("nContextPeekMessage, con(%p)", (RsContext)con);
-    jint *auxDataPtr = _env->GetIntArrayElements(auxData, NULL);
-    size_t receiveLen;
-    uint32_t subID;
-    int id = dispatchTab.ContextPeekMessage((RsContext)con, &receiveLen, sizeof(receiveLen),
-                                  &subID, sizeof(subID));
-    auxDataPtr[0] = (jint)subID;
-    auxDataPtr[1] = (jint)receiveLen;
-    _env->ReleaseIntArrayElements(auxData, auxDataPtr, 0);
-    return (jint)id;
-}
-
-static void nContextInitToClient(JNIEnv *_env, jobject _this, jlong con)
-{
-    LOG_API("nContextInitToClient, con(%p)", (RsContext)con);
-    dispatchTab.ContextInitToClient((RsContext)con);
-}
-
-static void nContextDeinitToClient(JNIEnv *_env, jobject _this, jlong con)
-{
-    LOG_API("nContextDeinitToClient, con(%p)", (RsContext)con);
-    dispatchTab.ContextDeinitToClient((RsContext)con);
-}
-
-static void
-nContextSendMessage(JNIEnv *_env, jobject _this, jlong con, jint id, jintArray data)
-{
-    jint *ptr = NULL;
-    jint len = 0;
-    if (data) {
-        len = _env->GetArrayLength(data);
-        ptr = _env->GetIntArrayElements(data, NULL);
-    }
-    LOG_API("nContextSendMessage, con(%p), id(%i), len(%i)", (RsContext)con, id, len);
-    dispatchTab.ContextSendMessage((RsContext)con, id, (const uint8_t *)ptr, len * sizeof(int));
-    if (data) {
-        _env->ReleaseIntArrayElements(data, ptr, JNI_ABORT);
-    }
-}
-
-
-
-static jlong
-nElementCreate(JNIEnv *_env, jobject _this, jlong con, jlong type, jint kind,
-               jboolean norm, jint size)
-{
-    LOG_API("nElementCreate, con(%p), type(%i), kind(%i), norm(%i), size(%i)", (RsContext)con,
-            type, kind, norm, size);
-    return (jlong)(uintptr_t)dispatchTab.ElementCreate((RsContext)con,
-                                                       (RsDataType)type,
-                                                       (RsDataKind)kind,
-                                                       norm, size);
-}
-
-static jlong
-nElementCreate2(JNIEnv *_env, jobject _this, jlong con,
-                jlongArray _ids, jobjectArray _names, jintArray _arraySizes)
-{
-    int fieldCount = _env->GetArrayLength(_ids);
-    LOG_API("nElementCreate2, con(%p)", (RsContext)con);
-
-    jlong *jIds = _env->GetLongArrayElements(_ids, NULL);
-    jint *jArraySizes = _env->GetIntArrayElements(_arraySizes, NULL);
-
-    RsElement *ids = (RsElement*)malloc(fieldCount * sizeof(RsElement));
-    uint32_t *arraySizes = (uint32_t *)malloc(fieldCount * sizeof(uint32_t));
-
-    for(int i = 0; i < fieldCount; i ++) {
-        ids[i] = (RsElement)jIds[i];
-        arraySizes[i] = (uint32_t)jArraySizes[i];
-    }
-
-    AutoJavaStringArrayToUTF8 names(_env, _names, fieldCount);
-
-    const char **nameArray = names.c_str();
-    size_t *sizeArray = names.c_str_len();
-
-    jlong id = (jlong)(uintptr_t)dispatchTab.ElementCreate2((RsContext)con, (RsElement *)ids,
-                                                            fieldCount, nameArray,
-                                                            fieldCount * sizeof(size_t),  sizeArray,
-                                                            (const uint32_t *)arraySizes, fieldCount);
-
-    free(ids);
-    free(arraySizes);
-    _env->ReleaseLongArrayElements(_ids, jIds, JNI_ABORT);
-    _env->ReleaseIntArrayElements(_arraySizes, jArraySizes, JNI_ABORT);
-    return id;
-}
-
-
-
-
-static void
-nElementGetSubElements(JNIEnv *_env, jobject _this, jlong con, jlong id,
-                       jlongArray _IDs,
-                       jobjectArray _names,
-                       jintArray _arraySizes)
-{
-    uint32_t dataSize = _env->GetArrayLength(_IDs);
-    LOG_API("nElementGetSubElements, con(%p)", (RsContext)con);
-
-    uintptr_t *ids = (uintptr_t *)malloc(dataSize * sizeof(uintptr_t));
-    const char **names = (const char **)malloc((uint32_t)dataSize * sizeof(const char *));
-    uint32_t *arraySizes = (uint32_t *)malloc((uint32_t)dataSize * sizeof(uint32_t));
-
-    dispatchTab.ElementGetSubElements((RsContext)con, (RsElement)id, ids, names, arraySizes,
-                                      (uint32_t)dataSize);
-
-    for(uint32_t i = 0; i < dataSize; i++) {
-        const jlong id = (jlong)(uintptr_t)ids[i];
-        const jint arraySize = (jint)arraySizes[i];
-        _env->SetObjectArrayElement(_names, i, _env->NewStringUTF(names[i]));
-        _env->SetLongArrayRegion(_IDs, i, 1, &id);
-        _env->SetIntArrayRegion(_arraySizes, i, 1, &arraySize);
-    }
-
-    free(ids);
-    free(names);
-    free(arraySizes);
-}
-
-// -----------------------------------
-
-static jlong
-nTypeCreate(JNIEnv *_env, jobject _this, jlong con, jlong eid,
-            jint dimx, jint dimy, jint dimz, jboolean mips, jboolean faces, jint yuv)
-{
-    LOG_API("nTypeCreate, con(%p) eid(%p), x(%i), y(%i), z(%i), mips(%i), faces(%i), yuv(%i)",
-            (RsContext)con, eid, dimx, dimy, dimz, mips, faces, yuv);
-
-    return (jlong)(uintptr_t)dispatchTab.TypeCreate((RsContext)con, (RsElement)eid, dimx, dimy,
-                                                    dimz, mips, faces, yuv);
-}
-
-// -----------------------------------
-
-static jlong
-nAllocationCreateTyped(JNIEnv *_env, jobject _this, jlong con, jlong type, jint mips, jint usage,
-                       jlong pointer)
-{
-    LOG_API("nAllocationCreateTyped, con(%p), type(%p), mip(%i), usage(%i), ptr(%p)",
-            (RsContext)con, (RsElement)type, mips, usage, (void *)pointer);
-    return (jlong)(uintptr_t) dispatchTab.AllocationCreateTyped((RsContext)con, (RsType)type,
-                                                                (RsAllocationMipmapControl)mips,
-                                                                (uint32_t)usage, (uintptr_t)pointer);
-}
-
-static void
-nAllocationSyncAll(JNIEnv *_env, jobject _this, jlong con, jlong a, jint bits)
-{
-    LOG_API("nAllocationSyncAll, con(%p), a(%p), bits(0x%08x)", (RsContext)con, (RsAllocation)a, bits);
-    dispatchTab.AllocationSyncAll((RsContext)con, (RsAllocation)a, (RsAllocationUsageType)bits);
-}
-
-static void
-nAllocationSetSurface(JNIEnv *_env, jobject _this, jlong con, jlong alloc, jobject sur)
-{
-    ioDispatch.sAllocationSetSurface(_env, _this, (RsContext)con, (RsAllocation)alloc, sur, dispatchTab);
-}
-
-static void
-nAllocationIoSend(JNIEnv *_env, jobject _this, jlong con, jlong alloc)
-{
-    dispatchTab.AllocationIoSend((RsContext)con, (RsAllocation)alloc);
-}
-
-static void
-nAllocationGenerateMipmaps(JNIEnv *_env, jobject _this, jlong con, jlong alloc)
-{
-    LOG_API("nAllocationGenerateMipmaps, con(%p), a(%p)", (RsContext)con, (RsAllocation)alloc);
-    dispatchTab.AllocationGenerateMipmaps((RsContext)con, (RsAllocation)alloc);
-}
-
-static size_t GetBitmapSize(JNIEnv *env, jobject jbitmap) {
-    AndroidBitmapInfo info;
-    memset(&info, 0, sizeof(info));
-    AndroidBitmap_getInfo(env, jbitmap, &info);
-    size_t s = info.width * info.height;
-    switch (info.format) {
-        case ANDROID_BITMAP_FORMAT_RGBA_8888: s *= 4; break;
-        case ANDROID_BITMAP_FORMAT_RGB_565: s *= 2; break;
-        case ANDROID_BITMAP_FORMAT_RGBA_4444: s *= 2; break;
-    }
-    return s;
-}
-
-static jlong
-nAllocationCreateFromBitmap(JNIEnv *_env, jobject _this, jlong con, jlong type, jint mip,
-                            jobject jbitmap, jint usage)
-{
-    jlong id = 0;
-    void *pixels = NULL;
-    AndroidBitmap_lockPixels(_env, jbitmap, &pixels);
-
-    if (pixels != NULL) {
-        id = (jlong)(uintptr_t)dispatchTab.AllocationCreateFromBitmap((RsContext)con,
-                                                                      (RsType)type,
-                                                                      (RsAllocationMipmapControl)mip,
-                                                                      pixels,
-                                                                      GetBitmapSize(_env, jbitmap),
-                                                                      usage);
-        AndroidBitmap_unlockPixels(_env, jbitmap);
-    }
-    return id;
-}
-
-static jlong
-nAllocationCreateBitmapBackedAllocation(JNIEnv *_env, jobject _this, jlong con, jlong type,
-                                        jint mip, jobject jbitmap, jint usage)
-{
-    jlong id = 0;
-    void *pixels = NULL;
-    AndroidBitmap_lockPixels(_env, jbitmap, &pixels);
-
-    if (pixels != NULL) {
-        id = (jlong)(uintptr_t)dispatchTab.AllocationCreateTyped((RsContext)con,
-                                                                 (RsType)type,
-                                                                 (RsAllocationMipmapControl)mip,
-                                                                 (uint32_t)usage,
-                                                                 (uintptr_t)pixels);
-        AndroidBitmap_unlockPixels(_env, jbitmap);
-    }
-    return id;
-}
-
-static jlong
-nAllocationCubeCreateFromBitmap(JNIEnv *_env, jobject _this, jlong con, jlong type,
-                                jint mip, jobject jbitmap, jint usage)
-{
-    void *pixels = NULL;
-    AndroidBitmap_lockPixels(_env, jbitmap, &pixels);
-
-    jlong id = 0;
-    if (pixels != NULL) {
-        id = (jlong)(uintptr_t)dispatchTab.AllocationCubeCreateFromBitmap((RsContext)con,
-                                                                          (RsType)type,
-                                                                          (RsAllocationMipmapControl)mip,
-                                                                          pixels,
-                                                                          GetBitmapSize(_env, jbitmap),
-                                                                          usage);
-        AndroidBitmap_unlockPixels(_env, jbitmap);
-    }
-    return id;
-}
-
-static void
-nAllocationCopyFromBitmap(JNIEnv *_env, jobject _this, jlong con, jlong alloc, jobject jbitmap)
-{
-    AndroidBitmapInfo info;
-    memset(&info, 0, sizeof(info));
-    AndroidBitmap_getInfo(_env, jbitmap, &info);
-
-    void *pixels = NULL;
-    AndroidBitmap_lockPixels(_env, jbitmap, &pixels);
-
-    if (pixels != NULL) {
-        dispatchTab.Allocation2DData((RsContext)con, (RsAllocation)alloc, 0, 0, 0,
-                                     RS_ALLOCATION_CUBEMAP_FACE_POSITIVE_X, info.width,
-                                     info.height, pixels, GetBitmapSize(_env, jbitmap), 0);
-        AndroidBitmap_unlockPixels(_env, jbitmap);
-    }
-}
-
-static void
-nAllocationCopyToBitmap(JNIEnv *_env, jobject _this, jlong con, jlong alloc, jobject jbitmap)
-{
-    AndroidBitmapInfo info;
-    memset(&info, 0, sizeof(info));
-    AndroidBitmap_getInfo(_env, jbitmap, &info);
-
-    void *pixels = NULL;
-    AndroidBitmap_lockPixels(_env, jbitmap, &pixels);
-
-    if (pixels != NULL) {
-        dispatchTab.AllocationCopyToBitmap((RsContext)con, (RsAllocation)alloc, pixels,
-                                           GetBitmapSize(_env, jbitmap));
-        AndroidBitmap_unlockPixels(_env, jbitmap);
-    }
-    //bitmap.notifyPixelsChanged();
-}
-
-// Copies from the Java object data into the Allocation pointed to by _alloc.
-static void
-nAllocationData1D(JNIEnv *_env, jobject _this, jlong con, jlong _alloc, jint offset, jint lod,
-                  jint count, jobject data, jint sizeBytes, jint dataType, jint mSize,
-                  jboolean usePadding)
-{
-    RsAllocation *alloc = (RsAllocation *)_alloc;
-    LOG_API("nAllocation1DData, con(%p), adapter(%p), offset(%i), count(%i), sizeBytes(%i), "
-            "dataType(%i)", (RsContext)con, (RsAllocation)alloc, offset, count, sizeBytes,
-            dataType);
-    PER_ARRAY_TYPE(nullptr, dispatchTab.Allocation1DData, true,
-                   (RsContext)con, alloc, offset, lod, count, ptr, sizeBytes);
-}
-
-
-static void
-nAllocationElementData1D(JNIEnv *_env, jobject _this, jlong con, jlong alloc, jint xoff,
-                         jint lod, jint compIdx, jbyteArray data, jint sizeBytes)
-{
-    LOG_API("nAllocationElementData1D, con(%p), alloc(%p), xoff(%i), comp(%i), len(%i), "
-            "sizeBytes(%i)", (RsContext)con, (RsAllocation)alloc, xoff, compIdx,
-            _env->GetArrayLength(data),
-            sizeBytes);
-    jbyte *ptr = _env->GetByteArrayElements(data, nullptr);
-    dispatchTab.Allocation1DElementData((RsContext)con, (RsAllocation)alloc, xoff,
-                                        lod, ptr, sizeBytes, compIdx);
-    _env->ReleaseByteArrayElements(data, ptr, JNI_ABORT);
-}
-
-/*
-static void
-nAllocationElementData(JNIEnv *_env, jobject _this, jlong con, jlong alloc,
-                       jint xoff, jint yoff, jint zoff,
-                       jint lod, jint compIdx, jbyteArray data, jint sizeBytes)
-{
-    jint len = _env->GetArrayLength(data);
-    LOG_API("nAllocationElementData, con(%p), alloc(%p), xoff(%i), yoff(%i), zoff(%i), comp(%i), len(%i), "
-            "sizeBytes(%i)", (RsContext)con, (RsAllocation)alloc, xoff, yoff, zoff, compIdx, len,
-            sizeBytes);
-    jbyte *ptr = _env->GetByteArrayElements(data, nullptr);
-    dispatchTab.AllocationElementData((RsContext)con, (RsAllocation)alloc,
-                                      xoff, yoff, zoff,
-                                      lod, ptr, sizeBytes, compIdx);
-    _env->ReleaseByteArrayElements(data, ptr, JNI_ABORT);
-}
-*/
-
-// Copies from the Java object data into the Allocation pointed to by _alloc.
-static void
-nAllocationData2D(JNIEnv *_env, jobject _this, jlong con, jlong _alloc, jint xoff, jint yoff, jint lod, jint _face,
-                  jint w, jint h, jobject data, jint sizeBytes, jint dataType, jint mSize,
-                  jboolean usePadding)
-{
-    RsAllocation *alloc = (RsAllocation *)_alloc;
-    RsAllocationCubemapFace face = (RsAllocationCubemapFace)_face;
-    LOG_API("nAllocation2DData, con(%p), adapter(%p), xoff(%i), yoff(%i), w(%i), h(%i), len(%i) "
-            "type(%i)", (RsContext)con, alloc, xoff, yoff, w, h, sizeBytes, dataType);
-    int count = w * h;
-    PER_ARRAY_TYPE(nullptr, dispatchTab.Allocation2DData, true,
-                   (RsContext)con, alloc, xoff, yoff, lod, face, w, h, ptr, sizeBytes, 0);
-}
-
-static void
-nAllocationData2D_alloc(JNIEnv *_env, jobject _this, jlong con,
-                        jlong dstAlloc, jint dstXoff, jint dstYoff,
-                        jint dstMip, jint dstFace,
-                        jint width, jint height,
-                        jlong srcAlloc, jint srcXoff, jint srcYoff,
-                        jint srcMip, jint srcFace)
-{
-    LOG_API("nAllocation2DData_s, con(%p), dstAlloc(%p), dstXoff(%i), dstYoff(%i),"
-            " dstMip(%i), dstFace(%i), width(%i), height(%i),"
-            " srcAlloc(%p), srcXoff(%i), srcYoff(%i), srcMip(%i), srcFace(%i)",
-            (RsContext)con, (RsAllocation)dstAlloc, dstXoff, dstYoff, dstMip, dstFace,
-            width, height, (RsAllocation)srcAlloc, srcXoff, srcYoff, srcMip, srcFace);
-
-    dispatchTab.AllocationCopy2DRange((RsContext)con,
-                                      (RsAllocation)dstAlloc,
-                                      dstXoff, dstYoff,
-                                      dstMip, dstFace,
-                                      width, height,
-                                      (RsAllocation)srcAlloc,
-                                      srcXoff, srcYoff,
-                                      srcMip, srcFace);
-}
-
-// Copies from the Java object data into the Allocation pointed to by _alloc.
-static void
-nAllocationData3D(JNIEnv *_env, jobject _this, jlong con, jlong _alloc, jint xoff, jint yoff, jint zoff, jint lod,
-                  jint w, jint h, jint d, jobject data, jint sizeBytes, jint dataType,
-                  jint mSize, jboolean usePadding)
-{
-    RsAllocation *alloc = (RsAllocation *)_alloc;
-    LOG_API("nAllocation3DData, con(%p), alloc(%p), xoff(%i), yoff(%i), zoff(%i), lod(%i), w(%i),"
-            " h(%i), d(%i), sizeBytes(%i)", (RsContext)con, (RsAllocation)alloc, xoff, yoff, zoff,
-            lod, w, h, d, sizeBytes);
-    int count = w * h * d;
-    PER_ARRAY_TYPE(nullptr, dispatchTab.Allocation3DData, true,
-                   (RsContext)con, alloc, xoff, yoff, zoff, lod, w, h, d, ptr, sizeBytes, 0);
-}
-
-static void
-nAllocationData3D_alloc(JNIEnv *_env, jobject _this, jlong con,
-                        jlong dstAlloc, jint dstXoff, jint dstYoff, jint dstZoff,
-                        jint dstMip,
-                        jint width, jint height, jint depth,
-                        jlong srcAlloc, jint srcXoff, jint srcYoff, jint srcZoff,
-                        jint srcMip)
-{
-    LOG_API("nAllocationData3D_alloc, con(%p), dstAlloc(%p), dstXoff(%i), dstYoff(%i),"
-            " dstMip(%i), width(%i), height(%i),"
-            " srcAlloc(%p), srcXoff(%i), srcYoff(%i), srcMip(%i)",
-            (RsContext)con, (RsAllocation)dstAlloc, dstXoff, dstYoff, dstMip, dstFace,
-            width, height, (RsAllocation)srcAlloc, srcXoff, srcYoff, srcMip, srcFace);
-
-    dispatchTab.AllocationCopy3DRange((RsContext)con,
-                                      (RsAllocation)dstAlloc,
-                                      dstXoff, dstYoff, dstZoff, dstMip,
-                                      width, height, depth,
-                                      (RsAllocation)srcAlloc,
-                                      srcXoff, srcYoff, srcZoff, srcMip);
-}
-
-// Copies from the Allocation pointed to by _alloc into the Java object data.
-static void
-nAllocationRead(JNIEnv *_env, jobject _this, jlong con, jlong _alloc, jobject data, jint dataType,
-                jint mSize, jboolean usePadding)
-{
-    RsAllocation *alloc = (RsAllocation *)_alloc;
-    LOG_API("nAllocationRead, con(%p), alloc(%p)", (RsContext)con, (RsAllocation)alloc);
-    int count = 0;
-    PER_ARRAY_TYPE(0, dispatchTab.AllocationRead, false,
-                   (RsContext)con, alloc, ptr, len * typeBytes);
-}
-
-// Copies from the Allocation pointed to by _alloc into the Java object data.
-static void
-nAllocationRead1D(JNIEnv *_env, jobject _this, jlong con, jlong _alloc, jint offset, jint lod,
-                  jint count, jobject data, jint sizeBytes, jint dataType,
-                  jint mSize, jboolean usePadding)
-{
-    RsAllocation *alloc = (RsAllocation *)_alloc;
-    LOG_API("nAllocation1DRead, con(%p), adapter(%p), offset(%i), count(%i), sizeBytes(%i), "
-              "dataType(%i)", (RsContext)con, alloc, offset, count, sizeBytes, dataType);
-    PER_ARRAY_TYPE(0, dispatchTab.Allocation1DRead, false,
-                   (RsContext)con, alloc, offset, lod, count, ptr, sizeBytes);
-}
-
-// Copies from the Element in the Allocation pointed to by _alloc into the Java array data.
-/*
-static void
-nAllocationElementRead(JNIEnv *_env, jobject _this, jlong con, jlong _alloc,
-                       jint xoff, jint yoff, jint zoff,
-                       jint lod, jint compIdx, jobject data, jint sizeBytes)
-{
-    jint len = _env->GetArrayLength(data);
-    LOG_API("nAllocationElementRead, con(%p), alloc(%p), xoff(%i), yoff(%i), zoff(%i), comp(%i), len(%i), "
-            "sizeBytes(%i)", (RsContext)con, (RsAllocation)alloc, xoff, yoff, zoff, compIdx, len,
-            sizeBytes);
-    jbyte *ptr = _env->GetByteArrayElements(data, nullptr);
-    dispatchTab.AllocationElementRead((RsContext)con, (RsAllocation)alloc,
-                                      xoff, yoff, zoff,
-                                      lod, ptr, sizeBytes, compIdx);
-    _env->ReleaseByteArrayElements(data, ptr, JNI_ABORT);
-}
-*/
-
-// Copies from the Allocation pointed to by _alloc into the Java object data.
-static void
-nAllocationRead2D(JNIEnv *_env, jobject _this, jlong con, jlong _alloc, jint xoff, jint yoff, jint lod, jint _face,
-                  jint w, jint h, jobject data, jint sizeBytes, jint dataType,
-                  jint mSize, jboolean usePadding)
-{
-    RsAllocation *alloc = (RsAllocation *)_alloc;
-    RsAllocationCubemapFace face = (RsAllocationCubemapFace)_face;
-    LOG_API("nAllocation2DRead, con(%p), adapter(%p), xoff(%i), yoff(%i), w(%i), h(%i), len(%i) "
-              "type(%i)", (RsContext)con, alloc, xoff, yoff, w, h, sizeBytes, dataType);
-    int count = w * h;
-    PER_ARRAY_TYPE(0, dispatchTab.Allocation2DRead, false,
-                   (RsContext)con, alloc, xoff, yoff, lod, face, w, h, ptr, sizeBytes, 0);
-}
-
-// Copies from the Allocation pointed to by _alloc into the Java object data.
-/*
-static void
-nAllocationRead3D(JNIEnv *_env, jobject _this, jlong con, jlong _alloc, jint xoff, jint yoff, jint zoff, jint lod,
-                  jint w, jint h, jint d, jobject data, int sizeBytes, int dataType,
-                  jint mSize, jboolean usePadding)
-{
-    RsAllocation *alloc = (RsAllocation *)_alloc;
-    LOG_API("nAllocation3DRead, con(%p), alloc(%p), xoff(%i), yoff(%i), zoff(%i), lod(%i), w(%i),"
-            " h(%i), d(%i), sizeBytes(%i)", (RsContext)con, (RsAllocation)alloc, xoff, yoff, zoff,
-            lod, w, h, d, sizeBytes);
-    int count = w * h * d;
-    PER_ARRAY_TYPE(nullptr, dispatchTab.Allocation3DRead, false,
-                   (RsContext)con, alloc, xoff, yoff, zoff, lod, w, h, d, ptr, sizeBytes, 0);
-}
-*/
-
-static jlong
-nAllocationGetType(JNIEnv *_env, jobject _this, jlong con, jlong a)
-{
-    LOG_API("nAllocationGetType, con(%p), a(%p)", (RsContext)con, (RsAllocation)a);
-    return (jlong)(uintptr_t) dispatchTab.AllocationGetType((RsContext)con, (RsAllocation)a);
-}
-
-static void
-nAllocationResize1D(JNIEnv *_env, jobject _this, jlong con, jlong alloc, jint dimX)
-{
-    LOG_API("nAllocationResize1D, con(%p), alloc(%p), sizeX(%i)", (RsContext)con,
-            (RsAllocation)alloc, dimX);
-    dispatchTab.AllocationResize1D((RsContext)con, (RsAllocation)alloc, dimX);
-}
-
-// -----------------------------------
-
-static void
-nScriptBindAllocation(JNIEnv *_env, jobject _this, jlong con, jlong script, jlong alloc, jint slot, jboolean mUseInc)
-{
-    LOG_API("nScriptBindAllocation, con(%p), script(%p), alloc(%p), slot(%i)",
-            (RsContext)con, (RsScript)script, (RsAllocation)alloc, slot);
-    if (mUseInc) {
-        dispatchTabInc.ScriptBindAllocation((RsContext)con, (RsScript)script, (RsAllocation)alloc, slot);
-    } else {
-        dispatchTab.ScriptBindAllocation((RsContext)con, (RsScript)script, (RsAllocation)alloc, slot);
-    }
-}
-
-static void
-nScriptSetVarI(JNIEnv *_env, jobject _this, jlong con, jlong script, jint slot, jint val, jboolean mUseInc)
-{
-    LOG_API("nScriptSetVarI, con(%p), s(%p), slot(%i), val(%i)", (RsContext)con,
-            (void *)script, slot, val);
-    if (mUseInc) {
-        dispatchTabInc.ScriptSetVarI((RsContext)con, (RsScript)script, slot, val);
-    } else {
-        dispatchTab.ScriptSetVarI((RsContext)con, (RsScript)script, slot, val);
-    }
-}
-
-static void
-nScriptSetVarObj(JNIEnv *_env, jobject _this, jlong con, jlong script, jint slot, jlong val, jboolean mUseInc)
-{
-    LOG_API("nScriptSetVarObj, con(%p), s(%p), slot(%i), val(%i)", (RsContext)con,
-            (void *)script, slot, val);
-    if (mUseInc) {
-        dispatchTabInc.ScriptSetVarObj((RsContext)con, (RsScript)script, slot, (RsObjectBase)val);
-    } else {
-        dispatchTab.ScriptSetVarObj((RsContext)con, (RsScript)script, slot, (RsObjectBase)val);
-    }
-}
-
-static void
-nScriptSetVarJ(JNIEnv *_env, jobject _this, jlong con, jlong script, jint slot, jlong val, jboolean mUseInc)
-{
-    LOG_API("nScriptSetVarJ, con(%p), s(%p), slot(%i), val(%lli)", (RsContext)con,
-            (void *)script, slot, val);
-    if (mUseInc) {
-        dispatchTabInc.ScriptSetVarJ((RsContext)con, (RsScript)script, slot, val);
-    } else {
-        dispatchTab.ScriptSetVarJ((RsContext)con, (RsScript)script, slot, val);
-    }
-}
-
-static void
-nScriptSetVarF(JNIEnv *_env, jobject _this, jlong con, jlong script, jint slot, float val, jboolean mUseInc)
-{
-    LOG_API("nScriptSetVarF, con(%p), s(%p), slot(%i), val(%f)", (RsContext)con,
-            (void *)script, slot, val);
-    if (mUseInc) {
-        dispatchTabInc.ScriptSetVarF((RsContext)con, (RsScript)script, slot, val);
-    } else {
-        dispatchTab.ScriptSetVarF((RsContext)con, (RsScript)script, slot, val);
-    }
-}
-
-static void
-nScriptSetVarD(JNIEnv *_env, jobject _this, jlong con, jlong script, jint slot, double val, jboolean mUseInc)
-{
-    LOG_API("nScriptSetVarD, con(%p), s(%p), slot(%i), val(%lf)", (RsContext)con,
-            (void *)script, slot, val);
-    if (mUseInc) {
-        dispatchTabInc.ScriptSetVarD((RsContext)con, (RsScript)script, slot, val);
-    } else {
-        dispatchTab.ScriptSetVarD((RsContext)con, (RsScript)script, slot, val);
-    }
-}
-
-static void
-nScriptSetVarV(JNIEnv *_env, jobject _this, jlong con, jlong script, jint slot, jbyteArray data, jboolean mUseInc)
-{
-    LOG_API("nScriptSetVarV, con(%p), s(%p), slot(%i)", (RsContext)con, (void *)script, slot);
-    jint len = _env->GetArrayLength(data);
-    jbyte *ptr = _env->GetByteArrayElements(data, NULL);
-    if (mUseInc) {
-        dispatchTabInc.ScriptSetVarV((RsContext)con, (RsScript)script, slot, ptr, len);
-    } else {
-        dispatchTab.ScriptSetVarV((RsContext)con, (RsScript)script, slot, ptr, len);
-    }
-    _env->ReleaseByteArrayElements(data, ptr, JNI_ABORT);
-}
-
-static void
-nScriptSetVarVE(JNIEnv *_env, jobject _this, jlong con, jlong script, jint slot, jbyteArray data,
-                jlong elem, jintArray dims, jboolean mUseInc)
-{
-    LOG_API("nScriptSetVarVE, con(%p), s(%p), slot(%i)", (RsContext)con, (void *)script, slot);
-    jint len = _env->GetArrayLength(data);
-    jbyte *ptr = _env->GetByteArrayElements(data, NULL);
-    jint dimsLen = _env->GetArrayLength(dims) * sizeof(int);
-    jint *dimsPtr = _env->GetIntArrayElements(dims, NULL);
-    if (mUseInc) {
-        dispatchTabInc.ScriptSetVarVE((RsContext)con, (RsScript)script, slot, ptr, len, (RsElement)elem,
-                                      (const uint32_t *)dimsPtr, dimsLen);
-    } else {
-        dispatchTab.ScriptSetVarVE((RsContext)con, (RsScript)script, slot, ptr, len, (RsElement)elem,
-                                   (const uint32_t *)dimsPtr, dimsLen);
-    }
-    _env->ReleaseByteArrayElements(data, ptr, JNI_ABORT);
-    _env->ReleaseIntArrayElements(dims, dimsPtr, JNI_ABORT);
-}
-
-
-static void
-nScriptSetTimeZone(JNIEnv *_env, jobject _this, jlong con, jlong script, jbyteArray timeZone, jboolean mUseInc)
-{
-    LOG_API("nScriptCSetTimeZone, con(%p), s(%p), timeZone(%s)", (RsContext)con,
-            (void *)script, (const char *)timeZone);
-
-    jint length = _env->GetArrayLength(timeZone);
-    jbyte* timeZone_ptr;
-    timeZone_ptr = (jbyte *) _env->GetPrimitiveArrayCritical(timeZone, (jboolean *)0);
-    if (mUseInc) {
-        dispatchTabInc.ScriptSetTimeZone((RsContext)con, (RsScript)script, (const char *)timeZone_ptr, length);
-    } else {
-        dispatchTab.ScriptSetTimeZone((RsContext)con, (RsScript)script, (const char *)timeZone_ptr, length);
-    }
-
-    if (timeZone_ptr) {
-        _env->ReleasePrimitiveArrayCritical(timeZone, timeZone_ptr, 0);
-    }
-}
-
-static void
-nScriptInvoke(JNIEnv *_env, jobject _this, jlong con, jlong obj, jint slot, jboolean mUseInc)
-{
-    LOG_API("nScriptInvoke, con(%p), script(%p)", (RsContext)con, (void *)obj);
-    if (mUseInc) {
-        dispatchTabInc.ScriptInvoke((RsContext)con, (RsScript)obj, slot);
-    } else {
-        dispatchTab.ScriptInvoke((RsContext)con, (RsScript)obj, slot);
-    }
-}
-
-static void
-nScriptInvokeV(JNIEnv *_env, jobject _this, jlong con, jlong script, jint slot, jbyteArray data, jboolean mUseInc)
-{
-    LOG_API("nScriptInvokeV, con(%p), s(%p), slot(%i)", (RsContext)con, (void *)script, slot);
-    jint len = _env->GetArrayLength(data);
-    jbyte *ptr = _env->GetByteArrayElements(data, NULL);
-    if (mUseInc) {
-        dispatchTabInc.ScriptInvokeV((RsContext)con, (RsScript)script, slot, ptr, len);
-    } else {
-        dispatchTab.ScriptInvokeV((RsContext)con, (RsScript)script, slot, ptr, len);
-    }
-    _env->ReleaseByteArrayElements(data, ptr, JNI_ABORT);
-}
-
-static void
-nScriptForEach(JNIEnv *_env, jobject _this, jlong con, jlong incCon,
-               jlong script, jint slot, jlong ain, jlong aout, jboolean mUseInc)
-{
-    LOG_API("nScriptForEach, con(%p), s(%p), slot(%i)", (RsContext)con, (void *)script, slot);
-    if (mUseInc) {
-        dispatchTab.ContextFinish((RsContext)con);
-        dispatchTabInc.ScriptForEach((RsContext)incCon, (RsScript)script, slot,
-                                     (RsAllocation)ain, (RsAllocation)aout,
-                                     NULL, 0, NULL, 0);
-    } else {
-        dispatchTab.ScriptForEach((RsContext)con, (RsScript)script, slot,
-                                  (RsAllocation)ain, (RsAllocation)aout,
-                                  NULL, 0, NULL, 0);
-    }
-}
-
-static void
-nScriptForEachV(JNIEnv *_env, jobject _this, jlong con, jlong incCon,
-                jlong script, jint slot, jlong ain, jlong aout, jbyteArray params, jboolean mUseInc)
-{
-    LOG_API("nScriptForEach, con(%p), s(%p), slot(%i)", (RsContext)con, (void *)script, slot);
-    jint len = _env->GetArrayLength(params);
-    jbyte *ptr = _env->GetByteArrayElements(params, NULL);
-    if (mUseInc) {
-        dispatchTab.ContextFinish((RsContext)con);
-        dispatchTabInc.ScriptForEach((RsContext)incCon, (RsScript)script, slot,
-                                     (RsAllocation)ain, (RsAllocation)aout,
-                                     ptr, len, NULL, 0);
-    } else {
-        dispatchTab.ScriptForEach((RsContext)con, (RsScript)script, slot,
-                                  (RsAllocation)ain, (RsAllocation)aout,
-                                  ptr, len, NULL, 0);
-    }
-    _env->ReleaseByteArrayElements(params, ptr, JNI_ABORT);
-}
-
-static void
-nScriptForEachClipped(JNIEnv *_env, jobject _this, jlong con, jlong incCon,
-                      jlong script, jint slot, jlong ain, jlong aout,
-                      jint xstart, jint xend,
-                      jint ystart, jint yend, jint zstart, jint zend, jboolean mUseInc)
-{
-    LOG_API("nScriptForEachClipped, con(%p), s(%p), slot(%i)", (RsContext)con, (void *)script, slot);
-    RsScriptCall sc;
-    sc.xStart = xstart;
-    sc.xEnd = xend;
-    sc.yStart = ystart;
-    sc.yEnd = yend;
-    sc.zStart = zstart;
-    sc.zEnd = zend;
-    sc.strategy = RS_FOR_EACH_STRATEGY_DONT_CARE;
-    sc.arrayStart = 0;
-    sc.arrayEnd = 0;
-    sc.array2Start = 0;
-    sc.array2End = 0;
-    sc.array3Start = 0;
-    sc.array3End = 0;
-    sc.array4Start = 0;
-    sc.array4End = 0;
-    if (mUseInc) {
-        dispatchTab.ContextFinish((RsContext)con);
-        dispatchTabInc.ScriptForEach((RsContext)incCon, (RsScript)script, slot,
-                                     (RsAllocation)ain, (RsAllocation)aout,
-                                     NULL, 0, &sc, sizeof(sc));
-    } else {
-        dispatchTab.ScriptForEach((RsContext)con, (RsScript)script, slot,
-                                  (RsAllocation)ain, (RsAllocation)aout,
-                                  NULL, 0, &sc, sizeof(sc));
-    }
-}
-
-static void
-nScriptForEachClippedV(JNIEnv *_env, jobject _this, jlong con, jlong incCon,
-                       jlong script, jint slot, jlong ain, jlong aout,
-                       jbyteArray params, jint xstart, jint xend,
-                       jint ystart, jint yend, jint zstart, jint zend, jboolean mUseInc)
-{
-    LOG_API("nScriptForEachClipped, con(%p), s(%p), slot(%i)", (RsContext)con, (void *)script, slot);
-    jint len = _env->GetArrayLength(params);
-    jbyte *ptr = _env->GetByteArrayElements(params, NULL);
-    RsScriptCall sc;
-    sc.xStart = xstart;
-    sc.xEnd = xend;
-    sc.yStart = ystart;
-    sc.yEnd = yend;
-    sc.zStart = zstart;
-    sc.zEnd = zend;
-    sc.strategy = RS_FOR_EACH_STRATEGY_DONT_CARE;
-    sc.arrayStart = 0;
-    sc.arrayEnd = 0;
-    sc.array2Start = 0;
-    sc.array2End = 0;
-    sc.array3Start = 0;
-    sc.array3End = 0;
-    sc.array4Start = 0;
-    sc.array4End = 0;
-    if (mUseInc) {
-        dispatchTab.ContextFinish((RsContext)con);
-        dispatchTabInc.ScriptForEach((RsContext)incCon, (RsScript)script, slot,
-                                     (RsAllocation)ain, (RsAllocation)aout,
-                                     ptr, len, &sc, sizeof(sc));
-    } else {
-        dispatchTab.ScriptForEach((RsContext)con, (RsScript)script, slot,
-                                  (RsAllocation)ain, (RsAllocation)aout,
-                                  ptr, len, &sc, sizeof(sc));
-    }
-    _env->ReleaseByteArrayElements(params, ptr, JNI_ABORT);
-}
-
-static void
-nScriptForEachMulti(JNIEnv *_env, jobject _this, jlong con, jlong script, jint slot,
-                    jlongArray ains, jlong aout, jbyteArray params,
-                    jintArray limits)
-{
-    LOG_API("nScriptForEach, con(%p), s(%p), slot(%i) ains(%p) aout(%" PRId64 ")", (RsContext)con, (void *)script, slot, ains, aout);
-
-    jint   in_len = 0;
-    jlong *in_ptr = nullptr;
-
-    RsAllocation *in_allocs = nullptr;
-
-    if (ains != nullptr) {
-        in_len = _env->GetArrayLength(ains);
-        if (in_len > (jint)RS_KERNEL_MAX_ARGUMENTS) {
-            LOG_ERR("Too many arguments in kernel launch.");
-            // TODO (b/20758983): Report back to Java and throw an exception
-            return;
-        }
-
-        // TODO (b/20760800): Check in_ptr is not null
-        in_ptr = _env->GetLongArrayElements(ains, nullptr);
-        if (sizeof(RsAllocation) == sizeof(jlong)) {
-            in_allocs = (RsAllocation*)in_ptr;
-
-        } else {
-            // Convert from 64-bit jlong types to the native pointer type.
-
-            in_allocs = (RsAllocation*)alloca(in_len * sizeof(RsAllocation));
-            if (in_allocs == nullptr) {
-                LOG_ERR("Failed launching kernel for lack of memory.");
-                _env->ReleaseLongArrayElements(ains, in_ptr, JNI_ABORT);
-                return;
-            }
-
-            for (int index = in_len; --index >= 0;) {
-                in_allocs[index] = (RsAllocation)in_ptr[index];
-            }
-        }
-    }
-
-    jint   param_len = 0;
-    jbyte *param_ptr = nullptr;
-
-    if (params != nullptr) {
-        param_len = _env->GetArrayLength(params);
-        param_ptr = _env->GetByteArrayElements(params, nullptr);
-    }
-
-    RsScriptCall sc, *sca = nullptr;
-    uint32_t sc_size = 0;
-
-    jint  limit_len = 0;
-    jint *limit_ptr = nullptr;
-
-    if (limits != nullptr) {
-        limit_len = _env->GetArrayLength(limits);
-        limit_ptr = _env->GetIntArrayElements(limits, nullptr);
-
-        if (limit_len != 6) {
-            LOG_ERR("LaunchOptions cannot be recognized.");
-            goto exit;
-        }
-
-        sc.xStart     = limit_ptr[0];
-        sc.xEnd       = limit_ptr[1];
-        sc.yStart     = limit_ptr[2];
-        sc.yEnd       = limit_ptr[3];
-        sc.zStart     = limit_ptr[4];
-        sc.zEnd       = limit_ptr[5];
-        sc.strategy   = RS_FOR_EACH_STRATEGY_DONT_CARE;
-        sc.arrayStart = 0;
-        sc.arrayEnd = 0;
-        sc.array2Start = 0;
-        sc.array2End = 0;
-        sc.array3Start = 0;
-        sc.array3End = 0;
-        sc.array4Start = 0;
-        sc.array4End = 0;
-
-        sca = &sc;
-    }
-
-    dispatchTabInc.ScriptForEachMulti((RsContext)con, (RsScript)script, slot,
-                                      in_allocs, in_len, (RsAllocation)aout,
-                                      param_ptr, param_len, sca, sc_size);
-
-exit:
-
-    if (ains != nullptr) {
-        _env->ReleaseLongArrayElements(ains, in_ptr, JNI_ABORT);
-    }
-
-    if (params != nullptr) {
-        _env->ReleaseByteArrayElements(params, param_ptr, JNI_ABORT);
-    }
-
-    if (limits != nullptr) {
-        _env->ReleaseIntArrayElements(limits, limit_ptr, JNI_ABORT);
-    }
-}
-
-static void
-nScriptReduce(JNIEnv *_env, jobject _this, jlong con, jlong script, jint slot,
-              jlongArray ains, jlong aout, jintArray limits)
-{
-    LOG_API("nScriptReduce, con(%p), s(%p), slot(%i) ains(%p) aout(%" PRId64 ")", (RsContext)con, (void *)script, slot, ains, aout);
-
-    if (ains == nullptr) {
-        LOG_ERR("At least one input required.");
-        // TODO (b/20758983): Report back to Java and throw an exception
-        return;
-    }
-    jint in_len = _env->GetArrayLength(ains);
-    if (in_len > (jint)RS_KERNEL_MAX_ARGUMENTS) {
-        LOG_ERR("Too many arguments in kernel launch.");
-        // TODO (b/20758983): Report back to Java and throw an exception
-        return;
-    }
-
-    jlong *in_ptr = _env->GetLongArrayElements(ains, nullptr);
-    if (in_ptr == nullptr) {
-        LOG_ERR("Failed to get Java array elements");
-        // TODO (b/20758983): Report back to Java and throw an exception
-        return;
-    }
-
-    RsAllocation *in_allocs = nullptr;
-    if (sizeof(RsAllocation) == sizeof(jlong)) {
-        in_allocs = (RsAllocation*)in_ptr;
-    } else {
-        // Convert from 64-bit jlong types to the native pointer type.
-
-        in_allocs = (RsAllocation*)alloca(in_len * sizeof(RsAllocation));
-        if (in_allocs == nullptr) {
-            LOG_ERR("Failed launching kernel for lack of memory.");
-            // TODO (b/20758983): Report back to Java and throw an exception
-            _env->ReleaseLongArrayElements(ains, in_ptr, JNI_ABORT);
-            return;
-        }
-
-        for (int index = in_len; --index >= 0;) {
-            in_allocs[index] = (RsAllocation)in_ptr[index];
-        }
-    }
-
-    RsScriptCall sc, *sca = nullptr;
-    uint32_t sc_size = 0;
-
-    jint  limit_len = 0;
-    jint *limit_ptr = nullptr;
-
-    if (limits != nullptr) {
-        limit_len = _env->GetArrayLength(limits);
-        limit_ptr = _env->GetIntArrayElements(limits, nullptr);
-        if (limit_ptr == nullptr) {
-            LOG_ERR("Failed to get Java array elements");
-            // TODO (b/20758983): Report back to Java and throw an exception
-            _env->ReleaseLongArrayElements(ains, in_ptr, JNI_ABORT);
-            return;
-        }
-
-        if (limit_len != 6) {
-            LOG_ERR("LaunchOptions cannot be recognized");
-            // TODO (b/20758983): Report back to Java and throw an exception
-            _env->ReleaseLongArrayElements(ains, in_ptr, JNI_ABORT);
-            return;
-        }
-
-        sc.xStart     = limit_ptr[0];
-        sc.xEnd       = limit_ptr[1];
-        sc.yStart     = limit_ptr[2];
-        sc.yEnd       = limit_ptr[3];
-        sc.zStart     = limit_ptr[4];
-        sc.zEnd       = limit_ptr[5];
-        sc.strategy   = RS_FOR_EACH_STRATEGY_DONT_CARE;
-        sc.arrayStart = 0;
-        sc.arrayEnd = 0;
-        sc.array2Start = 0;
-        sc.array2End = 0;
-        sc.array3Start = 0;
-        sc.array3End = 0;
-        sc.array4Start = 0;
-        sc.array4End = 0;
-
-        sca = &sc;
-        sc_size = sizeof(sc);
-    }
-
-    dispatchTab.ScriptReduce((RsContext)con, (RsScript)script, slot,
-                             in_allocs, in_len, (RsAllocation)aout,
-                             sca, sc_size);
-
-    _env->ReleaseLongArrayElements(ains, in_ptr, JNI_ABORT);
-
-    if (limits != nullptr) {
-        _env->ReleaseIntArrayElements(limits, limit_ptr, JNI_ABORT);
-    }
-}
-
-// -----------------------------------
-
-static jlong
-nScriptCCreate(JNIEnv *_env, jobject _this, jlong con,
-               jstring resName, jstring cacheDir,
-               jbyteArray scriptRef, jint length)
-{
-    LOG_API("nScriptCCreate, con(%p)", (RsContext)con);
-
-    AutoJavaStringToUTF8 resNameUTF(_env, resName);
-    AutoJavaStringToUTF8 cacheDirUTF(_env, cacheDir);
-    jlong ret = 0;
-    jbyte* script_ptr = NULL;
-    jint _exception = 0;
-    jint remaining;
-    if (!scriptRef) {
-        _exception = 1;
-        //jniThrowException(_env, "java/lang/IllegalArgumentException", "script == null");
-        goto exit;
-    }
-    if (length < 0) {
-        _exception = 1;
-        //jniThrowException(_env, "java/lang/IllegalArgumentException", "length < 0");
-        goto exit;
-    }
-    remaining = _env->GetArrayLength(scriptRef);
-    if (remaining < length) {
-        _exception = 1;
-        //jniThrowException(_env, "java/lang/IllegalArgumentException",
-        //        "length > script.length - offset");
-        goto exit;
-    }
-    script_ptr = (jbyte *)
-        _env->GetPrimitiveArrayCritical(scriptRef, (jboolean *)0);
-
-    //rsScriptCSetText(con, (const char *)script_ptr, length);
-
-    ret = (jlong)(uintptr_t)dispatchTab.ScriptCCreate((RsContext)con,
-                                                      resNameUTF.c_str(), resNameUTF.length(),
-                                                      cacheDirUTF.c_str(), cacheDirUTF.length(),
-                                                      (const char *)script_ptr, length);
-
-exit:
-    if (script_ptr) {
-        _env->ReleasePrimitiveArrayCritical(scriptRef, script_ptr,
-                _exception ? JNI_ABORT: 0);
-    }
-
-    return (jlong)(uintptr_t)ret;
-}
-
-static jlong
-nScriptIntrinsicCreate(JNIEnv *_env, jobject _this, jlong con, jint id, jlong eid, jboolean mUseInc)
-{
-    LOG_API("nScriptIntrinsicCreate, con(%p) id(%i) element(%p)", (RsContext)con, id, (void *)eid);
-    if (mUseInc) {
-        return (jlong)(uintptr_t)dispatchTabInc.ScriptIntrinsicCreate((RsContext)con, id, (RsElement)eid);
-    } else {
-        return (jlong)(uintptr_t)dispatchTab.ScriptIntrinsicCreate((RsContext)con, id, (RsElement)eid);
-    }
-}
-
-static jlong
-nScriptKernelIDCreate(JNIEnv *_env, jobject _this, jlong con, jlong sid, jint slot, jint sig, jboolean mUseInc)
-{
-    LOG_API("nScriptKernelIDCreate, con(%p) script(%p), slot(%i), sig(%i)", (RsContext)con,
-            (void *)sid, slot, sig);
-    if (mUseInc) {
-        return (jlong)(uintptr_t)dispatchTabInc.ScriptKernelIDCreate((RsContext)con, (RsScript)sid,
-                                                                     slot, sig);
-    } else {
-        return (jlong)(uintptr_t)dispatchTab.ScriptKernelIDCreate((RsContext)con, (RsScript)sid,
-                                                                  slot, sig);
-    }
-}
-
-static jlong
-nScriptInvokeIDCreate(JNIEnv *_env, jobject _this, jlong con, jlong sid, jint slot)
-{
-    LOG_API("nScriptInvokeIDCreate, con(%p) script(%p), slot(%i), sig(%i)", con,
-            (void *)sid, slot);
-    return (jlong)dispatchTab.ScriptInvokeIDCreate((RsContext)con, (RsScript)sid, slot);
-}
-
-static jlong
-nScriptFieldIDCreate(JNIEnv *_env, jobject _this, jlong con, jlong sid, jint slot, jboolean mUseInc)
-{
-    LOG_API("nScriptFieldIDCreate, con(%p) script(%p), slot(%i)", (RsContext)con, (void *)sid, slot);
-    if (mUseInc) {
-        return (jlong)(uintptr_t)dispatchTabInc.ScriptFieldIDCreate((RsContext)con, (RsScript)sid, slot);
-    } else {
-        return (jlong)(uintptr_t)dispatchTab.ScriptFieldIDCreate((RsContext)con, (RsScript)sid, slot);
-    }
-}
-
-static jlong
-nScriptGroupCreate(JNIEnv *_env, jobject _this, jlong con, jlongArray _kernels, jlongArray _src,
-    jlongArray _dstk, jlongArray _dstf, jlongArray _types)
-{
-    LOG_API("nScriptGroupCreate, con(%p)", (RsContext)con);
-
-    jlong id = 0;
-
-    RsScriptKernelID* kernelsPtr;
-    jint kernelsLen = _env->GetArrayLength(_kernels);
-    jlong *jKernelsPtr = _env->GetLongArrayElements(_kernels, nullptr);
-
-    RsScriptKernelID* srcPtr;
-    jint srcLen = _env->GetArrayLength(_src);
-    jlong *jSrcPtr = _env->GetLongArrayElements(_src, nullptr);
-
-    RsScriptKernelID* dstkPtr;
-    jint dstkLen = _env->GetArrayLength(_dstk);
-    jlong *jDstkPtr = _env->GetLongArrayElements(_dstk, nullptr);
-
-    RsScriptKernelID* dstfPtr;
-    jint dstfLen = _env->GetArrayLength(_dstf);
-    jlong *jDstfPtr = _env->GetLongArrayElements(_dstf, nullptr);
-
-    RsType* typesPtr;
-    jint typesLen = _env->GetArrayLength(_types);
-    jlong *jTypesPtr = _env->GetLongArrayElements(_types, nullptr);
-
-    if (jKernelsPtr == nullptr) {
-        LOG_ERR("Failed to get Java array elements: kernels");
-        goto cleanup;
-    }
-    if (jSrcPtr == nullptr) {
-        LOG_ERR("Failed to get Java array elements: src");
-        goto cleanup;
-    }
-    if (jDstkPtr == nullptr) {
-        LOG_ERR("Failed to get Java array elements: dstk");
-        goto cleanup;
-    }
-    if (jDstfPtr == nullptr) {
-        LOG_ERR("Failed to get Java array elements: dstf");
-        goto cleanup;
-    }
-    if (jTypesPtr == nullptr) {
-        LOG_ERR("Failed to get Java array elements: types");
-        goto cleanup;
-    }
-
-    kernelsPtr = (RsScriptKernelID*) malloc(sizeof(RsScriptKernelID) * kernelsLen);
-    for(int i = 0; i < kernelsLen; ++i) {
-        kernelsPtr[i] = (RsScriptKernelID)jKernelsPtr[i];
-    }
-
-    srcPtr = (RsScriptKernelID*) malloc(sizeof(RsScriptKernelID) * srcLen);
-    for(int i = 0; i < srcLen; ++i) {
-        srcPtr[i] = (RsScriptKernelID)jSrcPtr[i];
-    }
-
-    dstkPtr = (RsScriptKernelID*) malloc(sizeof(RsScriptKernelID) * dstkLen);
-    for(int i = 0; i < dstkLen; ++i) {
-        dstkPtr[i] = (RsScriptKernelID)jDstkPtr[i];
-    }
-
-    dstfPtr = (RsScriptKernelID*) malloc(sizeof(RsScriptKernelID) * dstfLen);
-    for(int i = 0; i < dstfLen; ++i) {
-        dstfPtr[i] = (RsScriptKernelID)jDstfPtr[i];
-    }
-
-    typesPtr = (RsType*) malloc(sizeof(RsType) * typesLen);
-    for(int i = 0; i < typesLen; ++i) {
-        typesPtr[i] = (RsType)jTypesPtr[i];
-    }
-
-    id = (jlong)(uintptr_t) dispatchTab.ScriptGroupCreate((RsContext)con,
-                               (RsScriptKernelID *)kernelsPtr, kernelsLen * sizeof(RsScriptKernelID),
-                               (RsScriptKernelID *)srcPtr, srcLen * sizeof(RsScriptKernelID),
-                               (RsScriptKernelID *)dstkPtr, dstkLen * sizeof(RsScriptKernelID),
-                               (RsScriptFieldID *)dstfPtr, dstfLen * sizeof(RsScriptKernelID),
-                               (RsType *)typesPtr, typesLen * sizeof(RsType));
-
-    free(kernelsPtr);
-    free(srcPtr);
-    free(dstkPtr);
-    free(dstfPtr);
-    free(typesPtr);
-
-cleanup:
-    if (jKernelsPtr != nullptr) {
-        _env->ReleaseLongArrayElements(_kernels, jKernelsPtr, 0);
-    }
-    if (jSrcPtr != nullptr) {
-        _env->ReleaseLongArrayElements(_src, jSrcPtr, 0);
-    }
-    if (jDstkPtr != nullptr) {
-        _env->ReleaseLongArrayElements(_dstk, jDstkPtr, 0);
-    }
-    if (jDstfPtr != nullptr) {
-        _env->ReleaseLongArrayElements(_dstf, jDstfPtr, 0);
-    }
-    if (jTypesPtr != nullptr) {
-        _env->ReleaseLongArrayElements(_types, jTypesPtr, 0);
-    }
-
-    return id;
-}
-
-static void
-nScriptGroupSetInput(JNIEnv *_env, jobject _this, jlong con, jlong gid, jlong kid, jlong alloc)
-{
-    LOG_API("nScriptGroupSetInput, con(%p) group(%p), kernelId(%p), alloc(%p)", (RsContext)con,
-            (void *)gid, (void *)kid, (void *)alloc);
-    dispatchTab.ScriptGroupSetInput((RsContext)con, (RsScriptGroup)gid, (RsScriptKernelID)kid,
-                                    (RsAllocation)alloc);
-}
-
-static void
-nScriptGroupSetOutput(JNIEnv *_env, jobject _this, jlong con, jlong gid, jlong kid, jlong alloc)
-{
-    LOG_API("nScriptGroupSetOutput, con(%p) group(%p), kernelId(%p), alloc(%p)", (RsContext)con,
-            (void *)gid, (void *)kid, (void *)alloc);
-    dispatchTab.ScriptGroupSetOutput((RsContext)con, (RsScriptGroup)gid, (RsScriptKernelID)kid,
-                                     (RsAllocation)alloc);
-}
-
-static void
-nScriptGroupExecute(JNIEnv *_env, jobject _this, jlong con, jlong gid)
-{
-    LOG_API("nScriptGroupSetOutput, con(%p) group(%p)", (RsContext)con, (void *)gid);
-    dispatchTab.ScriptGroupExecute((RsContext)con, (RsScriptGroup)gid);
-}
-
-// ---------------------------------------------------------------------------
-
-static jlong
-nSamplerCreate(JNIEnv *_env, jobject _this, jlong con, jint magFilter, jint minFilter,
-               jint wrapS, jint wrapT, jint wrapR, jfloat aniso)
-{
-    LOG_API("nSamplerCreate, con(%p)", (RsContext)con);
-    return (jlong)(uintptr_t)dispatchTab.SamplerCreate((RsContext)con,
-                                                       (RsSamplerValue)magFilter,
-                                                       (RsSamplerValue)minFilter,
-                                                       (RsSamplerValue)wrapS,
-                                                       (RsSamplerValue)wrapT,
-                                                       (RsSamplerValue)wrapR,
-                                                       aniso);
-}
-
-static jint
-nSystemGetPointerSize(JNIEnv *_env, jobject _this) {
-    return (jint)sizeof(void*);
-}
-
-// ---------------------------------------------------------------------------
-// For Incremental Intrinsic Support
-static jboolean nIncLoadSO(JNIEnv *_env, jobject _this, jint deviceApi, jstring libPath) {
-    void* handle = NULL;
-    // For API 9+, dlopen the full path of libRSSupport.
-    if (libPath != NULL) {
-        const char * libPathJni = _env->GetStringUTFChars(libPath, JNI_FALSE);
-        handle = dlopen(libPathJni, RTLD_LAZY | RTLD_LOCAL);
-        _env->ReleaseStringUTFChars(libPath, libPathJni);
-    } else {
-        handle = dlopen("libRSSupport.so", RTLD_LAZY | RTLD_LOCAL);
-    }
-
-    if (handle == NULL) {
-        LOG_ERR("couldn't dlopen %s;  librsjni version: %d", dlerror(), RS_JNI_VERSION);
-        return false;
-    }
-
-    if (loadSymbols(handle, dispatchTabInc, deviceApi) == false) {
-        LOG_ERR("Dispatch Table init failed! librsjni version: %d", RS_JNI_VERSION);
-        dlclose(handle);
-        return false;
-    }
-    dispatchTabInc.AllocationCreateStrided = (AllocationCreateStridedFnPtr)dlsym(handle, "rsAllocationCreateStrided");
-    if (dispatchTabInc.AllocationCreateStrided == NULL) {
-        LOG_ERR("Couldn't initialize dispatchTabInc.AllocationCreateStrided");
-        dlclose(handle);
-        return false;
-    }
-    LOG_API("Successfully loaded compat runtime");
-    return true;
-}
-
-// -----------------------------------
-// To create/destroy a dummy context
-static void
-nIncObjDestroy(JNIEnv *_env, jobject _this, jlong con, jlong obj)
-{
-    LOG_API("nObjDestroy, con(%p) obj(%p)", (RsContext)con, (void *)obj);
-    dispatchTabInc.ObjDestroy((RsContext)con, (void *)obj);
-}
-
-
-static jlong
-nIncDeviceCreate(JNIEnv *_env, jobject _this)
-{
-    LOG_API("nDeviceCreate");
-    return (jlong)(uintptr_t)dispatchTabInc.DeviceCreate();
-}
-
-static void
-nIncDeviceDestroy(JNIEnv *_env, jobject _this, jlong dev)
-{
-    LOG_API("nDeviceDestroy");
-    return dispatchTabInc.DeviceDestroy((RsDevice)dev);
-}
-
-static jlong
-nIncContextCreate(JNIEnv *_env, jobject _this, jlong dev, jint ver, jint sdkVer, jint ct)
-{
-    LOG_API("nContextCreate");
-    //The compat context for incremental support will be synchronous.
-    return (jlong)(uintptr_t)dispatchTabInc.ContextCreate((RsDevice)dev, ver, sdkVer,
-                                                          (RsContextType)ct,
-                                                          RS_CONTEXT_SYNCHRONOUS);
-}
-
-static void
-nIncContextFinish(JNIEnv *_env, jobject _this, jlong con)
-{
-    LOG_API("nContextFinish, con(%p)", (RsContext)con);
-    dispatchTabInc.ContextFinish((RsContext)con);
-}
-
-static void
-nIncContextDestroy(JNIEnv *_env, jobject _this, jlong con)
-{
-    LOG_API("nContextDestroy, con(%p)", (RsContext)con);
-    dispatchTabInc.ContextDestroy((RsContext)con);
-}
-
-// -----------------------------------
-// Create dummy Element
-static jlong
-nIncElementCreate(JNIEnv *_env, jobject _this, jlong con, jlong type, jint kind, jboolean norm, jint size)
-{
-    LOG_API("nElementCreate, con(%p), type(%i), kind(%i), norm(%i), size(%i)", (RsContext)con,
-            type, kind, norm, size);
-    return (jlong)(uintptr_t)dispatchTabInc.ElementCreate((RsContext)con, (RsDataType)type,
-                                                          (RsDataKind)kind, norm, size);
-}
-// -----------------------------------
-// Create dummy Type
-static jlong
-nIncTypeCreate(JNIEnv *_env, jobject _this, jlong con, jlong eid,
-            jint dimx, jint dimy, jint dimz, jboolean mips, jboolean faces, jint yuv)
-{
-    LOG_API("nTypeCreate, con(%p) eid(%p), x(%i), y(%i), z(%i), mips(%i), faces(%i), yuv(%i)",
-            incCon, eid, dimx, dimy, dimz, mips, faces, yuv);
-
-    return (jlong)(uintptr_t)dispatchTabInc.TypeCreate((RsContext)con, (RsElement)eid, dimx, dimy,
-                                                       dimz, mips, faces, yuv);
-}
-
-// -----------------------------------
-// Create Allocation from pointer
-static jlong
-nIncAllocationCreateTyped(JNIEnv *_env, jobject _this, jlong con, jlong incCon, jlong alloc, jlong type, jint xBytesSize)
-{
-    LOG_API("nAllocationCreateTyped, con(%p), type(%p), mip(%i), usage(%i), ptr(%p)",
-            incCon, (RsElement)type, mips, usage, (void *)pointer);
-    size_t strideIn;
-    void* pIn = NULL;
-    RsAllocation ainI = NULL;
-    if (alloc != 0) {
-        pIn = dispatchTab.AllocationGetPointer((RsContext)con, (RsAllocation)alloc, 0,
-                                               RS_ALLOCATION_CUBEMAP_FACE_POSITIVE_X, 0, 0,
-                                               &strideIn, sizeof(size_t));
-        /*
-         * By definition stride is a roundup of xBytesSize with requiredAlignment, so requiredAlignment must
-         * be strictly larger than the difference of (stride - xBytesSize).
-         *
-         * We can prove that as long as requiredAlignment satisfies the following two conditions, the
-         * memory layout will be identical :
-         * 1. Smaller or equal than stride;
-         * 2. Larger than minRequiredAlignment.
-         *
-         * In this case we can simply choose the first power of 2 that satisfies both conditions.
-         */
-        size_t requiredAlignment = 16;
-        size_t minRequiredAlignment = strideIn - xBytesSize;
-        while (requiredAlignment <= minRequiredAlignment) {
-            requiredAlignment <<= 1;
-        }
-        ainI = dispatchTabInc.AllocationCreateStrided((RsContext)incCon, (RsType)type,
-                                                      RS_ALLOCATION_MIPMAP_NONE,
-                                                      RS_ALLOCATION_USAGE_INCREMENTAL_SUPPORT | RS_ALLOCATION_USAGE_SHARED,
-                                                      (uintptr_t)pIn, requiredAlignment);
-    }
-    return (jlong)(uintptr_t) ainI;
-}
-
-static jobject
-nAllocationGetByteBuffer(JNIEnv *_env, jobject _this, jlong con, jlong alloc, jint xBytesSize, jint dimY, jint dimZ)
-{
-    LOG_API("nAllocationGetByteBuffer, con(%p), alloc(%p)", (RsContext)con, (RsAllocation)alloc);
-    size_t strideIn = xBytesSize;
-    void* ptr = NULL;
-    if (alloc != 0 && dispatchTab.AllocationGetPointer != nullptr) {
-        ptr = dispatchTab.AllocationGetPointer((RsContext)con, (RsAllocation)alloc, 0,
-                                               RS_ALLOCATION_CUBEMAP_FACE_POSITIVE_X, dimZ, 0,
-                                               &strideIn, sizeof(size_t));
-    }
-    if (ptr != NULL) {
-        size_t bufferSize = strideIn;
-        if (dimY > 0) {
-            bufferSize *= dimY;
-        }
-        if (dimZ > 0) {
-            bufferSize *= dimZ;
-        }
-        jobject byteBuffer = _env->NewDirectByteBuffer(ptr, (jlong) bufferSize);
-        return byteBuffer;
-    } else {
-        return NULL;
-    }
-}
-
-static jlong
-nAllocationGetStride(JNIEnv *_env, jobject _this, jlong con, jlong alloc)
-{
-    LOG_API("nAllocationGetStride, con(%p), alloc(%p)", (RsContext)con, (RsAllocation)alloc);
-    size_t strideIn = 0;
-    if (alloc != 0 && dispatchTab.AllocationGetPointer != nullptr) {
-        dispatchTab.AllocationGetPointer((RsContext)con, (RsAllocation)alloc, 0,
-                                         RS_ALLOCATION_CUBEMAP_FACE_POSITIVE_X, 0, 0,
-                                         &strideIn, sizeof(size_t));
-    }
-    return (jlong)strideIn;
-}
-
-// ---------------------------------------------------------------------------
-
-
-static const char *classPathName = "android/support/v8/renderscript/RenderScript";
-
-static JNINativeMethod methods[] = {
-{"nLoadSO",                        "(ZILjava/lang/String;)Z",                 (bool*)nLoadSO },
-{"nLoadIOSO",                      "()Z",                                     (bool*)nLoadIOSO },
-{"nDeviceCreate",                  "()J",                                     (void*)nDeviceCreate },
-{"nDeviceDestroy",                 "(J)V",                                    (void*)nDeviceDestroy },
-{"nDeviceSetConfig",               "(JII)V",                                  (void*)nDeviceSetConfig },
-{"nContextGetUserMessage",         "(J[I)I",                                  (void*)nContextGetUserMessage },
-{"nContextGetErrorMessage",        "(J)Ljava/lang/String;",                   (void*)nContextGetErrorMessage },
-{"nContextPeekMessage",            "(J[I)I",                                  (void*)nContextPeekMessage },
-{"nContextInitToClient",           "(J)V",                                    (void*)nContextInitToClient },
-{"nContextDeinitToClient",         "(J)V",                                    (void*)nContextDeinitToClient },
-
-
-// All methods below are thread protected in java.
-{"rsnContextCreate",                 "(JIIILjava/lang/String;)J",             (void*)nContextCreate },
-{"rsnContextFinish",                 "(J)V",                                  (void*)nContextFinish },
-{"rsnContextSetPriority",            "(JI)V",                                 (void*)nContextSetPriority },
-{"rsnContextDestroy",                "(J)V",                                  (void*)nContextDestroy },
-{"rsnContextDump",                   "(JI)V",                                 (void*)nContextDump },
-{"rsnContextSendMessage",            "(JI[I)V",                               (void*)nContextSendMessage },
-{"rsnClosureCreate",                 "(JJJ[J[J[I[J[J)J",                      (void*)nClosureCreate },
-{"rsnInvokeClosureCreate",           "(JJ[B[J[J[I)J",                         (void*)nInvokeClosureCreate },
-{"rsnClosureSetArg",                 "(JJIJI)V",                              (void*)nClosureSetArg },
-{"rsnClosureSetGlobal",              "(JJJJI)V",                              (void*)nClosureSetGlobal },
-{"rsnObjDestroy",                    "(JJ)V",                                 (void*)nObjDestroy },
-
-{"rsnElementCreate",                 "(JJIZI)J",                              (void*)nElementCreate },
-{"rsnElementCreate2",                "(J[J[Ljava/lang/String;[I)J",           (void*)nElementCreate2 },
-{"rsnElementGetSubElements",         "(JJ[J[Ljava/lang/String;[I)V",          (void*)nElementGetSubElements },
-
-{"rsnTypeCreate",                    "(JJIIIZZI)J",                           (void*)nTypeCreate },
-
-{"rsnAllocationCreateTyped",         "(JJIIJ)J",                              (void*)nAllocationCreateTyped },
-{"rsnAllocationCreateFromBitmap",    "(JJILandroid/graphics/Bitmap;I)J",      (void*)nAllocationCreateFromBitmap },
-{"rsnAllocationCreateBitmapBackedAllocation",    "(JJILandroid/graphics/Bitmap;I)J",      (void*)nAllocationCreateBitmapBackedAllocation },
-{"rsnAllocationCubeCreateFromBitmap","(JJILandroid/graphics/Bitmap;I)J",      (void*)nAllocationCubeCreateFromBitmap },
-
-{"rsnAllocationCopyFromBitmap",      "(JJLandroid/graphics/Bitmap;)V",        (void*)nAllocationCopyFromBitmap },
-{"rsnAllocationCopyToBitmap",        "(JJLandroid/graphics/Bitmap;)V",        (void*)nAllocationCopyToBitmap },
-
-{"rsnAllocationSyncAll",             "(JJI)V",                                (void*)nAllocationSyncAll },
-{"rsnAllocationSetSurface",          "(JJLandroid/view/Surface;)V",           (void*)nAllocationSetSurface },
-{"rsnAllocationIoSend",              "(JJ)V",                                 (void*)nAllocationIoSend },
-{"rsnAllocationData1D",              "(JJIIILjava/lang/Object;IIIZ)V",        (void*)nAllocationData1D },
-{"rsnAllocationElementData1D",       "(JJIII[BI)V",                           (void*)nAllocationElementData1D },
-//{"rsnAllocationElementData",         "(JJIIIII[BI)V",                         (void*)nAllocationElementData },
-{"rsnAllocationData2D",              "(JJIIIIIILjava/lang/Object;IIIZ)V",     (void*)nAllocationData2D },
-{"rsnAllocationData2D",              "(JJIIIIIIJIIII)V",                      (void*)nAllocationData2D_alloc },
-{"rsnAllocationData3D",              "(JJIIIIIIILjava/lang/Object;IIIZ)V",    (void*)nAllocationData3D },
-{"rsnAllocationData3D",              "(JJIIIIIIIJIIII)V",                     (void*)nAllocationData3D_alloc },
-{"rsnAllocationRead",                "(JJLjava/lang/Object;IIZ)V",            (void*)nAllocationRead },
-{"rsnAllocationRead1D",              "(JJIIILjava/lang/Object;IIIZ)V",        (void*)nAllocationRead1D },
-//{"rsnAllocationElementRead",         "(JJIIIII[BI)V",                         (void*)nAllocationElementRead },
-{"rsnAllocationRead2D",              "(JJIIIIIILjava/lang/Object;IIIZ)V",     (void*)nAllocationRead2D },
-//{"rsnAllocationRead3D",              "(JJIIIIIIILjava/lang/Object;IIIZ)V",  (void*)nAllocationRead3D },
-{"rsnAllocationGetType",             "(JJ)J",                                 (void*)nAllocationGetType},
-{"rsnAllocationResize1D",            "(JJI)V",                                (void*)nAllocationResize1D },
-{"rsnAllocationGenerateMipmaps",     "(JJ)V",                                 (void*)nAllocationGenerateMipmaps },
-
-{"rsnScriptBindAllocation",          "(JJJIZ)V",                              (void*)nScriptBindAllocation },
-{"rsnScriptSetTimeZone",             "(JJ[BZ)V",                              (void*)nScriptSetTimeZone },
-{"rsnScriptInvoke",                  "(JJIZ)V",                               (void*)nScriptInvoke },
-{"rsnScriptInvokeV",                 "(JJI[BZ)V",                             (void*)nScriptInvokeV },
-{"rsnScriptForEach",                 "(JJJIJJZ)V",                            (void*)nScriptForEach },
-{"rsnScriptForEach",                 "(JJJIJJ[BZ)V",                          (void*)nScriptForEachV },
-{"rsnScriptForEach",                 "(JJI[JJ[B[I)V",                         (void*)nScriptForEachMulti },
-{"rsnScriptForEachClipped",          "(JJJIJJIIIIIIZ)V",                      (void*)nScriptForEachClipped },
-{"rsnScriptForEachClipped",          "(JJJIJJ[BIIIIIIZ)V",                    (void*)nScriptForEachClippedV },
-{"rsnScriptReduce",                  "(JJI[JJ[I)V",                           (void*)nScriptReduce },
-{"rsnScriptSetVarI",                 "(JJIIZ)V",                              (void*)nScriptSetVarI },
-{"rsnScriptSetVarJ",                 "(JJIJZ)V",                              (void*)nScriptSetVarJ },
-{"rsnScriptSetVarF",                 "(JJIFZ)V",                              (void*)nScriptSetVarF },
-{"rsnScriptSetVarD",                 "(JJIDZ)V",                              (void*)nScriptSetVarD },
-{"rsnScriptSetVarV",                 "(JJI[BZ)V",                             (void*)nScriptSetVarV },
-{"rsnScriptSetVarVE",                "(JJI[BJ[IZ)V",                          (void*)nScriptSetVarVE },
-{"rsnScriptSetVarObj",               "(JJIJZ)V",                              (void*)nScriptSetVarObj },
-
-{"rsnScriptCCreate",                 "(JLjava/lang/String;Ljava/lang/String;[BI)J",  (void*)nScriptCCreate },
-{"rsnScriptIntrinsicCreate",         "(JIJZ)J",                               (void*)nScriptIntrinsicCreate },
-{"rsnScriptKernelIDCreate",          "(JJIIZ)J",                              (void*)nScriptKernelIDCreate },
-{"rsnScriptInvokeIDCreate",          "(JJI)J",                                (void*)nScriptInvokeIDCreate },
-{"rsnScriptFieldIDCreate",           "(JJIZ)J",                               (void*)nScriptFieldIDCreate },
-{"rsnScriptGroupCreate",             "(J[J[J[J[J[J)J",                        (void*)nScriptGroupCreate },
-{"rsnScriptGroup2Create",            "(JLjava/lang/String;Ljava/lang/String;[J)J", (void*)nScriptGroup2Create },
-{"rsnScriptGroupSetInput",           "(JJJJ)V",                               (void*)nScriptGroupSetInput },
-{"rsnScriptGroupSetOutput",          "(JJJJ)V",                               (void*)nScriptGroupSetOutput },
-{"rsnScriptGroupExecute",            "(JJ)V",                                 (void*)nScriptGroupExecute },
-{"rsnScriptGroup2Execute",           "(JJ)V",                                 (void*)nScriptGroup2Execute },
-
-{"rsnScriptIntrinsicBLAS_Single",    "(JJJIIIIIIIIIFJJFJIIIIZ)V",             (void*)nScriptIntrinsicBLAS_Single },
-{"rsnScriptIntrinsicBLAS_Double",    "(JJJIIIIIIIIIDJJDJIIIIZ)V",             (void*)nScriptIntrinsicBLAS_Double },
-{"rsnScriptIntrinsicBLAS_Complex",   "(JJJIIIIIIIIIFFJJFFJIIIIZ)V",           (void*)nScriptIntrinsicBLAS_Complex },
-{"rsnScriptIntrinsicBLAS_Z",         "(JJJIIIIIIIIIDDJJDDJIIIIZ)V",           (void*)nScriptIntrinsicBLAS_Z },
-
-{"rsnScriptIntrinsicBLAS_BNNM",      "(JJJIIIJIJIJIIZ)V",                     (void*)nScriptIntrinsicBLAS_BNNM },
-
-{"rsnSamplerCreate",                 "(JIIIIIF)J",                            (void*)nSamplerCreate },
-
-{"rsnSystemGetPointerSize",          "()I",                                   (void*)nSystemGetPointerSize },
-
-// Entry points for Inc libRSSupport
-{"nIncLoadSO",                       "(ILjava/lang/String;)Z",                (bool*)nIncLoadSO },
-{"nIncDeviceCreate",                 "()J",                                   (void*)nIncDeviceCreate },
-{"nIncDeviceDestroy",                "(J)V",                                  (void*)nIncDeviceDestroy },
-{"rsnIncContextCreate",              "(JIII)J",                               (void*)nIncContextCreate },
-{"rsnIncContextFinish",              "(J)V",                                  (void*)nIncContextFinish },
-{"rsnIncContextDestroy",             "(J)V",                                  (void*)nIncContextDestroy },
-{"rsnIncObjDestroy",                 "(JJ)V",                                 (void*)nIncObjDestroy },
-{"rsnIncElementCreate",              "(JJIZI)J",                              (void*)nIncElementCreate },
-{"rsnIncTypeCreate",                 "(JJIIIZZI)J",                           (void*)nIncTypeCreate },
-{"rsnIncAllocationCreateTyped",      "(JJJJI)J",                              (void*)nIncAllocationCreateTyped },
-{"rsnAllocationGetByteBuffer",       "(JJIII)Ljava/nio/ByteBuffer;",          (void*)nAllocationGetByteBuffer },
-{"rsnAllocationGetStride",           "(JJ)J",                                 (void*)nAllocationGetStride },
-};
-
-// ---------------------------------------------------------------------------
-
-jint JNI_OnLoad(JavaVM* vm, void* reserved)
-{
-    JNIEnv* env = NULL;
-    jclass clazz = NULL;
-    jint result = -1;
-
-    if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
-        //        __android_log_print(ANDROID_LOG_ERROR, LOG_TAG,
-        //            "ERROR: GetEnv failed\n");
-        goto bail;
-    }
-    if (env == NULL) {
-        //        __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "ERROR: env == NULL");
-        goto bail;
-    }
-
-    clazz = env->FindClass(classPathName);
-    if (clazz == NULL) {
-        goto bail;
-    }
-
-    if (env->RegisterNatives(clazz, methods, NELEM(methods)) < 0) {
-        //        __android_log_print(ANDROID_LOG_ERROR, LOG_TAG,
-        //            "ERROR: MediaPlayer native registration failed\n");
-        goto bail;
-    }
-
-    /* success -- return valid version number */
-    result = JNI_VERSION_1_4;
-
-bail:
-    return result;
-}
diff --git a/v8/renderscript/jni/android_rscompat_usage_io.cpp b/v8/renderscript/jni/android_rscompat_usage_io.cpp
deleted file mode 100644
index e29be1a..0000000
--- a/v8/renderscript/jni/android_rscompat_usage_io.cpp
+++ /dev/null
@@ -1,20 +0,0 @@
-#include <android/log.h>
-#include <android/native_window.h>
-#include <android/native_window_jni.h>
-
-#include <rsEnv.h>
-#include "rsDispatch.h"
-#define LOG_API(...)
-
-extern "C" void AllocationSetSurface(JNIEnv *_env, jobject _this, RsContext con, RsAllocation alloc, jobject sur, dispatchTable dispatchTab)
-{
-    LOG_API("nAllocationSetSurface, con(%p), alloc(%p), surface(%p)",
-            con, alloc, sur);
-
-    ANativeWindow* s = NULL;
-    if (sur != 0) {
-        s = ANativeWindow_fromSurface(_env, sur);
-    }
-    dispatchTab.AllocationSetSurface(con, alloc, s);
-}
-
diff --git a/v8/renderscript/jni/android_rscompat_usage_io_driver.cpp b/v8/renderscript/jni/android_rscompat_usage_io_driver.cpp
deleted file mode 100644
index 96eb19a..0000000
--- a/v8/renderscript/jni/android_rscompat_usage_io_driver.cpp
+++ /dev/null
@@ -1,113 +0,0 @@
-#include <android/native_window.h>
-#include <android/log.h>
-
-#include "rsCompatibilityLib.h"
-
-#include "rsdCore.h"
-#include "rsdAllocation.h"
-#include "rsAllocation.h"
-
-#define LOG_API(...)
-
-using namespace android;
-using namespace android::renderscript;
-
-static bool IoGetBuffer(const Context *rsc, Allocation *alloc, ANativeWindow *nw) {
-    DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
-    // Must lock the whole surface
-    if(drv->wndBuffer == NULL) {
-        drv->wndBuffer = new ANativeWindow_Buffer;
-    }
-    int32_t r = ANativeWindow_lock(nw, drv->wndBuffer, NULL);
-    if (r) {
-        LOG_API("Error Locking IO output buffer.");
-        return false;
-    }
-
-    void *dst = drv->wndBuffer->bits;
-    alloc->mHal.drvState.lod[0].mallocPtr = dst;
-    alloc->mHal.drvState.lod[0].stride = drv->wndBuffer->stride * alloc->mHal.state.elementSizeBytes;
-    return true;
-}
-
-extern "C" void rscAllocationSetSurface(RsContext rscR, RsAllocation allocR, ANativeWindow *nw) {
-    Context *rsc = (Context *)rscR;
-    Allocation *alloc = (Allocation *)allocR;
-    DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
-
-    // Cleanup old surface if there is one.
-    if (drv->wndSurface) {
-        ANativeWindow *old = drv->wndSurface;
-        ANativeWindow_unlockAndPost(old);
-        drv->wndSurface = NULL;
-        ANativeWindow_release(old);
-        old = NULL;
-    }
-
-    if (nw != NULL) {
-        int32_t r;
-        r = ANativeWindow_setBuffersGeometry(nw, alloc->mHal.drvState.lod[0].dimX,
-                                                 alloc->mHal.drvState.lod[0].dimY,
-                                                 WINDOW_FORMAT_RGBA_8888);
-        if (r) {
-            LOG_API("Error setting IO output buffer geometry.");
-            goto errorcmp;
-        }
-
-        IoGetBuffer(rsc, alloc, nw);
-        drv->wndSurface = nw;
-    }
-
-    return;
-
- errorcmp:
-
-    if (nw) {
-        nw = NULL;
-    }
-
-}
-
-extern "C" void rscAllocationDestroy(const Context *rsc, Allocation *alloc) {
-    DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
-    if (alloc->mHal.drvState.lod[0].mallocPtr) {
-        // don't free user-allocated ptrs or IO_OUTPUT buffers
-        if (!(drv->useUserProvidedPtr) &&
-            !(alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_IO_INPUT) &&
-            !(alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_IO_OUTPUT)) {
-                free(alloc->mHal.drvState.lod[0].mallocPtr);
-        }
-        alloc->mHal.drvState.lod[0].mallocPtr = NULL;
-    }
-
-    if ((alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_IO_OUTPUT) &&
-        (alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_SCRIPT)) {
-        ANativeWindow *nw = drv->wndSurface;
-        if (nw) {
-            //If we have an attached surface, need to release it.
-            ANativeWindow_unlockAndPost(nw);
-            drv->wndSurface = NULL;
-            ANativeWindow_release(nw);
-            nw = NULL;
-        }
-    }
-}
-
-extern "C" void rscAllocationIoSend(const Context *rsc, Allocation *alloc) {
-    DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
-    ANativeWindow *nw = drv->wndSurface;
-    if (nw) {
-        if (alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_SCRIPT) {
-            int32_t r = ANativeWindow_unlockAndPost(nw);
-            if (r) {
-                LOG_API("Error sending IO output buffer.");
-                return;
-            }
-            IoGetBuffer(rsc, alloc, nw);
-        }
-    } else {
-        LOG_API("Sent IO buffer with no attached surface.");
-        return;
-    }
-}
-
diff --git a/v8/renderscript/rs_support/Android.mk b/v8/renderscript/rs_support/Android.mk
deleted file mode 100644
index de8fae0..0000000
--- a/v8/renderscript/rs_support/Android.mk
+++ /dev/null
@@ -1,189 +0,0 @@
-
-LOCAL_PATH:=frameworks/rs
-rs_base_CFLAGS := -Werror -Wall -Wno-unused-parameter -Wno-unused-variable \
-		  -Wno-overloaded-virtual -DRS_COMPATIBILITY_LIB -std=c++11
-
-ifeq ($(ARCH_ARM_HAVE_NEON),true)
-rs_base_CFLAGS += -DARCH_ARM_HAVE_NEON
-endif
-
-ifeq ($(TARGET_BUILD_PDK), true)
-  rs_base_CFLAGS += -D__RS_PDK__
-endif
-
-# Build rsg-generator ====================
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := rsg-generator_support
-
-# These symbols are normally defined by BUILD_XXX, but we need to define them
-# here so that local-intermediates-dir works.
-
-LOCAL_IS_HOST_MODULE := true
-LOCAL_MODULE_CLASS := EXECUTABLES
-intermediates := $(local-intermediates-dir)
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_SRC_FILES:= \
-    spec.l \
-    rsg_generator.c
-
-LOCAL_CXX_STL := none
-LOCAL_SANITIZE := never
-
-include $(BUILD_HOST_EXECUTABLE)
-
-# TODO: This should go into build/core/config.mk
-RSG_GENERATOR_SUPPORT:=$(LOCAL_BUILT_MODULE)
-
-include $(CLEAR_VARS)
-LOCAL_CLANG := true
-LOCAL_MODULE := libRSSupport
-LOCAL_SDK_VERSION := 9
-
-
-LOCAL_MODULE_CLASS := SHARED_LIBRARIES
-generated_sources_dir := $(call local-generated-sources-dir)
-
-# Generate custom headers
-
-GEN := $(addprefix $(generated_sources_dir)/, \
-            rsgApiStructs.h \
-            rsgApiFuncDecl.h \
-        )
-
-$(GEN) : PRIVATE_PATH := $(LOCAL_PATH)
-$(GEN) : PRIVATE_CUSTOM_TOOL = cat $(PRIVATE_PATH)/rs.spec $(PRIVATE_PATH)/rs_compat.spec | $(RSG_GENERATOR_SUPPORT) $< $@
-$(GEN) : $(RSG_GENERATOR_SUPPORT) $(LOCAL_PATH)/rs.spec $(LOCAL_PATH)/rs_compat.spec
-$(GEN): $(generated_sources_dir)/%.h : $(LOCAL_PATH)/%.h.rsg
-	$(transform-generated-source)
-
-# used in jni/Android.mk
-rs_generated_source += $(GEN)
-LOCAL_GENERATED_SOURCES += $(GEN)
-
-# Generate custom source files
-
-GEN := $(addprefix $(generated_sources_dir)/, \
-            rsgApi.cpp \
-            rsgApiReplay.cpp \
-        )
-
-$(GEN) : PRIVATE_PATH := $(LOCAL_PATH)
-$(GEN) : PRIVATE_CUSTOM_TOOL = cat $(PRIVATE_PATH)/rs.spec $(PRIVATE_PATH)/rs_compat.spec | $(RSG_GENERATOR_SUPPORT) $< $@
-$(GEN) : $(RSG_GENERATOR_SUPPORT) $(LOCAL_PATH)/rs.spec $(LOCAL_PATH)/rs_compat.spec
-$(GEN): $(generated_sources_dir)/%.cpp : $(LOCAL_PATH)/%.cpp.rsg
-	$(transform-generated-source)
-
-# used in jni/Android.mk
-rs_generated_source += $(GEN)
-
-LOCAL_GENERATED_SOURCES += $(GEN)
-
-LOCAL_SRC_FILES:= \
-	rsAllocation.cpp \
-	rsApiAllocation.cpp \
-	rsApiContext.cpp \
-	rsApiDevice.cpp \
-	rsApiElement.cpp \
-	rsApiType.cpp \
-	rsClosure.cpp \
-	rsCompatibilityLib.cpp \
-	rsComponent.cpp \
-	rsContext.cpp \
-	rsCppUtils.cpp \
-	rsDevice.cpp \
-	rsDriverLoader.cpp \
-	rsElement.cpp \
-	rsFifoSocket.cpp \
-	rsObjectBase.cpp \
-	rsMatrix2x2.cpp \
-	rsMatrix3x3.cpp \
-	rsMatrix4x4.cpp \
-	rsMutex.cpp \
-	rsSampler.cpp \
-	rsScript.cpp \
-	rsScriptC.cpp \
-	rsScriptC_Lib.cpp \
-	rsScriptGroup.cpp \
-	rsScriptGroup2.cpp \
-	rsScriptIntrinsic.cpp \
-	rsSignal.cpp \
-	rsStream.cpp \
-	rsThreadIO.cpp \
-	rsType.cpp \
-	driver/rsdAllocation.cpp \
-	driver/rsdBcc.cpp \
-	driver/rsdCore.cpp \
-	driver/rsdElement.cpp \
-	driver/rsdRuntimeStubs.cpp \
-	driver/rsdSampler.cpp \
-	driver/rsdScriptGroup.cpp \
-	driver/rsdType.cpp \
-	cpu_ref/rsCpuCore.cpp \
-	cpu_ref/rsCpuExecutable.cpp \
-	cpu_ref/rsCpuScript.cpp \
-	cpu_ref/rsCpuRuntimeMath.cpp \
-	cpu_ref/rsCpuScriptGroup.cpp \
-	cpu_ref/rsCpuScriptGroup2.cpp \
-	cpu_ref/rsCpuIntrinsic.cpp \
-	cpu_ref/rsCpuIntrinsic3DLUT.cpp \
-	cpu_ref/rsCpuIntrinsicBlend.cpp \
-	cpu_ref/rsCpuIntrinsicBlur.cpp \
-	cpu_ref/rsCpuIntrinsicBLAS.cpp \
-	cpu_ref/rsCpuIntrinsicColorMatrix.cpp \
-	cpu_ref/rsCpuIntrinsicConvolve3x3.cpp \
-	cpu_ref/rsCpuIntrinsicConvolve5x5.cpp \
-	cpu_ref/rsCpuIntrinsicHistogram.cpp \
-	cpu_ref/rsCpuIntrinsicLUT.cpp \
-	cpu_ref/rsCpuIntrinsicResize.cpp \
-	cpu_ref/rsCpuIntrinsicYuvToRGB.cpp
-
-ifeq ($(ARCH_ARM_HAVE_ARMV7A),true)
-LOCAL_CFLAGS_arm := -DARCH_ARM_HAVE_VFP -DARCH_ARM_USE_INTRINSICS
-LOCAL_ASFLAGS_arm := -mfpu=neon
-LOCAL_SRC_FILES_arm := \
-    cpu_ref/rsCpuIntrinsics_neon_3DLUT.S \
-    cpu_ref/rsCpuIntrinsics_neon_Blend.S \
-    cpu_ref/rsCpuIntrinsics_neon_Blur.S \
-    cpu_ref/rsCpuIntrinsics_neon_ColorMatrix.S \
-    cpu_ref/rsCpuIntrinsics_neon_Convolve.S \
-    cpu_ref/rsCpuIntrinsics_neon_Resize.S \
-    cpu_ref/rsCpuIntrinsics_neon_YuvToRGB.S
-endif
-
-LOCAL_CFLAGS_arm64 += \
-    -DARCH_ARM_USE_INTRINSICS \
-    -DARCH_ARM64_USE_INTRINSICS \
-    -DARCH_ARM64_HAVE_NEON
-LOCAL_SRC_FILES_arm64 += \
-    cpu_ref/rsCpuIntrinsics_advsimd_3DLUT.S \
-    cpu_ref/rsCpuIntrinsics_advsimd_Blend.S \
-    cpu_ref/rsCpuIntrinsics_advsimd_Blur.S \
-    cpu_ref/rsCpuIntrinsics_advsimd_ColorMatrix.S \
-    cpu_ref/rsCpuIntrinsics_advsimd_Convolve.S \
-    cpu_ref/rsCpuIntrinsics_advsimd_Resize.S \
-    cpu_ref/rsCpuIntrinsics_advsimd_YuvToRGB.S
-
-LOCAL_CFLAGS_x86 += -DARCH_X86_HAVE_SSSE3
-LOCAL_SRC_FILES_x86 += cpu_ref/rsCpuIntrinsics_x86.cpp
-LOCAL_CFLAGS_x86_64 += -DARCH_X86_HAVE_SSSE3
-LOCAL_SRC_FILES_x86_64 += cpu_ref/rsCpuIntrinsics_x86.cpp
-
-LOCAL_REQUIRED_MODULES := libblasV8
-LOCAL_STATIC_LIBRARIES := libbnnmlowpV8
-LOCAL_LDFLAGS += -llog -ldl -Wl,--exclude-libs,libc++_static.a
-LOCAL_NDK_STL_VARIANT := c++_static
-
-LOCAL_C_INCLUDES += external/cblas/include
-LOCAL_C_INCLUDES += external/gemmlowp/eight_bit_int_gemm
-
-LOCAL_CFLAGS += $(rs_base_CFLAGS) -DGEMMLOWP_USE_STLPORT
-
-LOCAL_MODULE:= libRSSupport
-LOCAL_MODULE_TAGS := optional
-
-# TODO: why isn't this picked up from the host GLOBAL_CFLAGS?
-LOCAL_CFLAGS += -D__STDC_FORMAT_MACROS
-
-include $(BUILD_SHARED_LIBRARY)