Merge "Fixed RecyclerView scrap matching bug" into lmp-preview-dev
diff --git a/v17/leanback/res/layout/lb_details_overview.xml b/v17/leanback/res/layout/lb_details_overview.xml
index beca042..97d1490 100644
--- a/v17/leanback/res/layout/lb_details_overview.xml
+++ b/v17/leanback/res/layout/lb_details_overview.xml
@@ -38,23 +38,10 @@
             android:adjustViewBounds="true"
             />
 
-       <ImageView
-            android:id="@+id/details_overview_actions_more"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:src="@drawable/lb_ic_actions_right_arrow"
-            android:layout_alignParentRight="true"
-            android:layout_alignParentBottom="true"
-            android:layout_marginRight="@dimen/lb_details_overview_actions_more_margin_right"
-            android:layout_marginBottom="@dimen/lb_details_overview_actions_more_margin_bottom"
-            />
-
         <LinearLayout
             android:layout_width="match_parent"
             android:layout_height="match_parent"
             android:layout_toRightOf="@id/details_overview_image"
-            android:layout_marginLeft="@dimen/lb_details_overview_description_margin_left"
-            android:layout_marginRight="@dimen/lb_details_overview_description_margin_right"
             android:layout_marginBottom="@dimen/lb_details_overview_description_margin_bottom"
             android:layout_marginTop="@dimen/lb_details_overview_description_margin_top"
             android:orientation="vertical" >
@@ -64,7 +51,10 @@
             android:layout_width="wrap_content"
             android:layout_height="0dp"
             android:layout_weight="1"
-            android:gravity="top" />
+            android:gravity="top"
+            android:layout_marginLeft="@dimen/lb_details_overview_description_margin_left"
+            android:layout_marginRight="@dimen/lb_details_overview_description_margin_right"
+            />
 
         <android.support.v17.leanback.widget.HorizontalGridView
             android:id="@+id/details_overview_actions"
@@ -75,6 +65,8 @@
             android:clipToPadding="false"
             android:focusable="true"
             android:focusableInTouchMode="true"
+            android:paddingLeft="@dimen/lb_details_overview_description_margin_left"
+            android:paddingRight="@dimen/lb_details_overview_description_margin_right"
             lb:horizontalMargin="@dimen/lb_details_overview_action_items_margin"
             lb:rowHeight="@dimen/lb_details_overview_actions_height" />
 
diff --git a/v17/leanback/res/layout/lb_image_card_view.xml b/v17/leanback/res/layout/lb_image_card_view.xml
index 0a14ff7..f7225e6 100644
--- a/v17/leanback/res/layout/lb_image_card_view.xml
+++ b/v17/leanback/res/layout/lb_image_card_view.xml
@@ -70,6 +70,7 @@
                 android:layout_alignParentRight="true"
                 android:scaleType="fitCenter"
                 android:background="@color/lb_basic_card_info_bg_color"
+                android:visibility="gone"
                 android:contentDescription="@null" />
             <ImageView
                 android:id="@+id/fade_mask"
@@ -79,6 +80,7 @@
                 android:layout_alignParentBottom="true"
                 android:layout_toStartOf="@id/extra_badge"
                 android:scaleType="fitCenter"
+                android:visibility="gone"
                 android:contentDescription="@null" />
         </RelativeLayout>
     </FrameLayout>
diff --git a/v17/leanback/res/values/attrs.xml b/v17/leanback/res/values/attrs.xml
index f31cd96..a0fed63 100644
--- a/v17/leanback/res/values/attrs.xml
+++ b/v17/leanback/res/values/attrs.xml
@@ -169,5 +169,9 @@
         <!-- style for a vertical grid of items -->
         <attr name="itemsVerticalGridStyle" format="reference" />
 
+        <!-- Default colors -->
+        <attr name="defaultBrandColor" format="reference|color" />
+        <attr name="defaultSearchColor" format="reference|color" />
+
     </declare-styleable>
 </resources>
diff --git a/v17/leanback/res/values/colors.xml b/v17/leanback/res/values/colors.xml
index f78d9f3..14ee791 100644
--- a/v17/leanback/res/values/colors.xml
+++ b/v17/leanback/res/values/colors.xml
@@ -44,4 +44,7 @@
     <color name="lb_basic_card_info_bg_color">#FF1B1B1B</color>
     <color name="lb_basic_card_title_text_color">#FFEEEEEE</color>
     <color name="lb_basic_card_content_text_color">#FFEEEEEE</color>
+
+    <color name="lb_default_brand_color">#FF455A64</color>
+    <color name="lb_default_search_color">#FFFFAA3F</color>
 </resources>
diff --git a/v17/leanback/res/values/dimens.xml b/v17/leanback/res/values/dimens.xml
index b3ec3ee..f01e615 100644
--- a/v17/leanback/res/values/dimens.xml
+++ b/v17/leanback/res/values/dimens.xml
@@ -52,7 +52,10 @@
     <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">10dp</dimen>
+    <dimen name="lb_browse_item_vertical_margin">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>
 
     <item name="lb_focus_zoom_factor_small" type="fraction">106%</item>
     <item name="lb_focus_zoom_factor_medium" type="fraction">110%</item>
@@ -73,8 +76,6 @@
     <dimen name="lb_details_overview_actions_padding_left">294dp</dimen>
     <dimen name="lb_details_overview_actions_padding_right">132dp</dimen>
     <dimen name="lb_details_overview_actions_height">56dp</dimen>
-    <dimen name="lb_details_overview_actions_more_margin_right">12dp</dimen>
-    <dimen name="lb_details_overview_actions_more_margin_bottom">28dp</dimen>
     <dimen name="lb_details_overview_actions_fade_size">16dp</dimen>
     <dimen name="lb_details_rows_align_top">167dp</dimen>
 
diff --git a/v17/leanback/res/values/strings.xml b/v17/leanback/res/values/strings.xml
index 4cd08f2..bad8000 100644
--- a/v17/leanback/res/values/strings.xml
+++ b/v17/leanback/res/values/strings.xml
@@ -14,11 +14,15 @@
 See the License for the specific language governing permissions and
 limitations under the License.
 -->
-<resources>
-    <string name="orb_search_label">Search</string>
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- Image description for the call to search action visible when browsing content [CHAR LIMIT=40] -->
     <string name="orb_search_action">Search Action</string>
+    <!-- Hint showing in the empty search bar [CHAR LIMIT=40] -->
     <string name="lb_search_bar_hint">Search</string>
+    <!-- Hint showing in the empty search bar when using the voice input [CHAR LIMIT=40] -->
     <string name="lb_search_bar_hint_speech">Speak to search</string>
