Visual refresh for QS

Adds circles and things

Test: visual
Change-Id: I7d974fcfe6257357abfd1a7d0ee521f0e6cee588
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java
index 07ef5e0..5a6afca 100755
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java
@@ -292,12 +292,16 @@
         }
         int backgroundColor = getBackgroundColor(darkIntensity);
         int fillColor = getFillColor(darkIntensity);
+        setColors(fillColor, backgroundColor);
+        mOldDarkIntensity = darkIntensity;
+    }
+
+    public void setColors(int fillColor, int backgroundColor) {
         mIconTint = fillColor;
         mFramePaint.setColor(backgroundColor);
         mBoltPaint.setColor(fillColor);
         mChargeColor = fillColor;
         invalidateSelf();
-        mOldDarkIntensity = darkIntensity;
     }
 
     private int getBackgroundColor(float darkIntensity) {
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
index ef1c25d..030250a 100644
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
@@ -72,8 +72,6 @@
     @Override
     public void onAttachedToWindow() {
         super.onAttachedToWindow();
-        mBatteryController.addCallback(this);
-        mDrawable.startListening();
         TunerService.get(getContext()).addTunable(this, StatusBarIconController.ICON_BLACKLIST);
     }
 
@@ -100,9 +98,15 @@
     public void setBatteryController(BatteryController mBatteryController) {
         this.mBatteryController = mBatteryController;
         mDrawable.setBatteryController(mBatteryController);
+        mBatteryController.addCallback(this);
+        mDrawable.startListening();
     }
 
     public void setDarkIntensity(float f) {
         mDrawable.setDarkIntensity(f);
     }
+
+    public void setRawColors(int fgColor, int bgColor) {
+        mDrawable.setColors(fgColor, bgColor);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/PageIndicator.java b/packages/SystemUI/src/com/android/systemui/qs/PageIndicator.java
index 26da551..b22ea4c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/PageIndicator.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/PageIndicator.java
@@ -1,9 +1,12 @@
 package com.android.systemui.qs;
 
 import android.content.Context;
+import android.content.res.ColorStateList;
+import android.content.res.TypedArray;
 import android.graphics.drawable.AnimatedVectorDrawable;
 import android.util.AttributeSet;
 import android.util.Log;
+import android.util.TypedValue;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.ImageView;
@@ -49,9 +52,14 @@
         while (numPages < getChildCount()) {
             removeViewAt(getChildCount() - 1);
         }
+        TypedArray array = getContext().obtainStyledAttributes(
+                new int[]{android.R.attr.colorForeground});
+        int color = array.getColor(0, 0);
+        array.recycle();
         while (numPages > getChildCount()) {
             ImageView v = new ImageView(mContext);
             v.setImageResource(R.drawable.minor_a_b);
+            v.setImageTintList(ColorStateList.valueOf(color));
             addView(v, new LayoutParams(mPageIndicatorWidth, mPageIndicatorHeight));
         }
         // Refresh state.
@@ -196,7 +204,7 @@
         for (int i = 0; i < N; i++) {
             getChildAt(i).measure(widthChildSpec, heightChildSpec);
         }
-        int width = (mPageIndicatorWidth - mPageDotWidth) * N + mPageDotWidth;
+        int width = (mPageIndicatorWidth - mPageDotWidth) * (N - 1) + mPageDotWidth;
         setMeasuredDimension(width, mPageIndicatorHeight);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
index 1c242e9..a231e79 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
@@ -29,7 +29,6 @@
     private PageIndicator mPageIndicator;
 
     private int mNumPages;
-    private View mDecorGroup;
     private PageListener mPageListener;
 
     private int mPosition;
@@ -145,14 +144,14 @@
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
-        mPageIndicator = (PageIndicator) findViewById(R.id.page_indicator);
-        mDecorGroup = findViewById(R.id.page_decor);
-        ((LayoutParams) mDecorGroup.getLayoutParams()).isDecor = true;
-
-        mPages.add((TilePage) LayoutInflater.from(mContext)
+        mPages.add((TilePage) LayoutInflater.from(getContext())
                 .inflate(R.layout.qs_paged_page, this, false));
     }
 
+    public void setPageIndicator(PageIndicator indicator) {
+        mPageIndicator = indicator;
+    }
+
     @Override
     public int getOffsetTop(TileRecord tile) {
         final ViewGroup parent = (ViewGroup) tile.tileView.getParent();
@@ -196,7 +195,7 @@
                 if (++index == mPages.size()) {
                     if (DEBUG) Log.d(TAG, "Adding page for "
                             + tile.tile.getClass().getSimpleName());
-                    mPages.add((TilePage) LayoutInflater.from(mContext)
+                    mPages.add((TilePage) LayoutInflater.from(getContext())
                             .inflate(R.layout.qs_paged_page, this, false));
                 }
             }
@@ -211,7 +210,7 @@
             }
             if (DEBUG) Log.d(TAG, "Size: " + mNumPages);
             mPageIndicator.setNumPages(mNumPages);
-            mDecorGroup.setVisibility(mNumPages > 1 ? View.VISIBLE : View.GONE);
+            mPageIndicator.setVisibility(mNumPages > 1 ? View.VISIBLE : View.GONE);
             setAdapter(mAdapter);
             mAdapter.notifyDataSetChanged();
             setCurrentItem(0, false);
@@ -243,8 +242,7 @@
                 maxHeight = height;
             }
         }
