Make <font size> and <font height> in string resources respect density.

This unfortunately requires API changes because the existing text markup
classes had no access to the screen density.

TextPaint gains a "density" field so that TextView can pass the density
along.  AbsoluteSizeSpan gains a new flag to indicate that its argument
is in dip instead of in physical pixels.  LineHeightSpan gains an inner
interface whose chooseHeight() method includes a TextPaint argument so
it can get at the density.  And when StringBlock creates the markup
objects, it now uses the density-aware versions.

Bug 1976971, Bug 2031746
diff --git a/api/current.xml b/api/current.xml
index 397e25d..7d1e8e8 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -130128,6 +130128,16 @@
  visibility="public"
 >
 </field>
+<field name="density"
+ type="float"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="drawableState"
  type="int[]"
  transient="false"
@@ -135126,6 +135136,18 @@
  deprecated="not deprecated"
  visibility="public"
 >
+<parameter name="size" type="int">
+</parameter>
+<parameter name="dip" type="boolean">
+</parameter>
+</constructor>
+<constructor name="AbsoluteSizeSpan"
+ type="android.text.style.AbsoluteSizeSpan"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
 <parameter name="src" type="android.os.Parcel">
 </parameter>
 </constructor>
@@ -135140,6 +135162,17 @@
  visibility="public"
 >
 </method>
+<method name="getDip"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getSize"
  return="int"
  abstract="false"
@@ -136530,6 +136563,41 @@
 </parameter>
 </method>
 </interface>
+<interface name="LineHeightSpan.WithDensity"
+ abstract="true"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="android.text.style.LineHeightSpan">
+</implements>
+<method name="chooseHeight"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="text" type="java.lang.CharSequence">
+</parameter>
+<parameter name="start" type="int">
+</parameter>
+<parameter name="end" type="int">
+</parameter>
+<parameter name="spanstartv" type="int">
+</parameter>
+<parameter name="v" type="int">
+</parameter>
+<parameter name="fm" type="android.graphics.Paint.FontMetricsInt">
+</parameter>
+<parameter name="paint" type="android.text.TextPaint">
+</parameter>
+</method>
+</interface>
 <class name="MaskFilterSpan"
  extends="android.text.style.CharacterStyle"
  abstract="false"