-    <string name="lb_search_bar_hint_with_title">Search %1$s</string>
-    <string name="lb_search_bar_hint_with_title_speech">Speak to search %1$s</string>
-</resources>
\ No newline at end of file
+    <!-- Hint showing in the empty search bar using a provided context (usually the application name) [CHAR LIMIT=40] -->
+    <string name="lb_search_bar_hint_with_title">Search <xliff:g id="search context">%1$s</xliff:g></string>
+    <!-- Hint showing in the empty search bar using a provided context (usually the application name) while in voice input mode [CHAR LIMIT=40] -->
+    <string name="lb_search_bar_hint_with_title_speech">Speak to search <xliff:g id="search context">%1$s</xliff:g></string>
+</resources>
diff --git a/v17/leanback/res/values/themes.xml b/v17/leanback/res/values/themes.xml
index 3024054..a481488 100644
--- a/v17/leanback/res/values/themes.xml
+++ b/v17/leanback/res/values/themes.xml
@@ -49,6 +49,9 @@
         <item name="detailsDescriptionSubtitleStyle">@style/Widget.Leanback.DetailsDescriptionSubtitleStyle</item>
         <item name="detailsDescriptionBodyStyle">@style/Widget.Leanback.DetailsDescriptionBodyStyle</item>
         <item name="detailsActionButtonStyle">@style/Widget.Leanback.DetailsActionButtonStyle</item>
+
+        <item name="defaultBrandColor">@color/lb_default_brand_color</item>
+        <item name="defaultSearchColor">@color/lb_default_search_color</item>
     </style>
 
 </resources>
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 05c3749..3230fa0 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/BrowseFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/BrowseFragment.java
@@ -374,7 +374,7 @@
         }
 
         TypedValue outValue = new TypedValue();
-        getActivity().getTheme().resolveAttribute(android.R.attr.colorForeground, outValue, true);
+        getActivity().getTheme().resolveAttribute(R.attr.defaultSearchColor, outValue, true);
         return getResources().getColor(outValue.resourceId);
     }
 
diff --git a/v17/leanback/src/android/support/v17/leanback/app/HeadersFragment.java b/v17/leanback/src/android/support/v17/leanback/app/HeadersFragment.java
index 22c1ec6..03dc03b 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/HeadersFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/HeadersFragment.java
@@ -175,7 +175,7 @@
         }
 
         TypedValue outValue = new TypedValue();
-        getActivity().getTheme().resolveAttribute(android.R.attr.colorBackground, outValue, true);
+        getActivity().getTheme().resolveAttribute(R.attr.defaultBrandColor, outValue, true);
         return getResources().getColor(outValue.resourceId);
     }
 }
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 de911e1..3dfb161 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/RowsFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/RowsFragment.java
@@ -13,6 +13,8 @@
  */
 package android.support.v17.leanback.app;
 
+import java.util.ArrayList;
+
 import android.animation.TimeAnimator;
 import android.animation.TimeAnimator.TimeListener;
 import android.graphics.Canvas;
@@ -22,9 +24,11 @@
 import android.support.v17.leanback.widget.ItemBridgeAdapter;
 import android.support.v17.leanback.widget.RowPresenter.ViewHolder;
 import android.support.v17.leanback.widget.VerticalGridView;
+import android.support.v17.leanback.widget.HorizontalGridView;
 import android.support.v17.leanback.widget.OnItemSelectedListener;
 import android.support.v17.leanback.widget.OnItemClickedListener;
 import android.support.v17.leanback.widget.RowPresenter;
+import android.support.v17.leanback.widget.ListRowPresenter;
 import android.support.v17.leanback.widget.Presenter;
 import android.support.v7.widget.RecyclerView;
 import android.util.Log;
@@ -139,6 +143,9 @@
     int mSelectAnimatorDuration;
     Interpolator mSelectAnimatorInterpolator = new DecelerateInterpolator(2);
 
+    private RecyclerView.RecycledViewPool mRecycledViewPool;
+    private ArrayList<Presenter> mPresenterMapper;
+
     /**
      * Sets an item clicked listener on the fragment.
      * OnItemClickedListener will override {@link View.OnClickListener} that
@@ -235,6 +242,9 @@
         // Need set this for directly using RowsFragment.
         getVerticalGridView().setItemAlignmentViewId(R.id.row_content);
         getVerticalGridView().addItemDecoration(mItemDecoration);
+
+        mRecycledViewPool = null;
+        mPresenterMapper = null;
     }
 
     @Override
@@ -277,16 +287,16 @@
     private final ItemBridgeAdapter.AdapterListener mBridgeAdapterListener =
             new ItemBridgeAdapter.AdapterListener() {
         @Override
-        public void onAddPresenter(Presenter presenter) {
+        public void onAddPresenter(Presenter presenter, int type) {
             ((RowPresenter) presenter).setOnItemClickedListener(mOnItemClickedListener);
         }
         @Override
         public void onCreate(ItemBridgeAdapter.ViewHolder vh) {
-            Presenter rowPresenter = vh.getPresenter();
             VerticalGridView listView = getVerticalGridView();
             if (listView != null && ((RowPresenter) vh.getPresenter()).canDrawOutOfBounds()) {
                 listView.setClipChildren(false);
             }
+            setupSharedViewPool(vh.getViewHolder());
             mViewsCreated = true;
             vh.setExtraObject(new RowViewHolderExtra(vh));
             // selected state is initialized to false, then driven by grid view onChildSelected
@@ -312,6 +322,26 @@
         }
     };
 
+    private void setupSharedViewPool(Presenter.ViewHolder viewHolder) {
+        if (viewHolder instanceof ListRowPresenter.ViewHolder) {
+            HorizontalGridView view = ((ListRowPresenter.ViewHolder) viewHolder).getGridView();
+            // Recycled view pool is shared between all list rows
+            if (mRecycledViewPool == null) {
+                mRecycledViewPool = view.getRecycledViewPool();
+            } else {
+                view.setRecycledViewPool(mRecycledViewPool);
+            }
+
+            ItemBridgeAdapter bridgeAdapter =
+                    ((ListRowPresenter.ViewHolder) viewHolder).getBridgeAdapter();
+            if (mPresenterMapper == null) {
+                mPresenterMapper = bridgeAdapter.getPresenterMapper();
+            } else {
+                bridgeAdapter.setPresenterMapper(mPresenterMapper);
+            }
+        }
+    }
+
     @Override
     protected void updateAdapter() {
         super.updateAdapter();
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 53d6011..ce4faf3 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/SearchFragment.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/SearchFragment.java
@@ -31,7 +31,9 @@
 import android.support.v17.leanback.R;
 
 /**
- * A fragment to handle searches
+ * <p>A fragment to handle searches.</p>
+ *
+ * <p>Note: Your application will need to request android.permission.RECORD_AUDIO</p>
  */
 public class SearchFragment extends Fragment {
     private static final String TAG = SearchFragment.class.getSimpleName();
@@ -62,6 +64,9 @@
          * <p>This is called as soon as the query changes; it is up to the application to add a
          * delay before actually executing the queries if needed.</p>
          *
+         * <p>This method might not always be called before onQueryTextSubmit gets called, in
+         * particular for voice input cases.</p>
+         *
          * @param newQuery The current search query.
          * @return whether the results changed or not.
          */
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 6b08b29..f0a9483 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/DetailsOverviewRowPresenter.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/DetailsOverviewRowPresenter.java
@@ -46,21 +46,16 @@
         final ImageView mImageView;
         final FrameLayout mDetailsDescriptionFrame;
         final HorizontalGridView mActionsRow;
-        final View mMoreActionsView;
         Presenter.ViewHolder mDetailsDescriptionViewHolder;
         int mNumItems;
         boolean mShowMoreRight;
         boolean mShowMoreLeft;
-        boolean mShowMoreActions;
 
         void bind(ItemBridgeAdapter bridgeAdapter) {
             mNumItems = bridgeAdapter.getItemCount();
             bridgeAdapter.setAdapterListener(mAdapterListener);
 
-            mMoreActionsView.setAlpha(0f);
             mShowMoreRight = false;
-            mShowMoreActions = false;
-
             mShowMoreLeft = true;
             showMoreLeft(false);
         }
@@ -101,16 +96,12 @@
             boolean showRight = (viewHolder == null ||
                     viewHolder.itemView.getRight() > mActionsRow.getWidth());
 
-            boolean showMore = (viewHolder == null ||
-                    getViewCenter(viewHolder.itemView) > 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);
 
-            showMoreActions(showMore);
             showMoreRight(showRight);
             showMoreLeft(showLeft);
         }
