• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2009 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.browser.preferences;
18 
19 import android.app.AlertDialog;
20 import android.app.ListFragment;
21 import android.content.Context;
22 import android.content.DialogInterface;
23 import android.database.Cursor;
24 import android.graphics.Bitmap;
25 import android.graphics.BitmapFactory;
26 import android.net.Uri;
27 import android.os.AsyncTask;
28 import android.os.Bundle;
29 import android.os.Parcel;
30 import android.os.Parcelable;
31 import android.preference.PreferenceActivity;
32 import android.provider.BrowserContract.Bookmarks;
33 import android.util.Log;
34 import android.view.LayoutInflater;
35 import android.view.View;
36 import android.view.View.OnClickListener;
37 import android.view.ViewGroup;
38 import android.webkit.GeolocationPermissions;
39 import android.webkit.ValueCallback;
40 import android.webkit.WebStorage;
41 import android.widget.AdapterView;
42 import android.widget.ArrayAdapter;
43 import android.widget.ImageView;
44 import android.widget.TextView;
45 
46 import com.android.browser.R;
47 import com.android.browser.WebStorageSizeManager;
48 
49 import java.util.HashMap;
50 import java.util.HashSet;
51 import java.util.Iterator;
52 import java.util.Map;
53 import java.util.Set;
54 
55 /**
56  * Manage the settings for an origin.
57  * We use it to keep track of the 'HTML5' settings, i.e. database (webstorage)
58  * and Geolocation.
59  */
60 public class WebsiteSettingsFragment extends ListFragment implements OnClickListener {
61 
62     private static final String EXTRA_SITE = "site";
63     private String LOGTAG = "WebsiteSettingsActivity";
64     private static String sMBStored = null;
65     private SiteAdapter mAdapter = null;
66     private Site mSite = null;
67 
68     static class Site implements Parcelable {
69         private String mOrigin;
70         private String mTitle;
71         private Bitmap mIcon;
72         private int mFeatures;
73 
74         // These constants provide the set of features that a site may support
75         // They must be consecutive. To add a new feature, add a new FEATURE_XXX
76         // variable with value equal to the current value of FEATURE_COUNT, then
77         // increment FEATURE_COUNT.
78         final static int FEATURE_WEB_STORAGE = 0;
79         final static int FEATURE_GEOLOCATION = 1;
80         // The number of features available.
81         final static int FEATURE_COUNT = 2;
82 
Site(String origin)83         public Site(String origin) {
84             mOrigin = origin;
85             mTitle = null;
86             mIcon = null;
87             mFeatures = 0;
88         }
89 
addFeature(int feature)90         public void addFeature(int feature) {
91             mFeatures |= (1 << feature);
92         }
93 
removeFeature(int feature)94         public void removeFeature(int feature) {
95             mFeatures &= ~(1 << feature);
96         }
97 
hasFeature(int feature)98         public boolean hasFeature(int feature) {
99             return (mFeatures & (1 << feature)) != 0;
100         }
101 
102         /**
103          * Gets the number of features supported by this site.
104          */
getFeatureCount()105         public int getFeatureCount() {
106             int count = 0;
107             for (int i = 0; i < FEATURE_COUNT; ++i) {
108                 count += hasFeature(i) ? 1 : 0;
109             }
110             return count;
111         }
112 
113         /**
114          * Gets the ID of the nth (zero-based) feature supported by this site.
115          * The return value is a feature ID - one of the FEATURE_XXX values.
116          * This is required to determine which feature is displayed at a given
117          * position in the list of features for this site. This is used both
118          * when populating the view and when responding to clicks on the list.
119          */
getFeatureByIndex(int n)120         public int getFeatureByIndex(int n) {
121             int j = -1;
122             for (int i = 0; i < FEATURE_COUNT; ++i) {
123                 j += hasFeature(i) ? 1 : 0;
124                 if (j == n) {
125                     return i;
126                 }
127             }
128             return -1;
129         }
130 
getOrigin()131         public String getOrigin() {
132             return mOrigin;
133         }
134 
setTitle(String title)135         public void setTitle(String title) {
136             mTitle = title;
137         }
138 
setIcon(Bitmap icon)139         public void setIcon(Bitmap icon) {
140             mIcon = icon;
141         }
142 
getIcon()143         public Bitmap getIcon() {
144             return mIcon;
145         }
146 
getPrettyOrigin()147         public String getPrettyOrigin() {
148             return mTitle == null ? null : hideHttp(mOrigin);
149         }
150 
getPrettyTitle()151         public String getPrettyTitle() {
152             return mTitle == null ? hideHttp(mOrigin) : mTitle;
153         }
154 
hideHttp(String str)155         private String hideHttp(String str) {
156             Uri uri = Uri.parse(str);
157             return "http".equals(uri.getScheme()) ?  str.substring(7) : str;
158         }
159 
160         @Override
describeContents()161         public int describeContents() {
162             return 0;
163         }
164 
165         @Override
writeToParcel(Parcel dest, int flags)166         public void writeToParcel(Parcel dest, int flags) {
167             dest.writeString(mOrigin);
168             dest.writeString(mTitle);
169             dest.writeInt(mFeatures);
170             dest.writeParcelable(mIcon, flags);
171         }
172 
Site(Parcel in)173         private Site(Parcel in) {
174             mOrigin = in.readString();
175             mTitle = in.readString();
176             mFeatures = in.readInt();
177             mIcon = in.readParcelable(null);
178         }
179 
180         public static final Parcelable.Creator<Site> CREATOR
181                 = new Parcelable.Creator<Site>() {
182             public Site createFromParcel(Parcel in) {
183                 return new Site(in);
184             }
185 
186             public Site[] newArray(int size) {
187                 return new Site[size];
188             }
189         };
190 
191     }
192 
193     class SiteAdapter extends ArrayAdapter<Site>
194             implements AdapterView.OnItemClickListener {
195         private int mResource;
196         private LayoutInflater mInflater;
197         private Bitmap mDefaultIcon;
198         private Bitmap mUsageEmptyIcon;
199         private Bitmap mUsageLowIcon;
200         private Bitmap mUsageHighIcon;
201         private Bitmap mLocationAllowedIcon;
202         private Bitmap mLocationDisallowedIcon;
203         private Site mCurrentSite;
204 
SiteAdapter(Context context, int rsc)205         public SiteAdapter(Context context, int rsc) {
206             this(context, rsc, null);
207         }
208 
SiteAdapter(Context context, int rsc, Site site)209         public SiteAdapter(Context context, int rsc, Site site) {
210             super(context, rsc);
211             mResource = rsc;
212             mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
213             mDefaultIcon = BitmapFactory.decodeResource(getResources(),
214                     R.drawable.app_web_browser_sm);
215             mUsageEmptyIcon = BitmapFactory.decodeResource(getResources(),
216                     R.drawable.ic_list_data_off);
217             mUsageLowIcon = BitmapFactory.decodeResource(getResources(),
218                     R.drawable.ic_list_data_small);
219             mUsageHighIcon = BitmapFactory.decodeResource(getResources(),
220                     R.drawable.ic_list_data_large);
221             mLocationAllowedIcon = BitmapFactory.decodeResource(getResources(),
222                     R.drawable.ic_gps_on_holo_dark);
223             mLocationDisallowedIcon = BitmapFactory.decodeResource(getResources(),
224                     R.drawable.ic_gps_denied_holo_dark);
225             mCurrentSite = site;
226             if (mCurrentSite == null) {
227                 askForOrigins();
228             }
229         }
230 
231         /**
232          * Adds the specified feature to the site corresponding to supplied
233          * origin in the map. Creates the site if it does not already exist.
234          */
addFeatureToSite(Map<String, Site> sites, String origin, int feature)235         private void addFeatureToSite(Map<String, Site> sites, String origin, int feature) {
236             Site site = null;
237             if (sites.containsKey(origin)) {
238                 site = (Site) sites.get(origin);
239             } else {
240                 site = new Site(origin);
241                 sites.put(origin, site);
242             }
243             site.addFeature(feature);
244         }
245 
askForOrigins()246         public void askForOrigins() {
247             // Get the list of origins we want to display.
248             // All 'HTML 5 modules' (Database, Geolocation etc) form these
249             // origin strings using WebCore::SecurityOrigin::toString(), so it's
250             // safe to group origins here. Note that WebCore::SecurityOrigin
251             // uses 0 (which is not printed) for the port if the port is the
252             // default for the protocol. Eg http://www.google.com and
253             // http://www.google.com:80 both record a port of 0 and hence
254             // toString() == 'http://www.google.com' for both.
255 
256             WebStorage.getInstance().getOrigins(new ValueCallback<Map>() {
257                 public void onReceiveValue(Map origins) {
258                     Map<String, Site> sites = new HashMap<String, Site>();
259                     if (origins != null) {
260                         Iterator<String> iter = origins.keySet().iterator();
261                         while (iter.hasNext()) {
262                             addFeatureToSite(sites, iter.next(), Site.FEATURE_WEB_STORAGE);
263                         }
264                     }
265                     askForGeolocation(sites);
266                 }
267             });
268         }
269 
askForGeolocation(final Map<String, Site> sites)270         public void askForGeolocation(final Map<String, Site> sites) {
271             GeolocationPermissions.getInstance().getOrigins(new ValueCallback<Set<String> >() {
272                 public void onReceiveValue(Set<String> origins) {
273                     if (origins != null) {
274                         Iterator<String> iter = origins.iterator();
275                         while (iter.hasNext()) {
276                             addFeatureToSite(sites, iter.next(), Site.FEATURE_GEOLOCATION);
277                         }
278                     }
279                     populateIcons(sites);
280                     populateOrigins(sites);
281                 }
282             });
283         }
284 
populateIcons(Map<String, Site> sites)285         public void populateIcons(Map<String, Site> sites) {
286             // Create a map from host to origin. This is used to add metadata
287             // (title, icon) for this origin from the bookmarks DB. We must do
288             // the DB access on a background thread.
289             new UpdateFromBookmarksDbTask(this.getContext(), sites).execute();
290         }
291 
292         private class UpdateFromBookmarksDbTask extends AsyncTask<Void, Void, Void> {
293 
294             private Context mContext;
295             private boolean mDataSetChanged;
296             private Map<String, Site> mSites;
297 
UpdateFromBookmarksDbTask(Context ctx, Map<String, Site> sites)298             public UpdateFromBookmarksDbTask(Context ctx, Map<String, Site> sites) {
299                 mContext = ctx.getApplicationContext();
300                 mSites = sites;
301             }
302 
doInBackground(Void... unused)303             protected Void doInBackground(Void... unused) {
304                 HashMap<String, Set<Site>> hosts = new HashMap<String, Set<Site>>();
305                 Set<Map.Entry<String, Site>> elements = mSites.entrySet();
306                 Iterator<Map.Entry<String, Site>> originIter = elements.iterator();
307                 while (originIter.hasNext()) {
308                     Map.Entry<String, Site> entry = originIter.next();
309                     Site site = entry.getValue();
310                     String host = Uri.parse(entry.getKey()).getHost();
311                     Set<Site> hostSites = null;
312                     if (hosts.containsKey(host)) {
313                         hostSites = (Set<Site>)hosts.get(host);
314                     } else {
315                         hostSites = new HashSet<Site>();
316                         hosts.put(host, hostSites);
317                     }
318                     hostSites.add(site);
319                 }
320 
321                 // Check the bookmark DB. If we have data for a host used by any of
322                 // our origins, use it to set their title and favicon
323                 Cursor c = mContext.getContentResolver().query(Bookmarks.CONTENT_URI,
324                         new String[] { Bookmarks.URL, Bookmarks.TITLE, Bookmarks.FAVICON },
325                         Bookmarks.IS_FOLDER + " == 0", null, null);
326 
327                 if (c != null) {
328                     if (c.moveToFirst()) {
329                         int urlIndex = c.getColumnIndex(Bookmarks.URL);
330                         int titleIndex = c.getColumnIndex(Bookmarks.TITLE);
331                         int faviconIndex = c.getColumnIndex(Bookmarks.FAVICON);
332                         do {
333                             String url = c.getString(urlIndex);
334                             String host = Uri.parse(url).getHost();
335                             if (hosts.containsKey(host)) {
336                                 String title = c.getString(titleIndex);
337                                 Bitmap bmp = null;
338                                 byte[] data = c.getBlob(faviconIndex);
339                                 if (data != null) {
340                                     bmp = BitmapFactory.decodeByteArray(data, 0, data.length);
341                                 }
342                                 Set matchingSites = (Set) hosts.get(host);
343                                 Iterator<Site> sitesIter = matchingSites.iterator();
344                                 while (sitesIter.hasNext()) {
345                                     Site site = sitesIter.next();
346                                     // We should only set the title if the bookmark is for the root
347                                     // (i.e. www.google.com), as website settings act on the origin
348                                     // as a whole rather than a single page under that origin. If the
349                                     // user has bookmarked a page under the root but *not* the root,
350                                     // then we risk displaying the title of that page which may or
351                                     // may not have any relevance to the origin.
352                                     if (url.equals(site.getOrigin()) ||
353                                             (new String(site.getOrigin()+"/")).equals(url)) {
354                                         mDataSetChanged = true;
355                                         site.setTitle(title);
356                                     }
357 
358                                     if (bmp != null) {
359                                         mDataSetChanged = true;
360                                         site.setIcon(bmp);
361                                     }
362                                 }
363                             }
364                         } while (c.moveToNext());
365                     }
366                     c.close();
367                 }
368             return null;
369             }
370 
onPostExecute(Void unused)371             protected void onPostExecute(Void unused) {
372                 if (mDataSetChanged) {
373                     notifyDataSetChanged();
374                 }
375             }
376         }
377 
378 
populateOrigins(Map<String, Site> sites)379         public void populateOrigins(Map<String, Site> sites) {
380             clear();
381 
382             // We can now simply populate our array with Site instances
383             Set<Map.Entry<String, Site>> elements = sites.entrySet();
384             Iterator<Map.Entry<String, Site>> entryIterator = elements.iterator();
385             while (entryIterator.hasNext()) {
386                 Map.Entry<String, Site> entry = entryIterator.next();
387                 Site site = entry.getValue();
388                 add(site);
389             }
390 
391             notifyDataSetChanged();
392 
393             if (getCount() == 0) {
394                 finish(); // we close the screen
395             }
396         }
397 
getCount()398         public int getCount() {
399             if (mCurrentSite == null) {
400                 return super.getCount();
401             }
402             return mCurrentSite.getFeatureCount();
403         }
404 
sizeValueToString(long bytes)405         public String sizeValueToString(long bytes) {
406             // We display the size in MB, to 1dp, rounding up to the next 0.1MB.
407             // bytes should always be greater than zero.
408             if (bytes <= 0) {
409                 Log.e(LOGTAG, "sizeValueToString called with non-positive value: " + bytes);
410                 return "0";
411             }
412             float megabytes = (float) bytes / (1024.0F * 1024.0F);
413             int truncated = (int) Math.ceil(megabytes * 10.0F);
414             float result = (float) (truncated / 10.0F);
415             return String.valueOf(result);
416         }
417 
418         /*
419          * If we receive the back event and are displaying
420          * site's settings, we want to go back to the main
421          * list view. If not, we just do nothing (see
422          * dispatchKeyEvent() below).
423          */
backKeyPressed()424         public boolean backKeyPressed() {
425             if (mCurrentSite != null) {
426                 mCurrentSite = null;
427                 askForOrigins();
428                 return true;
429             }
430             return false;
431         }
432 
433         /**
434          * @hide
435          * Utility function
436          * Set the icon according to the usage
437          */
setIconForUsage(ImageView usageIcon, long usageInBytes)438         public void setIconForUsage(ImageView usageIcon, long usageInBytes) {
439             float usageInMegabytes = (float) usageInBytes / (1024.0F * 1024.0F);
440             // We set the correct icon:
441             // 0 < empty < 0.1MB
442             // 0.1MB < low < 5MB
443             // 5MB < high
444             if (usageInMegabytes <= 0.1) {
445                 usageIcon.setImageBitmap(mUsageEmptyIcon);
446             } else if (usageInMegabytes > 0.1 && usageInMegabytes <= 5) {
447                 usageIcon.setImageBitmap(mUsageLowIcon);
448             } else if (usageInMegabytes > 5) {
449                 usageIcon.setImageBitmap(mUsageHighIcon);
450             }
451         }
452 
453         @Override
getView(int position, View convertView, ViewGroup parent)454         public View getView(int position, View convertView, ViewGroup parent) {
455             View view;
456             final TextView title;
457             final TextView subtitle;
458             final ImageView icon;
459             final ImageView usageIcon;
460             final ImageView locationIcon;
461             final ImageView featureIcon;
462 
463             if (convertView == null) {
464                 view = mInflater.inflate(mResource, parent, false);
465             } else {
466                 view = convertView;
467             }
468 
469             title = (TextView) view.findViewById(R.id.title);
470             subtitle = (TextView) view.findViewById(R.id.subtitle);
471             icon = (ImageView) view.findViewById(R.id.icon);
472             featureIcon = (ImageView) view.findViewById(R.id.feature_icon);
473             usageIcon = (ImageView) view.findViewById(R.id.usage_icon);
474             locationIcon = (ImageView) view.findViewById(R.id.location_icon);
475             usageIcon.setVisibility(View.GONE);
476             locationIcon.setVisibility(View.GONE);
477 
478             if (mCurrentSite == null) {
479 
480                 Site site = getItem(position);
481                 title.setText(site.getPrettyTitle());
482                 String subtitleText = site.getPrettyOrigin();
483                 if (subtitleText != null) {
484                     title.setMaxLines(1);
485                     title.setSingleLine(true);
486                     subtitle.setVisibility(View.VISIBLE);
487                     subtitle.setText(subtitleText);
488                 } else {
489                     subtitle.setVisibility(View.GONE);
490                     title.setMaxLines(2);
491                     title.setSingleLine(false);
492                 }
493 
494                 icon.setVisibility(View.VISIBLE);
495                 usageIcon.setVisibility(View.INVISIBLE);
496                 locationIcon.setVisibility(View.INVISIBLE);
497                 featureIcon.setVisibility(View.GONE);
498                 Bitmap bmp = site.getIcon();
499                 if (bmp == null) {
500                     bmp = mDefaultIcon;
501                 }
502                 icon.setImageBitmap(bmp);
503                 // We set the site as the view's tag,
504                 // so that we can get it in onItemClick()
505                 view.setTag(site);
506 
507                 String origin = site.getOrigin();
508                 if (site.hasFeature(Site.FEATURE_WEB_STORAGE)) {
509                     WebStorage.getInstance().getUsageForOrigin(origin, new ValueCallback<Long>() {
510                         public void onReceiveValue(Long value) {
511                             if (value != null) {
512                                 setIconForUsage(usageIcon, value.longValue());
513                                 usageIcon.setVisibility(View.VISIBLE);
514                             }
515                         }
516                     });
517                 }
518 
519                 if (site.hasFeature(Site.FEATURE_GEOLOCATION)) {
520                     locationIcon.setVisibility(View.VISIBLE);
521                     GeolocationPermissions.getInstance().getAllowed(origin, new ValueCallback<Boolean>() {
522                         public void onReceiveValue(Boolean allowed) {
523                             if (allowed != null) {
524                                 if (allowed.booleanValue()) {
525                                     locationIcon.setImageBitmap(mLocationAllowedIcon);
526                                 } else {
527                                     locationIcon.setImageBitmap(mLocationDisallowedIcon);
528                                 }
529                             }
530                         }
531                     });
532                 }
533             } else {
534                 icon.setVisibility(View.GONE);
535                 locationIcon.setVisibility(View.GONE);
536                 usageIcon.setVisibility(View.GONE);
537                 featureIcon.setVisibility(View.VISIBLE);
538                 String origin = mCurrentSite.getOrigin();
539                 switch (mCurrentSite.getFeatureByIndex(position)) {
540                     case Site.FEATURE_WEB_STORAGE:
541                         WebStorage.getInstance().getUsageForOrigin(origin, new ValueCallback<Long>() {
542                             public void onReceiveValue(Long value) {
543                                 if (value != null) {
544                                     String usage = sizeValueToString(value.longValue()) + " " + sMBStored;
545                                     title.setText(R.string.webstorage_clear_data_title);
546                                     subtitle.setText(usage);
547                                     subtitle.setVisibility(View.VISIBLE);
548                                     setIconForUsage(featureIcon, value.longValue());
549                                 }
550                             }
551                         });
552                         break;
553                     case Site.FEATURE_GEOLOCATION:
554                         title.setText(R.string.geolocation_settings_page_title);
555                         GeolocationPermissions.getInstance().getAllowed(origin, new ValueCallback<Boolean>() {
556                             public void onReceiveValue(Boolean allowed) {
557                                 if (allowed != null) {
558                                     if (allowed.booleanValue()) {
559                                         subtitle.setText(R.string.geolocation_settings_page_summary_allowed);
560                                         featureIcon.setImageBitmap(mLocationAllowedIcon);
561                                     } else {
562                                         subtitle.setText(R.string.geolocation_settings_page_summary_not_allowed);
563                                         featureIcon.setImageBitmap(mLocationDisallowedIcon);
564                                     }
565                                     subtitle.setVisibility(View.VISIBLE);
566                                 }
567                             }
568                         });
569                         break;
570                 }
571             }
572 
573             return view;
574         }
575 
onItemClick(AdapterView<?> parent, View view, int position, long id)576         public void onItemClick(AdapterView<?> parent,
577                                 View view,
578                                 int position,
579                                 long id) {
580             if (mCurrentSite != null) {
581                 switch (mCurrentSite.getFeatureByIndex(position)) {
582                     case Site.FEATURE_WEB_STORAGE:
583                         new AlertDialog.Builder(getContext())
584                             .setMessage(R.string.webstorage_clear_data_dialog_message)
585                             .setPositiveButton(R.string.webstorage_clear_data_dialog_ok_button,
586                                                new AlertDialog.OnClickListener() {
587                                 public void onClick(DialogInterface dlg, int which) {
588                                     WebStorage.getInstance().deleteOrigin(mCurrentSite.getOrigin());
589                                     // If this site has no more features, then go back to the
590                                     // origins list.
591                                     mCurrentSite.removeFeature(Site.FEATURE_WEB_STORAGE);
592                                     if (mCurrentSite.getFeatureCount() == 0) {
593                                         finish();
594                                     }
595                                     askForOrigins();
596                                     notifyDataSetChanged();
597                                 }})
598                             .setNegativeButton(R.string.webstorage_clear_data_dialog_cancel_button, null)
599                             .setIconAttribute(android.R.attr.alertDialogIcon)
600                             .show();
601                         break;
602                     case Site.FEATURE_GEOLOCATION:
603                         new AlertDialog.Builder(getContext())
604                             .setMessage(R.string.geolocation_settings_page_dialog_message)
605                             .setPositiveButton(R.string.geolocation_settings_page_dialog_ok_button,
606                                                new AlertDialog.OnClickListener() {
607                                 public void onClick(DialogInterface dlg, int which) {
608                                     GeolocationPermissions.getInstance().clear(mCurrentSite.getOrigin());
609                                     mCurrentSite.removeFeature(Site.FEATURE_GEOLOCATION);
610                                     if (mCurrentSite.getFeatureCount() == 0) {
611                                         finish();
612                                     }
613                                     askForOrigins();
614                                     notifyDataSetChanged();
615                                 }})
616                             .setNegativeButton(R.string.geolocation_settings_page_dialog_cancel_button, null)
617                             .setIconAttribute(android.R.attr.alertDialogIcon)
618                             .show();
619                         break;
620                 }
621             } else {
622                 Site site = (Site) view.getTag();
623                 PreferenceActivity activity = (PreferenceActivity) getActivity();
624                 if (activity != null) {
625                     Bundle args = new Bundle();
626                     args.putParcelable(EXTRA_SITE, site);
627                     activity.startPreferencePanel(WebsiteSettingsFragment.class.getName(), args, 0,
628                             site.getPrettyTitle(), null, 0);
629                 }
630             }
631         }
632 
currentSite()633         public Site currentSite() {
634             return mCurrentSite;
635         }
636     }
637 
638     @Override
onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)639     public View onCreateView(LayoutInflater inflater, ViewGroup container,
640             Bundle savedInstanceState) {
641         View view = inflater.inflate(R.layout.website_settings, container, false);
642         Bundle args = getArguments();
643         if (args != null) {
644             mSite = (Site) args.getParcelable(EXTRA_SITE);
645         }
646         if (mSite == null) {
647             View clear = view.findViewById(R.id.clear_all_button);
648             clear.setVisibility(View.VISIBLE);
649             clear.setOnClickListener(this);
650         }
651         return view;
652     }
653 
654     @Override
onActivityCreated(Bundle savedInstanceState)655     public void onActivityCreated(Bundle savedInstanceState) {
656         super.onActivityCreated(savedInstanceState);
657         if (sMBStored == null) {
658             sMBStored = getString(R.string.webstorage_origin_summary_mb_stored);
659         }
660         mAdapter = new SiteAdapter(getActivity(), R.layout.website_settings_row);
661         if (mSite != null) {
662             mAdapter.mCurrentSite = mSite;
663         }
664         getListView().setAdapter(mAdapter);
665         getListView().setOnItemClickListener(mAdapter);
666     }
667 
668     @Override
onResume()669     public void onResume() {
670         super.onResume();
671         mAdapter.askForOrigins();
672     }
673 
finish()674     private void finish() {
675         PreferenceActivity activity = (PreferenceActivity) getActivity();
676         if (activity != null) {
677             activity.finishPreferencePanel(this, 0, null);
678         }
679     }
680 
681     @Override
onClick(View v)682     public void onClick(View v) {
683         switch (v.getId()) {
684         case R.id.clear_all_button:
685          // Show the prompt to clear all origins of their data and geolocation permissions.
686             new AlertDialog.Builder(getActivity())
687                     .setMessage(R.string.website_settings_clear_all_dialog_message)
688                     .setPositiveButton(R.string.website_settings_clear_all_dialog_ok_button,
689                             new AlertDialog.OnClickListener() {
690                                 public void onClick(DialogInterface dlg, int which) {
691                                     WebStorage.getInstance().deleteAllData();
692                                     GeolocationPermissions.getInstance().clearAll();
693                                     WebStorageSizeManager.resetLastOutOfSpaceNotificationTime();
694                                     mAdapter.askForOrigins();
695                                     finish();
696                                 }})
697                     .setNegativeButton(R.string.website_settings_clear_all_dialog_cancel_button, null)
698                     .setIconAttribute(android.R.attr.alertDialogIcon)
699                     .show();
700             break;
701         }
702     }
703 }
704