MediaRouter: New color scheme for main and group media controls

Instead of showing dark controls in a possibly dark (i.e. the primary
dark), modeled the white dialog and used the the primary color for the
group controls. Also, reverted opacity values back to 87% for better
contrast in a light background. In addition,
- Fixed a bug that the volume slider for a disabled media route is still
  movable.
- Fixed a bug that the volume sliders are always tinted with the primary
  color.
- Fixed a bug that the ripple drawables for the play/pause and group
  collapse/expand buttons are cut off by an invisible divider.
- Corrected the inconsistent disabled alpha values.
- Ensured the volume slider color is opaque so that the underlying
  progress bar is not seen through the thumb.

Bug: 24336474, Bug: 24779916, Bug: 24779734, Bug: 24779945
Change-Id: Ic163d73dd38558994ff5e0bf8b4c3d4b66800c23
diff --git a/v7/mediarouter/res/drawable/mr_ic_audiotrack_light.xml b/v7/mediarouter/res/drawable/mr_ic_audiotrack_light.xml
index 96093d1..05b4a8a 100644
--- a/v7/mediarouter/res/drawable/mr_ic_audiotrack_light.xml
+++ b/v7/mediarouter/res/drawable/mr_ic_audiotrack_light.xml
@@ -16,4 +16,4 @@
 
 <bitmap xmlns:android="http://schemas.android.com/apk/res/android"
     android:src="@drawable/ic_audiotrack_light"
-    android:alpha="0.54" />
+    android:alpha="0.87" />
diff --git a/v7/mediarouter/res/drawable/mr_ic_close_light.xml b/v7/mediarouter/res/drawable/mr_ic_close_light.xml
index af0445e..c663ae8 100644
--- a/v7/mediarouter/res/drawable/mr_ic_close_light.xml
+++ b/v7/mediarouter/res/drawable/mr_ic_close_light.xml
@@ -18,7 +18,7 @@
     <item>
         <bitmap
             android:src="@drawable/ic_close_light"
-            android:alpha="0.54" />
+            android:alpha="0.87" />
     </item>
 
 </selector>
diff --git a/v7/mediarouter/res/drawable/mr_ic_pause_light.xml b/v7/mediarouter/res/drawable/mr_ic_pause_light.xml
index 88eda3e..0cea425 100644
--- a/v7/mediarouter/res/drawable/mr_ic_pause_light.xml
+++ b/v7/mediarouter/res/drawable/mr_ic_pause_light.xml
@@ -18,6 +18,6 @@
     <item>
         <bitmap
             android:src="@drawable/ic_pause_light"
-            android:alpha="0.54" />
+            android:alpha="0.87" />
     </item>
 </selector>
diff --git a/v7/mediarouter/res/drawable/mr_ic_play_light.xml b/v7/mediarouter/res/drawable/mr_ic_play_light.xml
index 487a5d5..48a7e03 100644
--- a/v7/mediarouter/res/drawable/mr_ic_play_light.xml
+++ b/v7/mediarouter/res/drawable/mr_ic_play_light.xml
@@ -18,6 +18,6 @@
     <item>
         <bitmap
             android:src="@drawable/ic_play_light"
-            android:alpha="0.54" />
+            android:alpha="0.87" />
     </item>
 </selector>
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 232eeae..b44c1dc 100644
--- a/v7/mediarouter/res/layout/mr_controller_material_dialog_b.xml
+++ b/v7/mediarouter/res/layout/mr_controller_material_dialog_b.xml
@@ -72,14 +72,12 @@
                               android:orientation="vertical"
                               android:paddingTop="16dp"
                               android:paddingBottom="16dp"
-                              android:background="?attr/colorPrimary"
                               android:layout_gravity="bottom">
                     <include android:id="@+id/mr_playback_control"
                              layout="@layout/mr_playback_control" />
                     <View android:id="@+id/mr_control_divider"
                           android:layout_width="fill_parent"
                           android:layout_height="8dp"
