Fix large text setting for QS

Bug: 15591223
Change-Id: I9f514a4970edbda778b987dfc3eca3914e492011
diff --git a/packages/SystemUI/res/layout/data_usage.xml b/packages/SystemUI/res/layout/data_usage.xml
index 8831a05..c943f3d 100644
--- a/packages/SystemUI/res/layout/data_usage.xml
+++ b/packages/SystemUI/res/layout/data_usage.xml
@@ -14,7 +14,7 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<com.android.systemui.qs.tiles.DataUsageDetailView xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     android:paddingTop="16dp"
@@ -82,4 +82,4 @@
             android:textAppearance="@style/TextAppearance.QS.DataUsage.Secondary" />
     </LinearLayout>
 
-</LinearLayout>
\ No newline at end of file
+</com.android.systemui.qs.tiles.DataUsageDetailView>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/qs_user_detail_item.xml b/packages/SystemUI/res/layout/qs_user_detail_item.xml
index 2322f16..af22f03 100644
--- a/packages/SystemUI/res/layout/qs_user_detail_item.xml
+++ b/packages/SystemUI/res/layout/qs_user_detail_item.xml
@@ -44,7 +44,7 @@
             android:id="@+id/user_name"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:textSize="14sp"
+            android:textSize="@dimen/qs_detail_item_secondary_text_size"
             android:textColor="@color/qs_user_detail_name"
             android:gravity="center_horizontal" />
 
diff --git a/packages/SystemUI/res/layout/split_clock_view.xml b/packages/SystemUI/res/layout/split_clock_view.xml
index 87b7051..808460a 100644
--- a/packages/SystemUI/res/layout/split_clock_view.xml
+++ b/packages/SystemUI/res/layout/split_clock_view.xml
@@ -39,6 +39,7 @@
 
     <!-- Empty text view so we have the same height when expanded/collapsed-->
     <TextView
+        android:id="@+id/empty_time_view"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:visibility="invisible"
diff --git a/packages/SystemUI/res/layout/status_bar_expanded_header.xml b/packages/SystemUI/res/layout/status_bar_expanded_header.xml
index ef8a426..f9e7852 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded_header.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded_header.xml
@@ -87,6 +87,7 @@
         android:visibility="gone"
         android:textAppearance="@style/TextAppearance.StatusBar.Expanded.EmergencyCallsOnly"
         android:text="@*android:string/emergency_calls_only"
+        android:singleLine="true"
         android:gravity="center_vertical" />
 
     <FrameLayout
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 0af693d..cc14292 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -166,6 +166,7 @@
     <dimen name="qs_dual_tile_padding_vertical">8dp</dimen>
     <dimen name="qs_dual_tile_padding_horizontal">6dp</dimen>
     <dimen name="qs_tile_padding_top">16dp</dimen>
+    <dimen name="qs_tile_padding_top_large_text">4dp</dimen>
     <dimen name="qs_tile_padding_below_icon">12dp</dimen>
     <dimen name="qs_tile_padding_bottom">16dp</dimen>
     <dimen name="qs_tile_spacing">4dp</dimen>
@@ -173,7 +174,13 @@
     <dimen name="qs_detail_item_height">48dp</dimen>
     <dimen name="qs_detail_item_height_twoline">72dp</dimen>
     <dimen name="qs_brightness_padding_top">6dp</dimen>
-
+    <dimen name="qs_detail_header_text_size">20sp</dimen>
+    <dimen name="qs_detail_button_text_size">14sp</dimen>
+    <dimen name="qs_detail_item_primary_text_size">16sp</dimen>
+    <dimen name="qs_detail_item_secondary_text_size">14sp</dimen>
+    <dimen name="qs_detail_empty_text_size">14sp</dimen>
+    <dimen name="qs_data_usage_text_size">14sp</dimen>
+    <dimen name="qs_data_usage_usage_text_size">36sp</dimen>
 
     <dimen name="segmented_button_spacing">4dp</dimen>
     <dimen name="segmented_button_radius">2dp</dimen>
@@ -362,6 +369,9 @@
     <!-- The padding bottom of the clock group when QS is collapsed. -->
     <dimen name="clock_collapsed_bottom_margin">10dp</dimen>
 
