OSDN Git Service

am 8774c667: Remove "Show web suggestions" from browser settings
authorLeon Scroggins III <scroggo@google.com>
Fri, 17 Sep 2010 18:07:39 +0000 (11:07 -0700)
committerAndroid Git Automerger <android-git-automerger@android.com>
Fri, 17 Sep 2010 18:07:39 +0000 (11:07 -0700)
Merge commit '8774c667dd446346dca5f5d3c89092fbc86448d0' into gingerbread

* commit '8774c667dd446346dca5f5d3c89092fbc86448d0':
  Remove "Show web suggestions" from browser settings

33 files changed:
Android.mk
res/anim/dialog_enter.xml [moved from res/anim/find_dialog_enter.xml with 82% similarity]
res/anim/dialog_exit.xml [moved from res/anim/find_dialog_exit.xml with 82% similarity]
res/drawable-hdpi/ic_btn_copy.png [new file with mode: 0644]
res/drawable-hdpi/ic_btn_find.png [new file with mode: 0755]
res/drawable-hdpi/ic_btn_select_all.png [new file with mode: 0644]
res/drawable-hdpi/ic_btn_share.png [new file with mode: 0644]
res/layout/browser_select.xml [new file with mode: 0644]
res/layout/browser_subwindow.xml
res/values-de/strings.xml
res/values-es-rUS/strings.xml
res/values-ru/strings.xml
res/values-sv/strings.xml
res/values/strings.xml
res/values/styles.xml
res/values/themes.xml [deleted file]
src/com/android/browser/BrowserActivity.java
src/com/android/browser/BrowserBackupAgent.java
src/com/android/browser/BrowserBookmarksPage.java
src/com/android/browser/BrowserProvider.java
src/com/android/browser/BrowserSettings.java
src/com/android/browser/ErrorConsoleView.java
src/com/android/browser/FindDialog.java
src/com/android/browser/SelectDialog.java [new file with mode: 0644]
src/com/android/browser/SystemAllowGeolocationOrigins.java
src/com/android/browser/Tab.java
src/com/android/browser/TabControl.java
src/com/android/browser/WebDialog.java [new file with mode: 0644]
src/com/android/browser/WebsiteSettingsActivity.java
tests/assets/bindings_test.html
tests/src/com/android/browser/JNIBindingsTest.java
tests/src/com/android/browser/JNIBindingsTestApp.java
tests/src/com/android/browser/PopularUrlsTest.java

index 6e20ab8..e015dda 100644 (file)
@@ -12,6 +12,8 @@ LOCAL_SRC_FILES := \
 
 LOCAL_PACKAGE_NAME := Browser
 
+LOCAL_EMMA_COVERAGE_FILTER := *,-com.android.common.*
+
 include $(BUILD_PACKAGE)
 
 # additionally, build tests in sub-folders in a separate .apk
similarity index 82%
rename from res/anim/find_dialog_enter.xml
rename to res/anim/dialog_enter.xml
index 5e597a4..f98d845 100644 (file)
@@ -16,6 +16,6 @@
 
 <set xmlns:android="http://schemas.android.com/apk/res/android"
         android:interpolator="@android:anim/decelerate_interpolator">
-       <translate android:fromYDelta="25%" android:toYDelta="0" android:duration="75"/>
-       <alpha android:fromAlpha="0.0" android:toAlpha="1.0" android:duration="75" />
+    <translate android:fromYDelta="25%" android:toYDelta="0" android:duration="75"/>
+    <alpha android:fromAlpha="0.0" android:toAlpha="1.0" android:duration="75" />
 </set>
similarity index 82%
rename from res/anim/find_dialog_exit.xml
rename to res/anim/dialog_exit.xml
index 854abd0..dacb5c3 100644 (file)
@@ -16,7 +16,7 @@
 
 <set xmlns:android="http://schemas.android.com/apk/res/android"
         android:interpolator="@android:anim/accelerate_interpolator">
-       <translate android:fromYDelta="0" android:toYDelta="50%" android:duration="50"/>
-       <alpha android:fromAlpha="1.0" android:toAlpha="0.0" android:duration="50" />
+    <translate android:fromYDelta="0" android:toYDelta="50%" android:duration="50"/>
+    <alpha android:fromAlpha="1.0" android:toAlpha="0.0" android:duration="50" />
 </set>
 
diff --git a/res/drawable-hdpi/ic_btn_copy.png b/res/drawable-hdpi/ic_btn_copy.png
new file mode 100644 (file)
index 0000000..04fda7f
Binary files /dev/null and b/res/drawable-hdpi/ic_btn_copy.png differ
diff --git a/res/drawable-hdpi/ic_btn_find.png b/res/drawable-hdpi/ic_btn_find.png
new file mode 100755 (executable)
index 0000000..20e1fbc
Binary files /dev/null and b/res/drawable-hdpi/ic_btn_find.png differ
diff --git a/res/drawable-hdpi/ic_btn_select_all.png b/res/drawable-hdpi/ic_btn_select_all.png
new file mode 100644 (file)
index 0000000..839915b
Binary files /dev/null and b/res/drawable-hdpi/ic_btn_select_all.png differ
diff --git a/res/drawable-hdpi/ic_btn_share.png b/res/drawable-hdpi/ic_btn_share.png
new file mode 100644 (file)
index 0000000..44db9b1
Binary files /dev/null and b/res/drawable-hdpi/ic_btn_share.png differ
diff --git a/res/layout/browser_select.xml b/res/layout/browser_select.xml
new file mode 100644 (file)
index 0000000..b30be8d
--- /dev/null
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/selectControls"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:paddingTop="5dip"
+    android:paddingLeft="4dip"
+    android:paddingRight="4dip"
+    android:paddingBottom="1dip"
+    android:background="@android:drawable/bottom_bar">
+    <ImageButton
+        android:src="@drawable/ic_btn_copy"
+        android:id="@+id/copy"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        />
+
+    <ImageButton
+        android:src="@drawable/ic_btn_share"
+        android:id="@+id/share"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        />
+
+    <ImageButton
+        android:src="@drawable/ic_btn_select_all"
+        android:id="@+id/select_all"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        />
+
+    <ImageButton
+        android:src="@drawable/ic_btn_find"
+        android:id="@+id/find"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        />
+
+    <LinearLayout
+        android:layout_height="fill_parent"
+        android:layout_width="fill_parent"
+        android:layout_weight="1"
+        />
+
+    <ImageButton
+        android:src="@drawable/ic_btn_close_panel"
+        android:id="@+id/done"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        />
+</LinearLayout>
+
index 76d72d5..adf3284 100644 (file)
@@ -23,6 +23,7 @@
         android:layout_height="match_parent"
         android:padding="10dip" >
         <LinearLayout
+            android:id="@+id/inner_container"
             android:layout_width="match_parent"
             android:layout_height="match_parent"
             android:orientation="vertical"
index 7efb620..e9df9f4 100644 (file)
@@ -38,7 +38,7 @@
     <item quantity="few" msgid="5544267486978946555">"<xliff:g id="NUMBER">%d</xliff:g> Treffer"</item>
     <item quantity="other" msgid="6616125067364315405">"<xliff:g id="NUMBER">%d</xliff:g> Treffer"</item>
   </plurals>
-    <string name="title_bar_loading" msgid="7438217780834640678">"Ladevorgang läuft..."</string>
+    <string name="title_bar_loading" msgid="7438217780834640678">"Wird geladen..."</string>
     <string name="page_info" msgid="4048529256302257195">"Seiteninfo"</string>
     <string name="page_info_view" msgid="5303490449842635158">"Seiteninfo anzeigen"</string>
     <string name="page_info_address" msgid="2222306609532903254">"Adresse:"</string>
     <string name="contextmenu_copylink" msgid="5153657160294534270">"Link-URL kopieren"</string>
     <string name="contextmenu_download_image" msgid="4243829645180686912">"Bild speichern"</string>
     <string name="contextmenu_view_image" msgid="3870625602053600905">"Bild anzeigen"</string>
-    <string name="contextmenu_set_wallpaper" msgid="3691902960115350686">"Als Hintergrundbild festlegen"</string>
+    <string name="contextmenu_set_wallpaper" msgid="3691902960115350686">"Als Hintergrund festlegen"</string>
     <string name="contextmenu_dial_dot" msgid="5856550683415933806">"Wählen..."</string>
     <string name="contextmenu_add_contact" msgid="3183511922223645716">"Kontakt hinzufügen"</string>
     <string name="contextmenu_send_mail" msgid="1014513374828775660">"E-Mail senden"</string>
     <string name="website_settings_clear_all_dialog_message" msgid="6150502090601476333">"Alle Websitedaten und Standortberechtigungen werden gelöscht."</string>
     <string name="website_settings_clear_all_dialog_ok_button" msgid="6401582240627669431">"Alle Daten löschen"</string>
     <string name="website_settings_clear_all_dialog_cancel_button" msgid="1896757051856611674">"Abbrechen"</string>
-    <string name="progress_dialog_setting_wallpaper" msgid="4871900779338536674">"Hintergrundbild wird eingestellt..."</string>
+    <string name="progress_dialog_setting_wallpaper" msgid="4871900779338536674">"Hintergrund wird eingestellt..."</string>
 </resources>
