Merge "Handling missing RECORD_AUDIO permission." into lmp-preview-dev
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..747aebb 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>
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/widget/DetailsOverviewRowPresenter.java b/v17/leanback/src/android/support/v17/leanback/widget/DetailsOverviewRowPresenter.java
index 6b08b29..a8a50f9 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/DetailsOverviewRowPresenter.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/DetailsOverviewRowPresenter.java
@@ -222,7 +222,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 032098b..ef9c77d 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/GridLayoutManager.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/GridLayoutManager.java
@@ -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 :
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 8546755..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;
@@ -95,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.
@@ -278,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) {
@@ -291,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);
     }
 
     /*
@@ -335,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();
+    }
+}