+    <!-- The padding bottom of the clock group when QS is collapsed for large text -->
+    <dimen name="clock_collapsed_bottom_margin_large_text">6dp</dimen>
+
     <!-- The width of the multi user switch on keyguard and collapsed QS header. -->
     <dimen name="multi_user_switch_width_collapsed">34dp</dimen>
 
@@ -383,6 +393,12 @@
     <!-- The font size of the time when expanded in QS -->
     <dimen name="qs_time_expanded_size">20sp</dimen>
 
+    <!-- The font size of the "emergency calls only" label in QS -->
+    <dimen name="qs_emergency_calls_only_text_size">12sp</dimen>
+
+    <!-- The font size of the date in QS -->
+    <dimen name="qs_date_collapsed_size">14sp</dimen>
+
     <!-- Battery level padding end when in expanded QS (but not on Keyguard) -->
     <dimen name="battery_level_padding_end">4dp</dimen>
 
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index b39fe24..804766a 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -85,13 +85,13 @@
     </style>
 
     <style name="TextAppearance.StatusBar.Expanded.Date">
-        <item name="android:textSize">14sp</item>
+        <item name="android:textSize">@dimen/qs_date_collapsed_size</item>
         <item name="android:textStyle">normal</item>
         <item name="android:textColor">#b2ffffff</item>
     </style>
 
     <style name="TextAppearance.StatusBar.Expanded.AboveDateTime">
-        <item name="android:textSize">12dp</item>
+        <item name="android:textSize">@dimen/qs_emergency_calls_only_text_size</item>
         <item name="android:textStyle">normal</item>
         <item name="android:textColor">#66ffffff</item>
     </style>
@@ -125,16 +125,16 @@
     </style>
 
     <style name="TextAppearance.QS.DetailHeader">
-        <item name="android:textSize">20sp</item>
+        <item name="android:textSize">@dimen/qs_detail_header_text_size</item>
         <item name="android:fontFamily">sans-serif-medium</item>
     </style>
 
     <style name="TextAppearance.QS.DetailItemPrimary">
-        <item name="android:textSize">16sp</item>
+        <item name="android:textSize">@dimen/qs_detail_item_primary_text_size</item>
     </style>
 
     <style name="TextAppearance.QS.DetailItemSecondary">
-        <item name="android:textSize">14sp</item>
+        <item name="android:textSize">@dimen/qs_detail_item_secondary_text_size</item>
         <item name="android:textColor">@color/system_accent_color</item>
     </style>
 
@@ -144,14 +144,14 @@
     </style>
 
     <style name="TextAppearance.QS.DetailButton">
-        <item name="android:textSize">14sp</item>
+        <item name="android:textSize">@dimen/qs_detail_button_text_size</item>
         <item name="android:textAllCaps">true</item>
         <item name="android:fontFamily">sans-serif-medium</item>
         <item name="android:gravity">center</item>
     </style>
 
     <style name="TextAppearance.QS.DetailEmpty">
-        <item name="android:textSize">14sp</item>
+        <item name="android:textSize">@dimen/qs_detail_empty_text_size</item>
         <item name="android:textColor">@color/qs_subhead</item>
     </style>
 
@@ -167,11 +167,11 @@
     </style>
 
     <style name="TextAppearance.QS.DataUsage">
-        <item name="android:textSize">14sp</item>
+        <item name="android:textSize">@dimen/qs_data_usage_text_size</item>
     </style>
 
     <style name="TextAppearance.QS.DataUsage.Usage">
-        <item name="android:textSize">36sp</item>
+        <item name="android:textSize">@dimen/qs_data_usage_usage_text_size</item>
         <item name="android:textColor">@color/system_accent_color</item>
     </style>
 