@@ -129,14 +120,6 @@
             }
         }
 
-        private void showMoreActions(boolean show) {
-            if (show != mShowMoreActions) {
-                mMoreActionsView.animate().alpha(show ? 1f : 0).setDuration(
-                        MORE_ACTIONS_FADE_MS).start();
-                mShowMoreActions = show;
-            }
-        }
-
         public ViewHolder(View rootView) {
             super(rootView);
             mImageView = (ImageView) rootView.findViewById(R.id.details_overview_image);
@@ -149,11 +132,7 @@
             final int fadeLength = rootView.getResources().getDimensionPixelSize(
                     R.dimen.lb_details_overview_actions_fade_size);
             mActionsRow.setFadingRightEdgeLength(fadeLength);
-            mActionsRow.setFadingRightEdgeOffset(-fadeLength);
             mActionsRow.setFadingLeftEdgeLength(fadeLength);
-            mActionsRow.setFadingLeftEdgeOffset(-fadeLength);
-
-            mMoreActionsView = rootView.findViewById(R.id.details_overview_actions_more);
         }
     }
 
@@ -222,7 +201,7 @@
 
     private int getDefaultBackgroundColor(Context context) {
         TypedValue outValue = new TypedValue();
-        context.getTheme().resolveAttribute(android.R.attr.colorBackground, outValue, true);
+        context.getTheme().resolveAttribute(R.attr.defaultBrandColor, outValue, true);
         return context.getResources().getColor(outValue.resourceId);
     }
 
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 85e77f4..ef9c77d 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/GridLayoutManager.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/GridLayoutManager.java
@@ -735,7 +735,7 @@
             }
 
             // Adapter may have changed so remove all attached views permanently
-            removeAllViews();
+            removeAndRecycleAllViews(mRecycler);
 
             mScrollOffsetPrimary = 0;
             mScrollOffsetSecondary = 0;
@@ -797,12 +797,16 @@
         }
 
         if (mGrid == null) {
-            measureScrapChild(mFocusPosition == NO_POSITION ? 0 : mFocusPosition,
-                    MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
-                    MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
-                    mMeasuredDimension);
-            if (DEBUG) Log.v(TAG, "measured scrap child: " + mMeasuredDimension[0] +
-                    " " + mMeasuredDimension[1]);
+            if (mState.getItemCount() > 0) {
+                measureScrapChild(mFocusPosition == NO_POSITION ? 0 : mFocusPosition,
+                        MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
+                        MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
+                        mMeasuredDimension);
+                if (DEBUG) Log.v(TAG, "measured scrap child: " + mMeasuredDimension[0] +
+                        " " + mMeasuredDimension[1]);
+            } else {
+                mMeasuredDimension[0] = mMeasuredDimension[1] = 0;
+            }
         }
 
         List<Integer>[] rows = mGrid == null ? null :
@@ -1385,6 +1389,13 @@
         return mAnimateChildLayout;
     }
 
+    private void removeAndRecycleAllViews(RecyclerView.Recycler recycler) {
+        if (DEBUG) Log.v(TAG, "removeAndRecycleAllViews " + getChildCount());
+        for (int i = getChildCount() - 1; i >= 0; i--) {
+            removeAndRecycleViewAt(i, recycler);
+        }
+    }
+
     // Lays out items based on the current scroll position
     @Override
     public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
@@ -1408,7 +1419,7 @@
 
         if (!mLayoutEnabled) {
             discardLayoutInfo();
-            removeAllViews();
+            removeAndRecycleAllViews(recycler);
             return;
         }
         mInLayout = true;
