diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 62f0500991fbd9b07a761ac44558a9080a0e44c3..0f79f219d31042061d31d70f67909450a65caa60 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -29,6 +29,7 @@
         </activity>
         <activity android:name=".activity.NewsActivity"
                   android:label="I2P News"
+                  android:configChanges="orientation|keyboardHidden"
                   android.theme="@android:style/Theme.NoTitleBar" >
         </activity>
         <activity android:name=".activity.TextResourceActivity"
@@ -41,6 +42,7 @@
         </activity>
         <activity android:name=".activity.WebActivity"
                   android:label="I2P Web Browser"
+                  android:configChanges="orientation|keyboardHidden"
                   android.theme="@android:style/Theme.NoTitleBar" >
             <intent-filter>
                 <action android:name="android.intent.action.VIEW" />
diff --git a/res/layout/main.xml b/res/layout/main.xml
index 1375a464ee51d1b30e307144369580657b8786e4..eda98b9944aa04ddd1fcb9f77c01d7fc7e6227dd 100644
--- a/res/layout/main.xml
+++ b/res/layout/main.xml
@@ -102,19 +102,19 @@
     android:id="@+id/router_start_button"
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
-    android:text="Start router"
+    android:text="Start Router"
     />
  <Button 
     android:id="@+id/router_stop_button"
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
-    android:text="Stop router"
+    android:text="OLD STOP"
     />
  <Button 
     android:id="@+id/router_quit_button"
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
-    android:text="QUIT router"
+    android:text="Stop Router"
     />
 </LinearLayout>
 <TextView  