-        setMeasuredDimension(getMeasuredWidth(), maxHeight
-                + (mDecorGroup.getVisibility() != View.GONE ? mDecorGroup.getMeasuredHeight() : 0));
+        setMeasuredDimension(getMeasuredWidth(), maxHeight);
     }
 
     private final Runnable mDistribute = new Runnable() {
@@ -265,7 +263,7 @@
         public TilePage(Context context, AttributeSet attrs) {
             super(context, attrs);
             updateResources();
-            setContentDescription(mContext.getString(R.string.accessibility_desc_quick_settings));
+            setContentDescription(getContext().getString(R.string.accessibility_desc_quick_settings));
         }
 
         @Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
index fdefcf9..409943d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
@@ -194,6 +194,7 @@
                 translationYBuilder.addFloat(label, "translationY", -yDiff, 0);
 
                 mTopFiveQs.add(tileIcon);
+                mTopFiveQs.add(tileView.getBgCicle());
                 mAllViews.add(tileIcon);
                 mAllViews.add(quickTileView);
             } else if (mFullRows && isIconInAnimatedRow(count)) {
@@ -223,9 +224,10 @@
             // Make brightness appear static position and alpha in through second half.
             View brightness = mQsPanel.getBrightnessView();
             if (brightness != null) {
-                firstPageBuilder.addFloat(brightness, "translationY", mQsPanel.getHeight(), 0);
+//                firstPageBuilder.addFloat(brightness, "translationY", mQsPanel.getHeight(), 0);
                 mBrightnessAnimator = new TouchAnimator.Builder()
                         .addFloat(brightness, "alpha", 0, 1)
+                        .addFloat(mQsPanel.getPageIndicator(), "alpha", 0, 1)
                         .setStartDelay(.5f)
                         .build();
                 mAllViews.add(brightness);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
index f4da5ec..91b4d0d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
@@ -18,18 +18,12 @@
 
 import android.content.Context;
 import android.graphics.Point;
-import android.graphics.Rect;
 import android.util.AttributeSet;
 import android.view.View;
-import android.view.ViewGroup;
 import android.widget.FrameLayout;
 
 import com.android.systemui.R;
-import com.android.systemui.plugins.qs.QS.HeightListener;
 import com.android.systemui.qs.customize.QSCustomizer;
-import com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer;
-import com.android.systemui.statusbar.phone.QSTileHost;
-import com.android.systemui.statusbar.phone.QuickStatusBarHeader;
 
 /**
  * Wrapper view with background which contains {@link QSPanel} and {@link BaseStatusBarHeader}
@@ -95,7 +89,7 @@
         updateBottom();
     }
 
-    void updateBottom() {
+    public void updateBottom() {
         int height = calculateContainerHeight();
         setBottom(getTop() + height);
         mQSDetail.setBottom(getTop() + height);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSIconView.java b/packages/SystemUI/src/com/android/systemui/qs/QSIconView.java
index 9c4a149..f28a0e7 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSIconView.java
@@ -16,14 +16,20 @@
 
 package com.android.systemui.qs;
 
+import static com.android.systemui.qs.QSTile.getColorForState;
+
+import android.animation.ValueAnimator;
 import android.content.Context;
+import android.content.res.ColorStateList;
 import android.content.res.Resources;
+import android.graphics.Color;
 import android.graphics.drawable.Animatable;
 import android.graphics.drawable.Drawable;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.ImageView;
 import android.widget.ImageView.ScaleType;
+
 import com.android.systemui.R;
 
 import java.util.Objects;
@@ -34,6 +40,8 @@
     protected final int mIconSizePx;
     protected final int mTilePaddingBelowIconPx;
     private boolean mAnimationEnabled = true;
+    private int mState = -1;
+    private int mTint;
 
     public QSIconView(Context context) {
         super(context);
@@ -65,7 +73,6 @@
     @Override
     protected void onLayout(boolean changed, int l, int t, int r, int b) {
         final int w = getMeasuredWidth();
-        final int h = getMeasuredHeight();
         int top = 0;
         final int iconLeft = (w - mIcon.getMeasuredWidth()) / 2;
         layout(mIcon, iconLeft, top);
@@ -100,8 +107,43 @@
         } else {
             iv.clearColorFilter();
         }
+        if (state.state != mState) {
+            int color = getColorForState(getContext(), state.state);
+            mState = state.state;
+            if (iv.isShown()) {
+                animateGrayScale(mTint, color, iv);
+                mTint = color;
+            } else {
+                setTint(iv, color);
+                mTint = color;
+            }
+        }
     }
 
+    public static void animateGrayScale(int fromColor, int toColor, ImageView iv) {
+        final float fromAlpha = Color.alpha(fromColor);
+        final float toAlpha = Color.alpha(toColor);
+        final float fromChannel = Color.red(fromColor);
+        final float toChannel = Color.red(toColor);
+
+        ValueAnimator anim = ValueAnimator.ofFloat(0, 1);
+        anim.setDuration(350);
+
+        anim.addUpdateListener(animation -> {
+            float fraction = animation.getAnimatedFraction();
+            int alpha = (int) (fromAlpha + (toAlpha - fromAlpha) * fraction);
+            int channel = (int) (fromChannel + (toChannel - fromChannel) * fraction);
+
+            setTint(iv, Color.argb(alpha, channel, channel, channel));
+        });
+        anim.start();
+    }
+
+    public static void setTint(ImageView iv, int color) {
+        iv.setImageTintList(ColorStateList.valueOf(color));
+    }
+
+
     protected int getIconMeasureMode() {
         return MeasureSpec.EXACTLY;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 9feaa0a..2de32cc 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -54,6 +54,7 @@
     protected final ArrayList<TileRecord> mRecords = new ArrayList<TileRecord>();
     protected final View mBrightnessView;
     private final H mHandler = new H();
+    private final View mPageIndicator;
 
     private int mPanelPaddingBottom;
     private int mBrightnessPaddingTop;
@@ -84,21 +85,31 @@
 
         setOrientation(VERTICAL);
 
-        mBrightnessView = LayoutInflater.from(context).inflate(
-                R.layout.quick_settings_brightness_dialog, this, false);
-        addView(mBrightnessView);
-
         setupTileLayout();
 
         mFooter = new QSFooter(this, context);
         addView(mFooter.getView());
 
+        mPageIndicator = LayoutInflater.from(context).inflate(
+                R.layout.qs_page_indicator, this, false);
+        addView(mPageIndicator);
+        if (mTileLayout instanceof PagedTileLayout) {
+            ((PagedTileLayout) mTileLayout).setPageIndicator((PageIndicator) mPageIndicator);
+        }
+
         updateResources();
 
+        mBrightnessView = LayoutInflater.from(context).inflate(
+                R.layout.quick_settings_brightness_dialog, this, false);
+        addView(mBrightnessView);
+
         mBrightnessController = new BrightnessController(getContext(),
                 (ImageView) findViewById(R.id.brightness_icon),
                 (ToggleSliderView) findViewById(R.id.brightness_slider));
+    }
 
+    public View getPageIndicator() {
+        return mPageIndicator;
     }
 
     protected void setupTileLayout() {
@@ -359,20 +370,10 @@
         };
         r.tile.addCallback(callback);
         r.callback = callback;
-        final View.OnClickListener click = new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                onTileClick(r.tile);
-            }
-        };
-        final View.OnLongClickListener longClick = new View.OnLongClickListener() {
-            @Override
-            public boolean onLongClick(View v) {
-                r.tile.longClick();
-                return true;
-            }
-        };
-        r.tileView.init(click, longClick);
+        r.tileView.init(v -> r.tile.click(), v -> r.tile.secondaryClick(), v -> {
+            r.tile.longClick();
+            return true;
+        });
         r.tile.refreshState();
         mRecords.add(r);
 
@@ -402,10 +403,6 @@
         });
     }
 
-    protected void onTileClick(QSTile<?> tile) {
-        tile.click();
-    }
-
     public void closeDetail() {
         if (mCustomizePanel != null && mCustomizePanel.isShown()) {
             // Treat this as a detail panel for now, to make things easy.
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
index f73241c..dad37b0 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
@@ -24,6 +24,7 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
+import android.service.quicksettings.Tile;
 import android.util.ArraySet;
 import android.util.Log;
 import android.util.SparseArray;
@@ -52,8 +53,12 @@
 import java.util.Collection;
 import java.util.Objects;
 
+import com.android.settingslib.Utils;
+
 import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
 
+import com.android.systemui.R;
+
 /**
  * Base quick-settings tile, extend this to create a new tile.
  *
@@ -79,7 +84,9 @@
     private String mTileSpec;
 
     public abstract TState newTileState();
+
     abstract protected void handleClick();
+
     abstract protected void handleUpdateState(TState state, Object arg);
 
     /**
@@ -134,7 +141,9 @@
         return null; // optional
     }
 
-    protected DetailAdapter createDetailAdapter() { throw new UnsupportedOperationException(); }
+    protected DetailAdapter createDetailAdapter() {
+        throw new UnsupportedOperationException();
+    }
 
     /**
      * Is a startup check whether this device currently supports this tile.
@@ -319,6 +328,21 @@
 
     public abstract CharSequence getTileLabel();
 
+    public static int getColorForState(Context context, int state) {
+        switch (state) {
+            case Tile.STATE_UNAVAILABLE:
+                return Utils.getDisabled(context,
+                        Utils.getColorAttr(context, android.R.attr.textColorTertiary));
+            case Tile.STATE_INACTIVE:
+                return Utils.getColorAttr(context, android.R.attr.textColorSecondary);
+            case Tile.STATE_ACTIVE:
+                return Utils.getColorAttr(context, android.R.attr.colorPrimary);
+            default:
+                Log.e("QSTile", "Invalid state " + state);
+                return 0;
+        }
+    }
+
     protected final class H extends Handler {
         private static final int ADD_CALLBACK = 1;
         private static final int CLICK = 2;
@@ -546,6 +570,7 @@
 
     public static class State {
         public Icon icon;
+        public int state = Tile.STATE_ACTIVE;
         public CharSequence label;
         public CharSequence contentDescription;
         public CharSequence dualLabelContentDescription;
@@ -572,6 +597,7 @@
                     || !Objects.equals(other.expandedAccessibilityClassName,
                     expandedAccessibilityClassName)
                     || !Objects.equals(other.disabledByPolicy, disabledByPolicy)
+                    || !Objects.equals(other.state, state)
                     || !Objects.equals(other.enforcedAdmin, enforcedAdmin);
             other.icon = icon;
             other.label = label;
@@ -582,6 +608,7 @@
             other.expandedAccessibilityClassName = expandedAccessibilityClassName;
             other.autoMirrorDrawable = autoMirrorDrawable;
             other.disabledByPolicy = disabledByPolicy;
+            other.state = state;
             if (enforcedAdmin == null) {
                 other.enforcedAdmin = null;
             } else if (other.enforcedAdmin == null) {
@@ -609,6 +636,7 @@
             sb.append(",autoMirrorDrawable=").append(autoMirrorDrawable);
             sb.append(",disabledByPolicy=").append(disabledByPolicy);
             sb.append(",enforcedAdmin=").append(enforcedAdmin);
+            sb.append(",state=").append(state);
             return sb.append(']');
         }
     }
@@ -648,7 +676,6 @@
         public boolean connected;
         public boolean activityIn;
         public boolean activityOut;
-        public int overlayIconId;
         public boolean filter;
         public boolean isOverlayIconWide;
 
@@ -657,12 +684,10 @@
             final SignalState o = (SignalState) other;
             final boolean changed = o.connected != connected || o.activityIn != activityIn
                     || o.activityOut != activityOut
-                    || o.overlayIconId != overlayIconId
                     || o.isOverlayIconWide != isOverlayIconWide;
             o.connected = connected;
             o.activityIn = activityIn;
             o.activityOut = activityOut;
-            o.overlayIconId = overlayIconId;
             o.filter = filter;
             o.isOverlayIconWide = isOverlayIconWide;
             return super.copyTo(other) || changed;
@@ -674,7 +699,6 @@
             rt.insert(rt.length() - 1, ",connected=" + connected);
             rt.insert(rt.length() - 1, ",activityIn=" + activityIn);
             rt.insert(rt.length() - 1, ",activityOut=" + activityOut);
-            rt.insert(rt.length() - 1, ",overlayIconId=" + overlayIconId);
             rt.insert(rt.length() - 1, ",filter=" + filter);
             rt.insert(rt.length() - 1, ",wideOverlayIcon=" + isOverlayIconWide);
             return rt;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileBaseView.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileBaseView.java
index 2b7fcc5..a177cc3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTileBaseView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileBaseView.java
@@ -15,31 +15,49 @@
  */
 package com.android.systemui.qs;
 
+import android.animation.ValueAnimator;
 import android.content.Context;
+import android.content.res.ColorStateList;
 import android.content.res.TypedArray;
+import android.graphics.Color;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.RippleDrawable;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
+import android.service.quicksettings.Tile;
 import android.text.TextUtils;
+import android.util.Log;
+import android.view.Gravity;
 import android.view.View;
+import android.view.ViewGroup;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityNodeInfo;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.ImageView.ScaleType;
 import android.widget.LinearLayout;
 import android.widget.Switch;
 
+import com.android.settingslib.Utils;
+
 import com.android.systemui.R;
 
 public class QSTileBaseView extends LinearLayout {
 
+    private static final String TAG = "QSTileBaseView";
     private final H mHandler = new H();
+    private final ImageView mBg;
     protected QSIconView mIcon;
     protected RippleDrawable mRipple;
     private Drawable mTileBackground;
     private String mAccessibilityClass;
     private boolean mTileState;
     private boolean mCollapsedView;
+    private final int mColorActive;
+    private final int mColorInactive;
+    private final int mColorDisabled;
+    private int mCircleColor;
 
     public QSTileBaseView(Context context, QSIconView icon) {
         this(context, icon, false);
@@ -47,8 +65,26 @@
 
     public QSTileBaseView(Context context, QSIconView icon, boolean collapsedView) {
         super(context);
+        // Default to Quick Tile padding, and QSTileView will specify its own padding.
+        int padding = context.getResources().getDimensionPixelSize(R.dimen.qs_quick_tile_padding);
+
+        FrameLayout frame = new FrameLayout(context);
+        frame.setForegroundGravity(Gravity.CENTER);
+        int size = context.getResources().getDimensionPixelSize(R.dimen.qs_quick_tile_size);
+        addView(frame, new LayoutParams(size, size));
+        mBg = new ImageView(getContext());
+        mBg.setScaleType(ScaleType.FIT_CENTER);
+        mBg.setImageResource(R.drawable.ic_qs_circle);
+        frame.addView(mBg);
         mIcon = icon;
-        addView(mIcon);
+        FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
+                ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
+        params.setMargins(0, padding, 0, padding);
+        frame.addView(mIcon, params);
+        mColorActive = Utils.getColorAttr(context, android.R.attr.textColorPrimary);
+        mColorDisabled = Utils.getDisabled(context,
+                Utils.getColorAttr(context, android.R.attr.textColorTertiary));
+        mColorInactive = Utils.getColorAttr(context, android.R.attr.textColorSecondary);
 
         mTileBackground = newTileBackground();
         if (mTileBackground instanceof RippleDrawable) {
@@ -57,18 +93,20 @@
         setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
         setBackground(mTileBackground);
 
-        // Default to Quick Tile padding, and QSTileView will specify its own padding.
-        int padding = context.getResources().getDimensionPixelSize(R.dimen.qs_quick_tile_padding);
-        setPadding(0, padding, 0, padding);
+        setPadding(0, 0, 0, 0);
         setClipChildren(false);
         setClipToPadding(false);
         mCollapsedView = collapsedView;
         setFocusable(true);
     }
 
+    public View getBgCicle() {
+        return mBg;
+    }
+
     protected Drawable newTileBackground() {
-        final int[] attrs = new int[] { android.R.attr.selectableItemBackgroundBorderless };
-        final TypedArray ta = mContext.obtainStyledAttributes(attrs);
+        final int[] attrs = new int[]{android.R.attr.selectableItemBackgroundBorderless};
+        final TypedArray ta = getContext().obtainStyledAttributes(attrs);
         final Drawable d = ta.getDrawable(0);
         ta.recycle();
         return d;
@@ -85,11 +123,12 @@
         // center the touch feedback on the center of the icon, and dial it down a bit
         final int cx = width / 2;
         final int cy = height / 2;
-        final int rad = (int)(mIcon.getHeight() * .85f);
+        final int rad = (int) (mIcon.getHeight() * .85f);
         mRipple.setHotspotBounds(cx - rad, cy - rad, cx + rad, cy + rad);
     }
 
-    public void init(OnClickListener click, OnLongClickListener longClick) {
+    public void init(OnClickListener click, OnClickListener secondaryClick,
+            OnLongClickListener longClick) {
         setClickable(true);
         setOnClickListener(click);
         setOnLongClickListener(longClick);
@@ -128,6 +167,16 @@
     }
 
     protected void handleStateChanged(QSTile.State state) {
+        int circleColor = getCircleColor(state.state);
+        if (circleColor != mCircleColor) {
+            if (mBg.isShown()) {
+                QSIconView.animateGrayScale(mCircleColor, circleColor, mBg);
+            } else {
+                QSIconView.setTint(mBg, circleColor);
+            }
+            mCircleColor = circleColor;
+        }
+
         mIcon.setIcon(state);
         if (mCollapsedView && !TextUtils.isEmpty(state.minimalContentDescription)) {
             setContentDescription(state.minimalContentDescription);
@@ -144,6 +193,19 @@
         }
     }
 
+    private int getCircleColor(int state) {
+        switch (state) {
+            case Tile.STATE_ACTIVE:
+                return mColorActive;
+            case Tile.STATE_INACTIVE:
+            case Tile.STATE_UNAVAILABLE:
+                return mColorDisabled;
+            default:
+                Log.e(TAG, "Invalid state " + state);
+                return 0;
+        }
+    }
+
     public QSIconView getIcon() {
         return mIcon;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
index e59873a..7126f3c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
@@ -16,27 +16,34 @@
 
 package com.android.systemui.qs;
 
+import static com.android.systemui.qs.QSTile.getColorForState;
+
 import android.content.Context;
 import android.content.res.Configuration;
-import android.content.res.Resources;
-import android.util.MathUtils;
+import android.service.quicksettings.Tile;
+import android.text.SpannableStringBuilder;
+import android.text.style.ForegroundColorSpan;
 import android.view.Gravity;
 import android.view.LayoutInflater;
+import android.view.MotionEvent;
 import android.view.View;
+import android.view.ViewGroup;
 import android.widget.ImageView;
 import android.widget.TextView;
 
 import com.android.systemui.FontSizeUtils;
 import com.android.systemui.R;
+
 import libcore.util.Objects;
 
 /** View that represents a standard quick settings tile. **/
 public class QSTileView extends QSTileBaseView {
-    private final int mTileSpacingPx;
-    private int mTilePaddingTopPx;
 
     protected TextView mLabel;
     private ImageView mPadLock;
+    private int mState;
+    private OnClickListener mClick;
+    private OnClickListener mSecondaryClick;
 
     public QSTileView(Context context, QSIconView icon) {
         this(context, icon, false);
@@ -45,13 +52,10 @@
     public QSTileView(Context context, QSIconView icon, boolean collapsedView) {
         super(context, icon, collapsedView);
 
-        final Resources res = context.getResources();
-        mTileSpacingPx = res.getDimensionPixelSize(R.dimen.qs_tile_spacing);
-
         setClipChildren(false);
+        setClipToPadding(false);
 
         setClickable(true);
-        updateTopPadding();
         setId(View.generateViewId());
         createLabel();
         setOrientation(VERTICAL);
@@ -62,27 +66,17 @@
         return mLabel;
     }
 
-    protected void updateTopPadding() {
-        Resources res = getResources();
-        int padding = res.getDimensionPixelSize(R.dimen.qs_tile_padding_top);
-        int largePadding = res.getDimensionPixelSize(R.dimen.qs_tile_padding_top_large_text);
-        float largeFactor = (MathUtils.constrain(getResources().getConfiguration().fontScale,
-                1.0f, FontSizeUtils.LARGE_TEXT_SCALE) - 1f) / (FontSizeUtils.LARGE_TEXT_SCALE - 1f);
-        mTilePaddingTopPx = Math.round((1 - largeFactor) * padding + largeFactor * largePadding);
-        setPadding(mTileSpacingPx, mTilePaddingTopPx + mTileSpacingPx, mTileSpacingPx,
-                mTileSpacingPx);
-        requestLayout();
-    }
-
     @Override
     protected void onConfigurationChanged(Configuration newConfig) {
         super.onConfigurationChanged(newConfig);
-        updateTopPadding();
         FontSizeUtils.updateFontSize(mLabel, R.dimen.qs_tile_text_size);
     }
 
     protected void createLabel() {
-        View view = LayoutInflater.from(mContext).inflate(R.layout.qs_tile_label, null);
+        ViewGroup view = (ViewGroup) LayoutInflater.from(getContext())
+                .inflate(R.layout.qs_tile_label, null);
+        view.setClipChildren(false);
+        view.setClipToPadding(false);
         mLabel = (TextView) view.findViewById(R.id.tile_label);
         mPadLock = (ImageView) view.findViewById(R.id.restricted_padlock);
         addView(view);
@@ -91,10 +85,32 @@
     @Override
     protected void handleStateChanged(QSTile.State state) {
         super.handleStateChanged(state);
-        if (!Objects.equal(mLabel.getText(), state.label)) {
+        if (!Objects.equal(mLabel.getText(), state.label) || mState != state.state) {
+            if (state.state == Tile.STATE_UNAVAILABLE) {
+                int color = getColorForState(getContext(), state.state);
+                state.label = new SpannableStringBuilder().append(state.label,
+                        new ForegroundColorSpan(color),
+                        SpannableStringBuilder.SPAN_INCLUSIVE_INCLUSIVE);
+            }
+            mState = state.state;
             mLabel.setText(state.label);
         }
         mLabel.setEnabled(!state.disabledByPolicy);
         mPadLock.setVisibility(state.disabledByPolicy ? View.VISIBLE : View.GONE);
     }
+
+    @Override
+    public void init(OnClickListener click, OnClickListener secondaryClick, OnLongClickListener longClick) {
+        mClick = click;
+        mSecondaryClick = secondaryClick;
+        super.init(click, secondaryClick, longClick);
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent event) {
+        if (event.getActionMasked() == MotionEvent.ACTION_UP)  {
+            setOnClickListener(event.getY() < (getMeasuredHeight() / 2) ? mClick : mSecondaryClick);
+        }
+        return super.onTouchEvent(event);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
index de3e19c..16b351e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
@@ -56,7 +56,7 @@
         }
         mTileLayout = new HeaderTileLayout(context);
         mTileLayout.setListening(mListening);
-        addView((View) mTileLayout, 1 /* Between brightness and footer */);
+        addView((View) mTileLayout, 0 /* Between brightness and footer */);
     }
 
     @Override
@@ -113,11 +113,6 @@
     }
 
     @Override
-    protected void onTileClick(QSTile<?> tile) {
-        tile.secondaryClick();
-    }
-
-    @Override
     public void onTuningChanged(String key, String newValue) {
         // No tunings for you.
         if (key.equals(QS_SHOW_BRIGHTNESS)) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/SignalTileView.java b/packages/SystemUI/src/com/android/systemui/qs/SignalTileView.java
index b2bfa06..8555e31 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/SignalTileView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/SignalTileView.java
@@ -33,7 +33,6 @@
 
     private FrameLayout mIconFrame;
     private ImageView mSignal;
-    private ImageView mOverlay;
     private ImageView mIn;
     private ImageView mOut;
 
@@ -62,8 +61,6 @@
         mIconFrame = new FrameLayout(mContext);
         mSignal = new ImageView(mContext);
         mIconFrame.addView(mSignal);
-        mOverlay = new ImageView(mContext);
-        mIconFrame.addView(mOverlay, LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
         return mIconFrame;
     }
 
@@ -109,17 +106,6 @@
     public void setIcon(QSTile.State state) {
         final SignalState s = (SignalState) state;
         setIcon(mSignal, s);
-        if (s.overlayIconId > 0) {
-            mOverlay.setVisibility(VISIBLE);
-            mOverlay.setImageResource(s.overlayIconId);
-        } else {
-            mOverlay.setVisibility(GONE);
-        }
-        if (s.overlayIconId > 0 && s.isOverlayIconWide) {
-            mSignal.setPaddingRelative(mWideOverlayIconStartPadding, 0, 0, 0);
-        } else {
-            mSignal.setPaddingRelative(0, 0, 0, 0);
-        }
         Drawable drawable = mSignal.getDrawable();
         if (state.autoMirrorDrawable && drawable != null) {
             drawable.setAutoMirrored(true);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
index 9e3889b..cff4846 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
@@ -15,15 +15,10 @@
  */
 package com.android.systemui.qs.external;
 
-import static android.view.Display.DEFAULT_DISPLAY;
-import static android.view.WindowManager.LayoutParams.TYPE_QS_DIALOG;
-
 import android.app.ActivityManager;
 import android.content.ComponentName;
-import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
 import android.graphics.drawable.Drawable;
@@ -39,14 +34,19 @@
 import android.text.style.ForegroundColorSpan;
 import android.util.Log;
 import android.view.IWindowManager;
+import android.view.WindowManager;
 import android.view.WindowManagerGlobal;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.systemui.R;
 import com.android.systemui.qs.QSTile;
 import com.android.systemui.qs.external.TileLifecycleManager.TileChangeListener;
 import com.android.systemui.statusbar.phone.QSTileHost;
 import libcore.util.Objects;
 
+import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.WindowManager.LayoutParams.TYPE_QS_DIALOG;
+
 public class CustomTile extends QSTile<QSTile.State> implements TileChangeListener {
     public static final String PREFIX = "custom(";
 
@@ -63,7 +63,6 @@
     private final IQSTileService mService;
     private final TileServiceManager mServiceManager;
     private final int mUser;
-    private Context mAppContext;
     private android.graphics.drawable.Icon mDefaultIcon;
 
     private boolean mListening;
@@ -81,10 +80,6 @@
         mService = mServiceManager.getTileService();
         mServiceManager.setTileChangeListener(this);
         mUser = ActivityManager.getCurrentUser();
-        try {
-            mAppContext = mContext.createPackageContext(mComponent.getPackageName(), 0);
-        } catch (NameNotFoundException e) {
-        }
     }
 
     private void setTileIcon() {
@@ -287,27 +282,17 @@
         if (mServiceManager.hasPendingBind()) {
             tileState = Tile.STATE_UNAVAILABLE;
         }
+        state.state = tileState;
         Drawable drawable;
-        boolean mHasRes = false;
-        android.graphics.drawable.Icon icon = mTile.getIcon();
         try {
-            drawable = icon.loadDrawable(mAppContext);
-            mHasRes = icon.getType() == android.graphics.drawable.Icon.TYPE_RESOURCE;
+            drawable = mTile.getIcon().loadDrawable(mContext);
         } catch (Exception e) {
             Log.w(TAG, "Invalid icon, forcing into unavailable state");
             tileState = Tile.STATE_UNAVAILABLE;
-            drawable = mDefaultIcon.loadDrawable(mAppContext);
+            drawable = mDefaultIcon.loadDrawable(mContext);
         }
-        final int color = TileColorPicker.getInstance(mContext).getColor(tileState);
-        drawable.setTint(color);
-        state.icon = mHasRes ? new DrawableIconWithRes(drawable, icon.getResId())
-                : new DrawableIcon(drawable);
+        state.icon = new DrawableIcon(drawable);
         state.label = mTile.getLabel();
-        if (tileState == Tile.STATE_UNAVAILABLE) {
-            state.label = new SpannableStringBuilder().append(state.label,
-                    new ForegroundColorSpan(color),
-                    SpannableStringBuilder.SPAN_INCLUSIVE_INCLUSIVE);
-        }
         if (mTile.getContentDescription() != null) {
             state.contentDescription = mTile.getContentDescription();
         } else {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
index e57cd58..e8f90ac 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
@@ -23,6 +23,7 @@
 import android.net.ConnectivityManager;
 import android.provider.Settings;
 import android.provider.Settings.Global;
+import android.service.quicksettings.Tile;
 import android.widget.Switch;
 
 import com.android.internal.logging.MetricsLogger;
@@ -92,6 +93,7 @@
         } else {
             state.icon = mDisable;
         }
+        state.state = airplaneMode ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
         state.contentDescription = state.label;
         state.minimalAccessibilityClassName = state.expandedAccessibilityClassName
                 = Switch.class.getName();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java
index 833375e..a82f550 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java
@@ -19,10 +19,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.graphics.PorterDuff.Mode;
-import android.graphics.PorterDuffColorFilter;
 import android.graphics.drawable.Drawable;
-import android.os.Handler;
 import android.service.quicksettings.Tile;
 import android.text.SpannableStringBuilder;
 import android.text.Spanned;
@@ -44,7 +41,6 @@
 import com.android.systemui.R;
 import com.android.systemui.plugins.qs.QS.DetailAdapter;
 import com.android.systemui.qs.QSTile;
-import com.android.systemui.qs.external.TileColorPicker;
 import com.android.systemui.statusbar.phone.PhoneStatusBar;
 import com.android.systemui.statusbar.policy.BatteryController;
 
@@ -105,6 +101,11 @@
 
     @Override
     protected void handleClick() {
+        mBatteryController.setPowerSaveMode(!mPowerSave);
+    }
+
+    @Override
+    protected void handleSecondaryClick() {
         showDetail(true);
     }
 
@@ -118,26 +119,10 @@
         int level = (arg != null) ? (Integer) arg : mLevel;
         String percentage = NumberFormat.getPercentInstance().format((double) level / 100.0);
 
-        state.icon = new Icon() {
-            @Override
-            public Drawable getDrawable(Context context) {
-                BatteryMeterDrawable drawable =
-                        new BatteryMeterDrawable(context,
-                        context.getColor(R.color.batterymeter_frame_color));
-                drawable.onBatteryLevelChanged(mLevel, mPluggedIn, mCharging);
-                drawable.onPowerSaveChanged(mPowerSave);
-                final int color = TileColorPicker.getInstance(context).getColor(Tile.STATE_ACTIVE);
-                drawable.setColorFilter(new PorterDuffColorFilter(color, Mode.SRC_IN));
-                return drawable;
-            }
-
-            @Override
-            public int getPadding() {
-                return mHost.getContext().getResources().getDimensionPixelSize(
-                        R.dimen.qs_battery_padding);
-            }
-        };
-        state.label = percentage;
+        state.state = mCharging ? Tile.STATE_UNAVAILABLE
+                : mPowerSave ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
+        state.icon = ResourceIcon.get(R.drawable.ic_qs_battery_saver);
+        state.label = mContext.getString(R.string.battery_detail_switch_title);
         state.contentDescription = mContext.getString(R.string.accessibility_quick_settings_battery,
                 percentage) + "," +
                 (mPowerSave ? mContext.getString(R.string.battery_saver_notification_title)
@@ -153,7 +138,7 @@
         mLevel = level;
         mPluggedIn = pluggedIn;
         mCharging = charging;
-        refreshState((Integer) level);
+        refreshState(level);
         if (mDetailShown) {
             mBatteryDetail.postBindView();
         }
@@ -213,11 +198,6 @@
             mDrawable.onBatteryLevelChanged(100, false, false);
             mDrawable.onPowerSaveChanged(true);
             mDrawable.disableShowPercent();
-
-            final int color = TileColorPicker.getInstance(mCurrentView.getContext())
-                    .getColor(Tile.STATE_ACTIVE);
-            mDrawable.setColorFilter(new PorterDuffColorFilter(color, Mode.SRC_IN));
-
             ((ImageView) mCurrentView.findViewById(android.R.id.icon)).setImageDrawable(mDrawable);
             Checkable checkbox = (Checkable) mCurrentView.findViewById(android.R.id.toggle);
             checkbox.setChecked(mPowerSave);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
index f83b279..15f3c90 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
@@ -22,6 +22,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.provider.Settings;
+import android.service.quicksettings.Tile;
 import android.text.TextUtils;
 import android.view.View;
 import android.view.ViewGroup;
@@ -74,7 +75,7 @@
     }
 
     @Override
-    protected void handleSecondaryClick() {
+    protected void handleClick() {
         // Secondary clicks are header clicks, just toggle.
         final boolean isEnabled = (Boolean)mState.value;
         MetricsLogger.action(mContext, getMetricsCategory(), !isEnabled);
@@ -87,7 +88,7 @@
     }
 
     @Override
-    protected void handleClick() {
+    protected void handleSecondaryClick() {
         if (!mController.canConfigBluetooth()) {
             mHost.startActivityDismissingKeyguard(new Intent(Settings.ACTION_BLUETOOTH_SETTINGS));
             return;
@@ -140,11 +141,13 @@
             if (TextUtils.isEmpty(state.label)) {
                 state.label = mContext.getString(R.string.quick_settings_bluetooth_label);
             }
+            state.state = Tile.STATE_ACTIVE;
         } else {
             state.icon = ResourceIcon.get(R.drawable.ic_qs_bluetooth_off);
             state.label = mContext.getString(R.string.quick_settings_bluetooth_label);
             state.contentDescription = mContext.getString(
                     R.string.accessibility_quick_settings_bluetooth_off);
+            state.state = Tile.STATE_INACTIVE;
         }
 
         CharSequence bluetoothName = state.label;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
index 8afa91e..d61e2f2 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
@@ -19,6 +19,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.provider.Settings;
+import android.service.quicksettings.Tile;
 import android.util.Log;
 import android.view.View;
 import android.view.View.OnAttachStateChangeListener;
@@ -93,6 +94,11 @@
     }
 
     @Override
+    protected void handleSecondaryClick() {
+        handleClick();
+    }
+
+    @Override
     protected void handleClick() {
         if (mKeyguard.isSecure() && !mKeyguard.canSkipBouncer()) {
             mHost.startRunnableDismissingKeyguard(new Runnable() {
@@ -135,6 +141,7 @@
         if (!state.value && connecting) {
             state.label = mContext.getString(R.string.quick_settings_connecting);
         }
+        state.state = state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
         state.icon = ResourceIcon.get(state.value ? R.drawable.ic_qs_cast_on
                 : R.drawable.ic_qs_cast_off);
         mDetailAdapter.updateItems(devices);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
index 1406c9f..5f7c803 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
@@ -20,6 +20,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.res.Resources;
+import android.service.quicksettings.Tile;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -86,6 +87,11 @@
 
     @Override
     protected void handleClick() {
+        mDataController.setMobileDataEnabled(!mDataController.isMobileDataEnabled());
+    }
+
+    @Override
+    protected void handleSecondaryClick() {
         MetricsLogger.action(mContext, getMetricsCategory());
         if (mDataController.isMobileDataSupported()) {
             showDetail(true);
@@ -111,10 +117,13 @@
                 : !cb.enabled || cb.airplaneModeEnabled ? R.drawable.ic_qs_signal_disabled
                 : cb.mobileSignalIconId > 0 ? cb.mobileSignalIconId
                 : R.drawable.ic_qs_signal_no_signal;
-        state.icon = ResourceIcon.get(iconId);
+        if (cb.dataTypeIconId != 0) {
+            state.icon = ResourceIcon.get(cb.dataTypeIconId);
+        } else {
+            state.icon = ResourceIcon.get(iconId);
+        }
         state.isOverlayIconWide = cb.isDataTypeIconWide;
         state.autoMirrorDrawable = !cb.noSim;
-        state.overlayIconId = cb.enabled && (cb.dataTypeIconId > 0) ? cb.dataTypeIconId : 0;
         state.filter = iconId != R.drawable.ic_qs_no_sim;
         state.activityIn = cb.enabled && cb.activityIn;
         state.activityOut = cb.enabled && cb.activityOut;
@@ -148,6 +157,7 @@
                 = Button.class.getName();
         state.value = mDataController.isMobileDataSupported()
                 && mDataController.isMobileDataEnabled();
+        state.state = state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
index 77f063d..0a8afb0 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
@@ -19,6 +19,7 @@
 import android.content.Intent;
 import android.provider.Settings;
 import android.provider.Settings.Secure;
+import android.service.quicksettings.Tile;
 import android.widget.Switch;
 
 import com.android.internal.logging.MetricsLogger;
@@ -95,6 +96,7 @@
         final int value = arg instanceof Integer ? (Integer) arg : mSetting.getValue();
         final boolean enabled = value != 0;
         state.value = enabled;
+        state.state = state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
         state.label = mContext.getString(R.string.quick_settings_inversion_label);
         state.icon = enabled ? mEnable : mDisable;
         state.minimalAccessibilityClassName = state.expandedAccessibilityClassName
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java
index 65432dc..aadc8e7 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java
@@ -16,6 +16,7 @@
 
 import android.content.DialogInterface;
 import android.content.Intent;
+import android.service.quicksettings.Tile;
 import android.widget.Switch;
 
 import com.android.internal.logging.MetricsLogger;
@@ -96,6 +97,7 @@
     protected void handleUpdateState(BooleanState state, Object arg) {
         state.value = arg instanceof Boolean ? (Boolean) arg
                 : mDataSaverController.isDataSaverEnabled();
+        state.state = state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
         state.label = mContext.getString(R.string.data_saver);
         state.contentDescription = state.label;
         state.icon = ResourceIcon.get(state.value ? R.drawable.ic_data_saver
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
index 198375d..a25b7ea 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
@@ -25,6 +25,7 @@
 import android.os.UserManager;
 import android.provider.Settings;
 import android.provider.Settings.Global;
+import android.service.quicksettings.Tile;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.View.OnAttachStateChangeListener;
@@ -121,7 +122,17 @@
     }
 
     @Override
-    public void handleClick() {
+    protected void handleClick() {
+        if (mState.value) {
+            mController.setZen(Global.ZEN_MODE_OFF, null, TAG);
+        } else {
+            int zen = Prefs.getInt(mContext, Prefs.Key.DND_FAVORITE_ZEN, Global.ZEN_MODE_ALARMS);
+            mController.setZen(zen, null, TAG);
+        }
+    }
+
+    @Override
+    protected void handleSecondaryClick() {
         if (mController.isVolumeRestricted()) {
             // Collapse the panels, so the user can see the toast.
             mHost.collapsePanels();
@@ -131,13 +142,9 @@
             return;
         }
         MetricsLogger.action(mContext, getMetricsCategory(), !mState.value);
-        if (mState.value) {
-            mController.setZen(Global.ZEN_MODE_OFF, null, TAG);
-        } else {
-            showDetail(true);
-            int zen = Prefs.getInt(mContext, Prefs.Key.DND_FAVORITE_ZEN, Global.ZEN_MODE_ALARMS);
-            mController.setZen(zen, null, TAG);
-        }
+        showDetail(true);
+        int zen = Prefs.getInt(mContext, Prefs.Key.DND_FAVORITE_ZEN, Global.ZEN_MODE_ALARMS);
+        mController.setZen(zen, null, TAG);
     }
 
     @Override
@@ -151,6 +158,7 @@
         final boolean newValue = zen != Global.ZEN_MODE_OFF;
         final boolean valueChanged = state.value != newValue;
         state.value = newValue;
+        state.state = state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
         checkIfRestrictionEnforcedByAdminOnly(state, UserManager.DISALLOW_ADJUST_VOLUME);
         switch (zen) {
             case Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS:
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
index 416c7ce..4bbc458 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
@@ -29,7 +29,6 @@
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.systemui.R;
 import com.android.systemui.qs.QSTile;
-import com.android.systemui.qs.external.TileColorPicker;
 import com.android.systemui.statusbar.policy.FlashlightController;
 
 /** Quick settings tile: Control flashlight **/
@@ -47,11 +46,13 @@
     public FlashlightTile(Host host) {
         super(host);
         mFlashlightController = host.getFlashlightController();
+        mFlashlightController.addCallback(this);
     }
 
     @Override
     protected void handleDestroy() {
         super.handleDestroy();
+        mFlashlightController.removeCallback(this);
     }
 
     @Override
@@ -107,17 +108,12 @@
     protected void handleUpdateState(BooleanState state, Object arg) {
         state.label = mHost.getContext().getString(R.string.quick_settings_flashlight_label);
         if (!mFlashlightController.isAvailable()) {
-            Drawable icon = mHost.getContext().getDrawable(R.drawable.ic_signal_flashlight_disable)
+            Drawable icon = mHost.getContext().getDrawable(R.drawable.ic_signal_flashlight_enable)
                     .mutate();
-            final int disabledColor = TileColorPicker.getInstance(mContext)
-                    .getColor(Tile.STATE_UNAVAILABLE);
-            icon.setTint(disabledColor);
             state.icon = new DrawableIcon(icon);
-            state.label = new SpannableStringBuilder().append(state.label,
-                    new ForegroundColorSpan(disabledColor),
-                    SpannableStringBuilder.SPAN_INCLUSIVE_INCLUSIVE);
             state.contentDescription = mContext.getString(
                     R.string.accessibility_quick_settings_flashlight_unavailable);
+            state.state = Tile.STATE_UNAVAILABLE;
             return;
         }
         if (arg instanceof Boolean) {
@@ -134,6 +130,7 @@
         state.contentDescription = mContext.getString(R.string.quick_settings_flashlight_label);
         state.minimalAccessibilityClassName = state.expandedAccessibilityClassName
                 = Switch.class.getName();
+        state.state = state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
index 99485bb..9d495ce 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
@@ -32,7 +32,6 @@
 import com.android.systemui.R;
 import com.android.systemui.qs.GlobalSetting;
 import com.android.systemui.qs.QSTile;
-import com.android.systemui.qs.external.TileColorPicker;
 import com.android.systemui.statusbar.policy.HotspotController;
 
 /** Quick settings tile: Hotspot **/
@@ -126,11 +125,6 @@
         boolean wasAirplane = state.isAirplaneMode;
         state.isAirplaneMode = mAirplaneMode.getValue() != 0;
         if (state.isAirplaneMode) {
-            final int disabledColor = TileColorPicker.getInstance(mContext)
-                    .getColor(Tile.STATE_UNAVAILABLE);
-            state.label = new SpannableStringBuilder().append(state.label,
-                    new ForegroundColorSpan(disabledColor),
-                    SpannableStringBuilder.SPAN_INCLUSIVE_INCLUSIVE);
             state.icon = mUnavailable;
         } else if (wasAirplane) {
             state.icon = mDisableNoAnimation;
@@ -138,6 +132,8 @@
         state.minimalAccessibilityClassName = state.expandedAccessibilityClassName
                 = Switch.class.getName();
         state.contentDescription = state.label;
+        state.state = state.isAirplaneMode ? Tile.STATE_UNAVAILABLE
+                : state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
index 8a9a696..002e2a6 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
@@ -20,6 +20,7 @@
 import android.os.UserManager;
 
 import android.provider.Settings;
+import android.service.quicksettings.Tile;
 import android.widget.Switch;
 
 import com.android.internal.logging.MetricsLogger;
@@ -115,6 +116,7 @@
             state.contentDescription = mContext.getString(
                     R.string.accessibility_quick_settings_location_off);
         }
+        state.state = state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
         state.minimalAccessibilityClassName = state.expandedAccessibilityClassName
                 = Switch.class.getName();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java
index 10fde30..b8ba28d8 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java
@@ -19,6 +19,7 @@
 import android.app.ActivityManager;
 import android.content.Intent;
 import android.provider.Settings;
+import android.service.quicksettings.Tile;
 import android.widget.Switch;
 
 import com.android.internal.app.NightDisplayController;
@@ -81,6 +82,7 @@
                 : R.drawable.ic_qs_night_display_off);
         state.minimalAccessibilityClassName = state.expandedAccessibilityClassName =
                 Switch.class.getName();
+        state.state = state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
index cec5f15..9be67da 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
@@ -21,6 +21,7 @@
 import android.content.res.Configuration;
 
 import android.provider.Settings;
+import android.service.quicksettings.Tile;
 import android.widget.Switch;
 
 import com.android.internal.logging.MetricsLogger;
@@ -106,6 +107,7 @@
         state.contentDescription = getAccessibilityString(rotationLocked);
         state.minimalAccessibilityClassName = state.expandedAccessibilityClassName
                 = Switch.class.getName();
+        state.state = state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
     }
 
     public static boolean isCurrentOrientationLockPortrait(RotationLockController controller,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
index 3876c88..7d99041 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
@@ -21,6 +21,7 @@
 import android.content.pm.PackageManager;
 import android.content.res.Resources;
 import android.provider.Settings;
+import android.service.quicksettings.Tile;
 import android.util.Log;
 import android.view.View;
 import android.view.ViewGroup;
@@ -104,7 +105,7 @@
     }
 
     @Override
-    protected void handleSecondaryClick() {
+    protected void handleClick() {
         // Secondary clicks are header clicks, just toggle.
         mState.copyTo(mStateBeforeClick);
         MetricsLogger.action(mContext, getMetricsCategory(), !mState.value);
@@ -112,7 +113,7 @@
     }
 
     @Override
-    protected void handleClick() {
+    protected void handleSecondaryClick() {
         if (!mWifiController.canConfigWifi()) {
             mHost.startActivityDismissingKeyguard(new Intent(Settings.ACTION_WIFI_SETTINGS));
             return;
@@ -191,6 +192,7 @@
         state.dualLabelContentDescription = wifiName;
         state.expandedAccessibilityClassName = Button.class.getName();
         state.minimalAccessibilityClassName = Switch.class.getName();
+        state.state = state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java
index ce7fbd3..207deff 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java
@@ -18,6 +18,7 @@
 
 import android.content.Intent;
 import android.provider.Settings;
+import android.service.quicksettings.Tile;
 import android.widget.Switch;
 
 import com.android.internal.logging.MetricsLogger;
@@ -108,6 +109,7 @@
         }
         state.minimalAccessibilityClassName = state.expandedAccessibilityClassName
                 = Switch.class.getName();
+        state.state = state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
index 68d5cd4..d77e9ed 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
@@ -159,6 +159,7 @@
     public void setNetworkController(NetworkControllerImpl nc) {
         if (DEBUG) Log.d(TAG, "NetworkController=" + nc);
         mNC = nc;
+        mNC.addCallback(this);
     }
 
     public void setSecurityController(SecurityController sc) {
@@ -214,7 +215,9 @@
         super.onAttachedToWindow();
 
         for (PhoneState state : mPhoneStates) {
-            mMobileSignalGroup.addView(state.mMobileGroup);
+            if (state.mMobileGroup.getParent() == null) {
+                mMobileSignalGroup.addView(state.mMobileGroup);
+            }
         }
 
         int endPadding = mMobileSignalGroup.getChildCount() > 0 ? mMobileSignalGroupEndPadding : 0;
@@ -224,7 +227,6 @@
 
         apply();
         applyIconTint();
-        mNC.addCallback(this);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index d708261..001edb3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -849,6 +849,7 @@
                     mDozeServiceHost.firePowerSaveChanged(isPowerSave);
                 }
             }
+
             @Override
             public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
                 // noop
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
index 08a91bb..2fa961d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
@@ -21,9 +21,13 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.res.Configuration;
+import android.graphics.Color;
+import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.RippleDrawable;
+import android.icu.text.NumberFormat;
 import android.os.UserManager;
+import android.support.annotation.VisibleForTesting;
 import android.util.AttributeSet;
 import android.view.View;
 import android.view.View.OnClickListener;
@@ -32,21 +36,25 @@
 import android.widget.TextView;
 import android.widget.Toast;
 
-import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto;
 import com.android.keyguard.KeyguardStatusView;
+import com.android.settingslib.Utils;
+import com.android.systemui.BatteryMeterView;
 import com.android.systemui.FontSizeUtils;
 import com.android.systemui.R;
 import com.android.systemui.plugins.qs.QS.ActivityStarter;
 import com.android.systemui.plugins.qs.QS.BaseStatusBarHeader;
-import com.android.systemui.qs.QSPanel;
 import com.android.systemui.plugins.qs.QS.Callback;
+import com.android.systemui.qs.QSPanel;
 import com.android.systemui.qs.QuickQSPanel;
 import com.android.systemui.qs.TouchAnimator;
 import com.android.systemui.qs.TouchAnimator.Builder;
+import com.android.systemui.statusbar.SignalClusterView;
 import com.android.systemui.statusbar.policy.BatteryController;
+import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback;
 import com.android.systemui.statusbar.policy.NetworkController.EmergencyListener;
+import com.android.systemui.statusbar.policy.NetworkControllerImpl;
 import com.android.systemui.statusbar.policy.NextAlarmController;
 import com.android.systemui.statusbar.policy.NextAlarmController.NextAlarmChangeCallback;
 import com.android.systemui.statusbar.policy.UserInfoController;
@@ -54,7 +62,8 @@
 import com.android.systemui.tuner.TunerService;
 
 public class QuickStatusBarHeader extends BaseStatusBarHeader implements
-        NextAlarmChangeCallback, OnClickListener, OnUserInfoChangedListener, EmergencyListener {
+        NextAlarmChangeCallback, OnClickListener, OnUserInfoChangedListener, EmergencyListener,
+        BatteryStateChangeCallback {
 
     private static final String TAG = "QuickStatusBarHeader";
 
@@ -67,14 +76,14 @@
 
     private TextView mAlarmStatus;
     private View mAlarmStatusCollapsed;
+    private ViewGroup mDateTimeGroup;
+    private ViewGroup mDateTimeAlarmGroup;
 
     private QSPanel mQsPanel;
 
     private boolean mExpanded;
     private boolean mAlarmShowing;
 
-    private ViewGroup mDateTimeGroup;
-    private ViewGroup mDateTimeAlarmGroup;
     private TextView mEmergencyOnly;
 
     protected ExpandableIndicator mExpandIndicator;
@@ -95,6 +104,7 @@
     protected View mEdit;
     private boolean mShowFullAlarm;
     private float mDateTimeTranslation;
+    private TextView mBatteryLevel;
 
     public QuickStatusBarHeader(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -130,6 +140,8 @@
         mAlarmStatus = (TextView) findViewById(R.id.alarm_status);
         mAlarmStatus.setOnClickListener(this);
 
+        mBatteryLevel = (TextView) findViewById(R.id.battery_level);
+
         mMultiUserSwitch = (MultiUserSwitch) findViewById(R.id.multi_user_switch);
         mMultiUserAvatar = (ImageView) mMultiUserSwitch.findViewById(R.id.multi_user_avatar);
 
@@ -236,13 +248,11 @@
         mExpandIndicator.setExpanded(headerExpansionFraction > EXPAND_INDICATOR_THRESHOLD);
     }
 
-    @Override
     @VisibleForTesting
     public void onDetachedFromWindow() {
         setListening(false);
         mHost.getUserInfoController().removeCallback(this);
         mHost.getNetworkController().removeEmergencyListener(this);
-        mHost.getUserInfoController().removeCallback(this);
         super.onDetachedFromWindow();
     }
 
@@ -325,6 +335,19 @@
         if (isAPhone) {
             mHost.getNetworkController().addEmergencyListener(this);
         }
+
+        // Set the light/dark theming on the header status UI to match the current theme.
+        SignalClusterView cluster = (SignalClusterView) findViewById(R.id.signal_cluster);
+        cluster.setNetworkController((NetworkControllerImpl) host.getNetworkController());
+        cluster.setSecurityController(host.getSecurityController());
+        int colorForeground = Utils.getColorAttr(getContext(), android.R.attr.colorForeground);
+        float intensity = colorForeground / (float) Color.WHITE;
+        cluster.setIconTint(colorForeground, intensity,
+                new Rect(0, 0, 0, 0));
+        BatteryMeterView battery = (BatteryMeterView) findViewById(R.id.battery);
+        battery.setBatteryController(host.getBatteryController());
+        int colorSecondary = Utils.getColorAttr(getContext(), android.R.attr.textColorSecondary);
+        battery.setRawColors(colorForeground, colorSecondary);
     }
 
     @Override
@@ -367,7 +390,7 @@
     }
 
     public void setBatteryController(BatteryController batteryController) {
-        // Don't care
+        batteryController.addCallback(this);
     }
 
     public void setUserInfoController(UserInfoController userInfoController) {
@@ -391,6 +414,17 @@
     }
 
     @Override
+    public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
+        String percentage = NumberFormat.getPercentInstance().format((double) level / 100.0);
+        mBatteryLevel.setText(percentage);
+    }
+
+    @Override
+    public void onPowerSaveChanged(boolean isPowerSave) {
+        // Don't care.
+    }
+
+    @Override
     public void onUserInfoChanged(String name, Drawable picture, String userAccount) {
         mMultiUserAvatar.setImageDrawable(picture);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java
index ed8c7ff..b59cf68 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java
@@ -224,7 +224,7 @@
     static final int ICON_CARRIER_NETWORK_CHANGE =
             R.drawable.stat_sys_signal_carrier_network_change_animation;
 
-    static final int ICON_DATA_DISABLED = R.drawable.stat_sys_data_disabled;
+    static final int ICON_DATA_DISABLED = R.drawable.ic_qs_data_disabled;
 
     static final int QS_ICON_LTE = R.drawable.ic_qs_signal_lte;
     static final int QS_ICON_3G = R.drawable.ic_qs_signal_3g;