@@ -2296,6 +2307,7 @@
     public void onAdapterChanged(RecyclerView.Adapter oldAdapter,
             RecyclerView.Adapter newAdapter) {
         discardLayoutInfo();
+        mFocusPosition = NO_POSITION;
         super.onAdapterChanged(oldAdapter, newAdapter);
     }
 
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 bc4a476..bc89b11 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/ItemBridgeAdapter.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/ItemBridgeAdapter.java
@@ -33,7 +33,7 @@
      * Interface for listening to view holder operations.
      */
     public static class AdapterListener {
-        public void onAddPresenter(Presenter presenter) {
+        public void onAddPresenter(Presenter presenter, int type) {
         }
         public void onCreate(ViewHolder viewHolder) {
         }
@@ -198,6 +198,14 @@
         setAdapter(null);
     }
 
+    public void setPresenterMapper(ArrayList<Presenter> presenters) {
+        mPresenters = presenters;
+    }
+
+    public ArrayList<Presenter> getPresenterMapper() {
+        return mPresenters;
+    }
+
     @Override
     public int getItemCount() {
         return mAdapter.size();
@@ -213,8 +221,9 @@
         if (type < 0) {
             mPresenters.add(presenter);
             type = mPresenters.indexOf(presenter);
+            if (DEBUG) Log.v(TAG, "getItemViewType added presenter " + presenter + " type " + type);
             if (mAdapterListener != null) {
-                mAdapterListener.onAddPresenter(presenter);
+                mAdapterListener.onAddPresenter(presenter, type);
             }
         }
         return type;
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 93fdd9e..d200529 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/ListRowPresenter.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/ListRowPresenter.java
@@ -23,6 +23,7 @@
 import android.support.v17.leanback.widget.Presenter.ViewHolder;
 import android.support.v7.widget.RecyclerView;
 import android.util.AttributeSet;
+import android.util.Log;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewGroup.LayoutParams;
@@ -82,6 +83,10 @@
         public final HorizontalGridView getGridView() {
             return mGridView;
         }
+
+        public final ItemBridgeAdapter getBridgeAdapter() {
+            return mItemBridgeAdapter;
+        }
     }
 
     private int mRowHeight;
@@ -91,6 +96,10 @@
     private boolean mShadowEnabled = true;
     private int mBrowseRowsFadingEdgeLength = -1;
 
+    private static int sSelectedRowTopPadding;
+    private static int sExpandedSelectedRowTopPadding;
+    private static int sExpandedRowNoHovercardBottomPadding;
+
     /**
      * Constructs a ListRowPresenter with defaults.
      * Uses {@link FocusHighlight#ZOOM_FACTOR_MEDIUM} for focus zooming.
@@ -221,6 +230,11 @@
                 }
                 viewHolder.itemView.setActivated(rowViewHolder.mExpanded);
             }
+
+            @Override
+            public void onAddPresenter(Presenter presenter, int type) {
+                rowViewHolder.getGridView().getRecycledViewPool().setMaxRecycledViews(type, 24);
+            }
         });
     }
 
@@ -269,8 +283,51 @@
         }
     }
 
+    private static void initStatics(Context context) {
+        if (sSelectedRowTopPadding == 0) {
+            sSelectedRowTopPadding = context.getResources().getDimensionPixelSize(
+                    R.dimen.lb_browse_selected_row_top_padding);
+            sExpandedSelectedRowTopPadding = context.getResources().getDimensionPixelSize(
+                    R.dimen.lb_browse_expanded_selected_row_top_padding);
+            sExpandedRowNoHovercardBottomPadding = context.getResources().getDimensionPixelSize(
+                    R.dimen.lb_browse_expanded_row_no_hovercard_bottom_padding);
+        }
+    }
+
+    private int getSpaceUnderBaseline(ListRowPresenter.ViewHolder vh) {
+        RowHeaderPresenter.ViewHolder headerViewHolder = vh.getHeaderViewHolder();
+        if (headerViewHolder != null) {
+            if (getHeaderPresenter() != null) {
+                return getHeaderPresenter().getSpaceUnderBaseline(headerViewHolder);
+            }
+            return headerViewHolder.view.getPaddingBottom();
+        }
+        return 0;
+    }
+
+    private void setVerticalPadding(ListRowPresenter.ViewHolder vh) {
+        int paddingTop, paddingBottom;
+        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;
+        } else if (vh.isSelected()) {
+            paddingTop = sSelectedRowTopPadding;
+            paddingBottom = sSelectedRowTopPadding - vh.mPaddingTop;
+        } else {
+            paddingTop = vh.mPaddingTop;
+            paddingBottom = 0;
+        }
+        vh.getGridView().setPadding(vh.mPaddingLeft, paddingTop, vh.mPaddingRight,
+                paddingBottom);
+    }
+
     @Override
     protected RowPresenter.ViewHolder createRowViewHolder(ViewGroup parent) {
+        initStatics(parent.getContext());
         ListRowView rowView = new ListRowView(parent.getContext());
         setupFadingEffect(rowView);
         if (mRowHeight != 0) {
@@ -282,7 +339,9 @@
     @Override
     protected void onRowViewSelected(RowPresenter.ViewHolder holder, boolean selected) {
         super.onRowViewSelected(holder, selected);
-        updateFooterViewSwitcher((ViewHolder) holder);
+        ViewHolder vh = (ViewHolder) holder;
+        setVerticalPadding(vh);
+        updateFooterViewSwitcher(vh);
     }
 
     /*
@@ -326,13 +385,7 @@
             int newHeight = expanded ? getExpandedRowHeight() : getRowHeight();
             vh.getGridView().setRowHeight(newHeight);
         }
-        if (expanded) {
-            vh.getGridView().setPadding(vh.mPaddingLeft, vh.mPaddingTop,
-                    vh.mPaddingRight, vh.mPaddingBottom);
-        } else {
-            vh.getGridView().setPadding(vh.mPaddingLeft, vh.mPaddingTop,
-                    vh.mPaddingRight, 0);
-        }
+        setVerticalPadding(vh);
         vh.getGridView().setFadingLeftEdge(!expanded);
         updateFooterViewSwitcher(vh);
     }
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 64f46ad..2479420 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/RowHeaderPresenter.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/RowHeaderPresenter.java
@@ -13,10 +13,12 @@
  */
 package android.support.v17.leanback.widget;
 
+import android.graphics.Paint;
 import android.support.v17.leanback.R;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
+import android.widget.TextView;
 
 /**
  * RowHeaderPresenter provides a default implementation for header using TextView.
@@ -26,6 +28,7 @@
 public class RowHeaderPresenter extends Presenter {
 
     private final int mLayoutResourceId;
+    private final Paint mFontMeasurePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
 
     public RowHeaderPresenter() {
         this(R.layout.lb_row_header);
@@ -90,4 +93,26 @@
         holder.view.setAlpha(holder.mUnselectAlpha + holder.mSelectLevel *
                 (1f - holder.mUnselectAlpha));
     }
-}
\ No newline at end of file
+
+    /**
+     * Returns the space (distance in pixels) below the baseline of the
+     * text view, if one exists; otherwise, returns 0.
+     */
+    public int getSpaceUnderBaseline(ViewHolder holder) {
+        int space = holder.view.getPaddingBottom();
+        if (holder.view instanceof TextView) {
+            space += (int) getFontDescent((TextView) holder.view, mFontMeasurePaint);
+        }
+        return space;
+    }
+
+    protected static float getFontDescent(TextView textView, Paint fontMeasurePaint) {
+        if (fontMeasurePaint.getTextSize() != textView.getTextSize()) {
+            fontMeasurePaint.setTextSize(textView.getTextSize());
+        }
+        if (fontMeasurePaint.getTypeface() != textView.getTypeface()) {
+            fontMeasurePaint.setTypeface(textView.getTypeface());
+        }
+        return fontMeasurePaint.descent();
+    }
+}
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 ae717ab..75a66c6 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/SearchBar.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/SearchBar.java
@@ -15,6 +15,7 @@
 
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.PackageManager;
 import android.content.res.Resources;
 import android.graphics.Color;
 import android.graphics.drawable.Drawable;
@@ -46,7 +47,9 @@
 import java.util.List;
 
 /**
- * SearchBar is a search widget.
+ * <p>SearchBar is a search widget.</p>
+ *
+ * <p>Note: Your application will need to request android.permission.RECORD_AUDIO</p>
  */
 public class SearchBar extends RelativeLayout {
     private static final String TAG = SearchBar.class.getSimpleName();
@@ -68,7 +71,10 @@
         public void onSearchQueryChange(String query);
 
         /**
-         * Method invoked when the search query is submitted.
+         * <p>Method invoked when the search query is submitted.</p>
+         *
+         * <p>This method can be called without a preceeding onSearchQueryChange,
+         * in particular in the case of a voice input.</p>
          *
          * @param query The query being submitted.
          */
@@ -110,6 +116,8 @@
 
     public SearchBar(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
+        enforceAudioRecordPermission();
+
         Resources r = getResources();
 
         LayoutInflater inflater = LayoutInflater.from(getContext());
@@ -519,5 +527,12 @@
         }
     }
 
