Add a folder index view in debug mode

Change-Id: I67bb28d95cbe5ab6cf361271b46acc44398f188e
diff --git a/res/raw/folder_view.ktpl b/res/raw/folder_view.ktpl
new file mode 100644
index 0000000..2f360cc
--- /dev/null
+++ b/res/raw/folder_view.ktpl
@@ -0,0 +1,97 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

+

+<html>

+<head>

+<title>Index of <%= path %></title>

+<meta name="viewport" content="width=device-width; initial-scale=1.0; user-scalable=0" />

+

+<style type="text/css">

+

+* {

+    padding: 0;

+    margin: 0;

+}

+

+body {

+    padding: 0 8px 0 8px;

+}

+

+.table {

+    border-collapse: collapse;

+}

+

+tr.header {

+    font-weight: bold;

+}

+

+tr.alt {

+    background: #EEE;

+}

+

+td.details {

+    padding-left: 2em;

+    text-align: right;

+    white-space: nowrap;

+}

+

+.row {

+    padding: 8px 0 8px 8px;

+    display: block;

+    text-decoration: none;

+}

+

+h2 {

+    padding-top: 8px;

+    padding-bottom: 8px;

+}

+

+.icon {

+    padding-left: 1.5em;

+}

+

+.file {

+    background : url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAABnRSTlMAAAAAAABupgeRAAABHUlEQVR42o2RMW7DIBiF3498iHRJD5JKHurL+CRVBp+i2T16tTynF2gO0KSb5ZrBBl4HHDBuK/WXACH4eO9/CAAAbdvijzLGNE1TVZXfZuHg6XCAQESAZXbOKaXO57eiKG6ft9PrKQIkCQqFoIiQFBGlFIB5nvM8t9aOX2Nd18oDzjnPgCDpn/BH4zh2XZdlWVmWiUK4IgCBoFMUz9eP6zRN75cLgEQhcmTQIbl72O0f9865qLAAsURAAgKBJKEtgLXWvyjLuFsThCSstb8rBCaAQhDYWgIZ7myM+TUBjDHrHlZcbMYYk34cN0YSLcgS+wL0fe9TXDMbY33fR2AYBvyQ8L0Gk8MwREBrTfKe4TpTzwhArXWi8HI84h/1DfwI5mhxJamFAAAAAElFTkSuQmCC ") left top no-repeat;

+}

+

+.dir {

+    background : url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAd5JREFUeNqMU79rFUEQ/vbuodFEEkzAImBpkUabFP4ldpaJhZXYm/RiZWsv/hkWFglBUyTIgyAIIfgIRjHv3r39MePM7N3LcbxAFvZ2b2bn22/mm3XMjF+HL3YW7q28YSIw8mBKoBihhhgCsoORot9d3/ywg3YowMXwNde/PzGnk2vn6PitrT+/PGeNaecg4+qNY3D43vy16A5wDDd4Aqg/ngmrjl/GoN0U5V1QquHQG3q+TPDVhVwyBffcmQGJmSVfyZk7R3SngI4JKfwDJ2+05zIg8gbiereTZRHhJ5KCMOwDFLjhoBTn2g0ghagfKeIYJDPFyibJVBtTREwq60SpYvh5++PpwatHsxSm9QRLSQpEVSd7/TYJUb49TX7gztpjjEffnoVw66+Ytovs14Yp7HaKmUXeX9rKUoMoLNW3srqI5fWn8JejrVkK0QcrkFLOgS39yoKUQe292WJ1guUHG8K2o8K00oO1BTvXoW4yasclUTgZYJY9aFNfAThX5CZRmczAV52oAPoupHhWRIUUAOoyUIlYVaAa/VbLbyiZUiyFbjQFNwiZQSGl4IDy9sO5Wrty0QLKhdZPxmgGcDo8ejn+c/6eiK9poz15Kw7Dr/vN/z6W7q++091/AQYA5mZ8GYJ9K0AAAAAASUVORK5CYII= ") left top no-repeat;

+}

+

