fix UI Automator dump tool issues

AOSP bug 58733: NPE while dumping hierarchy
AOSP bug 62906: smileys (surrogates) causing dump tool to crash

Change-Id: Ia57686163dca3b27ee291f3114f15af98e50d914
diff --git a/uiautomator/library/core-src/com/android/uiautomator/core/AccessibilityNodeInfoDumper.java b/uiautomator/library/core-src/com/android/uiautomator/core/AccessibilityNodeInfoDumper.java
index 63c51e8..59616c8 100644
--- a/uiautomator/library/core-src/com/android/uiautomator/core/AccessibilityNodeInfoDumper.java
+++ b/uiautomator/library/core-src/com/android/uiautomator/core/AccessibilityNodeInfoDumper.java
@@ -197,6 +197,11 @@
         for (int x = 0; x < childCount; x++) {
             AccessibilityNodeInfo childNode = node.getChild(x);
 
+            if (childNode == null) {
+                Log.i(LOGTAG, String.format("Null child %d/%d, parent: %s",
+                        x, childCount, node.toString()));
+                continue;
+            }
             if (!safeCharSeqToString(childNode.getContentDescription()).isEmpty()
                     || !safeCharSeqToString(childNode.getText()).isEmpty())
                 return true;
@@ -216,34 +221,26 @@
     }
 
     private static String stripInvalidXMLChars(CharSequence cs) {
-        StringBuffer ret = new StringBuffer();
+        StringBuilder ret = new StringBuilder();
         char ch;
-        /* http://www.w3.org/TR/xml11/#charsets
-        [#x1-#x8], [#xB-#xC], [#xE-#x1F], [#x7F-#x84], [#x86-#x9F], [#xFDD0-#xFDDF],
-        [#x1FFFE-#x1FFFF], [#x2FFFE-#x2FFFF], [#x3FFFE-#x3FFFF],
-        [#x4FFFE-#x4FFFF], [#x5FFFE-#x5FFFF], [#x6FFFE-#x6FFFF],
-        [#x7FFFE-#x7FFFF], [#x8FFFE-#x8FFFF], [#x9FFFE-#x9FFFF],
-        [#xAFFFE-#xAFFFF], [#xBFFFE-#xBFFFF], [#xCFFFE-#xCFFFF],
-        [#xDFFFE-#xDFFFF], [#xEFFFE-#xEFFFF], [#xFFFFE-#xFFFFF],
-        [#x10FFFE-#x10FFFF].
-         */
         for (int i = 0; i < cs.length(); i++) {
             ch = cs.charAt(i);
 
-            if((ch >= 0x1 && ch <= 0x8) || (ch >= 0xB && ch <= 0xC) || (ch >= 0xE && ch <= 0x1F) ||
-                    (ch >= 0x7F && ch <= 0x84) || (ch >= 0x86 && ch <= 0x9f) ||
-                    (ch >= 0xFDD0 && ch <= 0xFDDF) || (ch >= 0x1FFFE && ch <= 0x1FFFF) ||
-                    (ch >= 0x2FFFE && ch <= 0x2FFFF) || (ch >= 0x3FFFE && ch <= 0x3FFFF) ||
-                    (ch >= 0x4FFFE && ch <= 0x4FFFF) || (ch >= 0x5FFFE && ch <= 0x5FFFF) ||
-                    (ch >= 0x6FFFE && ch <= 0x6FFFF) || (ch >= 0x7FFFE && ch <= 0x7FFFF) ||
-                    (ch >= 0x8FFFE && ch <= 0x8FFFF) || (ch >= 0x9FFFE && ch <= 0x9FFFF) ||
-                    (ch >= 0xAFFFE && ch <= 0xAFFFF) || (ch >= 0xBFFFE && ch <= 0xBFFFF) ||
-                    (ch >= 0xCFFFE && ch <= 0xCFFFF) || (ch >= 0xDFFFE && ch <= 0xDFFFF) ||
-                    (ch >= 0xEFFFE && ch <= 0xEFFFF) || (ch >= 0xFFFFE && ch <= 0xFFFFF) ||
-                    (ch >= 0x10FFFE && ch <= 0x10FFFF))
-                ret.append(".");
-            else
+            // code below from Html#withinStyle, this is a temporary workaround because XML
+            // serializer does not support surrogates
+            if (ch >= 0xD800 && ch <= 0xDFFF) {
+                if (ch < 0xDC00 && i + 1 < cs.length()) {
+                    char d = cs.charAt(i + 1);
+                    if (d >= 0xDC00 && d <= 0xDFFF) {
+                        i++;
+                        ret.append("?");
+                    }
+                }
+            } else if (ch > 0x7E || ch < ' ') {
+                ret.append("?");
+            } else {
                 ret.append(ch);
+            }
         }
         return ret.toString();
     }