index d69b315..02b06b1 100644 (file)
@@ -22,7 +22,7 @@
     <string name="active_tabs" msgid="3050623868203544623">"Windows"</string>
     <string name="tab_bookmarks" msgid="2305793036003473653">"Marcadores"</string>
     <string name="tab_most_visited" msgid="1077402532455000703">"Más visitados"</string>
-    <string name="tab_history" msgid="1979267558744613746">"Historial"</string>
+    <string name="tab_history" msgid="1979267558744613746">"Historial "</string>
     <string name="added_to_bookmarks" msgid="1020224130695956728">"Agregado a marcadores"</string>
     <string name="removed_from_bookmarks" msgid="6063705902028438800">"Suprimido de los marcadores"</string>
     <string name="sign_in_to" msgid="5939425800148759165">"Iniciar sesión en <xliff:g id="HOSTNAME">%s1</xliff:g> \"<xliff:g id="REALM">%s2</xliff:g>\""</string>
     <string name="popup_window_attempt" msgid="2673111696288657989">"Este sitio está intentando abrir una ventana emergente."</string>
     <string name="allow" msgid="1157313689171991335">"Permitir"</string>
     <string name="block" msgid="9172175889884707800">"Bloquear"</string>
-    <string name="too_many_windows_dialog_title" msgid="5175503564948906442">"Se alcanzó el límite de la ventana"</string>
+    <string name="too_many_windows_dialog_title" msgid="5175503564948906442">"Se alcanzó el límite de la ventana "</string>
     <string name="too_many_windows_dialog_message" msgid="1398571800233959583">"No se ha podido abrir una ventana nueva porque ya has abierto el máximo permitido."</string>
     <string name="too_many_subwindows_dialog_title" msgid="3805453941587725944">"Ventana emergente ya abierta"</string>
     <string name="too_many_subwindows_dialog_message" msgid="5827289829907966657">"No es posible abrir una ventana emergente nueva porque sólo puede abrirse una por vez."</string>
     <string name="download_title" msgid="2122874021047565594">"Historial de descarga"</string>
     <string name="download_unknown_filename" msgid="4013465542563652175">"&lt;Desconocido&gt;"</string>
     <string name="download_menu_open" msgid="4888327480367757513">"Abrir"</string>
-    <string name="download_menu_clear" msgid="6264454531553418124">"Borrar de la lista"</string>
+    <string name="download_menu_clear" msgid="6264454531553418124">"Borrar de la lista\n "</string>
     <string name="download_menu_delete" msgid="8815502136393894148">"Eliminar"</string>
     <string name="download_menu_cancel" msgid="2545333007601851574">"Cancelar descarga"</string>
-    <string name="download_menu_cancel_all" msgid="2136550823151999166">"Cancelar todas las descargas"</string>
+    <string name="download_menu_cancel_all" msgid="2136550823151999166">"Cancelar todas las descargas\n "</string>
     <string name="download_cancel_dlg_title" msgid="8909108500262799748">"Cancelar descargas"</string>
     <string name="download_cancel_dlg_msg" msgid="6285389170052357797">"Las <xliff:g id="DOWNLOAD_COUNT">%d</xliff:g> descargas se cancelarán y se borrarán del historial de descarga."</string>
     <string name="download_delete_file" msgid="5330036497843073249">"El archivo se eliminará"</string>
index b976eeb..6e19b2e 100644 (file)
@@ -62,7 +62,7 @@
     <string name="expires_on" msgid="8061200430557020704">"Дата окончания действия:"</string>
     <string name="stopping" msgid="4839698519340302982">"Остановка..."</string>
     <string name="stop" msgid="5687251076030630074">"Стоп"</string>
-    <string name="reload" msgid="8585220783228408062">"Ð\9eбновление"</string>
+    <string name="reload" msgid="8585220783228408062">"Ð\9eбновиÑ\82Ñ\8c"</string>
     <string name="back" msgid="8414603107175713668">"Назад"</string>
     <string name="forward" msgid="4288210890526641577">"Вперед"</string>
     <string name="save" msgid="5922311934992468496">"ОК"</string>
index b4dafb1..bbb698c 100644 (file)
@@ -90,7 +90,7 @@
     <string name="switch_to_thumbnails" msgid="5493351529609043151">"Miniatyrvy"</string>
     <string name="switch_to_list" msgid="8900531247982121055">"Listvy"</string>
     <string name="current_page" msgid="7510129573681663135">"från "</string>
-    <string name="delete_bookmark_warning" msgid="758043186202032205">"Bokmärket <xliff:g id="BOOKMARK">%s</xliff:g> tas bort."</string>
+    <string name="delete_bookmark_warning" msgid="758043186202032205">"Bokmärket <xliff:g id="BOOKMARK">%s</xliff:g> tas bort. "</string>
     <string name="open_in_new_window" msgid="6596775546468054510">"Öppna i nytt fönster"</string>
     <string name="goto_dot" msgid="3895839050522602723">"Kör"</string>
     <string name="find_dot" msgid="6259312434696611957">"Sök på sidan"</string>
index 3eb9a7e..9b7093c 100644 (file)
         <item>Android</item>
         <item>Desktop</item>
         <item>iPhone</item>
+        <item>iPad</item>
+        <item>Froyo-N1</item>
     </string-array>
     <!-- Do not tranlsate.  Development option -->
     <string-array name="pref_development_ua_values" translatable="false">
         <item>0</item>
         <item>1</item>
         <item>2</item>
+        <item>3</item>
+        <item>4</item>
     </string-array>
     <string name="pref_development_error_console" translatable="false">Show JavaScript Console</string>
     <!-- Settings screen, setting option name -->
index 4779aa1..2e8510a 100644 (file)
         <item name="android:windowContentOverlay">@null</item>
     </style>
 
-    <style name="FindDialog">
-        <item name="android:windowEnterAnimation">@anim/find_dialog_enter</item>
-        <item name="android:windowExitAnimation">@anim/find_dialog_exit</item>
-    </style>
-
     <style name="TitleBar">
         <item name="android:windowEnterAnimation">@anim/title_bar_enter</item>
         <item name="android:windowExitAnimation">@anim/title_bar_exit</item>
diff --git a/res/values/themes.xml b/res/values/themes.xml
deleted file mode 100644 (file)
index bb922dd..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2008 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<resources>
-    <style name="FindDialogTheme"> 
-        <item name="android:windowFrame">@null</item>
-        <item name="android:windowIsFloating">true</item>
-        <item name="android:windowIsTranslucent">true</item>
-        <item name="android:windowNoTitle">true</item>
-        <item name="android:background">@null</item>
-        <item name="android:windowBackground">@null</item>
-        <item name="android:windowAnimationStyle">@style/FindDialog</item>
-        <item name="android:backgroundDimEnabled">false</item>
-    </style>
-</resources>
index 5583466..aca7003 100644 (file)
@@ -359,6 +359,15 @@ public class BrowserActivity extends Activity
             attachTabToContentView(mTabControl.getCurrentTab());
         }
 
+        // Delete old thumbnails to save space
+        File dir = mTabControl.getThumbnailDir();
+        if (dir.exists()) {
+            for (String child : dir.list()) {
+                File f = new File(dir, child);
+                f.delete();
+            }
+        }
+
         // Read JavaScript flags if it exists.
         String jsFlags = mSettings.getJsFlags();
         if (jsFlags.trim().length() != 0) {
@@ -827,6 +836,13 @@ public class BrowserActivity extends Activity
             if (mainView == null) {
                 return;
             }
+            // Do not need to check for null, since the current tab will have
+            // at least a main WebView, or we would have returned above.
+            if (dialogIsUp()) {
+                // Do not show the fake title bar, which would cover up the
+                // find or select dialog.
+                return;
+            }
 
             WindowManager manager
                     = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
@@ -1270,6 +1286,22 @@ public class BrowserActivity extends Activity
         getTopWindow().requestFocus();
     }
 
