Merge "improvement and fixes for bindings test"
diff --git a/res/layout/browser_subwindow.xml b/res/layout/browser_subwindow.xml
index 76d72d5..adf3284 100644
--- a/res/layout/browser_subwindow.xml
+++ b/res/layout/browser_subwindow.xml
@@ -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"
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 4779aa1..2e8510a 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -30,11 +30,6 @@
         <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
index bb922dd..0000000
--- a/res/values/themes.xml
+++ /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>
diff --git a/src/com/android/browser/BrowserActivity.java b/src/com/android/browser/BrowserActivity.java
index 5e55789..8efb18a 100644
--- a/src/com/android/browser/BrowserActivity.java
+++ b/src/com/android/browser/BrowserActivity.java
@@ -1367,9 +1367,8 @@
                 if (null == mFindDialog) {
                     mFindDialog = new FindDialog(this);
                 }
-                mFindDialog.setWebView(getTopWindow());
-                mFindDialog.show();
-                getTopWindow().setFindIsUp(true);
+                // Need to do something special for Tablet
+                mTabControl.getCurrentTab().showFind(mFindDialog);
                 mMenuState = EMPTY_MENU;
                 break;
 
@@ -1450,7 +1449,14 @@
         return true;
     }
 
+    /*
+     * Remove the FindDialog.
+     */
     public void closeFind() {
+        if (mFindDialog != null) {
+            mTabControl.getCurrentTab().closeFind(mFindDialog);
+            mFindDialog.dismiss();
+        }
         mMenuState = R.id.MAIN_MENU;
     }
 
@@ -2462,7 +2468,9 @@
         onProgressChanged(view, INITIAL_PROGRESS);
         mDidStopLoad = false;
         if (!mIsNetworkUp) createAndShowNetworkDialog();
-
+        if (view.getFindIsUp()) {
+            closeFind();
+        }
         if (mSettings.isTracing()) {
             String host;
             try {
diff --git a/src/com/android/browser/BrowserBackupAgent.java b/src/com/android/browser/BrowserBackupAgent.java
index 6f6e829..c968ce5 100644
--- a/src/com/android/browser/BrowserBackupAgent.java
+++ b/src/com/android/browser/BrowserBackupAgent.java
@@ -84,6 +84,10 @@
             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 @@
                     } catch (IOException ioe) {
                         Log.w(TAG, "Bad backup data; not restoring");
                         crc = -1;
+                    } finally {
+                        if (in != null) {
+                            in.close();
+                        }
                     }
                 }
 
@@ -187,7 +195,7 @@
         }
     }
 
-    class Bookmark {
+    static class Bookmark {
         public String url;
         public int visits;
         public long date;
@@ -258,13 +266,18 @@
         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 @@
         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 @@
             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();
+            }
+        }
     }
 }
diff --git a/src/com/android/browser/ErrorConsoleView.java b/src/com/android/browser/ErrorConsoleView.java
index 0f87cb5..ca5fed4 100644
--- a/src/com/android/browser/ErrorConsoleView.java
+++ b/src/com/android/browser/ErrorConsoleView.java
@@ -230,7 +230,7 @@
          * 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;
diff --git a/src/com/android/browser/FindDialog.java b/src/com/android/browser/FindDialog.java
index 45c8016..caff852 100644
--- a/src/com/android/browser/FindDialog.java
+++ b/src/com/android/browser/FindDialog.java
@@ -16,24 +16,23 @@
 
 package com.android.browser;
 
-import android.app.Dialog;
 import android.content.Context;
-import android.os.Bundle;
 import android.text.Editable;
 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 {
+/* package */ class FindDialog extends LinearLayout implements TextWatcher {
     private WebView         mWebView;
     private TextView        mMatches;
     private BrowserActivity mBrowserActivity;
@@ -53,7 +52,7 @@
     private View.OnClickListener mFindCancelListener  = 
             new View.OnClickListener() {
         public void onClick(View v) {
-            dismiss();
+            mBrowserActivity.closeFind();
         }
     };
     
@@ -89,22 +88,11 @@
     }
 
     /* package */ FindDialog(BrowserActivity context) {
-        super(context, R.style.FindDialogTheme);
+        super(context);
         mBrowserActivity = context;
-        setCanceledOnTouchOutside(true);
-    }
 
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        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);
 
         mEditText = (EditText) findViewById(R.id.edit);
         
@@ -122,23 +110,38 @@
         mMatches = (TextView) findViewById(R.id.matches);
         mMatchesView = findViewById(R.id.matches_view);
         disableButtons();
-        theWindow.setSoftInputMode(
-                WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
+
     }