diff --git a/packages/SystemUI/src/com/android/systemui/FontSizeUtils.java b/packages/SystemUI/src/com/android/systemui/FontSizeUtils.java
new file mode 100644
index 0000000..35a70a5
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/FontSizeUtils.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui;
+
+import android.util.TypedValue;
+import android.view.View;
+import android.widget.TextView;
+
+/**
+ * Utility class to update the font size when the configuration has changed.
+ */
+public class FontSizeUtils {
+
+    public static final float LARGE_TEXT_SCALE = 1.3f;
+
+    public static void updateFontSize(View parent, int viewId, int dimensId) {
+        updateFontSize((TextView) parent.findViewById(viewId), dimensId);
+    }
+
+    public static void updateFontSize(TextView v, int dimensId) {
+        if (v != null) {
+            v.setTextSize(TypedValue.COMPLEX_UNIT_PX,
+                    v.getResources().getDimensionPixelSize(dimensId));
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSDetailItems.java b/packages/SystemUI/src/com/android/systemui/qs/QSDetailItems.java
index 24c1378..ce0d5f4 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSDetailItems.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSDetailItems.java
@@ -17,12 +17,14 @@
 package com.android.systemui.qs;
 
 import android.content.Context;
+import android.content.res.Configuration;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
 import android.text.TextUtils;
 import android.util.AttributeSet;
 import android.util.Log;
+import android.util.TypedValue;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -31,6 +33,7 @@
 import android.widget.LinearLayout;
 import android.widget.TextView;
 
+import com.android.systemui.FontSizeUtils;
 import com.android.systemui.R;
 
 /**
@@ -76,6 +79,20 @@
         mEmptyIcon = (ImageView) mEmpty.findViewById(android.R.id.icon);
     }
 
+    @Override
+    protected void onConfigurationChanged(Configuration newConfig) {
+        super.onConfigurationChanged(newConfig);
+        FontSizeUtils.updateFontSize(mEmptyText, R.dimen.qs_detail_empty_text_size);
+        int count = mItems.getChildCount();
+        for (int i = 0; i < count; i++) {
+            View item = mItems.getChildAt(i);
+            FontSizeUtils.updateFontSize(item, android.R.id.title,
+                    R.dimen.qs_detail_item_primary_text_size);
+            FontSizeUtils.updateFontSize(item, android.R.id.summary,
+                    R.dimen.qs_detail_item_secondary_text_size);
+        }
+    }
+
     public void setTagSuffix(String suffix) {
         mTag = TAG + "." + suffix;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
index a8199fa..82e6df2 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
@@ -18,10 +18,12 @@
 import android.app.AlertDialog;
 import android.content.Context;
 import android.content.DialogInterface;
+import android.content.res.Configuration;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
 import android.util.Log;
+import android.util.TypedValue;
 import android.view.ContextThemeWrapper;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -30,6 +32,7 @@
 import android.widget.ImageView;
 import android.widget.TextView;
 
+import com.android.systemui.FontSizeUtils;
 import com.android.systemui.R;
 import com.android.systemui.statusbar.phone.QSTileHost;
 import com.android.systemui.statusbar.phone.SystemUIDialog;
@@ -78,6 +81,10 @@
         }
     }
 
+    public void onConfigurationChanged() {
+        FontSizeUtils.updateFontSize(mFooterText, R.dimen.qs_tile_text_size);
+    }
+
     public View getView() {
         return mRootView;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index a2136d2..fac37e5 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -21,15 +21,19 @@
 import android.animation.AnimatorListenerAdapter;
 import android.content.Context;
 import android.content.Intent;
+import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.os.Handler;
 import android.os.Message;
 import android.util.AttributeSet;
+import android.util.TypedValue;
 import android.view.LayoutInflater;
 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 com.android.systemui.qs.QSTile.DetailAdapter;
 import com.android.systemui.settings.BrightnessController;
@@ -48,8 +52,8 @@
     private final ArrayList<TileRecord> mRecords = new ArrayList<TileRecord>();
     private final View mDetail;
     private final ViewGroup mDetailContent;
-    private final View mDetailSettingsButton;
-    private final View mDetailDoneButton;
+    private final TextView mDetailSettingsButton;
+    private final TextView mDetailDoneButton;
     private final View mBrightnessView;
     private final QSDetailClipper mClipper;
     private final H mHandler = new H();
@@ -83,8 +87,8 @@
 
         mDetail = LayoutInflater.from(context).inflate(R.layout.qs_detail, this, false);
         mDetailContent = (ViewGroup) mDetail.findViewById(android.R.id.content);
-        mDetailSettingsButton = mDetail.findViewById(android.R.id.button2);
-        mDetailDoneButton = mDetail.findViewById(android.R.id.button1);
+        mDetailSettingsButton = (TextView) mDetail.findViewById(android.R.id.button2);
+        mDetailDoneButton = (TextView) mDetail.findViewById(android.R.id.button1);
         mDetail.setVisibility(GONE);
         mDetail.setClickable(true);
         mBrightnessView = LayoutInflater.from(context).inflate(
@@ -148,6 +152,24 @@
         }
     }
 
+    @Override
+    protected void onConfigurationChanged(Configuration newConfig) {
+        super.onConfigurationChanged(newConfig);
+        FontSizeUtils.updateFontSize(mDetailDoneButton, R.dimen.qs_detail_button_text_size);
+        FontSizeUtils.updateFontSize(mDetailSettingsButton, R.dimen.qs_detail_button_text_size);
+
+        // We need to poke the detail views as well as they might not be attached to the view
+        // hierarchy but reused at a later point.
+        int count = mRecords.size();
+        for (int i = 0; i < count; i++) {
+            View detailView = mRecords.get(i).detailView;
+            if (detailView != null) {
+                detailView.dispatchConfigurationChanged(newConfig);
+            }
+        }
+        mFooter.onConfigurationChanged();
+    }
+
     public void setExpanded(boolean expanded) {
         if (mExpanded == expanded) return;
         mExpanded = expanded;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
index 20fd5a0..06d6401 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
@@ -17,6 +17,7 @@
 package com.android.systemui.qs;
 
 import android.content.Context;
+import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.graphics.Typeface;
@@ -25,6 +26,7 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
+import android.util.MathUtils;
 import android.util.TypedValue;
 import android.view.Gravity;
 import android.view.View;
@@ -33,6 +35,7 @@
 import android.widget.ImageView.ScaleType;
 import android.widget.TextView;
 
+import com.android.systemui.FontSizeUtils;
 import com.android.systemui.R;
 import com.android.systemui.qs.QSTile.State;
 
@@ -47,7 +50,7 @@
     private final H mHandler = new H();
     private final int mIconSizePx;
     private final int mTileSpacingPx;
-    private final int mTilePaddingTopPx;
+    private int mTilePaddingTopPx;
     private final int mTilePaddingBelowIconPx;
     private final int mDualTileVerticalPaddingPx;
     private final View mTopBackgroundView;
@@ -66,7 +69,6 @@
         final Resources res = context.getResources();
         mIconSizePx = res.getDimensionPixelSize(R.dimen.qs_tile_icon_size);
         mTileSpacingPx = res.getDimensionPixelSize(R.dimen.qs_tile_spacing);
-        mTilePaddingTopPx = res.getDimensionPixelSize(R.dimen.qs_tile_padding_top);
         mTilePaddingBelowIconPx =  res.getDimensionPixelSize(R.dimen.qs_tile_padding_below_icon);
         mDualTileVerticalPaddingPx =
                 res.getDimensionPixelSize(R.dimen.qs_dual_tile_padding_vertical);
@@ -86,6 +88,29 @@
         addView(mDivider);
 
         setClickable(true);
+
+        updateTopPadding();
+    }
+
+    private 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);
+        requestLayout();
+    }
+
+    @Override
+    protected void onConfigurationChanged(Configuration newConfig) {
+        super.onConfigurationChanged(newConfig);
+        updateTopPadding();
+        FontSizeUtils.updateFontSize(mLabel, R.dimen.qs_tile_text_size);
+        if (mDualLabel != null) {
+            mDualLabel.setTextSize(TypedValue.COMPLEX_UNIT_PX,
+                    getResources().getDimensionPixelSize(R.dimen.qs_tile_text_size));
+        }
     }
 
     private void recreateLabel() {
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 ce42d47..a7b6ca6 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
@@ -189,11 +189,6 @@
     };
 
     private final class CellularDetailAdapter implements DetailAdapter {
-        private static final double KB = 1024;
-        private static final double MB = 1024 * KB;
-        private static final double GB = 1024 * MB;
-
-        private final DecimalFormat FORMAT = new DecimalFormat("#.##");
 
         @Override
         public int getTitle() {
@@ -217,80 +212,17 @@
 
         @Override
         public View createDetailView(Context context, View convertView, ViewGroup parent) {
-            final View v = convertView != null ? convertView : LayoutInflater.from(mContext)
-                    .inflate(R.layout.data_usage, parent, false);
+            final DataUsageDetailView v = (DataUsageDetailView) (convertView != null
+                    ? convertView
+                    : LayoutInflater.from(mContext).inflate(R.layout.data_usage, parent, false));
             final DataUsageInfo info = mController.getDataUsageInfo();
             if (info == null) return v;
-            final Resources res = mContext.getResources();
-            final int titleId;
-            final long bytes;
-            int usageColor = R.color.system_accent_color;
-            final String top;
-            String bottom = null;
-            if (info.usageLevel < info.warningLevel || info.limitLevel <= 0) {
-                // under warning, or no limit
-                titleId = R.string.quick_settings_cellular_detail_data_usage;
-                bytes = info.usageLevel;
-                top = res.getString(R.string.quick_settings_cellular_detail_data_warning,
-                        formatBytes(info.warningLevel));
-            } else if (info.usageLevel <= info.limitLevel) {
-                // over warning, under limit
-                titleId = R.string.quick_settings_cellular_detail_remaining_data;
-                bytes = info.limitLevel - info.usageLevel;
-                top = res.getString(R.string.quick_settings_cellular_detail_data_used,
-                        formatBytes(info.usageLevel));
-                bottom = res.getString(R.string.quick_settings_cellular_detail_data_limit,
-                        formatBytes(info.limitLevel));
-            } else {
-                // over limit
-                titleId = R.string.quick_settings_cellular_detail_over_limit;
-                bytes = info.usageLevel - info.limitLevel;
-                top = res.getString(R.string.quick_settings_cellular_detail_data_used,
-                        formatBytes(info.usageLevel));
-                bottom = res.getString(R.string.quick_settings_cellular_detail_data_limit,
-                        formatBytes(info.limitLevel));
-                usageColor = R.color.system_warning_color;
-            }
-
-            final TextView title = (TextView) v.findViewById(android.R.id.title);
-            title.setText(titleId);
-            final TextView usage = (TextView) v.findViewById(R.id.usage_text);
-            usage.setText(formatBytes(bytes));
-            usage.setTextColor(res.getColor(usageColor));
-            final DataUsageGraph graph = (DataUsageGraph) v.findViewById(R.id.usage_graph);
-            graph.setLevels(info.limitLevel, info.warningLevel, info.usageLevel);
-            final TextView carrier = (TextView) v.findViewById(R.id.usage_carrier_text);
-            carrier.setText(info.carrier);
-            final TextView period = (TextView) v.findViewById(R.id.usage_period_text);
-            period.setText(info.period);
-            final TextView infoTop = (TextView) v.findViewById(R.id.usage_info_top_text);
-            infoTop.setVisibility(top != null ? View.VISIBLE : View.GONE);
-            infoTop.setText(top);
-            final TextView infoBottom = (TextView) v.findViewById(R.id.usage_info_bottom_text);
-            infoBottom.setVisibility(bottom != null ? View.VISIBLE : View.GONE);
-            infoBottom.setText(bottom);
+            v.bind(info);
             return v;
         }
 
         public void setMobileDataEnabled(boolean enabled) {
             fireToggleStateChanged(enabled);
         }
-
-        private String formatBytes(long bytes) {
-            final long b = Math.abs(bytes);
-            double val;
-            String suffix;
-            if (b > 100 * MB) {
-                val = b / GB;
-                suffix = "GB";
-            } else if (b > 100 * KB) {
-                val = b / MB;
-                suffix = "MB";
-            } else {
-                val = b / KB;
-                suffix = "KB";
-            }
-            return FORMAT.format(val * (bytes < 0 ? -1 : 1)) + " " + suffix;
-        }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DataUsageDetailView.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DataUsageDetailView.java
new file mode 100644
index 0000000..7bdb58f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DataUsageDetailView.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.qs.tiles;
+
+import android.content.Context;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.util.AttributeSet;
+import android.util.TypedValue;
+import android.view.View;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.android.systemui.FontSizeUtils;
+import com.android.systemui.R;
+import com.android.systemui.qs.DataUsageGraph;
+import com.android.systemui.statusbar.policy.NetworkController;
+
+import java.text.DecimalFormat;
+
+/**
+ * Layout for the data usage detail in quick settings.
+ */
+public class DataUsageDetailView extends LinearLayout {
+
+    private static final double KB = 1024;
+    private static final double MB = 1024 * KB;
+    private static final double GB = 1024 * MB;
+
+    private final DecimalFormat FORMAT = new DecimalFormat("#.##");
+
+    public DataUsageDetailView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    @Override
+    protected void onConfigurationChanged(Configuration newConfig) {
+        super.onConfigurationChanged(newConfig);
+        FontSizeUtils.updateFontSize(this, android.R.id.title, R.dimen.qs_data_usage_text_size);
+        FontSizeUtils.updateFontSize(this, R.id.usage_text, R.dimen.qs_data_usage_usage_text_size);
+        FontSizeUtils.updateFontSize(this, R.id.usage_carrier_text,
+                R.dimen.qs_data_usage_text_size);
+        FontSizeUtils.updateFontSize(this, R.id.usage_info_top_text,
+                R.dimen.qs_data_usage_text_size);
+        FontSizeUtils.updateFontSize(this, R.id.usage_period_text, R.dimen.qs_data_usage_text_size);
+        FontSizeUtils.updateFontSize(this, R.id.usage_info_bottom_text,
+                R.dimen.qs_data_usage_text_size);
+    }
+
+    public void bind(NetworkController.DataUsageInfo info) {
+        final Resources res = mContext.getResources();
+        final int titleId;
+        final long bytes;
+        int usageColor = R.color.system_accent_color;
+        final String top;
+        String bottom = null;
+        if (info.usageLevel < info.warningLevel || info.limitLevel <= 0) {
+            // under warning, or no limit
+            titleId = R.string.quick_settings_cellular_detail_data_usage;
+            bytes = info.usageLevel;
+            top = res.getString(R.string.quick_settings_cellular_detail_data_warning,
+                    formatBytes(info.warningLevel));
+        } else if (info.usageLevel <= info.limitLevel) {
+            // over warning, under limit
+            titleId = R.string.quick_settings_cellular_detail_remaining_data;
+            bytes = info.limitLevel - info.usageLevel;
+            top = res.getString(R.string.quick_settings_cellular_detail_data_used,
+                    formatBytes(info.usageLevel));
+            bottom = res.getString(R.string.quick_settings_cellular_detail_data_limit,
+                    formatBytes(info.limitLevel));
+        } else {
+            // over limit
+            titleId = R.string.quick_settings_cellular_detail_over_limit;
+            bytes = info.usageLevel - info.limitLevel;
+            top = res.getString(R.string.quick_settings_cellular_detail_data_used,
+                    formatBytes(info.usageLevel));
+            bottom = res.getString(R.string.quick_settings_cellular_detail_data_limit,
+                    formatBytes(info.limitLevel));
+            usageColor = R.color.system_warning_color;
+        }
+
+        final TextView title = (TextView) findViewById(android.R.id.title);
+        title.setText(titleId);
+        final TextView usage = (TextView) findViewById(R.id.usage_text);
+        usage.setText(formatBytes(bytes));
+        usage.setTextColor(res.getColor(usageColor));
+        final DataUsageGraph graph = (DataUsageGraph) findViewById(R.id.usage_graph);
+        graph.setLevels(info.limitLevel, info.warningLevel, info.usageLevel);
+        final TextView carrier = (TextView) findViewById(R.id.usage_carrier_text);
+        carrier.setText(info.carrier);
+        final TextView period = (TextView) findViewById(R.id.usage_period_text);
+        period.setText(info.period);
+        final TextView infoTop = (TextView) findViewById(R.id.usage_info_top_text);
+        infoTop.setVisibility(top != null ? View.VISIBLE : View.GONE);
+        infoTop.setText(top);
+        final TextView infoBottom = (TextView) findViewById(R.id.usage_info_bottom_text);
+        infoBottom.setVisibility(bottom != null ? View.VISIBLE : View.GONE);
+        infoBottom.setText(bottom);
+    }
+
+    private String formatBytes(long bytes) {
+        final long b = Math.abs(bytes);
+        double val;
+        String suffix;
+        if (b > 100 * MB) {
+            val = b / GB;
+            suffix = "GB";
+        } else if (b > 100 * KB) {
+            val = b / MB;
+            suffix = "MB";
+        } else {
+            val = b / KB;
+            suffix = "KB";
+        }
+        return FORMAT.format(val * (bytes < 0 ? -1 : 1)) + " " + suffix;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailItemView.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailItemView.java
index a56b7a7..c55cbcc 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailItemView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailItemView.java
@@ -17,15 +17,18 @@
 package com.android.systemui.qs.tiles;
 
 import com.android.internal.util.ArrayUtils;
+import com.android.systemui.FontSizeUtils;
 import com.android.systemui.R;
 import com.android.systemui.statusbar.phone.UserAvatarView;
 
 import android.content.Context;
+import android.content.res.Configuration;
 import android.content.res.TypedArray;
 import android.graphics.Bitmap;
 import android.graphics.Typeface;
 import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
+import android.util.TypedValue;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -107,6 +110,12 @@
     }
 
     @Override
+    protected void onConfigurationChanged(Configuration newConfig) {
+        super.onConfigurationChanged(newConfig);
+        FontSizeUtils.updateFontSize(mName, R.dimen.qs_detail_item_secondary_text_size);
+    }
+
+    @Override
     protected void drawableStateChanged() {
         super.drawableStateChanged();
         updateTypeface();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
index 938d888..e041de0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
@@ -20,11 +20,14 @@
 import android.app.PendingIntent;
 import android.content.Context;
 import android.content.Intent;
+import android.content.res.Configuration;
+import android.content.res.Resources;
 import android.graphics.Outline;
 import android.graphics.Rect;
 import android.graphics.drawable.Animatable;
 import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
+import android.util.MathUtils;
 import android.util.TypedValue;
 import android.view.View;
 import android.view.ViewGroup;
@@ -36,6 +39,7 @@
 import android.widget.TextView;
 
 import com.android.keyguard.KeyguardStatusView;
+import com.android.systemui.FontSizeUtils;
 import com.android.systemui.R;
 import com.android.systemui.qs.QSPanel;
 import com.android.systemui.qs.QSTile;
@@ -57,11 +61,11 @@
     private View mDateGroup;
     private View mClock;
     private TextView mTime;
-    private View mAmPm;
+    private TextView mAmPm;
     private MultiUserSwitch mMultiUserSwitch;
     private ImageView mMultiUserAvatar;
-    private View mDateCollapsed;
-    private View mDateExpanded;
+    private TextView mDateCollapsed;
+    private TextView mDateExpanded;
     private LinearLayout mSystemIcons;
     private View mStatusIcons;
     private View mSignalCluster;
@@ -70,7 +74,7 @@
     private TextView mQsDetailHeaderTitle;
     private Switch mQsDetailHeaderSwitch;
     private ImageView mQsDetailHeaderProgress;
-    private View mEmergencyCallsOnly;
+    private TextView mEmergencyCallsOnly;
     private TextView mBatteryLevel;
     private TextView mAlarmStatus;
 
@@ -129,11 +133,11 @@
         mDateGroup = findViewById(R.id.date_group);
         mClock = findViewById(R.id.clock);
         mTime = (TextView) findViewById(R.id.time_view);
-        mAmPm = findViewById(R.id.am_pm_view);
+        mAmPm = (TextView) findViewById(R.id.am_pm_view);
         mMultiUserSwitch = (MultiUserSwitch) findViewById(R.id.multi_user_switch);
         mMultiUserAvatar = (ImageView) findViewById(R.id.multi_user_avatar);
-        mDateCollapsed = findViewById(R.id.date_collapsed);
-        mDateExpanded = findViewById(R.id.date_expanded);
+        mDateCollapsed = (TextView) findViewById(R.id.date_collapsed);
+        mDateExpanded = (TextView) findViewById(R.id.date_expanded);
         mSettingsButton = findViewById(R.id.settings_button);
         mSettingsButton.setOnClickListener(this);
         mQsDetailHeader = findViewById(R.id.qs_detail_header);
@@ -141,7 +145,7 @@
         mQsDetailHeaderTitle = (TextView) mQsDetailHeader.findViewById(android.R.id.title);
         mQsDetailHeaderSwitch = (Switch) mQsDetailHeader.findViewById(android.R.id.toggle);
         mQsDetailHeaderProgress = (ImageView) findViewById(R.id.qs_detail_header_progress);
-        mEmergencyCallsOnly = findViewById(R.id.header_emergency_calls_only);
+        mEmergencyCallsOnly = (TextView) findViewById(R.id.header_emergency_calls_only);
         mBatteryLevel = (TextView) findViewById(R.id.battery_level);
         mAlarmStatus = (TextView) findViewById(R.id.alarm_status);
         mAlarmStatus.setOnClickListener(this);
@@ -187,6 +191,39 @@
         mAlarmStatus.setX(mDateGroup.getLeft() + mDateCollapsed.getRight());
     }
 
+    @Override
+    protected void onConfigurationChanged(Configuration newConfig) {
+        super.onConfigurationChanged(newConfig);
+        FontSizeUtils.updateFontSize(mBatteryLevel, R.dimen.battery_level_text_size);
+        FontSizeUtils.updateFontSize(mEmergencyCallsOnly,
+                R.dimen.qs_emergency_calls_only_text_size);
+        FontSizeUtils.updateFontSize(mDateCollapsed, R.dimen.qs_date_collapsed_size);
+        FontSizeUtils.updateFontSize(mDateExpanded, R.dimen.qs_date_collapsed_size);
+        FontSizeUtils.updateFontSize(mAlarmStatus, R.dimen.qs_date_collapsed_size);
+        FontSizeUtils.updateFontSize(this, android.R.id.title, R.dimen.qs_detail_header_text_size);
+        FontSizeUtils.updateFontSize(this, android.R.id.toggle, R.dimen.qs_detail_header_text_size);
+        FontSizeUtils.updateFontSize(mAmPm, R.dimen.qs_time_collapsed_size);
+        FontSizeUtils.updateFontSize(this, R.id.empty_time_view, R.dimen.qs_time_expanded_size);
+
+        mClockCollapsedSize = getResources().getDimensionPixelSize(R.dimen.qs_time_collapsed_size);
+        mClockExpandedSize = getResources().getDimensionPixelSize(R.dimen.qs_time_expanded_size);
+        mClockCollapsedScaleFactor = (float) mClockCollapsedSize / (float) mClockExpandedSize;
+
+        updateClockScale();
+        updateClockCollapsedMargin();
+    }
+
+    private void updateClockCollapsedMargin() {
+        Resources res = getResources();
+        int padding = res.getDimensionPixelSize(R.dimen.clock_collapsed_bottom_margin);
+        int largePadding = res.getDimensionPixelSize(
+                R.dimen.clock_collapsed_bottom_margin_large_text);
+        float largeFactor = (MathUtils.constrain(getResources().getConfiguration().fontScale, 1.0f,
+                FontSizeUtils.LARGE_TEXT_SCALE) - 1f) / (FontSizeUtils.LARGE_TEXT_SCALE - 1f);
+        mClockMarginBottomCollapsed = Math.round((1 - largeFactor) * padding + largeFactor * largePadding);
+        requestLayout();
+    }
+
     private void requestCaptureValues() {
         mCaptureValues = true;
         requestLayout();
@@ -200,11 +237,9 @@
                 getResources().getDimensionPixelSize(R.dimen.multi_user_switch_expanded_margin);
         mMultiUserCollapsedMargin =
                 getResources().getDimensionPixelSize(R.dimen.multi_user_switch_collapsed_margin);
-
         mClockMarginBottomExpanded =
                 getResources().getDimensionPixelSize(R.dimen.clock_expanded_bottom_margin);
-        mClockMarginBottomCollapsed =
-                getResources().getDimensionPixelSize(R.dimen.clock_collapsed_bottom_margin);
+        updateClockCollapsedMargin();
         mMultiUserSwitchWidthCollapsed =
                 getResources().getDimensionPixelSize(R.dimen.multi_user_switch_width_collapsed);
         mMultiUserSwitchWidthExpanded =
@@ -732,7 +767,9 @@
             final boolean showingDetail = detail != null;
             transition(mClock, !showingDetail);
             transition(mDateGroup, !showingDetail);
-            transition(mAlarmStatus, !showingDetail);
+            if (mAlarmShowing) {
+                transition(mAlarmStatus, !showingDetail);
+            }
             transition(mQsDetailHeader, showingDetail);
             mShowingDetail = showingDetail;
             if (showingDetail) {