+    private WebView showDialog(WebDialog dialog) {
+        // Need to do something special for Tablet
+        Tab tab = mTabControl.getCurrentTab();
+        if (tab.getSubWebView() == null) {
+            // If the find or select is being performed on the main webview,
+            // remove the embedded title bar.
+            WebView mainView = tab.getWebView();
+            if (mainView != null) {
+                mainView.setEmbeddedTitleBar(null);
+            }
+        }
+        hideFakeTitleBar();
+        mMenuState = EMPTY_MENU;
+        return tab.showDialog(dialog);
+    }
+
     @Override
     public boolean onOptionsItemSelected(MenuItem item) {
         if (!mCanChord) {
@@ -1363,18 +1395,13 @@ public class BrowserActivity extends Activity
                 break;
 
             case R.id.find_menu_id:
-                if (null == mFindDialog) {
-                    mFindDialog = new FindDialog(this);
-                }
-                mFindDialog.setWebView(getTopWindow());
-                mFindDialog.show();
-                getTopWindow().setFindIsUp(true);
-                mMenuState = EMPTY_MENU;
+                showFindDialog();
                 break;
 
             case R.id.select_text_id:
-                getTopWindow().emulateShiftHeld();
+                showSelectDialog();
                 break;
+
             case R.id.page_info_menu_id:
                 showPageInfo(mTabControl.getCurrentTab(), false);
                 break;
@@ -1449,8 +1476,59 @@ public class BrowserActivity extends Activity
         return true;
     }
 
-    public void closeFind() {
+    private boolean dialogIsUp() {
+        return null != mFindDialog && mFindDialog.isVisible() ||
+            null != mSelectDialog && mSelectDialog.isVisible();
+    }
+
+    private boolean closeDialog(WebDialog dialog) {
+        if (null == dialog || !dialog.isVisible()) return false;
+        Tab currentTab = mTabControl.getCurrentTab();
+        currentTab.closeDialog(dialog);
+        dialog.dismiss();
+        return true;
+    }
+
+    /*
+     * Remove the find dialog or select dialog.
+     */
+    public void closeDialogs() {
+        if (!(closeDialog(mFindDialog) || closeDialog(mSelectDialog))) return;
+        // If the Find was being performed in the main WebView, replace the
+        // embedded title bar.
+        Tab currentTab = mTabControl.getCurrentTab();
+        if (currentTab.getSubWebView() == null) {
+            WebView mainView = currentTab.getWebView();
+            if (mainView != null) {
+                mainView.setEmbeddedTitleBar(mTitleBar);
+            }
+        }
         mMenuState = R.id.MAIN_MENU;
+        if (mInLoad) {
+            // The title bar was hidden, because otherwise it would cover up the
+            // find or select dialog.  Now that the dialog has been removed,
+            // show the fake title bar once again.
+            showFakeTitleBar();
+        }
+    }
+
+    public void showFindDialog() {
+        if (null == mFindDialog) {
+            mFindDialog = new FindDialog(this);
+        }
+        showDialog(mFindDialog).setFindIsUp(true);
+    }
+
+    public void setFindDialogText(String text) {
+        mFindDialog.setText(text);
+    }
+
+    public void showSelectDialog() {
+        if (null == mSelectDialog) {
+            mSelectDialog = new SelectDialog(this);
+        }
+        showDialog(mSelectDialog).setUpSelect();
+        mSelectDialog.hideSoftInput();
     }
 
     @Override
@@ -2461,7 +2539,7 @@ public class BrowserActivity extends Activity
         onProgressChanged(view, INITIAL_PROGRESS);
         mDidStopLoad = false;
         if (!mIsNetworkUp) createAndShowNetworkDialog();
-
+        closeDialogs();
         if (mSettings.isTracing()) {
             String host;
             try {
@@ -3659,11 +3737,15 @@ public class BrowserActivity extends Activity
             // Nothing to do.
             return;
         }
+        Tab t = mTabControl.getCurrentTab();
+        if (t == null) {
+            // There is no current tab so we cannot toggle the error console
+            return;
+        }
 
         mShouldShowErrorConsole = flag;
 
-        ErrorConsoleView errorConsole = mTabControl.getCurrentTab()
-                .getErrorConsole(true);
+        ErrorConsoleView errorConsole = t.getErrorConsole(true);
 
         if (flag) {
             // Setting the show state of the console will cause it's the layout to be inflated.
@@ -3769,6 +3851,7 @@ public class BrowserActivity extends Activity
     private Menu mMenu;
 
     private FindDialog mFindDialog;
+    private SelectDialog mSelectDialog;
     // Used to prevent chording to result in firing two shortcuts immediately
     // one after another.  Fixes bug 1211714.
     boolean mCanChord;
index 6f6e829..c968ce5 100644 (file)
@@ -84,6 +84,10 @@ public class BrowserBackupAgent extends BackupAgent {
             savedVersion = in.readInt();
         } catch (EOFException e) {
             // It means we had no previous state; that's fine
+        } finally {
+            if (in != null) {
+                in.close();
+            }
         }
 
         // Build a flattened representation of the bookmarks table
@@ -174,6 +178,10 @@ public class BrowserBackupAgent extends BackupAgent {
                     } catch (IOException ioe) {
                         Log.w(TAG, "Bad backup data; not restoring");
                         crc = -1;
+                    } finally {
+                        if (in != null) {
+                            in.close();
+                        }
                     }
                 }
 
@@ -187,7 +195,7 @@ public class BrowserBackupAgent extends BackupAgent {
         }
     }
 
-    class Bookmark {
+    static class Bookmark {
         public String url;
         public int visits;
         public long date;
@@ -258,13 +266,18 @@ public class BrowserBackupAgent extends BackupAgent {
         data.writeEntityHeader(key, toCopy);
 
         FileInputStream in = new FileInputStream(file);
-        int nRead;
-        while (toCopy > 0) {
-            nRead = in.read(buf, 0, CHUNK);
-            data.writeEntityData(buf, nRead);
-            toCopy -= nRead;
+        try {
+            int nRead;
+            while (toCopy > 0) {
+                nRead = in.read(buf, 0, CHUNK);
+                data.writeEntityData(buf, nRead);
+                toCopy -= nRead;
+            }
+        } finally {
+            if (in != null) {
+                in.close();
+            }
         }
-        in.close();
     }
 
     // Read the given file from backup to a file, calculating a CRC32 along the way
@@ -275,14 +288,18 @@ public class BrowserBackupAgent extends BackupAgent {
         CRC32 crc = new CRC32();
         FileOutputStream out = new FileOutputStream(file);
 
-        while (toRead > 0) {
-            int numRead = data.readEntityData(buf, 0, CHUNK);
-            crc.update(buf, 0, numRead);
-            out.write(buf, 0, numRead);
-            toRead -= numRead;
+        try {
+            while (toRead > 0) {
+                int numRead = data.readEntityData(buf, 0, CHUNK);
+                crc.update(buf, 0, numRead);
+                out.write(buf, 0, numRead);
+                toRead -= numRead;
+            }
+        } finally {
+            if (out != null) {
+                out.close();
+            }
         }
-
-        out.close();
         return crc.getValue();
     }
 
@@ -291,8 +308,14 @@ public class BrowserBackupAgent extends BackupAgent {
             throws IOException {
         DataOutputStream out = new DataOutputStream(
                 new FileOutputStream(stateFile.getFileDescriptor()));
-        out.writeLong(fileSize);
-        out.writeLong(crc);
-        out.writeInt(BACKUP_AGENT_VERSION);
+        try {
+            out.writeLong(fileSize);
+            out.writeLong(crc);
+            out.writeInt(BACKUP_AGENT_VERSION);
+        } finally {
+            if (out != null) {
+                out.close();
+            }
+        }
     }
 }
index 7560c78..dd01009 100644 (file)
@@ -312,7 +312,7 @@ public class BrowserBookmarksPage extends Activity implements
         } else {
             ed.putInt(PREF_BOOKMARK_VIEW_MODE, mViewMode.ordinal());
         }
-        ed.commit();
+        ed.apply();
 
         if (mBookmarksAdapter != null) {
             mBookmarksAdapter.switchViewMode(viewMode);
index 6c9a769..f8574ed 100644 (file)
@@ -356,7 +356,7 @@ public class BrowserProvider extends ContentProvider {
                 fixPicasaBookmark();
                 Editor ed = p.edit();
                 ed.putBoolean("fix_picasa", false);
-                ed.commit();
+                ed.apply();
             }
         }
         mSettings = BrowserSettings.getInstance();
index 71777d6..3791eb0 100644 (file)
@@ -147,12 +147,20 @@ class BrowserSettings extends Observable {
             "privacy_clear_geolocation_access";
 
     private static final String DESKTOP_USERAGENT = "Mozilla/5.0 (Macintosh; " +
-            "U; Intel Mac OS X 10_5_7; en-us) AppleWebKit/530.17 (KHTML, " +
-            "like Gecko) Version/4.0 Safari/530.17";
+            "U; Intel Mac OS X 10_6_3; en-us) AppleWebKit/533.16 (KHTML, " +
+            "like Gecko) Version/5.0 Safari/533.16";
 
     private static final String IPHONE_USERAGENT = "Mozilla/5.0 (iPhone; U; " +
-            "CPU iPhone OS 3_0 like Mac OS X; en-us) AppleWebKit/528.18 " +
-            "(KHTML, like Gecko) Version/4.0 Mobile/7A341 Safari/528.16";
+            "CPU iPhone OS 4_0 like Mac OS X; en-us) AppleWebKit/532.9 " +
+            "(KHTML, like Gecko) Version/4.0.5 Mobile/8A293 Safari/6531.22.7";
+
+    private static final String IPAD_USERAGENT = "Mozilla/5.0 (iPad; U; " +
+            "CPU OS 3_2 like Mac OS X; en-us) AppleWebKit/531.21.10 " +
+            "(KHTML, like Gecko) Version/4.0.4 Mobile/7B367 Safari/531.21.10";
+
+    private static final String FROYO_USERAGENT = "Mozilla/5.0 (Linux; U; " +
+            "Android 2.2; en-us; Nexus One Build/FRF91) AppleWebKit/533.1 " +
+            "(KHTML, like Gecko) Version/4.0 Mobile Safari/533.1";
 
     // Value to truncate strings when adding them to a TextView within
     // a ListView
@@ -192,6 +200,10 @@ class BrowserSettings extends Observable {
                 s.setUserAgentString(DESKTOP_USERAGENT);
             } else if (b.userAgent == 2) {
                 s.setUserAgentString(IPHONE_USERAGENT);
+            } else if (b.userAgent == 3) {
+                s.setUserAgentString(IPAD_USERAGENT);
+            } else if (b.userAgent == 4) {
+                s.setUserAgentString(FROYO_USERAGENT);
             }
             s.setUseWideViewPort(b.useWideViewPort);
             s.setLoadsImagesAutomatically(b.loadsImagesAutomatically);
@@ -412,7 +424,7 @@ class BrowserSettings extends Observable {
         Editor ed = PreferenceManager.
                 getDefaultSharedPreferences(context).edit();
         ed.putString(PREF_HOMEPAGE, url);
-        ed.commit();
+        ed.apply();
         homeUrl = url;
     }
 
@@ -534,7 +546,10 @@ class BrowserSettings extends Observable {
     /* package */ void clearFormData(Context context) {
         WebViewDatabase.getInstance(context).clearFormData();
         if (mTabControl != null) {
-            mTabControl.getCurrentTopWebView().clearFormData();
+            WebView currentTopView = mTabControl.getCurrentTopWebView();
+            if (currentTopView != null) {
+                currentTopView.clearFormData();
+            }
         }
     }
 
@@ -589,7 +604,7 @@ class BrowserSettings extends Observable {
         reset();
         SharedPreferences p =
             PreferenceManager.getDefaultSharedPreferences(ctx);
-        p.edit().clear().commit();
+        p.edit().clear().apply();
         PreferenceManager.setDefaultValues(ctx, R.xml.browser_preferences,
                 true);
         // reset homeUrl
index 0f87cb5..ca5fed4 100644 (file)
@@ -230,7 +230,7 @@ import java.util.Vector;
          * This class is an adapter for ErrorConsoleListView that contains the error console
          * message data.
          */
-        private class ErrorConsoleMessageList extends android.widget.BaseAdapter
+        private static class ErrorConsoleMessageList extends android.widget.BaseAdapter
                 implements android.widget.ListAdapter {
 
             private Vector<ConsoleMessage> mMessages;
index 45c8016..726138e 100644 (file)
 
 package com.android.browser;
 
-import android.app.Dialog;
 import android.content.Context;
-import android.os.Bundle;
 import android.text.Editable;
+import android.text.Selection;
 import android.text.Spannable;
 import android.text.TextWatcher;
 import android.view.Gravity;
 import android.view.KeyEvent;
+import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
-import android.view.Window;
-import android.view.WindowManager;
+import android.view.animation.AnimationUtils;
 import android.view.inputmethod.InputMethodManager;
 import android.webkit.WebView;
 import android.widget.EditText;
+import android.widget.LinearLayout;
 import android.widget.TextView;
 
-/* package */ class FindDialog extends Dialog implements TextWatcher {
-    private WebView         mWebView;
+/* package */ class FindDialog extends WebDialog implements TextWatcher {
     private TextView        mMatches;
-    private BrowserActivity mBrowserActivity;
     
     // Views with which the user can interact.
     private EditText        mEditText;
@@ -44,39 +42,30 @@ import android.widget.TextView;
     private View            mPrevButton;
     private View            mMatchesView;
 
+    // When the dialog is opened up with old text, enter needs to be pressed
+    // (or the text needs to be changed) before WebView.findAll can be called.
+    // Once it has been called, enter should move to the next match.
+    private boolean         mMatchesFound;
+    private int             mNumberOfMatches;
+
     private View.OnClickListener mFindListener = new View.OnClickListener() {
         public void onClick(View v) {
             findNext();
         }
     };
 
-    private View.OnClickListener mFindCancelListener  = 
-            new View.OnClickListener() {
-        public void onClick(View v) {
-            dismiss();
-        }
-    };
-    
-    private View.OnClickListener mFindPreviousListener  = 
+    private View.OnClickListener mFindPreviousListener  =
             new View.OnClickListener() {
         public void onClick(View v) {
             if (mWebView == null) {
                 throw new AssertionError("No WebView for FindDialog::onClick");
             }
             mWebView.findNext(false);
+            updateMatchesString();
             hideSoftInput();
         }
     };
 
-    /*
-     * Remove the soft keyboard from the screen.
-     */
-    private void hideSoftInput() {
-        InputMethodManager imm = (InputMethodManager)
-                mBrowserActivity.getSystemService(Context.INPUT_METHOD_SERVICE);
-        imm.hideSoftInputFromWindow(mEditText.getWindowToken(), 0);
-    }
-
     private void disableButtons() {
         mPrevButton.setEnabled(false);
         mNextButton.setEnabled(false);
@@ -84,28 +73,13 @@ import android.widget.TextView;
         mNextButton.setFocusable(false);
     }
 
-    /* package */ void setWebView(WebView webview) {
-        mWebView = webview;
-    }
-
     /* package */ FindDialog(BrowserActivity context) {
-        super(context, R.style.FindDialogTheme);
-        mBrowserActivity = context;
-        setCanceledOnTouchOutside(true);
-    }
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
+        super(context);
 
-        Window theWindow = getWindow();
-        theWindow.setGravity(Gravity.BOTTOM|Gravity.FILL_HORIZONTAL);
-
-        setContentView(R.layout.browser_find);
-
-        theWindow.setLayout(ViewGroup.LayoutParams.MATCH_PARENT,
-                ViewGroup.LayoutParams.WRAP_CONTENT);
+        LayoutInflater factory = LayoutInflater.from(context);
+        factory.inflate(R.layout.browser_find, this);
 
+        addCancel();
         mEditText = (EditText) findViewById(R.id.edit);
         
         View button = findViewById(R.id.next);
@@ -116,29 +90,59 @@ import android.widget.TextView;
         button.setOnClickListener(mFindPreviousListener);
         mPrevButton = button;
         
-        button = findViewById(R.id.done);
-        button.setOnClickListener(mFindCancelListener);
-        
         mMatches = (TextView) findViewById(R.id.matches);
         mMatchesView = findViewById(R.id.matches_view);
         disableButtons();
-        theWindow.setSoftInputMode(
-                WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
+
     }
-    
+
+    /**
+     * Called by BrowserActivity.closeDialog.  Start the animation to hide
+     * the dialog, inform the WebView that the dialog is being dismissed,
+     * and hide the soft keyboard.
+     */
     public void dismiss() {
         super.dismiss();
-        mBrowserActivity.closeFind();
         mWebView.notifyFindDialogDismissed();
+        hideSoftInput();
+    }
+
+    @Override
+    public boolean dispatchKeyEventPreIme(KeyEvent event) {
+        if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
+            KeyEvent.DispatcherState state = getKeyDispatcherState();
+            if (state != null) {
+                int action = event.getAction();
+                if (KeyEvent.ACTION_DOWN == action
+                        && event.getRepeatCount() == 0) {
+                    state.startTracking(event, this);
+                    return true;
+                } else if (KeyEvent.ACTION_UP == action
+                        && !event.isCanceled() && state.isTracking(event)) {
+                    mBrowserActivity.closeDialogs();
+                    return true;
+                }
+            }
+        }
+        return super.dispatchKeyEventPreIme(event);
     }
 
     @Override
     public boolean dispatchKeyEvent(KeyEvent event) {
-        if (event.getKeyCode() == KeyEvent.KEYCODE_ENTER
-                && event.getAction() == KeyEvent.ACTION_UP
-                && mEditText.hasFocus()) {
-            findNext();
-            return true;
+        int keyCode = event.getKeyCode();
+        if (event.getAction() == KeyEvent.ACTION_UP) {
+            if (keyCode == KeyEvent.KEYCODE_ENTER
+                    && mEditText.hasFocus()) {
+                if (mMatchesFound) {
+                    findNext();
+                } else {
+                    findAll();
+                    // Set the selection to the end.
+                    Spannable span = (Spannable) mEditText.getText();
+                    Selection.setSelection(span, span.length());
+                }
+                return true;
+            }
         }
         return super.dispatchKeyEvent(event);
     }
@@ -148,18 +152,26 @@ import android.widget.TextView;
             throw new AssertionError("No WebView for FindDialog::findNext");
         }
         mWebView.findNext(true);
+        updateMatchesString();
         hideSoftInput();
     }
 
     public void show() {
         super.show();
+        // In case the matches view is showing from a previous search
+        mMatchesView.setVisibility(View.INVISIBLE);
+        mMatchesFound = false;
+        // This text is only here to ensure that mMatches has a height.
+        mMatches.setText("0");
         mEditText.requestFocus();
-        mEditText.setText("");
         Spannable span = (Spannable) mEditText.getText();
-        span.setSpan(this, 0, span.length(), 
-                     Spannable.SPAN_INCLUSIVE_INCLUSIVE);
-        setMatchesFound(0);
+        int length = span.length();
+        Selection.setSelection(span, 0, length);
+        span.setSpan(this, 0, length, Spannable.SPAN_INCLUSIVE_INCLUSIVE);
         disableButtons();
+        InputMethodManager imm = (InputMethodManager)
+                mBrowserActivity.getSystemService(Context.INPUT_METHOD_SERVICE);
+        imm.showSoftInput(mEditText, 0);
     }
     
     // TextWatcher methods
@@ -173,9 +185,13 @@ import android.widget.TextView;
                               int start, 
                               int before, 
                               int count) {
+        findAll();
+    }
+
+    private void findAll() {
         if (mWebView == null) {
             throw new AssertionError(
-                    "No WebView for FindDialog::onTextChanged");
+                    "No WebView for FindDialog::findAll");
         }
         CharSequence find = mEditText.getText();
         if (0 == find.length()) {
@@ -184,14 +200,18 @@ import android.widget.TextView;
             mMatchesView.setVisibility(View.INVISIBLE);
         } else {
             mMatchesView.setVisibility(View.VISIBLE);
-            mWebView.setFindDialogHeight(
-                getWindow().getDecorView().getHeight());
             int found = mWebView.findAll(find.toString());
+            mMatchesFound = true;
             setMatchesFound(found);
             if (found < 2) {
                 disableButtons();
                 if (found == 0) {
-                    setMatchesFound(0);
+                    // Cannot use getQuantityString, which ignores the "zero"
+                    // quantity.
+                    // FIXME: is this fix is beyond the scope
+                    // of adding touch selection to gingerbread?
+                    // mMatches.setText(mBrowserActivity.getResources().getString(
+                    //        R.string.no_matches));
                 }
             } else {
                 mPrevButton.setFocusable(true);
@@ -203,8 +223,21 @@ import android.widget.TextView;
     }
 
     private void setMatchesFound(int found) {
+        mNumberOfMatches = found;
+        updateMatchesString();
+    }
+
+    public void setText(String text) {
+        mEditText.setText(text);
+        findAll();
+    }
+
+    private void updateMatchesString() {
+        // Note: updateMatchesString is only called by methods that have already
+        // checked mWebView for null.
         String template = mBrowserActivity.getResources().
-                getQuantityString(R.plurals.matches_found, found, found);
+                getQuantityString(R.plurals.matches_found, mNumberOfMatches,
+                mWebView.findIndex() + 1, mNumberOfMatches);
 
         mMatches.setText(template);
     }
diff --git a/src/com/android/browser/SelectDialog.java b/src/com/android/browser/SelectDialog.java
new file mode 100644 (file)
index 0000000..461127a
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.browser;
+
+import android.provider.Browser;
+import android.view.LayoutInflater;
+import android.view.View;
+
+/* package */ class SelectDialog extends WebDialog {
+    private View mCopyButton;
+    private View mSelectAllButton;
+    private View mShareButton;
+    private View mFindButton;
+
+    SelectDialog(BrowserActivity context) {
+        super(context);
+        LayoutInflater factory = LayoutInflater.from(context);
+        factory.inflate(R.layout.browser_select, this);
+        addCancel();
+
+        mCopyButton = findViewById(R.id.copy);
+        mCopyButton.setOnClickListener(mCopyListener);
+        mSelectAllButton = findViewById(R.id.select_all);
+        mSelectAllButton.setOnClickListener(mSelectAllListener);
+        mShareButton = findViewById(R.id.share);
+        mShareButton.setOnClickListener(mShareListener);
+        mFindButton = findViewById(R.id.find);
+        mFindButton.setOnClickListener(mFindListener);
+    }
+
+    private View.OnClickListener mCopyListener = new View.OnClickListener() {
+        public void onClick(View v) {
+            mWebView.copySelection();
+            mBrowserActivity.closeDialogs();
+        }
+    };
+
+    private View.OnClickListener mSelectAllListener = new View.OnClickListener() {
+        public void onClick(View v) {
+            mWebView.selectAll();
+        }
+    };
+
+    private View.OnClickListener mShareListener = new View.OnClickListener() {
+        public void onClick(View v) {
+            String selection = mWebView.getSelection();
+            Browser.sendString(mBrowserActivity, selection);
+            mBrowserActivity.closeDialogs();
+        }
+    };
+
+    private View.OnClickListener mFindListener = new View.OnClickListener() {
+        public void onClick(View v) {
+            String selection = mWebView.getSelection();
+            mBrowserActivity.closeDialogs();
+            mBrowserActivity.showFindDialog();
+            mBrowserActivity.setFindDialogText(selection);
+        }
+    };
+
+    /**
+     * Called by BrowserActivity.closeDialog.  Start the animation to hide
+     * the dialog, and inform the WebView that the dialog is being dismissed.
+     */
+    @Override
+    public void dismiss() {
+        super.dismiss();
+        mWebView.notifySelectDialogDismissed();
+    }
+
+}
index 3f5a84e..b53611f 100644 (file)
@@ -103,7 +103,7 @@ class SystemAllowGeolocationOrigins {
         // Save the new value as the last read value
         preferences.edit()
                 .putString(LAST_READ_ALLOW_GEOLOCATION_ORIGINS, newSetting)
-                .commit();
+                .apply();
 
         Set<String> oldOrigins = parseAllowGeolocationOrigins(lastReadSetting);
         Set<String> newOrigins = parseAllowGeolocationOrigins(newSetting);
index 1700961..af0cdf8 100644 (file)
@@ -87,7 +87,7 @@ class Tab {
     // The Geolocation permissions prompt
     private GeolocationPermissionsPrompt mGeolocationPermissionsPrompt;
     // Main WebView wrapper
-    private View mContainer;
+    private LinearLayout mContainer;
     // Main WebView
     private WebView mMainView;
     // Subwindow container
@@ -151,7 +151,6 @@ class Tab {
     static final String CURRTAB = "currentTab";
     static final String CURRURL = "currentUrl";
     static final String CURRTITLE = "currentTitle";
-    static final String CURRPICTURE = "currentPicture";
     static final String CLOSEONEXIT = "closeonexit";
     static final String PARENTTAB = "parentTab";
     static final String APPID = "appid";
@@ -182,8 +181,8 @@ class Tab {
         return mVoiceSearchData != null;
     }
     /**
-     * Return true if the voice search Intent came with a String identifying
-     * that Google provided the Intent.
+     * Return true if the Tab is in voice search mode and the voice search
+     * Intent came with a String identifying that Google provided the Intent.
      */
     public boolean voiceSearchSourceIsGoogle() {
         return mVoiceSearchData != null && mVoiceSearchData.mSourceIsGoogle;
@@ -537,6 +536,18 @@ class Tab {
         // return true if want to hijack the url to let another app to handle it
         @Override
         public boolean shouldOverrideUrlLoading(WebView view, String url) {
+            if (voiceSearchSourceIsGoogle()) {
+                // This method is called when the user clicks on a link.
+                // VoiceSearchMode is turned off when the user leaves the
+                // Google results page, so at this point the user must be on
+                // that page.  If the user clicked a link on that page, assume
+                // that the voice search was effective, and broadcast an Intent
+                // so a receiver can take note of that fact.
+                Intent logIntent = new Intent(LoggingEvents.ACTION_LOG_EVENT);
+                logIntent.putExtra(LoggingEvents.EXTRA_EVENT,
+                        LoggingEvents.VoiceSearch.RESULT_CLICKED);
+                mActivity.sendBroadcast(logIntent);
+            }
             if (mInForeground) {
                 return mActivity.shouldOverrideUrlLoading(view, url);
             } else {
@@ -968,6 +979,9 @@ class Tab {
                     } else if (url.startsWith("http://")) {
                         url = url.substring(4);
                     }
+                    // Escape wildcards for LIKE operator.
+                    url = url.replace("\\", "\\\\").replace("%", "\\%")
+                            .replace("_", "\\_");
                     Cursor c = null;
                     try {
                         final ContentResolver cr
@@ -975,7 +989,7 @@ class Tab {
                         url = "%" + url;
                         String [] selArgs = new String[] { url };
                         String where = Browser.BookmarkColumns.URL
-                                + " LIKE ? AND "
+                                + " LIKE ? ESCAPE '\\' AND "
                                 + Browser.BookmarkColumns.BOOKMARK + " = 0";
                         c = cr.query(Browser.BOOKMARKS_URI, new String[]
                                 { Browser.BookmarkColumns._ID }, where, selArgs,
@@ -1034,6 +1048,16 @@ class Tab {
         }
 
         @Override
+        public void onSelectionDone(WebView view) {
+            if (mInForeground) mActivity.closeDialogs();
+        }
+
+        @Override
+        public void onSelectionStart(WebView view) {
+            if (false && mInForeground) mActivity.showSelectDialog();
+        }
+
+        @Override
         public void onShowCustomView(View view,
                 WebChromeClient.CustomViewCallback callback) {
             if (mInForeground) mActivity.onShowCustomView(view, callback);
@@ -1213,9 +1237,18 @@ class Tab {
     private static class SubWindowClient extends WebViewClient {
         // The main WebViewClient.
         private final WebViewClient mClient;
+        private final BrowserActivity mBrowserActivity;
 
-        SubWindowClient(WebViewClient client) {
+        SubWindowClient(WebViewClient client, BrowserActivity activity) {
             mClient = client;
+            mBrowserActivity = activity;
+        }
+        @Override
+        public void onPageStarted(WebView view, String url, Bitmap favicon) {
+            // Unlike the others, do not call mClient's version, which would
+            // change the progress bar.  However, we do want to remove the
+            // find or select dialog.
+            mBrowserActivity.closeDialogs();
         }
         @Override
         public void doUpdateVisitedHistory(WebView view, String url,
@@ -1305,7 +1338,7 @@ class Tab {
 
         // The tab consists of a container view, which contains the main
         // WebView, as well as any other UI elements associated with the tab.
-        mContainer = mInflateService.inflate(R.layout.tab, null);
+        mContainer = (LinearLayout) mInflateService.inflate(R.layout.tab, null);
 
         mDownloadListener = new DownloadListener() {
             public void onDownloadStart(String url, String userAgent,
@@ -1416,6 +1449,7 @@ class Tab {
      */
     boolean createSubWindow() {
         if (mSubView == null) {
+            mActivity.closeDialogs();
             mSubViewContainer = mInflateService.inflate(
                     R.layout.browser_subwindow, null);
             mSubView = (WebView) mSubViewContainer.findViewById(R.id.webview);
@@ -1424,7 +1458,8 @@ class Tab {
             mSubView.setMapTrackballToArrowKeys(false);
             // Enable the built-in zoom
             mSubView.getSettings().setBuiltInZoomControls(true);
-            mSubView.setWebViewClient(new SubWindowClient(mWebViewClient));
+            mSubView.setWebViewClient(new SubWindowClient(mWebViewClient,
+                    mActivity));
             mSubView.setWebChromeClient(new SubWindowChromeClient(
                     mWebChromeClient));
             // Set a different DownloadListener for the mSubView, since it will
@@ -1438,7 +1473,7 @@ class Tab {
                     if (mSubView.copyBackForwardList().getSize() == 0) {
                         // This subwindow was opened for the sole purpose of
                         // downloading a file. Remove it.
-                        dismissSubWindow();
+                        mActivity.dismissSubWindow(Tab.this);
                     }
                 }
             });
@@ -1462,6 +1497,7 @@ class Tab {
      */
     void dismissSubWindow() {
         if (mSubView != null) {
+            mActivity.closeDialogs();
             BrowserSettings.getInstance().deleteObserver(
                     mSubView.getSettings());
             mSubView.destroy();
@@ -1486,6 +1522,7 @@ class Tab {
     void removeSubWindow(ViewGroup content) {
         if (mSubView != null) {
             content.removeView(mSubViewContainer);
+            mActivity.closeDialogs();
         }
     }
 
@@ -1544,6 +1581,7 @@ class Tab {
                 (FrameLayout) mContainer.findViewById(R.id.webview_wrapper);
         wrapper.removeView(mMainView);
         content.removeView(mContainer);
+        mActivity.closeDialogs();
         removeSubWindow(content);
     }
 
@@ -1876,17 +1914,6 @@ class Tab {
 
         mSavedState = new Bundle();
         final WebBackForwardList list = mMainView.saveState(mSavedState);
-        if (list != null) {
-            final File f = new File(mActivity.getTabControl().getThumbnailDir(),
-                    mMainView.hashCode() + "_pic.save");
-            if (mMainView.savePicture(mSavedState, f)) {
-                mSavedState.putString(CURRPICTURE, f.getPath());
-            } else {
-                // if savePicture returned false, we can't trust the contents,
-                // and it may be large, so we delete it right away
-                f.delete();
-            }
-        }
 
         // Store some extra info for displaying the tab in the picker.
         final WebHistoryItem item = list != null ? list.getCurrentItem() : null;
@@ -1932,11 +1959,38 @@ class Tab {
         if (list == null) {
             return false;
         }
-        if (b.containsKey(CURRPICTURE)) {
-            final File f = new File(b.getString(CURRPICTURE));
-            mMainView.restorePicture(b, f);
-            f.delete();
-        }
         return true;
     }
+
+    /*
+     * Opens the find and select text dialogs.  Called by BrowserActivity.
+     */
+    WebView showDialog(WebDialog dialog) {
+        LinearLayout container;
+        WebView view;
+        if (mSubView != null) {
+            view = mSubView;
+            container = (LinearLayout) mSubViewContainer.findViewById(
+                    R.id.inner_container);
+        } else {
+            view = mMainView;
+            container = mContainer;
+        }
+        dialog.show();
+        container.addView(dialog, 0, new LinearLayout.LayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT,
+                ViewGroup.LayoutParams.WRAP_CONTENT));
+        dialog.setWebView(view);
+        return view;
+    }
+
+    /*
+     * Close the find or select dialog. Called by BrowserActivity.closeDialog.
+     */
+    void closeDialog(WebDialog dialog) {
+        // The dialog may be attached to the subwindow.  Ensure that the
+        // correct parent has it removed.
+        LinearLayout parent = (LinearLayout) dialog.getParent();
+        if (parent != null) parent.removeView(dialog);
+    }
 }
index 7cd2ccb..afd4ea8 100644 (file)
@@ -229,15 +229,6 @@ class TabControl {
             }
         }
 
-        // This tab may have been pushed in to the background and then closed.
-        // If the saved state contains a picture file, delete the file.
-        Bundle savedState = t.getSavedState();
-        if (savedState != null) {
-            if (savedState.containsKey(Tab.CURRPICTURE)) {
-                new File(savedState.getString(Tab.CURRPICTURE)).delete();
-            }
-        }
-
         // Remove it from the queue of viewed tabs.
         mTabQueue.remove(t);
         return true;
diff --git a/src/com/android/browser/WebDialog.java b/src/com/android/browser/WebDialog.java
new file mode 100644 (file)
index 0000000..9995e8f
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.browser;
+
+import android.content.Context;
+import android.view.View;
+import android.view.animation.AnimationUtils;
+import android.view.inputmethod.InputMethodManager;
+import android.webkit.WebView;
+import android.widget.LinearLayout;
+
+/* package */ class WebDialog extends LinearLayout {
+    protected WebView         mWebView;
+    protected BrowserActivity mBrowserActivity;
+    private boolean           mIsVisible;
+
+    /* package */ WebDialog(BrowserActivity context) {
+        super(context);
+        mBrowserActivity = context;
+    }
+
+    /* dialogs that have cancel buttons can optionally share code by including a
+     * view with an id of 'done'.
+     */
+    protected void addCancel() {
+        View button = findViewById(R.id.done);
+        if (button != null) button.setOnClickListener(mCancelListener);
+    }
+
+    private View.OnClickListener mCancelListener = new View.OnClickListener() {
+        public void onClick(View v) {
+            mBrowserActivity.closeDialogs();
+        }
+    };
+
+    protected void dismiss() {
+        startAnimation(AnimationUtils.loadAnimation(mBrowserActivity,
+                R.anim.dialog_exit));
+        mIsVisible = false;
+    }
+
+    /*
+     * Remove the soft keyboard from the screen.
+     */
+    protected void hideSoftInput() {
+        InputMethodManager imm = (InputMethodManager)
+                mBrowserActivity.getSystemService(Context.INPUT_METHOD_SERVICE);
+        imm.hideSoftInputFromWindow(mWebView.getWindowToken(), 0);
+    }
+
+    protected boolean isVisible() {
+        return mIsVisible;
+    }
+
+    /* package */ void setWebView(WebView webview) {
+        mWebView = webview;
+    }
+
+    protected void show() {
+        startAnimation(AnimationUtils.loadAnimation(mBrowserActivity,
+            R.anim.dialog_enter));
+        mIsVisible = true;
+    }
+
+}
index 430286f..1e27092 100644 (file)
@@ -62,7 +62,7 @@ public class WebsiteSettingsActivity extends ListActivity {
     private static String sMBStored = null;
     private SiteAdapter mAdapter = null;
 
-    class Site {
+    static class Site {
         private String mOrigin;
         private String mTitle;
         private Bitmap mIcon;
@@ -190,7 +190,7 @@ public class WebsiteSettingsActivity extends ListActivity {
          * Adds the specified feature to the site corresponding to supplied
          * origin in the map. Creates the site if it does not already exist.
          */
-        private void addFeatureToSite(Map sites, String origin, int feature) {
+        private void addFeatureToSite(Map<String, Site> sites, String origin, int feature) {
             Site site = null;
             if (sites.containsKey(origin)) {
                 site = (Site) sites.get(origin);
@@ -213,7 +213,7 @@ public class WebsiteSettingsActivity extends ListActivity {
 
             WebStorage.getInstance().getOrigins(new ValueCallback<Map>() {
                 public void onReceiveValue(Map origins) {
-                    Map sites = new HashMap<String, Site>();
+                    Map<String, Site> sites = new HashMap<String, Site>();
                     if (origins != null) {
                         Iterator<String> iter = origins.keySet().iterator();
                         while (iter.hasNext()) {
@@ -225,7 +225,7 @@ public class WebsiteSettingsActivity extends ListActivity {
             });
         }
 
-        public void askForGeolocation(final Map sites) {
+        public void askForGeolocation(final Map<String, Site> sites) {
             GeolocationPermissions.getInstance().getOrigins(new ValueCallback<Set<String> >() {
                 public void onReceiveValue(Set<String> origins) {
                     if (origins != null) {
@@ -240,19 +240,19 @@ public class WebsiteSettingsActivity extends ListActivity {
             });
         }
 
-        public void populateIcons(Map sites) {
+        public void populateIcons(Map<String, Site> sites) {
             // Create a map from host to origin. This is used to add metadata
             // (title, icon) for this origin from the bookmarks DB.
-            HashMap hosts = new HashMap<String, Set<Site> >();
-            Set keys = sites.keySet();
-            Iterator<String> originIter = keys.iterator();
+            HashMap<String, Set<Site>> hosts = new HashMap<String, Set<Site>>();
+            Set<Map.Entry<String, Site>> elements = sites.entrySet();
+            Iterator<Map.Entry<String, Site>> originIter = elements.iterator();
             while (originIter.hasNext()) {
-                String origin = originIter.next();
-                Site site = (Site) sites.get(origin);
-                String host = Uri.parse(origin).getHost();
-                Set hostSites = null;
+                Map.Entry<String, Site> entry = originIter.next();
+                Site site = entry.getValue();
+                String host = Uri.parse(entry.getKey()).getHost();
+                Set<Site> hostSites = null;
                 if (hosts.containsKey(host)) {
-                    hostSites = (Sethosts.get(host);
+                    hostSites = (Set<Site>)hosts.get(host);
                 } else {
                     hostSites = new HashSet<Site>();
                     hosts.put(host, hostSites);
@@ -266,55 +266,56 @@ public class WebsiteSettingsActivity extends ListActivity {
                     new String[] { Browser.BookmarkColumns.URL, Browser.BookmarkColumns.TITLE,
                     Browser.BookmarkColumns.FAVICON }, "bookmark = 1", null, null);
 
-            if ((c != null) && c.moveToFirst()) {
-                int urlIndex = c.getColumnIndex(Browser.BookmarkColumns.URL);
-                int titleIndex = c.getColumnIndex(Browser.BookmarkColumns.TITLE);
-                int faviconIndex = c.getColumnIndex(Browser.BookmarkColumns.FAVICON);
-                do {
-                    String url = c.getString(urlIndex);
-                    String host = Uri.parse(url).getHost();
-                    if (hosts.containsKey(host)) {
-                        String title = c.getString(titleIndex);
-                        Bitmap bmp = null;
-                        byte[] data = c.getBlob(faviconIndex);
-                        if (data != null) {
-                            bmp = BitmapFactory.decodeByteArray(data, 0, data.length);
-                        }
-                        Set matchingSites = (Set) hosts.get(host);
-                        Iterator<Site> sitesIter = matchingSites.iterator();
-                        while (sitesIter.hasNext()) {
-                            Site site = sitesIter.next();
-                            // We should only set the title if the bookmark is for the root
-                            // (i.e. www.google.com), as website settings act on the origin
-                            // as a whole rather than a single page under that origin. If the
-                            // user has bookmarked a page under the root but *not* the root,
-                            // then we risk displaying the title of that page which may or
-                            // may not have any relevance to the origin.
-                            if (url.equals(site.getOrigin()) ||
-                                    (new String(site.getOrigin()+"/")).equals(url)) {
-                                site.setTitle(title);
+            if (c != null) {
+                if (c.moveToFirst()) {
+                    int urlIndex = c.getColumnIndex(Browser.BookmarkColumns.URL);
+                    int titleIndex = c.getColumnIndex(Browser.BookmarkColumns.TITLE);
+                    int faviconIndex = c.getColumnIndex(Browser.BookmarkColumns.FAVICON);
+                    do {
+                        String url = c.getString(urlIndex);
+                        String host = Uri.parse(url).getHost();
+                        if (hosts.containsKey(host)) {
+                            String title = c.getString(titleIndex);
+                            Bitmap bmp = null;
+                            byte[] data = c.getBlob(faviconIndex);
+                            if (data != null) {
+                                bmp = BitmapFactory.decodeByteArray(data, 0, data.length);
                             }
-                            if (bmp != null) {
-                                site.setIcon(bmp);
+                            Set matchingSites = (Set) hosts.get(host);
+                            Iterator<Site> sitesIter = matchingSites.iterator();
+                            while (sitesIter.hasNext()) {
+                                Site site = sitesIter.next();
+                                // We should only set the title if the bookmark is for the root
+                                // (i.e. www.google.com), as website settings act on the origin
+                                // as a whole rather than a single page under that origin. If the
+                                // user has bookmarked a page under the root but *not* the root,
+                                // then we risk displaying the title of that page which may or
+                                // may not have any relevance to the origin.
+                                if (url.equals(site.getOrigin()) ||
+                                        (new String(site.getOrigin()+"/")).equals(url)) {
+                                    site.setTitle(title);
+                                }
+                                if (bmp != null) {
+                                    site.setIcon(bmp);
+                                }
                             }
                         }
-                    }
-                } while (c.moveToNext());
+                    } while (c.moveToNext());
+                }
+                c.close();
             }
-
-            c.close();
         }
 
 
-        public void populateOrigins(Map sites) {
+        public void populateOrigins(Map<String, Site> sites) {
             clear();
 
             // We can now simply populate our array with Site instances
-            Set keys = sites.keySet();
-            Iterator<String> originIter = keys.iterator();
-            while (originIter.hasNext()) {
-                String origin = originIter.next();
-                Site site = (Site) sites.get(origin);
+            Set<Map.Entry<String, Site>> elements = sites.entrySet();
+            Iterator<Map.Entry<String, Site>> entryIterator = elements.iterator();
+            while (entryIterator.hasNext()) {
+                Map.Entry<String, Site> entry = entryIterator.next();
+                Site site = entry.getValue();
                 add(site);
             }
 
index c20ccec..71f3438 100755 (executable)
@@ -175,7 +175,7 @@ function appendLog(msg) {
 function runTests() {
 
   // Assume that if the test isn't done after 10s that we failed.
-  window.setTimeout(function() { JNIBindingsTest.testComplete(); }, 10000);
+  window.setTimeout(function() { JNIBindingsTest.notifyComplete(); }, 10000);
 
   if (testPrimitiveTypes()) {
     appendLog("testPrimitiveTypes passed!");
@@ -231,7 +231,7 @@ function runTests() {
     appendLog("testParameterTypeMismatch failed!");
   }
 
-  JNIBindingsTest.testComplete();
+  JNIBindingsTest.notifyComplete();
 }
 </script>
 
index bfa3ac1..ba3c66a 100644 (file)
@@ -20,6 +20,7 @@ import android.test.AndroidTestCase;
 import android.util.Log;
 
 import java.util.Arrays;
+
 import junit.framework.AssertionFailedError;
 
 public class JNIBindingsTest extends AndroidTestCase {
@@ -34,9 +35,9 @@ public class JNIBindingsTest extends AndroidTestCase {
         mTestApp = testApp;
     }
 
-    public void testComplete() {
+    public void notifyComplete() {
         Log.v(LOGTAG, "Completing the test.");
-        mTestApp.testComplete();
+        mTestApp.notifyComplete();
     }
 
     public void printAssertionFailed(AssertionFailedError e) {
@@ -232,7 +233,7 @@ public class JNIBindingsTest extends AndroidTestCase {
             assertEquals(expectedIntParam, intParam);
             assertEquals(expectedDoubleParam, doubleParam);
             assertEquals(expectedBooleanParam, booleanParam);
-            assertEquals(expectedCharParam, charParam);;
+            assertEquals(expectedCharParam, charParam);
 
             // EMULATE_JSC_BINDINGS  JSC passes "undefined" for undefined types.
             assertEquals(expectedUndefinedParam, undefinedParam);
index e01aca2..4f083f6 100644 (file)
@@ -18,7 +18,6 @@ package com.android.browser;
 
 import android.app.Instrumentation;
 import android.net.http.SslError;
-import android.os.Environment;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
@@ -29,6 +28,12 @@ import android.webkit.JsResult;
 import android.webkit.SslErrorHandler;
 import android.webkit.WebView;
 
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
 /**
  * Adds a JavaScript interface to the webview and calls functions on it to verify variables
  * are passed from JS to Java correctly.
@@ -37,6 +42,8 @@ public class JNIBindingsTestApp extends ActivityInstrumentationTestCase2<Browser
 
     private final static String TAG = "JNIBindingsTest";
 
+    private static final String SDCARD_BINDINGS_TEST_HTML = "/sdcard/bindings_test.html";
+
     private static final int MSG_WEBKIT_DATA_READY = 101;
 
     private BrowserActivity mActivity = null;
@@ -67,9 +74,11 @@ public class JNIBindingsTestApp extends ActivityInstrumentationTestCase2<Browser
             mWebView = webView;
         }
 
+        @Override
         public void run() {
             Looper.prepare();
             mHandler = new Handler() {
+                @Override
                 public void handleMessage(Message msg) {
                     switch (msg.what) {
                         case MSG_WEBKIT_DATA_READY: {
@@ -102,6 +111,32 @@ public class JNIBindingsTestApp extends ActivityInstrumentationTestCase2<Browser
         mInst = getInstrumentation();
         mInst.waitForIdleSync();
 
+        extractAsset();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        removeAsset();
+        super.tearDown();
+    }
+
+    protected void extractAsset() throws IOException {
+        InputStream in = getInstrumentation().getContext().getAssets().open("bindings_test.html");
+        OutputStream out = new FileOutputStream(SDCARD_BINDINGS_TEST_HTML);
+
+        byte[] buf = new byte[2048];
+        int len;
+
+        while ((len = in.read(buf)) >= 0 ) {
+            out.write(buf, 0, len);
+        }
+        out.close();
+        in.close();
+    }
+
+    protected void removeAsset(){
+        File fileToDelete = new File(SDCARD_BINDINGS_TEST_HTML);
+        fileToDelete.delete();
     }
 
     /**
@@ -183,7 +218,7 @@ public class JNIBindingsTestApp extends ActivityInstrumentationTestCase2<Browser
         });
     }
 
-    public synchronized void testComplete() {
+    public synchronized void notifyComplete() {
         mTestDone = true;
         notify();
     }
@@ -193,7 +228,7 @@ public class JNIBindingsTestApp extends ActivityInstrumentationTestCase2<Browser
 
         Tab tab = mActivity.getTabControl().getCurrentTab();
         WebView webView = tab.getWebView();
-        webView.loadUrl("file:///sdcard/bindings_test.html");
+        webView.loadUrl("file://" + SDCARD_BINDINGS_TEST_HTML);
         synchronized(this) {
             while(!mTestDone) {
                 try {
index d3806a0..98a0e9f 100644 (file)
 
 package com.android.browser;
 
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileReader;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.io.OutputStreamWriter;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
 import android.app.Instrumentation;
 import android.content.Intent;
 import android.net.Uri;
@@ -42,6 +29,19 @@ import android.webkit.JsResult;
 import android.webkit.SslErrorHandler;
 import android.webkit.WebView;
 
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
 /**
  *
  * Iterates over a list of URLs from a file and outputs the time to load each.
@@ -63,6 +63,7 @@ public class PopularUrlsTest extends ActivityInstrumentationTestCase2<BrowserAct
     private Instrumentation mInst = null;
     private CountDownLatch mLatch = new CountDownLatch(1);
     private RunStatus mStatus;
+    private boolean pageLoadFinishCalled, pageProgressFull;
 
     public PopularUrlsTest() {
         super(BrowserActivity.class);
@@ -72,6 +73,8 @@ public class PopularUrlsTest extends ActivityInstrumentationTestCase2<BrowserAct
     protected void setUp() throws Exception {
         super.setUp();
 
+        Intent i = new Intent(Intent.ACTION_VIEW, Uri.parse("about:blank"));
+        setActivityIntent(i);
         mActivity = getActivity();
         mInst = getInstrumentation();
         mInst.waitForIdleSync();
@@ -122,14 +125,18 @@ public class PopularUrlsTest extends ActivityInstrumentationTestCase2<BrowserAct
 
         webView.setWebChromeClient(new TestWebChromeClient(webView.getWebChromeClient()) {
 
-            /**
-             * Reset the latch whenever page progress reaches 100%.
-             */
             @Override
             public void onProgressChanged(WebView view, int newProgress) {
                 super.onProgressChanged(view, newProgress);
                 if (newProgress >= 100) {
-                    resetLatch();
+                    if (!pageProgressFull) {
+                        // void duplicate calls
+                        pageProgressFull  = true;
+                        if (pageLoadFinishCalled) {
+                            //reset latch and move forward only if both indicators are true
+                            resetLatch();
+                        }
+                    }
                 }
             }
 
@@ -206,20 +213,38 @@ public class PopularUrlsTest extends ActivityInstrumentationTestCase2<BrowserAct
                     String host, String realm) {
                 handler.proceed("user", "passwd");
             }
+
+            /* (non-Javadoc)
+             * @see com.android.browser.TestWebViewClient#onPageFinished(android.webkit.WebView, java.lang.String)
+             */
+            @Override
+            public void onPageFinished(WebView view, String url) {
+                if (!pageLoadFinishCalled) {
+                    pageLoadFinishCalled = true;
+                    if (pageProgressFull) {
+                        //reset latch and move forward only if both indicators are true
+                        resetLatch();
+                    }
+                }
+            }
+
         });
     }
 
     void resetLatch() {
-        CountDownLatch temp = mLatch;
-        mLatch = new CountDownLatch(1);
-        if (temp != null) {
-            // Notify existing latch that it's done.
-            while (temp.getCount() > 0) {
-                temp.countDown();
-            }
+        if (mLatch.getCount() != 1) {
+            Log.w(TAG, "Expecting latch to be 1, but it's not!");
+        } else {
+            mLatch.countDown();
         }
     }
 
+    void resetForNewPage() {
+        mLatch = new CountDownLatch(1);
+        pageLoadFinishCalled = false;
+        pageProgressFull = false;
+    }
+
     void waitForLoad() throws InterruptedException {
         boolean timedout = !mLatch.await(PAGE_LOAD_TIMEOUT, TimeUnit.MILLISECONDS);
         if (timedout) {
@@ -249,16 +274,26 @@ public class PopularUrlsTest extends ActivityInstrumentationTestCase2<BrowserAct
             mFile = new File(file);
             FileReader input = null;
             BufferedReader reader = null;
+            isRecovery = false;
+            iteration = 0;
+            page = 0;
             try {
                 input = new FileReader(mFile);
                 isRecovery = true;
                 reader = new BufferedReader(input);
-                iteration = Integer.parseInt(reader.readLine());
-                page = Integer.parseInt(reader.readLine());
+                String line = reader.readLine();
+                if (line == null)
+                    return;
+                iteration = Integer.parseInt(line);
+                line = reader.readLine();
+                if (line == null)
+                    return;
+                page = Integer.parseInt(line);
             } catch (FileNotFoundException ex) {
-                isRecovery = false;
-                iteration = 0;
-                page = 0;
+                return;
+            } catch (NumberFormatException nfe) {
+                Log.wtf(TAG, "unexpected data in status file, will start from begining");
+                return;
             } finally {
                 try {
                     if (reader != null) {
@@ -282,7 +317,6 @@ public class PopularUrlsTest extends ActivityInstrumentationTestCase2<BrowserAct
 
         public void write() throws IOException {
             FileWriter output = null;
-            OutputStreamWriter writer = null;
             if (mFile.exists()) {
                 mFile.delete();
             }
@@ -292,14 +326,8 @@ public class PopularUrlsTest extends ActivityInstrumentationTestCase2<BrowserAct
                 output.write(page + newLine);
                 output.write(url + newLine);
             } finally {
-                try {
-                    if (writer != null) {
-                        writer.close();
-                    }
-                } finally {
-                    if (output != null) {
-                        output.close();
-                    }
+                if (output != null) {
+                    output.close();
                 }
             }
         }
@@ -369,21 +397,23 @@ public class PopularUrlsTest extends ActivityInstrumentationTestCase2<BrowserAct
 
         if (mStatus.getIsRecovery()) {
             Log.e(TAG, "Recovering after crash: " + iterator.next());
+            mStatus.incrementPage();
         }
 
         while (mStatus.getIteration() < loopCount) {
+            if (clearCache) {
+                webView.clearCache(true);
+            }
             while(iterator.hasNext()) {
                 page = iterator.next();
                 mStatus.setUrl(page);
                 mStatus.write();
                 Log.i(TAG, "start: " + page);
                 Uri uri = Uri.parse(page);
-                if (clearCache) {
-                    webView.clearCache(true);
-                }
                 final Intent intent = new Intent(Intent.ACTION_VIEW, uri);
 
                 long startTime = System.currentTimeMillis();
+                resetForNewPage();
                 mInst.runOnMainSync(new Runnable() {
 
                     public void run() {
@@ -423,6 +453,9 @@ public class PopularUrlsTest extends ActivityInstrumentationTestCase2<BrowserAct
                     bufferedReader.close();
                 }
             }
+        } catch (FileNotFoundException fnfe) {
+            Log.e(TAG, fnfe.getMessage(), fnfe);
+            fail("Test environment not setup correctly");
         } finally {
             if (writer != null) {
                 writer.close();
@@ -436,6 +469,9 @@ public class PopularUrlsTest extends ActivityInstrumentationTestCase2<BrowserAct
         BufferedReader bufferedReader = getInputStream();
         try {
             loopUrls(bufferedReader, null, true, STABILITY_LOOPCOUNT);
+        } catch (FileNotFoundException fnfe) {
+            Log.e(TAG, fnfe.getMessage(), fnfe);
+            fail("Test environment not setup correctly");
         } finally {
             if (bufferedReader != null) {
                 bufferedReader.close();