diff --git a/core/java/android/content/res/StringBlock.java b/core/java/android/content/res/StringBlock.java
index e684cb8..8fb82be 100644
--- a/core/java/android/content/res/StringBlock.java
+++ b/core/java/android/content/res/StringBlock.java
@@ -202,7 +202,7 @@
                     sub = subtag(tag, ";size=");
                     if (sub != null) {
                         int size = Integer.parseInt(sub);
-                        buffer.setSpan(new AbsoluteSizeSpan(size),
+                        buffer.setSpan(new AbsoluteSizeSpan(size, true),
                                        style[i+1], style[i+2]+1,
                                        Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
                     }
@@ -310,7 +310,7 @@
      * the ascent if possible, or the descent if shrinking the ascent further
      * will make the text unreadable.
      */
-    private static class Height implements LineHeightSpan {
+    private static class Height implements LineHeightSpan.WithDensity {
         private int mSize;
         private static float sProportion = 0;
 
@@ -321,9 +321,21 @@
         public void chooseHeight(CharSequence text, int start, int end,
                                  int spanstartv, int v,
                                  Paint.FontMetricsInt fm) {
-            if (fm.bottom - fm.top < mSize) {
-                fm.top = fm.bottom - mSize;
-                fm.ascent = fm.ascent - mSize;
+            // Should not get called, at least not by StaticLayout.
+            chooseHeight(text, start, end, spanstartv, v, fm, null);
+        }
+
+        public void chooseHeight(CharSequence text, int start, int end,
+                                 int spanstartv, int v,
+                                 Paint.FontMetricsInt fm, TextPaint paint) {
+            int size = mSize;
+            if (paint != null) {
+                size *= paint.density;
+            }
+
+            if (fm.bottom - fm.top < size) {
+                fm.top = fm.bottom - size;
+                fm.ascent = fm.ascent - size;
             } else {
                 if (sProportion == 0) {
                     /*
@@ -343,27 +355,27 @@
 
                 int need = (int) Math.ceil(-fm.top * sProportion);
 
-                if (mSize - fm.descent >= need) {
+                if (size - fm.descent >= need) {
                     /*
                      * It is safe to shrink the ascent this much.
                      */
 
-                    fm.top = fm.bottom - mSize;
-                    fm.ascent = fm.descent - mSize;
-                } else if (mSize >= need) {
+                    fm.top = fm.bottom - size;
+                    fm.ascent = fm.descent - size;
+                } else if (size >= need) {
                     /*
                      * We can't show all the descent, but we can at least
                      * show all the ascent.
                      */
 
                     fm.top = fm.ascent = -need;
-                    fm.bottom = fm.descent = fm.top + mSize;
+                    fm.bottom = fm.descent = fm.top + size;
                 } else {
                     /*
                      * Show as much of the ascent as we can, and no descent.
                      */
 
-                    fm.top = fm.ascent = -mSize;
+                    fm.top = fm.ascent = -size;
                     fm.bottom = fm.descent = 0;
                 }
             }
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index c133cf2..f0a5ffd 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -968,7 +968,13 @@
             fm.bottom = bottom;
 
             for (int i = 0; i < chooseht.length; i++) {
-                chooseht[i].chooseHeight(text, start, end, choosehtv[i], v, fm);
+                if (chooseht[i] instanceof LineHeightSpan.WithDensity) {
+                    ((LineHeightSpan.WithDensity) chooseht[i]).
+                        chooseHeight(text, start, end, choosehtv[i], v, fm, paint);
+
+                } else {
+                    chooseht[i].chooseHeight(text, start, end, choosehtv[i], v, fm);
+                }
             }
 
             above = fm.ascent;
diff --git a/core/java/android/text/TextPaint.java b/core/java/android/text/TextPaint.java
index f13820d..f9e7cac 100644
--- a/core/java/android/text/TextPaint.java
+++ b/core/java/android/text/TextPaint.java
@@ -27,6 +27,7 @@
     public int baselineShift;
     public int linkColor;
     public int[] drawableState;
+    public float density = 1.0f;
 
     public TextPaint() {
         super();
@@ -51,5 +52,6 @@
         baselineShift = tp.baselineShift;
         linkColor = tp.linkColor;
         drawableState = tp.drawableState;
+        density = tp.density;
     }
 }
diff --git a/core/java/android/text/style/AbsoluteSizeSpan.java b/core/java/android/text/style/AbsoluteSizeSpan.java
index 484f8ce..1214040 100644
--- a/core/java/android/text/style/AbsoluteSizeSpan.java
+++ b/core/java/android/text/style/AbsoluteSizeSpan.java
@@ -24,13 +24,28 @@
 public class AbsoluteSizeSpan extends MetricAffectingSpan implements ParcelableSpan {
 
     private final int mSize;
+    private boolean mDip;
 
+    /**
+     * Set the text size to <code>size</code> physical pixels.
+     */
     public AbsoluteSizeSpan(int size) {
         mSize = size;
     }
 
+    /**
+     * Set the text size to <code>size</code> physical pixels,
+     * or to <code>size</code> device-independent pixels if
+     * <code>dip</code> is true.
+     */
+    public AbsoluteSizeSpan(int size, boolean dip) {
+        mSize = size;
+        mDip = dip;
+    }
+
     public AbsoluteSizeSpan(Parcel src) {
         mSize = src.readInt();
+        mDip = src.readInt() != 0;
     }
     
     public int getSpanTypeId() {
@@ -43,19 +58,32 @@
 
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeInt(mSize);
+        dest.writeInt(mDip ? 1 : 0);
     }
 
     public int getSize() {
         return mSize;
     }
 
+    public boolean getDip() {
+        return mDip;
+    }
+
     @Override
     public void updateDrawState(TextPaint ds) {
-        ds.setTextSize(mSize);
+        if (mDip) {
+            ds.setTextSize(mSize * ds.density);
+        } else {
+            ds.setTextSize(mSize);
+        }
     }
 
     @Override
     public void updateMeasureState(TextPaint ds) {
-        ds.setTextSize(mSize);
+        if (mDip) {
+            ds.setTextSize(mSize * ds.density);
+        } else {
+            ds.setTextSize(mSize);
+        }
     }
 }
diff --git a/core/java/android/text/style/LineHeightSpan.java b/core/java/android/text/style/LineHeightSpan.java
index c0ef97c..44a1706 100644
--- a/core/java/android/text/style/LineHeightSpan.java
+++ b/core/java/android/text/style/LineHeightSpan.java
@@ -19,6 +19,7 @@
 import android.graphics.Paint;
 import android.graphics.Canvas;
 import android.text.Layout;
+import android.text.TextPaint;
 
 public interface LineHeightSpan
 extends ParagraphStyle, WrapTogetherSpan
@@ -26,4 +27,10 @@
     public void chooseHeight(CharSequence text, int start, int end,
                              int spanstartv, int v,
                              Paint.FontMetricsInt fm);
+
+    public interface WithDensity extends LineHeightSpan {
+        public void chooseHeight(CharSequence text, int start, int end,
+                                 int spanstartv, int v,
+                                 Paint.FontMetricsInt fm, TextPaint paint);
+    }
 }
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 591f9bb..e0a268e 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -327,6 +327,7 @@
         mText = "";
 
         mTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
+        mTextPaint.density = getResources().getDisplayMetrics().density;
         // If we get the paint from the skin, we should set it to left, since
         // the layout always wants it to be left.
         // mTextPaint.setTextAlign(Paint.Align.LEFT);