-                          android:background="?attr/colorPrimary"
                           android:visibility="gone" />
                     <include android:id="@+id/mr_volume_control"
                              layout="@layout/mr_volume_control" />
diff --git a/v7/mediarouter/src/android/support/v7/app/MediaRouteControllerDialog.java b/v7/mediarouter/src/android/support/v7/app/MediaRouteControllerDialog.java
index fe33882..526230a 100644
--- a/v7/mediarouter/src/android/support/v7/app/MediaRouteControllerDialog.java
+++ b/v7/mediarouter/src/android/support/v7/app/MediaRouteControllerDialog.java
@@ -83,7 +83,7 @@
     // route descriptor.
     private static final int VOLUME_UPDATE_DELAY_MILLIS = 250;
     private static final int VOLUME_SLIDER_TAG_MASTER = 0;
-    private static final int VOLUME_SLIDER_TAG_BASE = 100;
+    private static final int VOLUME_SLIDER_TAG_GROUP_BASE = 100;
 
     private static final int BUTTON_NEUTRAL_RES_ID = android.R.id.button3;
     private static final int BUTTON_DISCONNECT_RES_ID = android.R.id.button2;
@@ -325,8 +325,11 @@
         mVolumeSlider.setOnSeekBarChangeListener(mVolumeChangeListener);
 
         mVolumeGroupList = (ListView) findViewById(R.id.mr_volume_group_list);