+.up {

+    background : url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAmlJREFUeNpsU0toU0EUPfPysx/tTxuDH9SCWhUDooIbd7oRUUTMouqi2iIoCO6lceHWhegy4EJFinWjrlQUpVm0IIoFpVDEIthm0dpikpf3ZuZ6Z94nrXhhMjM3c8895977BBHB2PznK8WPtDgyWH5q77cPH8PpdXuhpQT4ifR9u5sfJb1bmw6VivahATDrxcRZ2njfoaMv+2j7mLDn93MPiNRMvGbL18L9IpF8h9/TN+EYkMffSiOXJ5+hkD+PdqcLpICWHOHc2CC+LEyA/K+cKQMnlQHJX8wqYG3MAJy88Wa4OLDvEqAEOpJd0LxHIMdHBziowSwVlF8D6QaicK01krw/JynwcKoEwZczewroTvZirlKJs5CqQ5CG8pb57FnJUA0LYCXMX5fibd+p8LWDDemcPZbzQyjvH+Ki1TlIciElA7ghwLKV4kRZstt2sANWRjYTAGzuP2hXZFpJ/GsxgGJ0ox1aoFWsDXyyxqCs26+ydmagFN/rRjymJ1898bzGzmQE0HCZpmk5A0RFIv8Pn0WYPsiu6t/Rsj6PauVTwffTSzGAGZhUG2F06hEc9ibS7OPMNp6ErYFlKavo7MkhmTqCxZ/jwzGA9Hx82H2BZSw1NTN9Gx8ycHkajU/7M+jInsDC7DiaEmo1bNl1AMr9ASFgqVu9MCTIzoGUimXVAnnaN0PdBBDCCYbEtMk6wkpQwIG0sn0PQIUF4GsTwLSIFKNqF6DVrQq+IWVrQDxAYQC/1SsYOI4pOxKZrfifiUSbDUisif7XlpGIPufXd/uvdvZm760M0no1FZcnrzUdjw7au3vu/BVgAFLXeuTxhTXVAAAAAElFTkSuQmCC ") left top no-repeat;

+}

+

+</style>

+

+</head>

+<body>

+    <h2>Index of <%= path %></h2>

+    <table class="table">

+        <tr class="header">

+            <td>Name</th>

+            <td class="details">Size</th>

+            <td class="details">Date Modified</th>

+        </tr>

+        <tr>

+            <td>

+                <a href="<%= parent_url %>" class="row">

+                    <span class="icon up">[parent directory]</span>

+                </a>

+            </td>

+            <td class="details"></td>

+            <td class="details"></td>

+        </tr>

+        <%{ files %>

+            <tr class="<%= alt %>">

+                <td>

+                    <a href="<%= url %>" class="row">

+                        <span class="icon <%= type %>"><%= name %></span>

+                    </a>

+                </td>

+                <td class="details"><%= size %></td>

+                <td class="details"><%= last_modified %></td>

+            </tr>

+        <%} files %>

+    </table>

+</body>

+</html>

diff --git a/src/com/android/browser/homepages/HomeProvider.java b/src/com/android/browser/homepages/HomeProvider.java
index 98fcfbe..49ae694 100644
--- a/src/com/android/browser/homepages/HomeProvider.java
+++ b/src/com/android/browser/homepages/HomeProvider.java
@@ -16,8 +16,6 @@
  */

 package com.android.browser.homepages;

 

-import com.android.browser.BrowserSettings;

-

 import android.content.ContentProvider;

 import android.content.ContentValues;

 import android.content.Context;

@@ -28,8 +26,13 @@
 import android.util.Log;

 import android.webkit.WebResourceResponse;

 

+import com.android.browser.BrowserSettings;

+

+import java.io.File;

 import java.io.IOException;

 import java.io.InputStream;

+import java.io.PipedInputStream;

+import java.io.PipedOutputStream;

 

 public class HomeProvider extends ContentProvider {

 

@@ -95,8 +98,27 @@
                     return new WebResourceResponse("text/html", "utf-8", ins);

                 }

             }

+            boolean listFiles = BrowserSettings.getInstance().isDebugEnabled();

