Preloading support in browser

	   Apps like the QSB can request the browser to preload a
	   web page.
           - preloaded pages are not added to the browser history
	     if they'r not seen by the user
	   - when a request is received, a new tab is created for the
	     preloaded page, but not added to the tab list
 	   - upon receiving the view intent for the preloaded page
             the tab is added to the tab list, and shown
	   - if several pages are preloaded consecutively in the same tab,
             the back stack is cleared before it is displayed
           - preloaded pages use the main browser cookie jar, so pages that
             have never been viewed by the user can drop cookies

Change-Id: I9ed21f2c9560fda0ed042b460b73bb33988a2e8a
diff --git a/src/com/android/browser/IntentHandler.java b/src/com/android/browser/IntentHandler.java
index 088a788..a99164a 100644
--- a/src/com/android/browser/IntentHandler.java
+++ b/src/com/android/browser/IntentHandler.java
@@ -135,8 +135,14 @@
                 urlData = new UrlData(mSettings.getHomePage());
             }
 
-            if (intent.getBooleanExtra(Browser.EXTRA_CREATE_NEW_TAB, false)) {
-                mController.openTab(urlData);
+            if (intent.getBooleanExtra(Browser.EXTRA_CREATE_NEW_TAB, false)
+                  || urlData.isPreloaded()) {
+                Tab t = mController.openTab(urlData);
+                if (t == null && urlData.isPreloaded()) {
+                    Tab pre = urlData.getPreloadedTab();
+                    // TODO: check if we need to stop loading
+                    pre.destroy();
+                }
                 return;
             }
             /*
@@ -220,9 +226,10 @@
         }
     }
 
-    protected UrlData getUrlDataFromIntent(Intent intent) {
+    protected static UrlData getUrlDataFromIntent(Intent intent) {
         String url = "";
         Map<String, String> headers = null;
+        Tab preloaded = null;
         if (intent != null
                 && (intent.getFlags() & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) == 0) {
             final String action = intent.getAction();
@@ -241,6 +248,10 @@
                         }
                     }
                 }
+                if (intent.hasExtra(PreloadRequestReceiver.EXTRA_PRELOAD_ID)) {
+                    String id = intent.getStringExtra(PreloadRequestReceiver.EXTRA_PRELOAD_ID);
+                    preloaded = Preloader.getInstance().getPreloadedTab(id);
+                }
             } else if (Intent.ACTION_SEARCH.equals(action)
                     || MediaStore.INTENT_ACTION_MEDIA_SEARCH.equals(action)
                     || Intent.ACTION_WEB_SEARCH.equals(action)) {
@@ -265,7 +276,7 @@
                 }
             }
         }
-        return new UrlData(url, headers, intent);
+        return new UrlData(url, headers, intent, preloaded);
     }
 
     /**
@@ -348,14 +359,20 @@
         final String mUrl;
         final Map<String, String> mHeaders;
         final Intent mVoiceIntent;
+        final Tab mPreloadedTab;
 
         UrlData(String url) {
             this.mUrl = url;
             this.mHeaders = null;
             this.mVoiceIntent = null;
+            this.mPreloadedTab = null;
         }
 
         UrlData(String url, Map<String, String> headers, Intent intent) {
+            this(url, headers, intent, null);
+        }
+
+        UrlData(String url, Map<String, String> headers, Intent intent, Tab preloaded) {
             this.mUrl = url;
             this.mHeaders = headers;
             if (RecognizerResultsIntent.ACTION_VOICE_SEARCH_RESULTS
@@ -364,11 +381,20 @@
             } else {
                 this.mVoiceIntent = null;
             }
+            mPreloadedTab = preloaded;
         }
 
         boolean isEmpty() {
             return mVoiceIntent == null && (mUrl == null || mUrl.length() == 0);
         }
+
+        boolean isPreloaded() {
+            return mPreloadedTab != null;
+        }
+
+        Tab getPreloadedTab() {
+            return mPreloadedTab;
+        }
     }
 
 }