diff --git a/src/net/i2p/android/apps/EepGetFetcher.java b/src/net/i2p/android/apps/EepGetFetcher.java
index 8b64836c10d5cdfa4f7aeab0a75b7d623a3c18f1..6c8ee6a33cc9ca1092d26f2d989f9949e7b4cf8d 100644
--- a/src/net/i2p/android/apps/EepGetFetcher.java
+++ b/src/net/i2p/android/apps/EepGetFetcher.java
@@ -32,7 +32,8 @@ public class EepGetFetcher implements EepGet.StatusListener {
 
     /**
      *  Writes to temp file, call getData()
-     *  to get the data as a String
+     *  to get the data as a String.
+     *  Temp file sticks around forever.
      */
     public EepGetFetcher(String url) {
         _context = I2PAppContext.getGlobalContext();
@@ -50,7 +51,7 @@ public class EepGetFetcher implements EepGet.StatusListener {
     /**
      *  Writes to output stream
      */
-    public EepGetFetcher(String url, OutputStream out) {
+    public EepGetFetcher(String url, OutputStream out, boolean writeErrorToStream) {
         _context = I2PAppContext.getGlobalContext();
         _log = _context.logManager().getLog(EepGetFetcher.class);
         _url = url;
@@ -58,7 +59,8 @@ public class EepGetFetcher implements EepGet.StatusListener {
         _eepget = new EepGet(_context, true, "localhost", 4444, 0, -1, MAX_LEN,
                              null, out, url,
                              true, null, null, null);
-        //_eepget.setWriteErrorToOutput();
+        if (writeErrorToStream)
+            _eepget.setWriteErrorToOutput();
     }
     
     public void addStatusListener(EepGet.StatusListener l) {
@@ -100,6 +102,13 @@ public class EepGetFetcher implements EepGet.StatusListener {
         return rv;
     }
 
+    /**
+     *  @return -1 if nothing back from server
+     */
+    public int getStatusCode() {
+        return _eepget.getStatusCode();
+    }
+
     /**
      *  Only for the constructor without the output stream
      *  Only call ONCE!
diff --git a/src/net/i2p/android/router/activity/I2PWebViewClient.java b/src/net/i2p/android/router/activity/I2PWebViewClient.java
index f7981cf945f1bfbd854ba678f79fe46655389442..24c73d5a9b8abf8485e1601a06d58b25cb8019b9 100644
--- a/src/net/i2p/android/router/activity/I2PWebViewClient.java
+++ b/src/net/i2p/android/router/activity/I2PWebViewClient.java
@@ -12,13 +12,17 @@ import android.webkit.WebView;
 import android.webkit.WebViewClient;
 import android.widget.Toast;
 
+import java.io.File;
+import java.io.FileInputStream;
 import java.io.IOException;
+import java.io.InputStream;
 import java.io.OutputStream;
 
 import net.i2p.android.apps.EepGetFetcher;
 import net.i2p.android.router.provider.CacheProvider;
 import net.i2p.android.router.util.AppCache;
 import net.i2p.android.router.util.Util;
+import net.i2p.data.DataHelper;
 import net.i2p.util.EepGet;
 
 class I2PWebViewClient extends WebViewClient {
@@ -26,9 +30,11 @@ class I2PWebViewClient extends WebViewClient {
     private BGLoad _lastTask;
 
     // TODO add some inline style
+    private static final String CONTENT = "content";
     private static final String HEADER = "<html><head></head><body>";
     private static final String FOOTER = "</body></html>";
-    private static final String ERROR_EEPSITE = HEADER + "Sorry, eepsites not yet supported" + FOOTER;
+    private static final String ERROR_URL = "<p>Unable to load URL: ";
+    private static final String ERROR_ROUTER = "<p>Your router does not appear to be up.</p>";
 
     public I2PWebViewClient(Context ctx) {
         super();
@@ -47,7 +53,7 @@ class I2PWebViewClient extends WebViewClient {
             }
             s = s.toLowerCase();
             if (!(s.equals("http") || s.equals("https") ||
-                  s.equals("content"))) {
+                  s.equals(CONTENT))) {
                 Util.e("Not loading URL " + url);
                 return false;
             }
@@ -75,16 +81,22 @@ class I2PWebViewClient extends WebViewClient {
                 int hash = url.indexOf("#");
                 if (hash > 0)
                     url = url.substring(0, hash);
-                view.getSettings().setLoadsImagesAutomatically(false);
+                view.getSettings().setLoadsImagesAutomatically(true);
                 ///////// API 8
                 // Otherwise hangs waiting for CSS
-                view.getSettings().setBlockNetworkLoads(true);
-                //view.loadData(ERROR_EEPSITE, "text/html", "UTF-8");
+                view.getSettings().setBlockNetworkLoads(false);
                 BGLoad task = new BackgroundEepLoad(view, h);
                 _lastTask = task;
                 task.execute(url);
             } else {
-                if (s.equals("content")) {
+                if (s.equals(CONTENT)) {
+                    if (h.equals(CacheProvider.AUTHORITY)) {
+                        if (!url.startsWith(CacheProvider.CONTENT_URI.toString()))
+                            Util.e("Content URI bad nonce, FIXME: " + url);
+                    } else {
+                        Util.e("Content URI but not for us?? " + url);
+                    }
+
                     // canonicalize to append query to path
                     // because the resolver doesn't send a query to the provider
                     Uri canon = CacheProvider.getContentUri(uri);
@@ -143,6 +155,20 @@ class I2PWebViewClient extends WebViewClient {
         }
     }
 
+    /**
+     *  This should always be a content url
+     */
+    void deleteCurrentPageCache(WebView view) {
+        String url = view.getUrl();
+        Uri uri = Uri.parse(url);
+        if (CONTENT.equals(uri.getScheme())) {
+            // this actually only deletes the row in the provider,
+            // not the actual file, but it will be overwritten in the reload.
+            Util.e("clearing provider entry for current page " + url);
+            view.getContext().getContentResolver().delete(uri, null, null);
+        }
+    }
+
     private abstract static class BGLoad extends AsyncTask<String, Integer, Integer> implements DialogInterface.OnCancelListener {
         protected final WebView _view;
         protected ProgressDialog _dialog;
@@ -223,7 +249,8 @@ class I2PWebViewClient extends WebViewClient {
         protected Integer doInBackground(String... urls) {
             String url = urls[0];
             Uri uri = Uri.parse(url);
-            if (AppCache.getInstance(_view.getContext()).getCacheFile(uri).exists()) {
+            File cacheFile = AppCache.getInstance(_view.getContext()).getCacheFile(uri);
+            if (cacheFile.exists()) {
                 Uri resUri = AppCache.getInstance(_view.getContext()).getCacheUri(uri);
                 Util.e("Loading " + url + " from resource cache " + resUri);
                 _view.getSettings().setLoadsImagesAutomatically(true);
@@ -234,56 +261,82 @@ class I2PWebViewClient extends WebViewClient {
                     // CalledFromWrongThreadException
                     cancel(false);
                 }
-                return Integer.valueOf(0);
+                // 1 means show the cache toast message
+                return Integer.valueOf(1);
             }
 
             publishProgress(Integer.valueOf(-1));
-            EepGetFetcher fetcher = new EepGetFetcher(url);
-            fetcher.addStatusListener(this);
-            boolean success = fetcher.fetch();
-            if (isCancelled()) {
-                Util.e("Fetch cancelled for " + url);
-                return Integer.valueOf(0);
-            }
-            if (!success)
-                Util.e("Fetch failed for " + url);
-            String t = fetcher.getContentType();
-            String d = fetcher.getData();
-            int len = d.length();
-            // http://stackoverflow.com/questions/3961589/android-webview-and-loaddata
-            if (success && t.startsWith("text/html") && !d.startsWith("<?xml"))
-                d = XML_HEADER + d;
-            String e = fetcher.getEncoding();
-            Util.e("Len: " + len + " type: \"" + t + "\" encoding: \"" + e + '"');
-            if (isCancelled()) {
-                Util.e("Fetch cancelled for " + url);
-                return Integer.valueOf(0);
-            }
-            String history = url;
-            if (success) {
-                OutputStream out = null;
-                try {
-                    out = AppCache.getInstance(_view.getContext()).createCacheFile(uri);
-                    out.write(d.getBytes(e));
+            //EepGetFetcher fetcher = new EepGetFetcher(url);
+            OutputStream out = null;
+            try {
+                out = AppCache.getInstance(_view.getContext()).createCacheFile(uri);
+                // write error to stream
+                EepGetFetcher fetcher = new EepGetFetcher(url, out, true);
+                fetcher.addStatusListener(this);
+                boolean success = fetcher.fetch();
+                if (isCancelled()) {
+                    Util.e("Fetch cancelled for " + url);
+                    return Integer.valueOf(0);
+                }
+                try { out.close(); } catch (IOException ioe) {}
+                if (success) {
+                    // store in cache, get content URL, and load that way
                     Uri content = AppCache.getInstance(_view.getContext()).addCacheFile(uri);
-                    if (content != null)
-                        history = content.toString();
-                    Util.e("Stored cache in " + history);
-                } catch (Exception ex) {
+                    if (content != null) {
+                        Util.e("Stored cache in " + content);
+                    } else {
+                        AppCache.getInstance(_view.getContext()).removeCacheFile(uri);
+                        Util.e("cache create error");
+                        return Integer.valueOf(0);
+                    }
+                    Util.e("loading data, base URL: " + uri + " content URL: " + content);
+                    try {
+                        _view.loadUrl(content.toString());
+                    } catch (Exception exc) {
+                        // CalledFromWrongThreadException
+                        cancel(false);
+                    }
+                    Util.e("Fetch failed for " + url);
+                } else {
+                    // Load the error message in as a string, delete the file
+                    String t = fetcher.getContentType();
+                    String e = fetcher.getEncoding();
+                    String msg;
+                    int statusCode = fetcher.getStatusCode();
+                    if (statusCode < 0) {
+                        msg = HEADER + ERROR_URL + "<a href=\"" + url + "\">" + url +
+                              "</a></p>" + ERROR_ROUTER + FOOTER;
+                    } else if (cacheFile.length() <= 0) {
+                        msg = HEADER + ERROR_URL + "<a href=\"" + url + "\">" + url +
+                              "</a> No data returned, error code: " + statusCode +
+                              "</p>" + FOOTER;
+                    } else {
+                        InputStream fis = null;
+                        try {
+                            fis = new FileInputStream(cacheFile);
+                            byte[] data = new byte[(int) cacheFile.length()];
+                            DataHelper.read(fis, data);
+                            msg = new String(data, e);
+                        } catch (IOException ioe) {
+                            Util.e("WVC", ioe);
+                            msg = HEADER + "I/O error" + FOOTER;
+                        } finally {
+                              if (fis != null) try { fis.close(); } catch (IOException ioe) {}
+                        }
+                    }
                     AppCache.getInstance(_view.getContext()).removeCacheFile(uri);
-                    Util.e("cache create error", ex);
-                } finally {
-                    if (out != null) try { out.close(); } catch (IOException ioe) {}
+                    try {
+                         Util.e("loading error data URL: " + url);
+                        _view.loadDataWithBaseURL(url, msg, t, e, url);
+                    } catch (Exception exc) {
+                        // CalledFromWrongThreadException
+                        cancel(false);
+                    }
                 }
-            } else {
-                history = url;
-            }
-            try {
-                Util.e("loading data, base URL: " + url + " history URL: " + history);
-                _view.loadDataWithBaseURL(url, d, t, e, history);
-            } catch (Exception exc) {
-                // CalledFromWrongThreadException
-                cancel(false);
+            } catch (IOException ioe) {
+                    Util.e("IOE for " + url, ioe);
+            } finally {
+                if (out != null) try { out.close(); } catch (IOException ioe) {}
             }
             return Integer.valueOf(0);
         }
@@ -316,6 +369,16 @@ class I2PWebViewClient extends WebViewClient {
             }
         }
 
+        @Override
+        protected void onPostExecute(Integer result) {
+            if (result.equals(Integer.valueOf(1))) {
+                Toast toast = Toast.makeText(_view.getContext(), "Loading from cache, click settings to reload", Toast.LENGTH_SHORT);
+                toast.setGravity(Gravity.CENTER, 0, 0);
+                toast.show();
+            }
+            super.onPostExecute(result);
+        }
+
         // EepGet callbacks
 
         public void attemptFailed(String url, long bytesTransferred, long bytesRemaining, int currentAttempt, int numRetries, Exception cause) {}
diff --git a/src/net/i2p/android/router/activity/MainActivity.java b/src/net/i2p/android/router/activity/MainActivity.java
index 102afd11fd66e4c950ceeb0728b7a94e5094c8a3..d5242ea8f3a43795812e74b93bdcf3bd60f2b13a 100644
--- a/src/net/i2p/android/router/activity/MainActivity.java
+++ b/src/net/i2p/android/router/activity/MainActivity.java
@@ -244,8 +244,9 @@ public class MainActivity extends I2PActivityBase {
         start.setVisibility(showStart ? View.VISIBLE : View.INVISIBLE);
 
         boolean showStop = svc != null && _isBound && svc.canManualStop();
+        // Old stop but leave in memory. Always hide for now.
         Button stop = (Button) findViewById(R.id.router_stop_button);
-        stop.setVisibility(showStop ? View.VISIBLE : View.INVISIBLE);
+        stop.setVisibility( /* showStop ? View.VISIBLE : */ View.INVISIBLE);
 
         Button quit = (Button) findViewById(R.id.router_quit_button);
         quit.setVisibility(showStop ? View.VISIBLE : View.INVISIBLE);
diff --git a/src/net/i2p/android/router/activity/WebActivity.java b/src/net/i2p/android/router/activity/WebActivity.java
index 98a2fa5113155196515d03ea2770c18d3a3bb7fb..4818f64bbd7f02e62a78b2cccfa677e6125d93a4 100644
--- a/src/net/i2p/android/router/activity/WebActivity.java
+++ b/src/net/i2p/android/router/activity/WebActivity.java
@@ -5,6 +5,7 @@ import android.content.res.Resources;
 import android.net.Uri;
 import android.os.Bundle;
 import android.view.KeyEvent;
+import android.view.MenuItem;
 import android.webkit.WebView;
 import android.webkit.WebViewClient;
 import android.widget.TextView;
@@ -91,4 +92,22 @@ public class WebActivity extends I2PActivityBase {
         }
         return super.onKeyDown(keyCode, event);
     }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        WebView wv = (WebView) findViewById(R.id.browser_webview);
+        switch (item.getItemId()) {
+        case R.id.menu_reload:
+            _wvClient.cancelAll();
+            wv.stopLoading();
+            _wvClient.deleteCurrentPageCache(wv);
+            // should go through the WVC instead??
+            wv.reload();
+            return true;
+
+        default:
+            return super.onOptionsItemSelected(item);
+        }
+    }
+
 }
diff --git a/src/net/i2p/android/router/provider/CacheProvider.java b/src/net/i2p/android/router/provider/CacheProvider.java
index dc34887daa49257cf2c89e464164c47904202c22..8e64fd575c3017e26564f87d49940ed5af7e315d 100644
--- a/src/net/i2p/android/router/provider/CacheProvider.java
+++ b/src/net/i2p/android/router/provider/CacheProvider.java
@@ -47,7 +47,7 @@ public class CacheProvider extends ContentProvider {
     //private static final String NONCE = Integer.toString(Math.abs((new java.util.Random()).nextInt()));
     private static final String NONCE = "0";
     private static final String SCHEME = "content";
-    private static final String AUTHORITY = "net.i2p.android.router";
+    public static final String AUTHORITY = "net.i2p.android.router";
     /** includes the nonce */
     public static final Uri CONTENT_URI = Uri.parse(SCHEME + "://" + AUTHORITY + '/' + NONCE);
     /** the database key */
@@ -177,7 +177,7 @@ public class CacheProvider extends ContentProvider {
             throw new FileNotFoundException(ioe.toString());
         }
         // in this constructor we don't use the error output, for now
-        EepGetFetcher fetcher = new EepGetFetcher(uri.toString(), out);
+        EepGetFetcher fetcher = new EepGetFetcher(uri.toString(), out, false);
         boolean success = fetcher.fetch();
         if (success) {
             File file = cache.getCacheFile(uri);