OSDN Git Service

Fixes
[android-x86/packages-apps-Browser.git] / src / com / android / browser / WebsiteSettingsActivity.java
index f91879f..645e084 100644 (file)
@@ -29,8 +29,13 @@ import android.provider.Browser;
 import android.util.Log;
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
 import android.view.View;
 import android.view.ViewGroup;
+import android.webkit.GeolocationPermissions;
+import android.webkit.ValueCallback;
 import android.webkit.WebIconDatabase;
 import android.webkit.WebStorage;
 import android.widget.ArrayAdapter;
@@ -42,12 +47,14 @@ import android.widget.TextView;
 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 +66,59 @@ public class WebsiteSettingsActivity extends ListActivity {
         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;
+        private final static int FEATURE_GEOLOCATION = 1;
+        // The number of features available.
+        private final static int FEATURE_COUNT = 2;
 
         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 populating 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() {
@@ -101,8 +156,12 @@ public class WebsiteSettingsActivity extends ListActivity {
         private int mResource;
         private LayoutInflater mInflater;
         private Bitmap mDefaultIcon;
+        private Bitmap mUsageEmptyIcon;
+        private Bitmap mUsageLowIcon;
+        private Bitmap mUsageHighIcon;
+        private Bitmap mLocationAllowedIcon;
+        private Bitmap mLocationDisallowedIcon;
         private Site mCurrentSite;
-        private final static int STORED_DATA = 0;
 
         public SiteAdapter(Context context, int rsc) {
             super(context, rsc);
@@ -110,31 +169,83 @@ public class WebsiteSettingsActivity extends ListActivity {
             mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
             mDefaultIcon = BitmapFactory.decodeResource(getResources(),
                     R.drawable.ic_launcher_shortcut_browser_bookmark);
-            populateOrigins();
+            mUsageEmptyIcon = BitmapFactory.decodeResource(getResources(),
+                    R.drawable.ic_list_data_off);
+            mUsageLowIcon = BitmapFactory.decodeResource(getResources(),
+                    R.drawable.ic_list_data_small);
+            mUsageHighIcon = BitmapFactory.decodeResource(getResources(),
+                    R.drawable.ic_list_data_large);
+            mLocationAllowedIcon = BitmapFactory.decodeResource(getResources(),
+                    R.drawable.ic_list_gps_on);
+            mLocationDisallowedIcon = BitmapFactory.decodeResource(getResources(),
+                    R.drawable.ic_list_gps_denied);
+            askForOrigins();
         }
 
-        public void populateOrigins() {
-            clear();
+        /**
+         * 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);
+        }
 
-            // Get the list of origins we want to display
-            Set origins = WebStorage.getInstance().getOrigins();
-            Set sites = new HashSet<Site>();
-            if (origins != null) {
-                Iterator<String> iter = origins.iterator();
-                while (iter.hasNext()) {
-                    String origin = iter.next();
-                    Site site = new Site(origin);
-                    sites.add(site);
+        public void askForOrigins() {
+            // 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.
+
+            WebStorage.getInstance().getOrigins(new ValueCallback<Map>() {
+                public void onReceiveValue(Map origins) {
+                    Map sites = new HashMap<String, Site>();
+                    if (origins != null) {
+                        Iterator<String> iter = origins.keySet().iterator();
+                        while (iter.hasNext()) {
+                            addFeatureToSite(sites, iter.next(), Site.FEATURE_WEB_STORAGE);
+                        }
+                    }
+                    askForGeolocation(sites);
                 }
-            }
+            });
+        }
+
+        public void askForGeolocation(final Map sites) {
+            GeolocationPermissions.getInstance().getOrigins(new ValueCallback<Set>() {
+                public void onReceiveValue(Set origins) {
+                    if (origins != null) {
+                        Iterator<String> iter = origins.iterator();
+                        while (iter.hasNext()) {
+                            addFeatureToSite(sites, iter.next(), Site.FEATURE_GEOLOCATION);
+                        }
+                    }
+                    populateIcons(sites);
+                    populateOrigins(sites);
+                }
+            });
+        }
 
+        public void populateIcons(Map 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> >();
-            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 +277,7 @@ public class WebsiteSettingsActivity extends ListActivity {
                             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);
@@ -178,13 +289,24 @@ public class WebsiteSettingsActivity extends ListActivity {
                 } while (c.moveToNext());
             }
 
+            c.close();
+        }
+
+
+        public void populateOrigins(Map sites) {
+            clear();
+
             // We can now simply populate our array with Site instances
-            sitesIter = sites.iterator();
-            while (sitesIter.hasNext()) {
-                Site site = sitesIter.next();
+            Set keys = sites.keySet();
+            Iterator<String> originIter = keys.iterator();
+            while (originIter.hasNext()) {
+                String origin = originIter.next();
+                Site site = (Site) sites.get(origin);
                 add(site);
             }
 
+            notifyDataSetChanged();
+
             if (getCount() == 0) {
                 finish(); // we close the screen
             }
@@ -194,17 +316,20 @@ public class WebsiteSettingsActivity extends ListActivity {
             if (mCurrentSite == null) {
                 return super.getCount();
             }
-            return 1; // db view
+            return mCurrentSite.getFeatureCount();
         }
 
-        public String sizeValueToString(long value) {
-            float mb = (float) value / (1024.0F * 1024.0F);
-            int val = (int) (mb * 10);
-            float ret = (float) (val / 10.0F);
-            if (ret <= 0) {
+        public String sizeValueToString(long bytes) {
+            // We display the size in MB, to 1dp, rounding up to the next 0.1MB.
+            // bytes should always be greater than zero.
+            if (bytes <= 0) {
+                Log.e(LOGTAG, "sizeValueToString called with non-positive value");
                 return "0";
             }
-            return String.valueOf(ret);
+            float megabytes = (float) bytes / (1024.0F * 1024.0F);
+            int truncated = (int) Math.ceil(megabytes * 10.0F);
+            float result = (float) (truncated / 10.0F);
+            return String.valueOf(result);
         }
 
         /*
@@ -216,18 +341,41 @@ public class WebsiteSettingsActivity extends ListActivity {
         public boolean backKeyPressed() {
             if (mCurrentSite != null) {
                 mCurrentSite = null;
-                populateOrigins();
-                notifyDataSetChanged();
+                askForOrigins();
                 return true;
             }
             return false;
         }
 
+        /**
+         * @hide
+         * Utility function
+         * Set the icon according to the usage
+         */
+        public void setIconForUsage(ImageView usageIcon, long usageInBytes) {
+            float usageInMegabytes = (float) usageInBytes / (1024.0F * 1024.0F);
+            usageIcon.setVisibility(View.VISIBLE);
+
+            // We set the correct icon:
+            // 0 < empty < 0.1MB
+            // 0.1MB < low < 5MB
+            // 5MB < high
+            if (usageInMegabytes <= 0.1) {
+                usageIcon.setImageBitmap(mUsageEmptyIcon);
+            } else if (usageInMegabytes > 0.1 && usageInMegabytes <= 5) {
+                usageIcon.setImageBitmap(mUsageLowIcon);
+            } else if (usageInMegabytes > 5) {
+                usageIcon.setImageBitmap(mUsageHighIcon);
+            }
+        }
+
         public View getView(int position, View convertView, ViewGroup parent) {
             View view;
-            TextView title;
-            TextView subtitle;
+            final TextView title;
+            final TextView subtitle;
             ImageView icon;
+            final ImageView usageIcon;
+            final ImageView locationIcon;
 
             if (convertView == null) {
                 view = mInflater.inflate(mResource, parent, false);
@@ -238,12 +386,20 @@ public class WebsiteSettingsActivity extends ListActivity {
             title = (TextView) view.findViewById(R.id.title);
             subtitle = (TextView) view.findViewById(R.id.subtitle);
             icon = (ImageView) view.findViewById(R.id.icon);
+            usageIcon = (ImageView) view.findViewById(R.id.usage_icon);
+            locationIcon = (ImageView) view.findViewById(R.id.location_icon);
+            usageIcon.setVisibility(View.GONE);
+            locationIcon.setVisibility(View.GONE);
 
             if (mCurrentSite == null) {
+                setTitle(getString(R.string.pref_extras_website_settings));
+
                 Site site = getItem(position);
                 title.setText(site.getPrettyTitle());
                 subtitle.setText(site.getPrettyOrigin());
                 icon.setVisibility(View.VISIBLE);
+                usageIcon.setVisibility(View.INVISIBLE);
+                locationIcon.setVisibility(View.INVISIBLE);
                 Bitmap bmp = site.getIcon();
                 if (bmp == null) {
                     bmp = mDefaultIcon;
@@ -252,15 +408,62 @@ public class WebsiteSettingsActivity extends ListActivity {
                 // We set the site as the view's tag,
                 // so that we can get it in onItemClick()
                 view.setTag(site);
+
+                String origin = site.getOrigin();
+                if (site.hasFeature(Site.FEATURE_WEB_STORAGE)) {
+                    WebStorage.getInstance().getUsageForOrigin(origin, new ValueCallback<Long>() {
+                        public void onReceiveValue(Long value) {
+                            if (value != null) {
+                                setIconForUsage(usageIcon, value.longValue());
+                            }
+                        }
+                    });
+                }
+
+                if (site.hasFeature(Site.FEATURE_GEOLOCATION)) {
+                    locationIcon.setVisibility(View.VISIBLE);
+                    GeolocationPermissions.getInstance().getAllowed(origin, new ValueCallback<Boolean>() {
+                        public void onReceiveValue(Boolean allowed) {
+                            if (allowed != null) {
+                                if (allowed.booleanValue()) {
+                                    locationIcon.setImageBitmap(mLocationAllowedIcon);
+                                } else {
+                                    locationIcon.setImageBitmap(mLocationDisallowedIcon);
+                                }
+                            }
+                        }
+                    });
+                }
             } else {
+                setTitle(mCurrentSite.getPrettyTitle());
                 icon.setVisibility(View.GONE);
-                if (position == STORED_DATA) {
-                    String origin = mCurrentSite.getOrigin();
-                    long usageValue = WebStorage.getInstance().getUsageForOrigin(origin);
-                    String usage = sizeValueToString(usageValue) + " " + sMBStored;
-
-                    title.setText(R.string.webstorage_clear_data_title);
-                    subtitle.setText(usage);
+                String origin = mCurrentSite.getOrigin();
+                switch (mCurrentSite.getFeatureByIndex(position)) {
+                    case Site.FEATURE_WEB_STORAGE:
+                        WebStorage.getInstance().getUsageForOrigin(origin, new ValueCallback<Long>() {
+                            public void onReceiveValue(Long value) {
+                                if (value != null) {
+                                    String usage = sizeValueToString(value.longValue()) + " " + sMBStored;
+                                    title.setText(R.string.webstorage_clear_data_title);
+                                    subtitle.setText(usage);
+                                }
+                            }
+                        });
+                        break;
+                    case Site.FEATURE_GEOLOCATION:
+                        title.setText(R.string.geolocation_settings_page_title);
+                        GeolocationPermissions.getInstance().getAllowed(origin, new ValueCallback<Boolean>() {
+                            public void onReceiveValue(Boolean allowed) {
+                                if (allowed != null) {
+                                    if (allowed.booleanValue()) {
+                                        subtitle.setText(R.string.geolocation_settings_page_summary_allowed);
+                                    } else {
+                                        subtitle.setText(R.string.geolocation_settings_page_summary_not_allowed);
+                                    }
+                                }
+                            }
+                        });
+                        break;
                 }
             }
 
@@ -272,21 +475,37 @@ public class WebsiteSettingsActivity extends ListActivity {
                                 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;
+                                    askForOrigins();
+                                }})
+                            .setNegativeButton(R.string.webstorage_clear_data_dialog_cancel_button, null)
+                            .setIcon(android.R.drawable.ic_dialog_alert)
+                            .show();
+                        break;
+                    case Site.FEATURE_GEOLOCATION:
+                        new AlertDialog.Builder(getContext())
+                            .setTitle(R.string.geolocation_settings_page_dialog_title)
+                            .setMessage(R.string.geolocation_settings_page_dialog_message)
+                            .setPositiveButton(R.string.geolocation_settings_page_dialog_ok_button,
+                                               new AlertDialog.OnClickListener() {
+                                public void onClick(DialogInterface dlg, int which) {
+                                    GeolocationPermissions.getInstance().clear(mCurrentSite.getOrigin());
+                                    mCurrentSite = null;
+                                    askForOrigins();
+                                }})
+                            .setNegativeButton(R.string.geolocation_settings_page_dialog_cancel_button, null)
+                            .setIcon(android.R.drawable.ic_dialog_alert)
+                            .show();
+                        break;
                 }
             } else {
                 mCurrentSite = (Site) view.getTag();
@@ -315,8 +534,46 @@ public class WebsiteSettingsActivity extends ListActivity {
         if (sMBStored == null) {
             sMBStored = getString(R.string.webstorage_origin_summary_mb_stored);
         }
-        mAdapter = new SiteAdapter(this, R.layout.application);
+        mAdapter = new SiteAdapter(this, R.layout.website_settings_row);
         setListAdapter(mAdapter);
         getListView().setOnItemClickListener(mAdapter);
     }
+
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        MenuInflater inflater = getMenuInflater();
+        inflater.inflate(R.menu.websitesettings, menu);
+        return true;
+    }
+
+    @Override
+    public boolean onPrepareOptionsMenu(Menu menu) {
+        // If we aren't listing any sites hide the clear all button (and hence the menu).
+        return mAdapter.getCount() > 0;
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        switch (item.getItemId()) {
+            case R.id.website_settings_menu_clear_all:
+                // Show the prompt to clear all origins of their data and geolocation permissions.
+                new AlertDialog.Builder(this)
+                        .setTitle(R.string.website_settings_clear_all_dialog_title)
+                        .setMessage(R.string.website_settings_clear_all_dialog_message)
+                        .setPositiveButton(R.string.website_settings_clear_all_dialog_ok_button,
+                                new AlertDialog.OnClickListener() {
+                                    public void onClick(DialogInterface dlg, int which) {
+                                        WebStorage.getInstance().deleteAllData();
+                                        GeolocationPermissions.getInstance().clearAll();
+                                        WebStorageSizeManager.resetLastOutOfSpaceNotificationTime();
+                                        mAdapter.askForOrigins();
+                                        finish();
+                                    }})
+                        .setNegativeButton(R.string.website_settings_clear_all_dialog_cancel_button, null)
+                        .setIcon(android.R.drawable.ic_dialog_alert)
+                        .show();
+                return true;
+        }
+        return false;
+    }
 }