Support for measuring page load times.

An app can attached a pending intent to an intent sent to the browser
which will be send when the load completes. The browser will fill in
the timestamp of when the page load completed, and details of preloading
success or otherwise if this was used.

Bug: 5259031
Change-Id: I2d025caabd6055ac25f06e69897a03d5c57c4f41
diff --git a/src/com/android/browser/Controller.java b/src/com/android/browser/Controller.java
index 67c42dd..d05a845 100644
--- a/src/com/android/browser/Controller.java
+++ b/src/com/android/browser/Controller.java
@@ -18,6 +18,7 @@
 
 import android.app.Activity;
 import android.app.DownloadManager;
+import android.app.PendingIntent;
 import android.app.SearchManager;
 import android.content.ClipboardManager;
 import android.content.ContentProvider;
@@ -93,6 +94,7 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.regex.Pattern;
 
 /**
  * Controller for browser
@@ -761,6 +763,7 @@
     public void stopLoading() {
         mLoadStopped = true;
         Tab tab = mTabControl.getCurrentTab();
+        tab.clearPageLoadCompleteListener();
         WebView w = getCurrentTopWebView();
         w.stopLoading();
         mUi.onPageStopped(tab);
@@ -2154,7 +2157,8 @@
         final PreloadedTabControl tabControl = urlData.getPreloadedTab();
         final String sbQuery = urlData.getSearchBoxQueryToSubmit();
         if (sbQuery != null) {
-            if (!tabControl.searchBoxSubmit(sbQuery, urlData.mUrl, urlData.mHeaders)) {
+            if (!tabControl.searchBoxSubmit(sbQuery, urlData.mUrl, urlData.mHeaders,
+                    urlData.getOnLoadCompletePendingIntent())) {
                 // Could not submit query. Fallback to regular tab creation
                 tabControl.destroy();
                 return null;
@@ -2172,6 +2176,18 @@
         mTabControl.addPreloadedTab(t);
         addTab(t);
         setActiveTab(t);
+        if (sbQuery == null) {
+            // if the searchbox query is set, the load complete notification is handled within
+            // the preloaded tab controller.
+            if (t.inPageLoad()) {
+                requestLoadCompleteNotification(urlData.mOnLoadCompletePendingIntent, t,
+                        urlData.mUrl, true, true);
+            } else {
+                // the page is already fully loaded
+                IntentHandler.sendPageLoadCompletePendingIntent(mActivity,
+                        urlData.mOnLoadCompletePendingIntent, true, true);
+            }
+        }
         return t;
     }
 
@@ -2365,10 +2381,26 @@
                 // this isn't called for preloaded tabs
             } else {
                 loadUrl(t, data.mUrl, data.mHeaders);
+                requestLoadCompleteNotification(data.mOnLoadCompletePendingIntent, t, data.mUrl,
+                        null, null);
             }
         }
     }
 
+    private void requestLoadCompleteNotification(final PendingIntent loadCompletePendingIntent,
+            Tab t, String forUrl, final Boolean preloaded, final Boolean preloadSuccess) {
+        if (loadCompletePendingIntent != null) {
+            Pattern urlMatch = Pattern.compile(Pattern.quote(forUrl));
+            t.setOnPageLoadCompleteListener(urlMatch, new Tab.OnPageLoadCompleteListener() {
+                @Override
+                public void onPageLoadComplete() {
+                    IntentHandler.sendPageLoadCompletePendingIntent(mActivity,
+                            loadCompletePendingIntent, preloaded, preloadSuccess);
+                }
+            });
+        }
+    }
+
     @Override
     public void onUserCanceledSsl(Tab tab) {
         // TODO: Figure out the "right" behavior