+    private void enforceAudioRecordPermission() {
+        String permission = "android.permission.RECORD_AUDIO";
+        int res = getContext().checkCallingOrSelfPermission(permission);
+        if (PackageManager.PERMISSION_GRANTED != res) {
+            throw new IllegalStateException("android.premission.RECORD_AUDIO required for search");
+        }
+    }
 
 }
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/VerticalGridPresenter.java b/v17/leanback/src/android/support/v17/leanback/widget/VerticalGridPresenter.java
index 586ebf9..c68c59d 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/VerticalGridPresenter.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/VerticalGridPresenter.java
@@ -182,6 +182,11 @@
                     });
                 }
             }
+
+            @Override
+            public void onAttachedToWindow(ItemBridgeAdapter.ViewHolder viewHolder) {
+                viewHolder.itemView.setActivated(true);
+            }
         });
     }
 
diff --git a/v4/api21/android/support/v4/content/res/ResourcesCompatApi21.java b/v4/api21/android/support/v4/content/res/ResourcesCompatApi21.java
new file mode 100644
index 0000000..645b633
--- /dev/null
+++ b/v4/api21/android/support/v4/content/res/ResourcesCompatApi21.java
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+
+package android.support.v4.content.res;
+
+import android.content.res.Resources;
+import android.content.res.Resources.Theme;
+import android.graphics.drawable.Drawable;
+
+class ResourcesCompatApi21 {
+    public static Drawable getDrawable(Resources res, int id, Theme theme) {
+        return res.getDrawable(id, theme);
+    }
+}
diff --git a/v4/java/android/support/v4/content/res/ResourcesCompat.java b/v4/java/android/support/v4/content/res/ResourcesCompat.java
new file mode 100644
index 0000000..2dbd334
--- /dev/null
+++ b/v4/java/android/support/v4/content/res/ResourcesCompat.java
@@ -0,0 +1,56 @@
+/*
+ * 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.
+ */
+
+package android.support.v4.content.res;
+
+import android.content.res.Resources;
+import android.content.res.Resources.NotFoundException;
+import android.content.res.Resources.Theme;
+import android.graphics.drawable.Drawable;
+import android.os.Build;
+
+/**
+ * Helper for accessing features in {@link android.content.res.Resources}
+ * introduced after API level 4 in a backwards compatible fashion.
+ */
+public class ResourcesCompat {
+    /**
+     * Return a drawable object associated with a particular resource ID and
+     * styled for the specified theme. Various types of objects will be
+     * returned depending on the underlying resource -- for example, a solid
+     * color, PNG image, scalable image, etc.
+     * <p>
+     * Prior to API level 21, the theme will not be applied and this method
+     * simply calls through to {@link Resources#getDrawable(int)}.
+     *
+     * @param id The desired resource identifier, as generated by the aapt
+     *           tool. This integer encodes the package, type, and resource
+     *           entry. The value 0 is an invalid identifier.
+     * @param theme The theme used to style the drawable attributes, may be {@code null}.
+     * @return Drawable An object that can be used to draw this resource.
+     * @throws NotFoundException Throws NotFoundException if the given ID does
+     *         not exist.
+     */
+    public Drawable getDrawable(Resources res, int id, Theme theme)
+            throws NotFoundException {
+        final int version = Build.VERSION.SDK_INT;
+        if (version >= 21) {
+            return ResourcesCompatApi21.getDrawable(res, id, theme);
+        } else {
+            return res.getDrawable(id);
+        }
+    }
+}
diff --git a/v7/appcompat/res/values-v11/themes_base.xml b/v7/appcompat/res/values-v11/themes_base.xml
index ddd9d59..0539a1a 100644
--- a/v7/appcompat/res/values-v11/themes_base.xml
+++ b/v7/appcompat/res/values-v11/themes_base.xml
@@ -16,6 +16,20 @@
 
 <resources>
 
+    <!--
+        Theme in the "Theme.Platform.AppCompat" family are designed to be aliases for the default
+        theme on a given platform version. They should not set any styleable attributes. Instead
+        you should create a "Theme.Base" theme which inherits from a "Theme.Platform" theme.
+    -->
+    <eat-comment/>
+    <style name="Theme.Platform.AppCompat" parent="android:Theme.Holo" />
+
+    <style name="Theme.Platform.AppCompat.Light" parent="android:Theme.Holo.Light" />
+
+    <style name="Theme.Platform.AppCompat.Dialog" parent="android:Theme.Holo.Dialog" />
+
+    <style name="Theme.Platform.AppCompat.Light.Dialog" parent="android:Theme.Holo.Light.Dialog" />
+
     <!-- Themes in the "Theme.Base" family vary based on the current platform
           version to provide the correct basis on each device. You probably don't
           want to use them directly in your apps.
@@ -28,7 +42,7 @@
     <eat-comment/>
 
     <!-- Base platform-dependent theme  -->
-    <style name="Theme.Base" parent="android:Theme.Holo">
+    <style name="Theme.Base" parent="Theme.Platform.AppCompat">
         <item name="android:windowNoTitle">true</item>
         <item name="android:windowActionBar">false</item>
 
@@ -46,7 +60,7 @@
     </style>
 
     <!-- Base platform-dependent theme providing a light-themed activity. -->
-    <style name="Theme.Base.Light" parent="android:Theme.Holo.Light">
+    <style name="Theme.Base.Light" parent="Theme.Platform.AppCompat.Light">
         <item name="android:windowNoTitle">true</item>
         <item name="android:windowActionBar">false</item>
 
@@ -63,7 +77,7 @@
         <item name="selectableItemBackground">?android:attr/selectableItemBackground</item>
     </style>
 
-    <style name="Theme.Base.AppCompat.Dialog.FixedSize" parent="android:Theme.Holo.Dialog">
+    <style name="Theme.Base.AppCompat.Dialog.FixedSize" parent="Theme.Platform.AppCompat.Dialog">
         <item name="windowFixedWidthMajor">@dimen/dialog_fixed_width_major</item>
         <item name="windowFixedWidthMinor">@dimen/dialog_fixed_width_minor</item>
         <item name="windowFixedHeightMajor">@dimen/dialog_fixed_height_major</item>
@@ -77,7 +91,7 @@
     </style>
 
     <style name="Theme.Base.AppCompat.Dialog.Light.FixedSize"
-           parent="android:Theme.Holo.Light.Dialog">
+           parent="Theme.Platform.AppCompat.Light.Dialog">
         <item name="windowFixedWidthMajor">@dimen/dialog_fixed_width_major</item>
         <item name="windowFixedWidthMinor">@dimen/dialog_fixed_width_minor</item>
         <item name="windowFixedHeightMajor">@dimen/dialog_fixed_height_major</item>
