Generalizes WebsiteSettingsActivity to handle more than just database permissions.

This is in preparation for the addition of Geolocation permissions.
diff --git a/src/com/android/browser/WebsiteSettingsActivity.java b/src/com/android/browser/WebsiteSettingsActivity.java
index f91879f..fc21967 100644
--- a/src/com/android/browser/WebsiteSettingsActivity.java
+++ b/src/com/android/browser/WebsiteSettingsActivity.java
@@ -42,12 +42,14 @@
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
+import java.util.Map;
 import java.util.Set;
 import java.util.Vector;
 
 /**
  * Manage the settings for an origin.
- * We use it to keep track of the HTML5 settings, i.e. database (webstorage).
+ * We use it to keep track of the 'HTML5' settings, i.e. database (webstorage)
+ * and Geolocation.
  */
 public class WebsiteSettingsActivity extends ListActivity {
 
@@ -59,11 +61,58 @@
         private String mOrigin;
         private String mTitle;
         private Bitmap mIcon;
+        private int mFeatures;
+
+        // These constants provide the set of features that a site may support
+        // They must be consecutive. To add a new feature, add a new FEATURE_XXX
+        // variable with value equal to the current value of FEATURE_COUNT, then
+        // increment FEATURE_COUNT.
+        private final static int FEATURE_WEB_STORAGE = 0;
+        // The number of features available.
+        private final static int FEATURE_COUNT = 1;
 
         public Site(String origin) {
             mOrigin = origin;
             mTitle = null;
             mIcon = null;
+            mFeatures = 0;
+        }
+
+        public void addFeature(int feature) {
+            mFeatures |= (1 << feature);
+        }
+
+        public boolean hasFeature(int feature) {
+            return (mFeatures & (1 << feature)) != 0;
+        }
+
+        /**
+         * Gets the number of features supported by this site.
+         */
+        public int getFeatureCount() {
+            int count = 0;
+            for (int i = 0; i < FEATURE_COUNT; ++i) {
+                count += hasFeature(i) ? 1 : 0;
+            }
+            return count;
+        }
+
+        /**
+         * Gets the ID of the nth (zero-based) feature supported by this site.
+         * The return value is a feature ID - one of the FEATURE_XXX values.
+         * This is required to determine which feature is displayed at a given
+         * position in the list of features for this site. This is used both
+         * when populateing the view and when responding to clicks on the list.
+         */
+        public int getFeatureByIndex(int n) {
+            int j = -1;
+            for (int i = 0; i < FEATURE_COUNT; ++i) {
+                j += hasFeature(i) ? 1 : 0;
+                if (j == n) {
+                    return i;
+                }
+            }
+            return -1;
         }
 
         public String getOrigin() {
@@ -102,7 +151,6 @@
         private LayoutInflater mInflater;
         private Bitmap mDefaultIcon;
         private Site mCurrentSite;
-        private final static int STORED_DATA = 0;
 
         public SiteAdapter(Context context, int rsc) {
             super(context, rsc);
@@ -113,28 +161,50 @@
             populateOrigins();
         }
 
+        /**
+         * 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) {
+            Site site = null;
+            if (sites.containsKey(origin)) {
+                site = (Site) sites.get(origin);
+            } else {
+                site = new Site(origin);
+                sites.put(origin, site);
+            }
+            site.addFeature(feature);
+        }
+
         public void populateOrigins() {
             clear();
 
-            // Get the list of origins we want to display
+            // Get the list of origins we want to display.
+            // All 'HTML 5 modules' (Database, Geolocation etc) form these
+            // origin strings using WebCore::SecurityOrigin::toString(), so it's
+            // safe to group origins here. Note that WebCore::SecurityOrigin
+            // uses 0 (which is not printed) for the port if the port is the
+            // default for the protocol. Eg http://www.google.com and
+            // http://www.google.com:80 both record a port of 0 and hence
+            // toString() == 'http://www.google.com' for both.
             Set origins = WebStorage.getInstance().getOrigins();
-            Set sites = new HashSet<Site>();
+            Map sites = new HashMap<String, Site>();
             if (origins != null) {
                 Iterator<String> iter = origins.iterator();
                 while (iter.hasNext()) {
-                    String origin = iter.next();
-                    Site site = new Site(origin);
-                    sites.add(site);
+                    addFeatureToSite(sites, iter.next(), Site.FEATURE_WEB_STORAGE);
                 }
             }
 
             // 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> >();
-            Iterator<Site> sitesIter = sites.iterator();
-            while (sitesIter.hasNext()) {
-                Site site = sitesIter.next();
-                String host = Uri.parse(site.getOrigin()).getHost();
+            Set keys = sites.keySet();
+            Iterator<String> originIter = keys.iterator();
+            while (originIter.hasNext()) {
+                String origin = originIter.next();
+                Site site = (Site) sites.get(origin);
+                String host = Uri.parse(origin).getHost();
                 Set hostSites = null;
                 if (hosts.containsKey(host)) {
                     hostSites = (Set) hosts.get(host);
@@ -166,7 +236,7 @@
                             bmp = BitmapFactory.decodeByteArray(data, 0, data.length);
                         }
                         Set matchingSites = (Set) hosts.get(host);
-                        sitesIter = matchingSites.iterator();
+                        Iterator<Site> sitesIter = matchingSites.iterator();
                         while (sitesIter.hasNext()) {
                             Site site = sitesIter.next();
                             site.setTitle(title);
@@ -179,9 +249,11 @@
             }
 
             // We can now simply populate our array with Site instances
-            sitesIter = sites.iterator();
-            while (sitesIter.hasNext()) {
-                Site site = sitesIter.next();
+            keys = sites.keySet();
+            originIter = keys.iterator();
+            while (originIter.hasNext()) {
+                String origin = originIter.next();
+                Site site = (Site) sites.get(origin);
                 add(site);
             }
 
@@ -194,7 +266,7 @@
             if (mCurrentSite == null) {
                 return super.getCount();
             }
-            return 1; // db view
+            return mCurrentSite.getFeatureCount();
         }
 
         public String sizeValueToString(long value) {
@@ -254,13 +326,15 @@
                 view.setTag(site);
             } else {
                 icon.setVisibility(View.GONE);
-                if (position == STORED_DATA) {
-                    String origin = mCurrentSite.getOrigin();
-                    long usageValue = WebStorage.getInstance().getUsageForOrigin(origin);
-                    String usage = sizeValueToString(usageValue) + " " + sMBStored;
+                String origin = mCurrentSite.getOrigin();
+                switch (mCurrentSite.getFeatureByIndex(position)) {
+                    case Site.FEATURE_WEB_STORAGE:
+                        long usageValue = WebStorage.getInstance().getUsageForOrigin(origin);
+                        String usage = sizeValueToString(usageValue) + " " + sMBStored;
 
-                    title.setText(R.string.webstorage_clear_data_title);
-                    subtitle.setText(usage);
+                        title.setText(R.string.webstorage_clear_data_title);
+                        subtitle.setText(usage);
+                        break;
                 }
             }
 
@@ -272,21 +346,23 @@
                                 int position,
                                 long id) {
             if (mCurrentSite != null) {
-                if (position == STORED_DATA) {
-                    new AlertDialog.Builder(getContext())
-                        .setTitle(R.string.webstorage_clear_data_dialog_title)
-                        .setMessage(R.string.webstorage_clear_data_dialog_message)
-                        .setPositiveButton(R.string.webstorage_clear_data_dialog_ok_button,
-                                           new AlertDialog.OnClickListener() {
-                            public void onClick(DialogInterface dlg, int which) {
-                                WebStorage.getInstance().deleteOrigin(mCurrentSite.getOrigin());
-                                mCurrentSite = null;
-                                populateOrigins();
-                                notifyDataSetChanged();
-                            }})
-                        .setNegativeButton(R.string.webstorage_clear_data_dialog_cancel_button, null)
-                        .setIcon(android.R.drawable.ic_dialog_alert)
-                        .show();
+                switch (mCurrentSite.getFeatureByIndex(position)) {
+                    case Site.FEATURE_WEB_STORAGE:
+                        new AlertDialog.Builder(getContext())
+                            .setTitle(R.string.webstorage_clear_data_dialog_title)
+                            .setMessage(R.string.webstorage_clear_data_dialog_message)
+                            .setPositiveButton(R.string.webstorage_clear_data_dialog_ok_button,
+                                               new AlertDialog.OnClickListener() {
+                                public void onClick(DialogInterface dlg, int which) {
+                                    WebStorage.getInstance().deleteOrigin(mCurrentSite.getOrigin());
+                                    mCurrentSite = null;
+                                    populateOrigins();
+                                    notifyDataSetChanged();
+                                }})
+                            .setNegativeButton(R.string.webstorage_clear_data_dialog_cancel_button, null)
+                            .setIcon(android.R.drawable.ic_dialog_alert)
+                            .show();
+                        break;
                 }
             } else {
                 mCurrentSite = (Site) view.getTag();