+            if (listFiles && interceptFile(url)) {

+                PipedInputStream ins = new PipedInputStream();

+                PipedOutputStream outs = new PipedOutputStream(ins);

+                new RequestHandler(context, Uri.parse(url), outs).start();

+                return new WebResourceResponse("text/html", "utf-8", ins);

+            }

         } catch (Exception e) {}

         return null;

     }

 

+    private static boolean interceptFile(String url) {

+        if (!url.startsWith("file:///")) {

+            return false;

+        }

+        String fpath = url.substring(7);

+        File f = new File(fpath);

+        if (!f.isDirectory()) {

+            return false;

+        }

+        return true;

+    }

+

 }

diff --git a/src/com/android/browser/homepages/RequestHandler.java b/src/com/android/browser/homepages/RequestHandler.java
index 3eb58e6..1ae5b3e 100644
--- a/src/com/android/browser/homepages/RequestHandler.java
+++ b/src/com/android/browser/homepages/RequestHandler.java
@@ -29,10 +29,14 @@
 import android.util.Log;

 

 import com.android.browser.R;

+import com.android.browser.homepages.Template.ListEntityIterator;

 

+import java.io.File;

 import java.io.IOException;

 import java.io.InputStream;

 import java.io.OutputStream;

+import java.text.DateFormat;

+import java.text.DecimalFormat;

 import java.util.regex.Matcher;

 import java.util.regex.Pattern;

 

@@ -71,6 +75,10 @@
     }

 

     void doHandleRequest() throws IOException {

+        if ("file".equals(mUri.getScheme())) {

+            writeFolderIndex();

+            return;

+        }

         int match = sUriMatcher.match(mUri);

         switch (match) {

         case INDEX:

@@ -127,6 +135,71 @@
         t.write(mOutput);

     }

 

+    void writeFolderIndex() throws IOException {

+        File f = new File(mUri.getPath());

+        final File[] files = f.listFiles();

+        Template t = Template.getCachedTemplate(mContext, R.raw.folder_view);

+        t.assign("path", mUri.getPath());

+        t.assign("parent_url", f.getParent() != null ? f.getParent() : f.getPath());

+        t.assignLoop("files", new ListEntityIterator() {

+            int index = -1;

+

+            @Override

+            public void writeValue(OutputStream stream, String key) throws IOException {

+                File f = files[index];

+                if ("name".equals(key)) {

+                    stream.write(f.getName().getBytes());

+                }

+                if ("url".equals(key)) {

+                    stream.write(("file://" + f.getAbsolutePath()).getBytes());

+                }

+                if ("type".equals(key)) {

+                    stream.write((f.isDirectory() ? "dir" : "file").getBytes());

+                }

+                if ("size".equals(key)) {

+                    if (f.isFile()) {

+                        stream.write(readableFileSize(f.length()).getBytes());

+                    }

+                }

+                if ("last_modified".equals(key)) {

+                    String date = DateFormat.getDateTimeInstance(

+                            DateFormat.SHORT, DateFormat.SHORT)

+                            .format(f.lastModified());

+                    stream.write(date.getBytes());

+                }

+                if ("alt".equals(key)) {

+                    if (index % 2 == 0) {

+                        stream.write("alt".getBytes());

+                    }

+                }

+            }

+

+            @Override

+            public ListEntityIterator getListIterator(String key) {

+                return null;

+            }

+

+            @Override

+            public void reset() {

+                index = -1;

+            }

+

+            @Override

+            public boolean moveToNext() {

+                return (++index) < files.length;

+            }

+        });

+        t.write(mOutput);

+    }

+

+    static String readableFileSize(long size) {

+        if(size <= 0) return "0";

+        final String[] units = new String[] { "B", "KB", "MB", "GB", "TB" };

+        int digitGroups = (int) (Math.log10(size) / Math.log10(1024));

+        return new DecimalFormat("#,##0.#").format(

+                size / Math.pow(1024, digitGroups)) + " " + units[digitGroups];

+    }

+

     String getUriResourcePath() {

         final Pattern pattern = Pattern.compile("/?res/([\\w/]+)");

         Matcher m = pattern.matcher(mUri.getPath());