-        mVolumeGroupList.setBackgroundColor(
-                MediaRouterThemeHelper.getVolumeGroupListBackgroundColor(mContext));
+        MediaRouterThemeHelper.setMediaControlsBackgroundColor(mContext,
+                mMediaMainControlLayout, mVolumeGroupList, getGroup() != null);
+        MediaRouterThemeHelper.setVolumeSliderColor(mContext,
+                (MediaRouteVolumeSlider) mVolumeSlider, mMediaMainControlLayout);
+
         mGroupExpandCollapseButton =
                 (MediaRouteExpandCollapseButton) findViewById(R.id.mr_group_expand_collapse);
         mGroupExpandCollapseButton.setOnClickListener(new View.OnClickListener() {
@@ -875,19 +878,22 @@
                 int tag = (int) seekBar.getTag();
                 if (tag == VOLUME_SLIDER_TAG_MASTER) {
                     mRoute.requestSetVolume(progress);
-                } else if (tag - VOLUME_SLIDER_TAG_BASE >= 0
-                        && tag - VOLUME_SLIDER_TAG_BASE < getGroup().getRouteCount()) {
-                    getGroup().getRouteAt(tag - VOLUME_SLIDER_TAG_BASE).requestSetVolume(progress);
+                } else {
+                    int index = tag - VOLUME_SLIDER_TAG_GROUP_BASE;
+                    if (index >= 0 && index < getGroup().getRouteCount()) {
+                        getGroup().getRouteAt(index).requestSetVolume(progress);
+                    }
                 }
             }
         }
     }
 
     private class VolumeGroupAdapter extends ArrayAdapter<MediaRouter.RouteInfo> {
-        final static float DISABLED_ALPHA = .3f;
+        final float mDisabledAlpha;
 
         public VolumeGroupAdapter(Context context, List<MediaRouter.RouteInfo> objects) {
             super(context, 0, objects);
+            mDisabledAlpha = MediaRouterThemeHelper.getDisabledAlpha(context);
         }
 
         @Override
@@ -910,14 +916,16 @@
 
                 MediaRouteVolumeSlider volumeSlider =
                         (MediaRouteVolumeSlider) v.findViewById(R.id.mr_volume_slider);
-                volumeSlider.setTag(VOLUME_SLIDER_TAG_BASE + position);
+                MediaRouterThemeHelper.setVolumeSliderColor(
+                        mContext, volumeSlider, mVolumeGroupList);
+                volumeSlider.setTag(VOLUME_SLIDER_TAG_GROUP_BASE + position);
                 volumeSlider.setHideThumb(!isEnabled);
+                volumeSlider.setEnabled(isEnabled);
                 if (isEnabled) {
                     if (isVolumeControlAvailable(route)) {
                         volumeSlider.setMax(route.getVolumeMax());
                         volumeSlider.setProgress(route.getVolume());
                         volumeSlider.setOnSeekBarChangeListener(mVolumeChangeListener);
-                        volumeSlider.setEnabled(true);
                     } else {
                         volumeSlider.setMax(100);
                         volumeSlider.setProgress(100);
@@ -927,7 +935,7 @@
 
                 ImageView volumeItemIcon =
                         (ImageView) v.findViewById(R.id.mr_volume_item_icon);
-                volumeItemIcon.setAlpha(isEnabled ? 255 : (int) (255 * DISABLED_ALPHA));
+                volumeItemIcon.setAlpha(isEnabled ? 0xFF : (int) (0xFF * mDisabledAlpha));
             }
             return v;
         }
diff --git a/v7/mediarouter/src/android/support/v7/app/MediaRouteVolumeSlider.java b/v7/mediarouter/src/android/support/v7/app/MediaRouteVolumeSlider.java
index 88dbcc5..a7aafd2 100644
--- a/v7/mediarouter/src/android/support/v7/app/MediaRouteVolumeSlider.java
+++ b/v7/mediarouter/src/android/support/v7/app/MediaRouteVolumeSlider.java
@@ -17,24 +17,28 @@
 package android.support.v7.app;
 
 import android.content.Context;
-import android.content.res.TypedArray;
+import android.graphics.Color;
 import android.graphics.PorterDuff;
 import android.graphics.drawable.Drawable;
 import android.support.v7.mediarouter.R;
 import android.support.v7.widget.AppCompatSeekBar;
 import android.util.AttributeSet;
+import android.util.Log;
 
 /**
  * Volume slider with showing, hiding, and applying alpha supports to the thumb.
  */
 class MediaRouteVolumeSlider extends AppCompatSeekBar {
+    private static final String TAG = "MediaRouteVolumeSlider";
+
+    private final float mDisabledAlpha;
+
     private boolean mHideThumb;
     private Drawable mThumb;
     private int mColor;
-    private float mDisabledAlpha;
 
     public MediaRouteVolumeSlider(Context context) {
-        super(context, null);
+        this(context, null);
     }
 
     public MediaRouteVolumeSlider(Context context, AttributeSet attrs) {
@@ -43,23 +47,13 @@
 
     public MediaRouteVolumeSlider(Context context, AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr);
-        mColor = MediaRouterThemeHelper.getVolumeSliderColor(context);
-        TypedArray ta = context.obtainStyledAttributes(
-                attrs, new int[] {android.R.attr.disabledAlpha}, defStyleAttr, 0);
-        mDisabledAlpha = ta.getFloat(0, 0.5f);
-        ta.recycle();
-    }
-
-    @Override
-    public void setThumb(Drawable thumb) {
-        mThumb = thumb;
-        super.setThumb(mHideThumb ? null : mThumb);
+        mDisabledAlpha = MediaRouterThemeHelper.getDisabledAlpha(context);
     }
 
     @Override
     protected void drawableStateChanged() {
         super.drawableStateChanged();
-        int alpha = isEnabled() ? 0xFF : (int)(mDisabledAlpha * 0xFF);
+        int alpha = isEnabled() ? 0xFF : (int) (0xFF * mDisabledAlpha);
 
         // The thumb drawable is a collection of drawables and its current drawables are changed per
         // state. Apply the color filter and alpha on every state change.
@@ -70,8 +64,14 @@
         getProgressDrawable().setAlpha(alpha);
     }
 
+    @Override
+    public void setThumb(Drawable thumb) {
+        mThumb = thumb;
+        super.setThumb(mHideThumb ? null : mThumb);
+    }
+
     /**
-     * Sets whether to show/hide thumb.
+     * Sets whether to show or hide thumb.
      */
     public void setHideThumb(boolean hideThumb) {
         if (mHideThumb == hideThumb) {
@@ -80,4 +80,21 @@
         mHideThumb = hideThumb;
         super.setThumb(mHideThumb ? null : mThumb);
     }
+
+    /**
+     * Sets the volume slider color. The change takes effect next time drawable state is changed.
+     * <p>
+     * The color cannot be translucent, otherwise the underlying progress bar will be seen through
+     * the thumb.
+     * </p>
+     */
+    public void setColor(int color) {
+        if (mColor == color) {
+            return;
+        }
+        if (Color.alpha(color) != 0xFF) {
+            Log.e(TAG, "Volume slider color cannot be translucent: #" + Integer.toHexString(color));
+        }
+        mColor = color;
+    }
 }
diff --git a/v7/mediarouter/src/android/support/v7/app/MediaRouterThemeHelper.java b/v7/mediarouter/src/android/support/v7/app/MediaRouterThemeHelper.java
index fb37f4e..f5a258c 100644
--- a/v7/mediarouter/src/android/support/v7/app/MediaRouterThemeHelper.java
+++ b/v7/mediarouter/src/android/support/v7/app/MediaRouterThemeHelper.java
@@ -18,27 +18,24 @@
 
 import android.content.Context;
 import android.graphics.Color;
-import android.graphics.drawable.Drawable;
 import android.support.annotation.IntDef;
 import android.support.v4.graphics.ColorUtils;
 import android.support.v7.mediarouter.R;
 import android.util.TypedValue;
 import android.view.ContextThemeWrapper;
+import android.view.View;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 
 final class MediaRouterThemeHelper {
     private static final float MIN_CONTRAST = 3.0f;
-    private static final float MIN_CONTRAST_GROUP_VOLUMES = 4.5f;
-
-    private static final float COLOR_LIGHTNESS_MULTIPLIER = 1.15f;
 
     @IntDef({COLOR_DARK_ON_LIGHT_BACKGROUND, COLOR_WHITE_ON_DARK_BACKGROUND})
     @Retention(RetentionPolicy.SOURCE)
     private @interface ControllerColorType {}
 
-    private static final int COLOR_DARK_ON_LIGHT_BACKGROUND = 0x8A000000; /* Opacity of 54% */
+    private static final int COLOR_DARK_ON_LIGHT_BACKGROUND = 0xDE000000; /* Opacity of 87% */
     private static final int COLOR_WHITE_ON_DARK_BACKGROUND = Color.WHITE;
 
     private MediaRouterThemeHelper() {
@@ -67,9 +64,10 @@
         return context.getTheme().resolveAttribute(attr, value, true) ? value.resourceId : 0;
     }
 
-    public static Drawable getThemeDrawable(Context context, int attr) {
-        int res = getThemeResource(context, attr);
-        return res != 0 ? context.getResources().getDrawable(res) : null;
+    public static float getDisabledAlpha(Context context) {
+        TypedValue value = new TypedValue();
+        return context.getTheme().resolveAttribute(android.R.attr.disabledAlpha, value, true)
+                ? value.getFloat() : 0.5f;
     }
 
     public static @ControllerColorType int getControllerColor(Context context) {
@@ -81,45 +79,46 @@
         return COLOR_DARK_ON_LIGHT_BACKGROUND;
     }
 
-    public static int getVolumeSliderColor(Context context) {
-        int primaryColor = getThemeColor(context, R.attr.colorPrimary);
-        if (ColorUtils.calculateContrast(COLOR_WHITE_ON_DARK_BACKGROUND, primaryColor)
-                >= MIN_CONTRAST) {
-            return COLOR_WHITE_ON_DARK_BACKGROUND;
-        }
-        // Composite with the background in order not to show the underlying progress bar through
-        // the thumb.
-        // TODO: Use the actual background color instead and ensure the resulting color is opaque.
-        return ColorUtils.compositeColors(COLOR_DARK_ON_LIGHT_BACKGROUND, primaryColor);
-    }
-
     public static int getButtonTextColor(Context context) {
         int primaryColor = getThemeColor(context, R.attr.colorPrimary);
         int backgroundColor = getThemeColor(context, android.R.attr.colorBackground);
 
-        double contrast = ColorUtils.calculateContrast(primaryColor, backgroundColor);
-        if (contrast < MIN_CONTRAST) {
+        if (ColorUtils.calculateContrast(primaryColor, backgroundColor) < MIN_CONTRAST) {
             // Default to colorAccent if the contrast ratio is low.
             return getThemeColor(context, R.attr.colorAccent);
         }
         return primaryColor;
     }
 
-    public static int getVolumeGroupListBackgroundColor(Context context) {
+    public static void setMediaControlsBackgroundColor(
+            Context context, View mainControls, View groupControls, boolean hasGroup) {
+        int primaryColor = getThemeColor(context, R.attr.colorPrimary);
         int primaryDarkColor = getThemeColor(context, R.attr.colorPrimaryDark);
-        if (getControllerColor(context) == COLOR_DARK_ON_LIGHT_BACKGROUND) {
-            // We are showing dark volume sliders in a darker background. Check whether they have
-            // sufficient contrast.
-            double contrast = ColorUtils.calculateContrast(
-                    COLOR_DARK_ON_LIGHT_BACKGROUND, primaryDarkColor);
-            if (contrast < MIN_CONTRAST_GROUP_VOLUMES) {
-                // Generate a lighter color based on the 'colorPrimary' and use it instead for
-                // better contrast.
-                int primaryColor = getThemeColor(context, R.attr.colorPrimary);
-                return adjustColorLightness(primaryColor, COLOR_LIGHTNESS_MULTIPLIER);
-            }
+        if (hasGroup && ColorUtils.calculateContrast(COLOR_WHITE_ON_DARK_BACKGROUND, primaryColor)
+                < MIN_CONTRAST) {
+            // Instead of showing dark controls in a possibly dark (i.e. the primary dark), model
+            // the white dialog and use the primary color for the group controls.
+            primaryDarkColor = primaryColor;
+            primaryColor = Color.WHITE;
         }
-        return primaryDarkColor;
+        mainControls.setBackgroundColor(primaryColor);
+        groupControls.setBackgroundColor(primaryDarkColor);
+        // Also store the background colors to the view tags. They are used in
+        // setVolumeSliderColor() below.
+        mainControls.setTag(primaryColor);
+        groupControls.setTag(primaryDarkColor);
+    }
+
+    public static void setVolumeSliderColor(
+            Context context, MediaRouteVolumeSlider volumeSlider, View backgroundView) {
+        int controllerColor = getControllerColor(context);
+        if (Color.alpha(controllerColor) != 0xFF) {
+            // Composite with the background in order not to show the underlying progress bar
+            // through the thumb.
+            int backgroundColor = (int) backgroundView.getTag();
+            controllerColor = ColorUtils.compositeColors(controllerColor, backgroundColor);
+        }
+        volumeSlider.setColor(controllerColor);
     }
 
     private static boolean isLightTheme(Context context) {
@@ -128,14 +127,6 @@
                 && value.data != 0;
     }
 
-    private static int adjustColorLightness(int color, float lightness) {
-        float[] hsl = new float[3];
-        ColorUtils.colorToHSL(color, hsl);
-        // Clip the lightness to 100%
-        hsl[2] = Math.min(1f, hsl[2] * lightness);
-        return ColorUtils.HSLToColor(hsl);
-    }
-
     private static int getThemeColor(Context context, int attr) {
         TypedValue value = new TypedValue();
         context.getTheme().resolveAttribute(attr, value, true);