Browser incognito mode session expiration.

Change-Id: I3736ce91bd5ecbcead7a80228680c9fcbf7c374b
diff --git a/src/com/android/browser/BrowserActivity.java b/src/com/android/browser/BrowserActivity.java
index 24796a6..2260200 100644
--- a/src/com/android/browser/BrowserActivity.java
+++ b/src/com/android/browser/BrowserActivity.java
@@ -116,6 +116,7 @@
 import java.net.URISyntaxException;
 import java.net.URL;
 import java.net.URLEncoder;
+import java.util.Calendar;
 import java.util.Date;
 import java.util.HashMap;
 import java.util.Iterator;
@@ -276,7 +277,19 @@
                 }
             };
 
-        if (!mTabControl.restoreState(icicle)) {
+        // Unless the last browser usage was within 24 hours, destroy any
+        // remaining incognito tabs.
+
+        Calendar lastActiveDate = icicle != null ? (Calendar) icicle.getSerializable("lastActiveDate") : null;
+        Calendar today = Calendar.getInstance();
+        Calendar yesterday = Calendar.getInstance();
+        yesterday.add(Calendar.DATE, -1);
+
+        boolean dontRestoreIncognitoTabs = lastActiveDate == null
+            || lastActiveDate.before(yesterday)
+            || lastActiveDate.after(today);
+
+        if (!mTabControl.restoreState(icicle, dontRestoreIncognitoTabs)) {
             // clear up the thumbnail directory if we can't restore the state as
             // none of the files in the directory are referenced any more.
             new ClearThumbnails().execute(
@@ -284,6 +297,8 @@
             // there is no quit on Android. But if we can't restore the state,
             // we can treat it as a new Browser, remove the old session cookies.
             CookieManager.getInstance().removeSessionCookie();
+            // remove any incognito files
+            WebView.cleanupPrivateBrowsingFiles(this);
             final Intent intent = getIntent();
             final Bundle extra = intent.getExtras();
             // Create an initial tab.
@@ -316,6 +331,10 @@
                 loadUrlDataIn(t, urlData);
             }
         } else {
+            if (dontRestoreIncognitoTabs) {
+                WebView.cleanupPrivateBrowsingFiles(this);
+            }
+
             // TabControl.restoreState() will create a new tab even if
             // restoring the state fails.
             attachTabToContentView(mTabControl.getCurrentTab());
@@ -930,6 +949,9 @@
 
         // Save all the tabs
         mTabControl.saveState(outState);
+
+        // Save time so that we know how old incognito tabs (if any) are.
+        outState.putSerializable("lastActiveDate", Calendar.getInstance());
     }
 
     @Override
diff --git a/src/com/android/browser/Tab.java b/src/com/android/browser/Tab.java
index a9ab058..7c52bb6 100644
--- a/src/com/android/browser/Tab.java
+++ b/src/com/android/browser/Tab.java
@@ -156,6 +156,7 @@
     static final String PARENTTAB = "parentTab";
     static final String APPID = "appid";
     static final String ORIGINALURL = "originalUrl";
+    static final String INCOGNITO = "privateBrowsingEnabled";
 
     // -------------------------------------------------------------------------
 
diff --git a/src/com/android/browser/TabControl.java b/src/com/android/browser/TabControl.java
index 37834c0..7377a1e 100644
--- a/src/com/android/browser/TabControl.java
+++ b/src/com/android/browser/TabControl.java
@@ -29,6 +29,7 @@
 
 import java.io.File;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.Vector;
 
 class TabControl {
@@ -155,7 +156,7 @@
      */
     boolean hasAnyOpenIncognitoTabs() {
         for (Tab tab : mTabs) {
-            if (tab.getWebView().isPrivateBrowsingEnabled()) {
+            if (tab.getWebView() != null && tab.getWebView().isPrivateBrowsingEnabled()) {
                 return true;
             }
         }
@@ -297,29 +298,56 @@
      * @return True if there were previous tabs that were restored. False if
      *         there was no saved state or restoring the state failed.
      */
-    boolean restoreState(Bundle inState) {
+    boolean restoreState(Bundle inState, boolean dontRestoreIncognitoTabs) {
         final int numTabs = (inState == null)
                 ? -1 : inState.getInt(Tab.NUMTABS, -1);
         if (numTabs == -1) {
             return false;
         } else {
-            final int currentTab = inState.getInt(Tab.CURRTAB, -1);
+            final int oldCurrentTab = inState.getInt(Tab.CURRTAB, -1);
+
+            // Determine whether the saved current tab can be restored, and
+            // if not, which tab will take its place.
+            int currentTab = -1;
+            if (!dontRestoreIncognitoTabs
+                    || !inState.getBundle(Tab.WEBVIEW + oldCurrentTab).getBoolean(Tab.INCOGNITO)) {
+                currentTab = oldCurrentTab;
+            } else {
+                for (int i = 0; i < numTabs; i++) {
+                    if (!inState.getBundle(Tab.WEBVIEW + i).getBoolean(Tab.INCOGNITO)) {
+                        currentTab = i;
+                        break;
+                    }
+                }
+            }
+            if (currentTab < 0) {
+                return false;
+            }
+
+            // Map saved tab indices to new indices, in case any incognito tabs
+            // need to not be restored.
+            HashMap<Integer, Integer> originalTabIndices = new HashMap<Integer, Integer>();
+            originalTabIndices.put(-1, -1);
             for (int i = 0; i < numTabs; i++) {
-                if (i == currentTab) {
+                Bundle state = inState.getBundle(Tab.WEBVIEW + i);
+
+                if (dontRestoreIncognitoTabs && state != null && state.getBoolean(Tab.INCOGNITO)) {
+                    originalTabIndices.put(i, -1);
+                } else if (i == currentTab) {
                     Tab t = createNewTab();
                     // Me must set the current tab before restoring the state
                     // so that all the client classes are set.
                     setCurrentTab(t);
-                    if (!t.restoreState(inState.getBundle(Tab.WEBVIEW + i))) {
+                    if (!t.restoreState(state)) {
                         Log.w(LOGTAG, "Fail in restoreState, load home page.");
                         t.getWebView().loadUrl(BrowserSettings.getInstance()
                                 .getHomePage());
                     }
+                    originalTabIndices.put(i, getTabCount() - 1);
                 } else {
                     // Create a new tab and don't restore the state yet, add it
                     // to the tab list
                     Tab t = new Tab(mActivity, null, false, null, null);
-                    Bundle state = inState.getBundle(Tab.WEBVIEW + i);
                     if (state != null) {
                         t.setSavedState(state);
                         t.populatePickerDataFromSavedState();
@@ -331,15 +359,17 @@
                     mTabs.add(t);
                     // added the tab to the front as they are not current
                     mTabQueue.add(0, t);
+                    originalTabIndices.put(i, getTabCount() - 1);
                 }
             }
+
             // Rebuild the tree of tabs. Do this after all tabs have been
             // created/restored so that the parent tab exists.
             for (int i = 0; i < numTabs; i++) {
                 final Bundle b = inState.getBundle(Tab.WEBVIEW + i);
                 final Tab t = getTab(i);
                 if (b != null && t != null) {
-                    final int parentIndex = b.getInt(Tab.PARENTTAB, -1);
+                    final Integer parentIndex = originalTabIndices.get(b.getInt(Tab.PARENTTAB, -1));
                     if (parentIndex != -1) {
                         final Tab parent = getTab(parentIndex);
                         if (parent != null) {