diff --git a/v7/appcompat/res/values-v14/themes_base.xml b/v7/appcompat/res/values-v14/themes_base.xml
index 3b30074..e182b2e 100644
--- a/v7/appcompat/res/values-v14/themes_base.xml
+++ b/v7/appcompat/res/values-v14/themes_base.xml
@@ -16,6 +16,23 @@
 
 <resources>
 
+    <!--
+        Theme in the "Theme.Platform.AppCompat" family are designed to be aliases for the default
+        theme on a given platform version. They should not set any styleable attributes. Instead
+        you should create a "Theme.Base" theme which inherits from a "Theme.Platform" theme.
+    -->
+    <eat-comment/>
+
+    <style name="Theme.Platform.AppCompat.Light.DarkActionBar"
+           parent="android:Theme.Holo.Light.DarkActionBar" />
+
+    <style name="Theme.Platform.AppCompat.DialogWhenLarge"
+           parent="android:Theme.Holo.DialogWhenLarge" />
+
+    <style name="Theme.Platform.AppCompat.Light.DialogWhenLarge"
+           parent="android:Theme.Holo.Light.DialogWhenLarge" />
+
+
     <!-- Themes in the "Theme.Base" family vary based on the current platform
           version to provide the correct basis on each device. You probably don't
           want to use them directly in your apps.
@@ -28,7 +45,7 @@
     <eat-comment/>
 
     <!-- Base platform-dependent theme providing an action bar in a dark-themed activity. -->
-    <style name="Theme.Base.AppCompat" parent="android:Theme.Holo">
+    <style name="Theme.Base.AppCompat" parent="Theme.Platform.AppCompat">
         <!-- Copy system flag values for our use -->
         <item name="windowActionBar">?android:attr/windowActionBar</item>
         <item name="actionBarSize">?android:attr/actionBarSize</item>
@@ -58,7 +75,7 @@
     </style>
 
     <!-- Base platform-dependent theme providing an action bar in a light-themed activity. -->
-    <style name="Theme.Base.AppCompat.Light" parent="android:Theme.Holo.Light">
+    <style name="Theme.Base.AppCompat.Light" parent="Theme.Platform.AppCompat.Light">
         <!-- Copy system flag values for our use -->
         <item name="windowActionBar">?android:attr/windowActionBar</item>
         <item name="actionBarSize">?android:attr/actionBarSize</item>
@@ -89,7 +106,7 @@
 
     <!-- Base platform-dependent theme providing a dark action bar in a light-themed activity. -->
     <style name="Theme.Base.AppCompat.Light.DarkActionBar"
-           parent="android:Theme.Holo.Light.DarkActionBar">
+           parent="Theme.Platform.AppCompat.Light.DarkActionBar">
         <!-- Copy system flag values for our use -->
         <item name="windowActionBar">?android:attr/windowActionBar</item>
         <item name="actionBarSize">?android:attr/actionBarSize</item>
@@ -132,7 +149,7 @@
     -->
 
     <style name="Theme.Base.AppCompat.DialogWhenLarge.Base"
-           parent="android:Theme.Holo.DialogWhenLarge">
+           parent="Theme.Platform.AppCompat.DialogWhenLarge">
         <!-- Copy system flag values for our use -->
         <item name="windowActionBar">?android:attr/windowActionBar</item>
         <item name="actionBarSize">?android:attr/actionBarSize</item>
@@ -158,7 +175,7 @@
     </style>
 
     <style name="Theme.Base.AppCompat.Light.DialogWhenLarge.Base"
-           parent="android:Theme.Holo.Light.DialogWhenLarge">
+           parent="Theme.Platform.AppCompat.Light.DialogWhenLarge">
         <!-- Copy system flag values for our use -->
         <item name="windowActionBar">?android:attr/windowActionBar</item>
         <item name="actionBarSize">?android:attr/actionBarSize</item>