-    
+
+    /**
+     * Called by BrowserActivity.closeFind.  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();
+        startAnimation(AnimationUtils.loadAnimation(mBrowserActivity,
+                R.anim.find_dialog_exit));
+        InputMethodManager imm = (InputMethodManager)
+                getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
+
+        imm.hideSoftInputFromWindow(this.getWindowToken(), 0);
     }
 
     @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 (keyCode == KeyEvent.KEYCODE_BACK) {
+            if (event.getAction() == KeyEvent.ACTION_UP) {
+                mBrowserActivity.closeFind();
+                return true;
+            }
+        } else if (event.getAction() == KeyEvent.ACTION_UP) {
+            if (keyCode == KeyEvent.KEYCODE_ENTER
+                    && mEditText.hasFocus()) {
+                findNext();
+                return true;
+            }
         }
         return super.dispatchKeyEvent(event);
     }
@@ -152,7 +155,6 @@
     }
 
     public void show() {
-        super.show();
         mEditText.requestFocus();
         mEditText.setText("");
         Spannable span = (Spannable) mEditText.getText();
@@ -160,6 +162,11 @@
                      Spannable.SPAN_INCLUSIVE_INCLUSIVE);
         setMatchesFound(0);
         disableButtons();
+        startAnimation(AnimationUtils.loadAnimation(mBrowserActivity,
+                R.anim.find_dialog_enter));
+        InputMethodManager imm = (InputMethodManager)
+                mBrowserActivity.getSystemService(Context.INPUT_METHOD_SERVICE);
+        imm.showSoftInput(mEditText, 0);
     }
     
     // TextWatcher methods
@@ -184,8 +191,6 @@
             mMatchesView.setVisibility(View.INVISIBLE);
         } else {
             mMatchesView.setVisibility(View.VISIBLE);
-            mWebView.setFindDialogHeight(
-                getWindow().getDecorView().getHeight());
             int found = mWebView.findAll(find.toString());
             setMatchesFound(found);
             if (found < 2) {
diff --git a/src/com/android/browser/Tab.java b/src/com/android/browser/Tab.java
index 2dac050..12f0cf6 100644
--- a/src/com/android/browser/Tab.java
+++ b/src/com/android/browser/Tab.java
@@ -87,7 +87,7 @@
     // The Geolocation permissions prompt
     private GeolocationPermissionsPrompt mGeolocationPermissionsPrompt;
     // Main WebView wrapper
-    private View mContainer;
+    private LinearLayout mContainer;
     // Main WebView
     private WebView mMainView;
     // Subwindow container
@@ -1205,9 +1205,18 @@
     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 dialog.
+            if (view.getFindIsUp()) mBrowserActivity.closeFind();
         }
         @Override
         public void doUpdateVisitedHistory(WebView view, String url,
@@ -1297,7 +1306,7 @@
 
         // 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,
@@ -1408,6 +1417,7 @@
      */
     boolean createSubWindow() {
         if (mSubView == null) {
+            if (mMainView.getFindIsUp()) mActivity.closeFind();
             mSubViewContainer = mInflateService.inflate(
                     R.layout.browser_subwindow, null);
             mSubView = (WebView) mSubViewContainer.findViewById(R.id.webview);
@@ -1416,7 +1426,8 @@
             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
@@ -1454,6 +1465,9 @@
      */
     void dismissSubWindow() {
         if (mSubView != null) {
+            if (mSubView.getFindIsUp()) {
+                mActivity.closeFind();
+            }
             BrowserSettings.getInstance().deleteObserver(
                     mSubView.getSettings());
             mSubView.destroy();
@@ -1478,6 +1492,7 @@
     void removeSubWindow(ViewGroup content) {
         if (mSubView != null) {
             content.removeView(mSubViewContainer);
+            if (mSubView.getFindIsUp()) mActivity.closeFind();
         }
     }
 
@@ -1536,6 +1551,7 @@
                 (FrameLayout) mContainer.findViewById(R.id.webview_wrapper);
         wrapper.removeView(mMainView);
         content.removeView(mContainer);
+        if (mMainView.getFindIsUp()) mActivity.closeFind();
         removeSubWindow(content);
     }
 
@@ -1931,4 +1947,36 @@
         }
         return true;
     }
+
+    /*
+     * Open the find dialog.  Called by BrowserActivity.
+     */
+    void showFind(FindDialog 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, new LinearLayout.LayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT,
+                ViewGroup.LayoutParams.WRAP_CONTENT));
+        dialog.setWebView(view);
+        view.setFindIsUp(true);
+    }
+
+    /*
+     * Close the find dialog.  Called by BrowserActivity.closeFind.
+     */
+    void closeFind(FindDialog 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);
+    }
 }
diff --git a/src/com/android/browser/WebsiteSettingsActivity.java b/src/com/android/browser/WebsiteSettingsActivity.java
index 430286f..1e27092 100644
--- a/src/com/android/browser/WebsiteSettingsActivity.java
+++ b/src/com/android/browser/WebsiteSettingsActivity.java
@@ -62,7 +62,7 @@
     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 @@
          * 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 @@
 
             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 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 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 = (Set) hosts.get(host);
+                    hostSites = (Set<Site>)hosts.get(host);
                 } else {
                     hostSites = new HashSet<Site>();
                     hosts.put(host, hostSites);
@@ -266,55 +266,56 @@
                     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);
             }