example/ivy/android: use escapeHtmlTags in ivy output processing

Android App emulates terminal-like functionality in WebView by
appending the input and output lines of Ivy to the WebView HTML
document as a new div entry using javascript. The app used
Android's TextUtils.htmlEncode to get HTML escaped representation
of the input and output. Among those escaped characters, `&` is
included (HTML entity prefix).

Ivy's mobile.Eval returns lines that include HTML entities (e.g.
\ instead of backslash -- see
https://github.com/robpike/ivy/blob/master/mobile/mobile.go#L43)
TextUtils.htmlEncode escapes this `&` and as a result, the backslash
is left broken.

escapeHtmlTags is identical to TextUtils.htmlEncode except it
leaves the entity alone.

Change-Id: Ifec401f07b46f4c6aee6d8df7d61933ae8dbc666
Reviewed-on: https://go-review.googlesource.com/c/mobile/+/356731
Trust: Hyang-Ah Hana Kim <hyangah@gmail.com>
Trust: Peter Weinberger <pjw@google.com>
Run-TryBot: Hyang-Ah Hana Kim <hyangah@gmail.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Peter Weinberger <pjw@google.com>
diff --git a/example/ivy/android/app/src/main/java/org/golang/ivy/MainActivity.java b/example/ivy/android/app/src/main/java/org/golang/ivy/MainActivity.java
index 1a3c021..7cbf0b4 100644
--- a/example/ivy/android/app/src/main/java/org/golang/ivy/MainActivity.java
+++ b/example/ivy/android/app/src/main/java/org/golang/ivy/MainActivity.java
@@ -196,11 +196,49 @@
         });
     }
 
+    private String escapeHtmlTags(final String s) {
+        // Leaves entities (&-prefixed) alone unlike TextUtils.htmlEncode
+        // (https://github.com/aosp-mirror/platform_frameworks_base/blob/d59921149bb5948ffbcb9a9e832e9ac1538e05a0/core/java/android/text/TextUtils.java#L1361).
+        // Ivy mobile.Eval result may include encoding starting with &.
+
+        StringBuilder sb = new StringBuilder();
+        char c;
+        for (int i = 0; i < s.length(); i++) {
+            c = s.charAt(i);
+            switch (c) {
+                case '<':
+                    sb.append("&lt;"); //$NON-NLS-1$
+                    break;
+                case '>':
+                    sb.append("&gt;"); //$NON-NLS-1$
+                    break;
+                case '"':
+                    sb.append("&quot;"); //$NON-NLS-1$
+                    break;
+                case '\'':
+                    //http://www.w3.org/TR/xhtml1
+                    // The named character reference &apos; (the apostrophe, U+0027) was introduced in
+                    // XML 1.0 but does not appear in HTML. Authors should therefore use &#39; instead
+                    // of &apos; to work as expected in HTML 4 user agents.
+                    sb.append("&#39;"); //$NON-NLS-1$
+                    break;
+                default:
+                    sb.append(c);
+            }
+        }
+        return sb.toString();
+    }
+
     private void appendShowText(final String s, final String tag) {
         mWebView.loadUrl("javascript:appendDiv('" + TextUtils.htmlEncode(s).replaceAll("(\r\n|\n)", "<br />") + "', '" + tag + "')");
         mWebView.setBackgroundColor(getResources().getColor(R.color.body));
     }
 
+    private void appendShowPreformattedText(final String s, final String tag) {
+        mWebView.loadUrl("javascript:appendDiv('" + escapeHtmlTags(s).replaceAll("\r?\n", "<br/>") + "', '" + tag + "')");
+        mWebView.setBackgroundColor(getResources().getColor(R.color.body));
+    }
+
     private void callIvy() {
         String s = mEditText.getText().toString().trim();
         if (s != null && !s.isEmpty()) {
@@ -308,11 +346,8 @@
                 public void run() {
                     String showText = result.first;
                     if (showText != null) {
-                        if (showText.startsWith("#")) {
-                            appendShowText(showText, "comment");
-                        } else {
-                            appendShowText(showText, "result");
-                        }
+                        final String tag = (showText.startsWith("#")) ? "comment" : "result";
+                        appendShowPreformattedText(showText, tag);
                     }
                     String editText = result.second;
                     if (editText != null) {