diff --git a/v7/appcompat/res/values-v21/styles_base.xml b/v7/appcompat/res/values-v21/styles_base.xml
new file mode 100644
index 0000000..d3bef1b
--- /dev/null
+++ b/v7/appcompat/res/values-v21/styles_base.xml
@@ -0,0 +1,241 @@
+<?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.
+-->
+
+<resources>
+
+    <!-- Like in themes_base.xml, the namespace "*.AppCompat.Base" is used to
+     define base styles for the platform version. The "*.AppCompat"
+     variants are for direct use or use as parent styles by the app. -->
+    <eat-comment/>
+
+    <style name="Widget.AppCompat.Base.ActionBar"
+           parent="android:Widget.Quantum.ActionBar">
+    </style>
+
+    <style name="Widget.AppCompat.Light.Base.ActionBar"
+           parent="android:Widget.Quantum.Light.ActionBar">
+    </style>
+
+    <style name="Widget.AppCompat.Base.ActionBar.Solid"
+           parent="android:Widget.Quantum.ActionBar.Solid">
+    </style>
+
+    <style name="Widget.AppCompat.Light.Base.ActionBar.Solid"
+           parent="android:Widget.Quantum.Light.ActionBar.Solid">
+    </style>
+
+    <style name="Widget.AppCompat.Light.Base.ActionBar.Solid.Inverse"
+           parent="android:Widget.Quantum.Light.ActionBar.Solid">
+    </style>
+
+    <style name="Widget.AppCompat.Base.ActionBar.TabBar"
+           parent="android:Widget.Quantum.ActionBar.TabBar">
+    </style>
+
+    <style name="Widget.AppCompat.Light.Base.ActionBar.TabBar"
+           parent="android:Widget.Quantum.Light.ActionBar.TabBar">
+    </style>
+
+    <style name="Widget.AppCompat.Light.Base.ActionBar.TabBar.Inverse"
+           parent="android:Widget.Quantum.Light.ActionBar.TabBar">
+    </style>
+
+    <style name="Widget.AppCompat.Base.ActionBar.TabView"
+           parent="android:Widget.Quantum.ActionBar.TabView">
+    </style>
+
+    <style name="Widget.AppCompat.Light.Base.ActionBar.TabView"
+           parent="android:Widget.Quantum.Light.ActionBar.TabView">
+    </style>
+
+    <style name="Widget.AppCompat.Light.Base.ActionBar.TabView.Inverse"
+           parent="android:Widget.Quantum.Light.ActionBar.TabView">
+    </style>
+
+    <style name="Widget.AppCompat.Base.ActionBar.TabText"
+           parent="android:Widget.Quantum.ActionBar.TabText">
+    </style>
+
+    <style name="Widget.AppCompat.Light.Base.ActionBar.TabText"
+           parent="android:Widget.Quantum.Light.ActionBar.TabText">
+    </style>
+
+    <style name="Widget.AppCompat.Light.Base.ActionBar.TabText.Inverse"
+           parent="android:Widget.Quantum.Light.ActionBar.TabText">
+    </style>
+
+    <style name="Widget.AppCompat.Light.Base.ActionMode.Inverse"
+           parent="android:Widget.Quantum.Light.ActionMode">
+    </style>
+
+    <style name="TextAppearance.AppCompat.Widget.Base.ActionBar.Menu"
+           parent="android:TextAppearance.Quantum.Widget.ActionBar.Menu">
+    </style>
+
+    <style name="TextAppearance.AppCompat.Widget.Base.ActionBar.Title"
+           parent="android:TextAppearance.Quantum.Widget.ActionBar.Title">
+    </style>
+
+    <style name="TextAppearance.AppCompat.Widget.Base.ActionBar.Subtitle"
+           parent="android:TextAppearance.Quantum.Widget.ActionBar.Subtitle">
+    </style>
+
+
+    <!--
+    TODO Hidden
+    <style name="TextAppearance.AppCompat.Widget.Base.ActionBar.Title.Inverse"
+           parent="android:TextAppearance.Quantum.Widget.ActionBar.Title.Inverse">
+    </style>
+
+    <style name="TextAppearance.AppCompat.Widget.Base.ActionBar.Subtitle.Inverse"
+           parent="android:TextAppearance.Quantum.Widget.ActionBar.Subtitle.Inverse">
+    </style>
+    -->
+
+    <style name="TextAppearance.AppCompat.Widget.Base.ActionMode.Title"
+           parent="android:TextAppearance.Quantum.Widget.ActionMode.Title">
+    </style>
+
+    <style name="TextAppearance.AppCompat.Widget.Base.ActionMode.Subtitle"
+           parent="android:TextAppearance.Quantum.Widget.ActionMode.Subtitle">
+    </style>
+
+    <!--
+    TODO Hidden
+    <style name="TextAppearance.AppCompat.Widget.Base.ActionMode.Title.Inverse"
+           parent="android:TextAppearance.Quantum.Widget.ActionMode.Title.Inverse">
+    </style>
+
+    <style name="TextAppearance.AppCompat.Widget.Base.ActionMode.Subtitle.Inverse"
+           parent="android:TextAppearance.Quantum.Widget.ActionMode.Subtitle.Inverse">
+    </style>
+    -->
+
+    <!-- Action Button Styles -->
+
+    <style name="Widget.AppCompat.Base.ActionButton"
+           parent="android:Widget.Quantum.ActionButton">
+    </style>
+
+    <style name="Widget.AppCompat.Light.Base.ActionButton"
+           parent="android:Widget.Quantum.Light.ActionButton">
+    </style>
+
+    <style name="Widget.AppCompat.Base.ActionButton.CloseMode"
+           parent="android:Widget.Quantum.ActionButton.CloseMode">
+    </style>
+
+    <style name="Widget.AppCompat.Light.Base.ActionButton.CloseMode"
+           parent="android:Widget.Quantum.Light.ActionButton.CloseMode">
+    </style>
+
+    <style name="Widget.AppCompat.Base.ActionButton.Overflow"
+           parent="android:Widget.Quantum.ActionButton.Overflow">
+    </style>
+
+    <style name="Widget.AppCompat.Light.Base.ActionButton.Overflow"
+           parent="android:Widget.Quantum.Light.ActionButton.Overflow">
+    </style>
+
+    <!-- Spinner Widgets -->
+
+    <style name="Widget.AppCompat.Base.ListView.DropDown"
+           parent="android:Widget.Quantum.ListView.DropDown"/>
+
+    <style name="Widget.AppCompat.Light.Base.ListView.DropDown"
+           parent="android:Widget.Quantum.ListView.DropDown"/>
+
+    <style name="Widget.AppCompat.Base.DropDownItem.Spinner"
+           parent="android:Widget.Quantum.DropDownItem.Spinner"/>
+
+    <style name="Widget.AppCompat.Light.Base.DropDownItem.Spinner"
+           parent="android:Widget.Quantum.Light.DropDownItem.Spinner"/>
+
+    <style name="Widget.AppCompat.Base.Spinner"
+           parent="android:Widget.Quantum.Spinner" />
+
+    <style name="Widget.AppCompat.Light.Base.Spinner"
+           parent="android:Widget.Quantum.Light.Spinner"/>
+
+    <style name="Widget.AppCompat.Base.ListView.Menu"
+           parent="android:Widget.ListView.Menu" />
+
+    <!-- Popup Menu -->
+
+    <style name="Widget.AppCompat.Base.ListPopupWindow"
+           parent="android:Widget.Quantum.ListPopupWindow">
+    </style>
+
+    <style name="Widget.AppCompat.Light.Base.ListPopupWindow"
+           parent="android:Widget.Quantum.Light.ListPopupWindow">
+    </style>
+
+    <style name="Widget.AppCompat.Base.PopupMenu" parent="android:Widget.Quantum.PopupMenu">
+    </style>
+
+    <style name="Widget.AppCompat.Light.Base.PopupMenu"
+        parent="android:Widget.Quantum.Light.PopupMenu">
+    </style>
+
+    <style name="TextAppearance.AppCompat.Base.Widget.PopupMenu.Large"
+        parent="android:TextAppearance.Quantum.Widget.PopupMenu.Large">
+    </style>
+
+    <style name="TextAppearance.AppCompat.Base.Widget.PopupMenu.Small"
+        parent="android:TextAppearance.Quantum.Widget.PopupMenu.Small">
+    </style>
+
+    <style name="TextAppearance.AppCompat.Light.Base.Widget.PopupMenu.Large"
+        parent="android:TextAppearance.Quantum.Widget.PopupMenu.Large">
+    </style>
+
+    <style name="TextAppearance.AppCompat.Light.Base.Widget.PopupMenu.Small"
+        parent="android:TextAppearance.Quantum.Widget.PopupMenu.Small">
+    </style>
+
+    <!-- Search View result styles -->
+
+    <style name="TextAppearance.AppCompat.Base.SearchResult.Title"
+           parent="@android:TextAppearance.Quantum.SearchResult.Title">
+    </style>
+
+    <style name="TextAppearance.AppCompat.Base.SearchResult.Subtitle"
+           parent="@android:TextAppearance.Quantum.SearchResult.Subtitle">
+    </style>
+
+    <!--
+        TextAppearance.Quantum.Light.SearchResult.* are private so we extend from the default
+        versions instead (which are exactly the same).
+    -->
+    <style name="TextAppearance.AppCompat.Light.Base.SearchResult.Title"
+           parent="TextAppearance.AppCompat.Base.SearchResult.Title">
+    </style>
+
+    <style name="TextAppearance.AppCompat.Light.Base.SearchResult.Subtitle"
+           parent="TextAppearance.AppCompat.Base.SearchResult.Subtitle">
+    </style>
+
+    <!-- TODO. Needs updating for QP -->
+    <style name="Widget.AppCompat.Base.ActivityChooserView" parent="">
+        <item name="android:gravity">center</item>
+        <item name="android:background">@drawable/abc_ab_share_pack_holo_dark</item>
+        <item name="android:divider">?attr/dividerVertical</item>
+        <item name="android:showDividers">middle</item>
+        <item name="android:dividerPadding">6dip</item>
+    </style>
+
+</resources>
diff --git a/v7/appcompat/res/values-v21/themes_base.xml b/v7/appcompat/res/values-v21/themes_base.xml
new file mode 100644
index 0000000..43a174b
--- /dev/null
+++ b/v7/appcompat/res/values-v21/themes_base.xml
@@ -0,0 +1,45 @@
+<?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.
+-->
+
+<resources>
+
+    <!--
+        Theme in the "Theme.Platform.AppCompat" family are designed to be aliases for the default
+        theme on a given platform version. They should not set any styleable attributes. Instead
+        you should create a "Theme.Base" theme which inherits from a "Theme.Platform" theme.
+    -->
+    <eat-comment/>
+    <style name="Theme.Platform.AppCompat" parent="android:Theme.Quantum" />
+
+    <style name="Theme.Platform.AppCompat.Light" parent="android:Theme.Quantum.Light" />
+
+    <style name="Theme.Platform.AppCompat.Light.DarkActionBar"
+           parent="android:Theme.Quantum.Light.DarkActionBar" />
+
+    <style name="Theme.Platform.AppCompat.DialogWhenLarge"
+           parent="android:Theme.Quantum.DialogWhenLarge" />
+
+    <style name="Theme.Platform.AppCompat.Light.DialogWhenLarge"
+           parent="android:Theme.Quantum.Light.DialogWhenLarge" />
+
+    <style name="Theme.Platform.AppCompat.Dialog"
+           parent="android:Theme.Quantum.Dialog" />
+
+    <style name="Theme.Platform.AppCompat.Light.Dialog"
+           parent="android:Theme.Quantum.Light.Dialog" />
+
+</resources>
diff --git a/v7/appcompat/res/values/themes_base.xml b/v7/appcompat/res/values/themes_base.xml
index c48b57c..f707c3a 100644
--- a/v7/appcompat/res/values/themes_base.xml
+++ b/v7/appcompat/res/values/themes_base.xml
@@ -16,6 +16,23 @@
 
 <resources>
 
+    <!--
+        Theme in the "Theme.Platform.AppCompat" family are designed to be aliases for the default
+        theme on a given platform version. They should not set any styleable attributes. Instead
+        you should create a "Theme.Base" theme which inherits from a "Theme.Platform" theme.
+    -->
+    <eat-comment/>
+    <style name="Theme.Platform.AppCompat" parent="android:Theme" />
+
+    <style name="Theme.Platform.AppCompat.Light" parent="android:Theme.Light" />
+
+    <style name="Theme.Platform.AppCompat.Dialog"
+           parent="android:Theme.Dialog" />
+
+    <style name="Theme.Platform.AppCompat.Light.Dialog"
+           parent="Theme.Platform.AppCompat.Dialog" />
+
+
     <!-- Themes in the "Theme.Base" family vary based on the current platform
          version to provide the correct basis on each device. You probably don't
          want to use them directly in your apps.
@@ -24,10 +41,10 @@
          directly by apps. -->
     <eat-comment/>
 
-    <style name="Theme.Base" parent="android:Theme">
+    <style name="Theme.Base" parent="Theme.Platform.AppCompat">
     </style>
 
-    <style name="Theme.Base.Light" parent="android:Theme.Light">
+    <style name="Theme.Base.Light" parent="Theme.Platform.AppCompat.Light">
     </style>
 
     <!-- Base platform-dependent theme providing an action bar in a dark-themed activity. -->
@@ -206,7 +223,7 @@
            parent="Theme.Base.AppCompat.Light">
     </style>
 
-    <style name="Theme.Base.AppCompat.Dialog.FixedSize" parent="android:Theme.Dialog">
+    <style name="Theme.Base.AppCompat.Dialog.FixedSize" parent="Theme.Platform.AppCompat.Dialog">
         <item name="windowFixedWidthMajor">@dimen/dialog_fixed_width_major</item>
         <item name="windowFixedWidthMinor">@dimen/dialog_fixed_width_minor</item>
         <item name="windowFixedHeightMajor">@dimen/dialog_fixed_height_major</item>
diff --git a/v7/mediarouter/build.gradle b/v7/mediarouter/build.gradle
index 3af0dd4..d4dae83 100644
--- a/v7/mediarouter/build.gradle
+++ b/v7/mediarouter/build.gradle
@@ -40,7 +40,7 @@
 }
 
 android {
-    compileSdkVersion 19
+    compileSdkVersion 'current'
     buildToolsVersion '19.0.3'
 
     sourceSets {
diff --git a/v7/recyclerview/src/android/support/v7/widget/RecyclerView.java b/v7/recyclerview/src/android/support/v7/widget/RecyclerView.java
index c965ba1..95a1d0e 100644
--- a/v7/recyclerview/src/android/support/v7/widget/RecyclerView.java
+++ b/v7/recyclerview/src/android/support/v7/widget/RecyclerView.java
@@ -252,6 +252,18 @@
         if (mAdapter != null) {
             mAdapter.unregisterAdapterDataObserver(mObserver);
         }
+        // end all running animations
+        if (mItemAnimator != null) {
+            mItemAnimator.endAnimations();
+        }
+        // Since animations are ended, mLayout.children should be equal to recyclerView.children.
+        // This may not be true if item animator's end does not work as expected. (e.g. not release
+        // children instantly). It is safer to use mLayout's child count.
+        if (mLayout != null) {
+            mLayout.removeAndRecycleAllViews(mRecycler);
+            mLayout.removeAndRecycleScrapInt(mRecycler, true);
+        }
+
         final Adapter oldAdapter = mAdapter;
         mAdapter = adapter;
         if (adapter != null) {
@@ -3538,13 +3550,15 @@
             final Adapter adapter = mRecyclerView.getAdapter();
             // Only remove non-animating views
             final int childCount = mRecyclerView.getChildCount() - mRecyclerView.mNumAnimatingViews;
-            if (adapter != null) {
-                for (int i = 0; i < childCount; i++) {
-                    final View child = mRecyclerView.getChildAt(i);
+
+            for (int i = 0; i < childCount; i++) {
+                final View child = mRecyclerView.getChildAt(i);
+                if (adapter != null) {
                     adapter.onViewDetachedFromWindow(getChildViewHolderInt(child));
-                    mRecyclerView.onChildDetachedFromWindow(child);
                 }
+                mRecyclerView.onChildDetachedFromWindow(child);
             }
+
             for (int i = childCount - 1; i >= 0; i--) {
                 mRecyclerView.removeViewAt(i);
                 if (mRecyclerView.mAnimatingViewIndex >= 0) {
@@ -4506,6 +4520,12 @@
                 mSmoothScroller = null;
             }
         }
+
+        void removeAndRecycleAllViews(Recycler recycler) {
+            for (int i = getChildCount() - 1; i >= 0; i--) {
+                removeAndRecycleViewAt(i, recycler);
+            }
+        }
     }
 
     /**