// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser.preferences.website;
import android.content.Context;
import android.content.DialogInterface;
import android.content.res.Resources;
import android.net.Uri;
import android.os.Bundle;
import android.preference.ListPreference;
import android.preference.Preference;
import android.preference.Preference.OnPreferenceChangeListener;
import android.preference.Preference.OnPreferenceClickListener;
import android.preference.PreferenceFragment;
import android.preference.PreferenceScreen;
import android.support.v7.app.AlertDialog;
import android.text.format.Formatter;
import android.widget.ListAdapter;
import android.widget.ListView;
import org.chromium.base.VisibleForTesting;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.ContentSettingsType;
import org.chromium.chrome.browser.omnibox.geo.GeolocationHeader;
import org.chromium.chrome.browser.search_engines.TemplateUrlService;
import org.chromium.components.url_formatter.UrlFormatter;
import org.chromium.content_public.browser.WebContents;
import java.net.URI;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
/**
* Shows the permissions and other settings for a particular website.
*/
public class SingleWebsitePreferences extends PreferenceFragment
implements DialogInterface.OnClickListener, OnPreferenceChangeListener,
OnPreferenceClickListener {
// SingleWebsitePreferences expects either EXTRA_SITE (a Website) or
// EXTRA_ORIGIN (a WebsiteAddress) to be present (but not both). If
// EXTRA_SITE is present, the fragment will display the permissions in that
// Website object. If EXTRA_ORIGIN is present, the fragment will find all
// permissions for that website address and display those. If EXTRA_LOCATION
// is present, the fragment will add a Location toggle, even if the site
// specifies no Location permission.
public static final String EXTRA_SITE = "org.chromium.chrome.preferences.site";
public static final String EXTRA_ORIGIN = "org.chromium.chrome.preferences.origin";
public static final String EXTRA_LOCATION = "org.chromium.chrome.preferences.location";
public static final String EXTRA_WEB_CONTENTS = "org.chromium.chrome.preferences.web_contents";
public static final String EXTRA_USB_INFO = "org.chromium.chrome.preferences.usb_info";
// Preference keys, see single_website_preferences.xml
// Headings:
public static final String PREF_SITE_TITLE = "site_title";
public static final String PREF_USAGE = "site_usage";
public static final String PREF_PERMISSIONS = "site_permissions";
public static final String PREF_OS_PERMISSIONS_WARNING = "os_permissions_warning";
public static final String PREF_OS_PERMISSIONS_WARNING_EXTRA = "os_permissions_warning_extra";
public static final String PREF_OS_PERMISSIONS_WARNING_DIVIDER =
"os_permissions_warning_divider";
// Actions at the top (if adding new, see hasUsagePreferences below):
public static final String PREF_CLEAR_DATA = "clear_data";
// Buttons:
public static final String PREF_RESET_SITE = "reset_site_button";
// Website permissions (if adding new, see hasPermissionsPreferences and resetSite below):
public static final String PREF_AUTOPLAY_PERMISSION = "autoplay_permission_list";
public static final String PREF_BACKGROUND_SYNC_PERMISSION = "background_sync_permission_list";
public static final String PREF_CAMERA_CAPTURE_PERMISSION = "camera_permission_list";
public static final String PREF_COOKIES_PERMISSION = "cookies_permission_list";
public static final String PREF_FULLSCREEN_PERMISSION = "fullscreen_permission_list";
public static final String PREF_JAVASCRIPT_PERMISSION = "javascript_permission_list";
public static final String PREF_KEYGEN_PERMISSION = "keygen_permission_list";
public static final String PREF_LOCATION_ACCESS = "location_access_list";
public static final String PREF_MIC_CAPTURE_PERMISSION = "microphone_permission_list";
public static final String PREF_MIDI_SYSEX_PERMISSION = "midi_sysex_permission_list";
public static final String PREF_NOTIFICATIONS_PERMISSION = "push_notifications_list";
public static final String PREF_POPUP_PERMISSION = "popup_permission_list";
public static final String PREF_PROTECTED_MEDIA_IDENTIFIER_PERMISSION =
"protected_media_identifier_permission_list";
// All permissions from the permissions preference category must be listed here.
// TODO(mvanouwerkerk): Use this array in more places to reduce verbosity.
private static final String[] PERMISSION_PREFERENCE_KEYS = {
PREF_AUTOPLAY_PERMISSION,
PREF_BACKGROUND_SYNC_PERMISSION,
PREF_CAMERA_CAPTURE_PERMISSION,
PREF_COOKIES_PERMISSION,
PREF_FULLSCREEN_PERMISSION,
PREF_JAVASCRIPT_PERMISSION,
PREF_KEYGEN_PERMISSION,
PREF_LOCATION_ACCESS,
PREF_MIC_CAPTURE_PERMISSION,
PREF_MIDI_SYSEX_PERMISSION,
PREF_NOTIFICATIONS_PERMISSION,
PREF_POPUP_PERMISSION,
PREF_PROTECTED_MEDIA_IDENTIFIER_PERMISSION,
};
// The website this page is displaying details about.
private Website mSite;
// The address of the site we want to display. Used only if EXTRA_ADDRESS is provided.
private WebsiteAddress mSiteAddress;
// The number of USB device permissions displayed.
private int mUsbPermissionCount;
private class SingleWebsitePermissionsPopulator
implements WebsitePermissionsFetcher.WebsitePermissionsCallback {
private final WebContents mWebContents;
public SingleWebsitePermissionsPopulator(WebContents webContents) {
mWebContents = webContents;
}
@Override
public void onWebsitePermissionsAvailable(Collection<Website> sites) {
// This method may be called after the activity has been destroyed.
// In that case, bail out.
if (getActivity() == null) return;
// TODO(mvanouwerkerk): Avoid modifying the outer class from this inner class.
mSite = mergePermissionInfoForTopLevelOrigin(mSiteAddress, sites);
// Display Keygen Content Setting if Keygen is blocked.
if (mSite.getKeygenInfo() == null && mWebContents != null
&& WebsitePreferenceBridge.getKeygenBlocked(mWebContents)) {
String origin = mSiteAddress.getOrigin();
mSite.setKeygenInfo(new KeygenInfo(origin, origin, false));
}
displaySitePermissions();
}
}
/**
* Creates a Bundle with the correct arguments for opening this fragment for
* the website with the given url.
*
* @param url The URL to open the fragment with. This is a complete url including scheme,
* domain, port, path, etc.
* @return The bundle to attach to the preferences intent.
*/
public static Bundle createFragmentArgsForSite(String url) {
Bundle fragmentArgs = new Bundle();
// TODO(mvanouwerkerk): Define a pure getOrigin method in UrlUtilities that is the
// equivalent of the call below, because this is perfectly fine for non-display purposes.
String origin =
UrlFormatter.formatUrlForSecurityDisplay(URI.create(url), true /* showScheme */);
fragmentArgs.putString(SingleWebsitePreferences.EXTRA_ORIGIN, origin);
return fragmentArgs;
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
getActivity().setTitle(R.string.prefs_site_settings);
ListView listView = (ListView) getView().findViewById(android.R.id.list);
listView.setDivider(null);
Object extraSite = getArguments().getSerializable(EXTRA_SITE);
Object extraOrigin = getArguments().getSerializable(EXTRA_ORIGIN);
getArguments().setClassLoader(WebContents.class.getClassLoader());
Object webContents = getArguments().get(EXTRA_WEB_CONTENTS);
if (extraSite != null && extraOrigin == null) {
mSite = (Website) extraSite;
displaySitePermissions();
} else if (extraOrigin != null && extraSite == null) {
mSiteAddress = WebsiteAddress.create((String) extraOrigin);
WebsitePermissionsFetcher fetcher;
fetcher = new WebsitePermissionsFetcher(
new SingleWebsitePermissionsPopulator((WebContents) webContents));
fetcher.fetchAllPreferences();
} else {
assert false : "Exactly one of EXTRA_SITE or EXTRA_SITE_ADDRESS must be provided.";
}
super.onActivityCreated(savedInstanceState);
}
/**
* Given an address and a list of sets of websites, returns a new site with the same origin
* as |address| which has merged into it the permissions of the matching input sites. If a
* permission is found more than once, the one found first is used and the latter are ignored.
* This should not drop any relevant data as there should not be duplicates like that in the
* first place.
*
* @param address The address to search for.
* @param websites The websites to search in.
* @return The merged website.
*/
private static Website mergePermissionInfoForTopLevelOrigin(
WebsiteAddress address, Collection<Website> websites) {
String origin = address.getOrigin();
String host = Uri.parse(origin).getHost();
Website merged = new Website(address, null);
// This loop looks expensive, but the amount of data is likely to be relatively small
// because most sites have very few permissions.
for (Website other : websites) {
if (merged.getFullscreenInfo() == null && other.getFullscreenInfo() != null
&& permissionInfoIsForTopLevelOrigin(other.getFullscreenInfo(), origin)) {
merged.setFullscreenInfo(other.getFullscreenInfo());
}
if (merged.getGeolocationInfo() == null && other.getGeolocationInfo() != null
&& permissionInfoIsForTopLevelOrigin(other.getGeolocationInfo(), origin)) {
merged.setGeolocationInfo(other.getGeolocationInfo());
}
if (merged.getKeygenInfo() == null && other.getKeygenInfo() != null
&& permissionInfoIsForTopLevelOrigin(other.getKeygenInfo(), origin)) {
merged.setKeygenInfo(other.getKeygenInfo());
}
if (merged.getMidiInfo() == null && other.getMidiInfo() != null
&& permissionInfoIsForTopLevelOrigin(other.getMidiInfo(), origin)) {
merged.setMidiInfo(other.getMidiInfo());
}
if (merged.getProtectedMediaIdentifierInfo() == null
&& other.getProtectedMediaIdentifierInfo() != null
&& permissionInfoIsForTopLevelOrigin(
other.getProtectedMediaIdentifierInfo(), origin)) {
merged.setProtectedMediaIdentifierInfo(other.getProtectedMediaIdentifierInfo());
}
if (merged.getNotificationInfo() == null
&& other.getNotificationInfo() != null
&& permissionInfoIsForTopLevelOrigin(
other.getNotificationInfo(), origin)) {
merged.setNotificationInfo(other.getNotificationInfo());
}
if (merged.getCameraInfo() == null && other.getCameraInfo() != null
&& permissionInfoIsForTopLevelOrigin(
other.getCameraInfo(), origin)) {
merged.setCameraInfo(other.getCameraInfo());
}
if (merged.getMicrophoneInfo() == null && other.getMicrophoneInfo() != null
&& permissionInfoIsForTopLevelOrigin(other.getMicrophoneInfo(), origin)) {
merged.setMicrophoneInfo(other.getMicrophoneInfo());
}
if (merged.getLocalStorageInfo() == null
&& other.getLocalStorageInfo() != null
&& origin.equals(other.getLocalStorageInfo().getOrigin())) {
merged.setLocalStorageInfo(other.getLocalStorageInfo());
}
for (StorageInfo storageInfo : other.getStorageInfo()) {
if (host.equals(storageInfo.getHost())) {
merged.addStorageInfo(storageInfo);
}
}
for (UsbInfo usbInfo : other.getUsbInfo()) {
if (origin.equals(usbInfo.getOrigin())
&& (usbInfo.getEmbedder() == null || usbInfo.getEmbedder().equals("*"))) {
merged.addUsbInfo(usbInfo);
}
}
// TODO(mvanouwerkerk): Make the various info types share a common interface that
// supports reading the origin or host.
// TODO(mvanouwerkerk): Merge in PopupExceptionInfo? It uses a pattern, and is never
// set on Android.
// TODO(mvanouwerkerk): Merge in JavaScriptExceptionInfo? It uses a pattern.
// TODO(lshang): Merge in CookieException? It will use patterns.
}
return merged;
}
private static boolean permissionInfoIsForTopLevelOrigin(PermissionInfo info, String origin) {
// TODO(mvanouwerkerk): Find a more generic place for this method.
return origin.equals(info.getOrigin())
&& (origin.equals(info.getEmbedderSafe()) || "*".equals(info.getEmbedderSafe()));
}
/**
* Updates the permissions displayed in the UI by fetching them from mSite.
* Must only be called once mSite is set.
*/
private void displaySitePermissions() {
addPreferencesFromResource(R.xml.single_website_preferences);
Set<String> permissionPreferenceKeys =
new HashSet<>(Arrays.asList(PERMISSION_PREFERENCE_KEYS));
int maxPermissionOrder = 0;
ListAdapter preferences = getPreferenceScreen().getRootAdapter();
for (int i = 0; i < preferences.getCount(); ++i) {
Preference preference = (Preference) preferences.getItem(i);
if (PREF_SITE_TITLE.equals(preference.getKey())) {
preference.setTitle(mSite.getTitle());
} else if (PREF_CLEAR_DATA.equals(preference.getKey())) {
long usage = mSite.getTotalUsage();
if (usage > 0) {
Context context = preference.getContext();
preference.setTitle(String.format(
context.getString(R.string.origin_settings_storage_usage_brief),
Formatter.formatShortFileSize(context, usage)));
((ClearWebsiteStorage) preference).setConfirmationListener(this);
} else {
getPreferenceScreen().removePreference(preference);
}
} else if (PREF_RESET_SITE.equals(preference.getKey())) {
preference.setOnPreferenceClickListener(this);
} else if (PREF_AUTOPLAY_PERMISSION.equals(preference.getKey())) {
setUpListPreference(preference, mSite.getAutoplayPermission());
} else if (PREF_BACKGROUND_SYNC_PERMISSION.equals(preference.getKey())) {
setUpListPreference(preference, mSite.getBackgroundSyncPermission());
} else if (PREF_CAMERA_CAPTURE_PERMISSION.equals(preference.getKey())) {
setUpListPreference(preference, mSite.getCameraPermission());
} else if (PREF_COOKIES_PERMISSION.equals(preference.getKey())) {
setUpListPreference(preference, mSite.getCookiePermission());
} else if (PREF_FULLSCREEN_PERMISSION.equals(preference.getKey())) {
preference.setEnabled(false);
setUpListPreference(preference, mSite.getFullscreenPermission());
} else if (PREF_JAVASCRIPT_PERMISSION.equals(preference.getKey())) {
setUpListPreference(preference, mSite.getJavaScriptPermission());
} else if (PREF_KEYGEN_PERMISSION.equals(preference.getKey())) {
setUpListPreference(preference, mSite.getKeygenPermission());
} else if (PREF_LOCATION_ACCESS.equals(preference.getKey())) {
setUpLocationPreference(preference);
} else if (PREF_MIC_CAPTURE_PERMISSION.equals(preference.getKey())) {
setUpListPreference(preference, mSite.getMicrophonePermission());
} else if (PREF_MIDI_SYSEX_PERMISSION.equals(preference.getKey())) {
setUpListPreference(preference, mSite.getMidiPermission());
} else if (PREF_NOTIFICATIONS_PERMISSION.equals(preference.getKey())) {
setUpListPreference(preference, mSite.getNotificationPermission());
} else if (PREF_POPUP_PERMISSION.equals(preference.getKey())) {
setUpListPreference(preference, mSite.getPopupPermission());
} else if (PREF_PROTECTED_MEDIA_IDENTIFIER_PERMISSION.equals(preference.getKey())) {
setUpListPreference(preference, mSite.getProtectedMediaIdentifierPermission());
}
if (permissionPreferenceKeys.contains(preference.getKey())) {
maxPermissionOrder = Math.max(maxPermissionOrder, preference.getOrder());
}
}
for (UsbInfo info : mSite.getUsbInfo()) {
Preference preference = new Preference(getActivity());
preference.getExtras().putSerializable(EXTRA_USB_INFO, info);
preference.setIcon(R.drawable.settings_usb);
preference.setOnPreferenceClickListener(this);
preference.setOrder(maxPermissionOrder);
preference.setTitle(info.getName());
preference.setWidgetLayoutResource(R.layout.usb_permission);
getPreferenceScreen().addPreference(preference);
mUsbPermissionCount++;
}
// Remove the 'permission is off in Android' message if not needed.
PreferenceScreen preferenceScreen = getPreferenceScreen();
SiteSettingsCategory categoryWithWarning = getWarningCategory();
if (categoryWithWarning == null) {
getPreferenceScreen().removePreference(
preferenceScreen.findPreference(PREF_OS_PERMISSIONS_WARNING));
getPreferenceScreen().removePreference(
preferenceScreen.findPreference(PREF_OS_PERMISSIONS_WARNING_EXTRA));
getPreferenceScreen().removePreference(
preferenceScreen.findPreference(PREF_OS_PERMISSIONS_WARNING_DIVIDER));
} else {
Preference osWarning = preferenceScreen.findPreference(PREF_OS_PERMISSIONS_WARNING);
Preference osWarningExtra =
preferenceScreen.findPreference(PREF_OS_PERMISSIONS_WARNING_EXTRA);
categoryWithWarning.configurePermissionIsOffPreferences(
osWarning, osWarningExtra, getActivity(), false);
if (osWarning.getTitle() == null) {
getPreferenceScreen().removePreference(
preferenceScreen.findPreference(PREF_OS_PERMISSIONS_WARNING));
} else if (osWarningExtra.getTitle() == null) {
getPreferenceScreen().removePreference(
preferenceScreen.findPreference(PREF_OS_PERMISSIONS_WARNING_EXTRA));
}
}
// Remove categories if no sub-items.
if (!hasUsagePreferences()) {
Preference heading = preferenceScreen.findPreference(PREF_USAGE);
preferenceScreen.removePreference(heading);
}
if (!hasPermissionsPreferences()) {
Preference heading = preferenceScreen.findPreference(PREF_PERMISSIONS);
preferenceScreen.removePreference(heading);
}
}
private SiteSettingsCategory getWarningCategory() {
// If more than one per-app permission is disabled in Android, we can pick any category to
// show the warning, because they will all show the same warning and all take the user to
// the user to the same location. It is preferrable, however, that we give Geolocation some
// priority because that category is the only one that potentially shows an additional
// warning (when Location is turned off globally).
if (showWarningFor(ContentSettingsType.CONTENT_SETTINGS_TYPE_GEOLOCATION)) {
return SiteSettingsCategory.fromContentSettingsType(
ContentSettingsType.CONTENT_SETTINGS_TYPE_GEOLOCATION);
}
if (showWarningFor(ContentSettingsType.CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA)) {
return SiteSettingsCategory.fromContentSettingsType(
ContentSettingsType.CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA);
}
if (showWarningFor(ContentSettingsType.CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC)) {
return SiteSettingsCategory.fromContentSettingsType(
ContentSettingsType.CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC);
}
return null;
}
private boolean showWarningFor(int type) {
ContentSetting setting = null;
if (type == ContentSettingsType.CONTENT_SETTINGS_TYPE_GEOLOCATION) {
setting = mSite.getGeolocationPermission();
} else if (type == ContentSettingsType.CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA) {
setting = mSite.getCameraPermission();
} else if (type == ContentSettingsType.CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC) {
setting = mSite.getMicrophonePermission();
}
if (setting == null) {
return false;
}
SiteSettingsCategory category = SiteSettingsCategory.fromContentSettingsType(type);
return category.showPermissionBlockedMessage(getActivity());
}
private boolean hasUsagePreferences() {
// New actions under the Usage preference category must be listed here so that the category
// heading can be removed when no actions are shown.
return getPreferenceScreen().findPreference(PREF_CLEAR_DATA) != null;
}
private boolean hasPermissionsPreferences() {
if (mUsbPermissionCount > 0) return true;
PreferenceScreen screen = getPreferenceScreen();
for (String key : PERMISSION_PREFERENCE_KEYS) {
if (screen.findPreference(key) != null) return true;
}
return false;
}
/**
* Initialize a ListPreference with a certain value.
* @param preference The ListPreference to initialize.
* @param value The value to initialize it to.
*/
private void setUpListPreference(Preference preference, ContentSetting value) {
if (value == null) {
getPreferenceScreen().removePreference(preference);
return;
}
ListPreference listPreference = (ListPreference) preference;
int contentType = getContentSettingsTypeFromPreferenceKey(preference.getKey());
CharSequence[] keys = new String[2];
CharSequence[] descriptions = new String[2];
keys[0] = ContentSetting.ALLOW.toString();
keys[1] = ContentSetting.BLOCK.toString();
descriptions[0] = getResources().getString(
ContentSettingsResources.getSiteSummary(ContentSetting.ALLOW));
descriptions[1] = getResources().getString(
ContentSettingsResources.getSiteSummary(ContentSetting.BLOCK));
listPreference.setEntryValues(keys);
listPreference.setEntries(descriptions);
int index = (value == ContentSetting.ALLOW ? 0 : 1);
listPreference.setValueIndex(index);
int explanationResourceId = ContentSettingsResources.getExplanation(contentType);
if (explanationResourceId != 0) {
listPreference.setTitle(explanationResourceId);
}
if (listPreference.isEnabled()) {
SiteSettingsCategory category =
SiteSettingsCategory.fromContentSettingsType(contentType);
if (category != null && !category.enabledInAndroid(getActivity())) {
listPreference.setIcon(category.getDisabledInAndroidIcon(getActivity()));
listPreference.setEnabled(false);
} else {
listPreference.setIcon(ContentSettingsResources.getIcon(contentType));
}
} else {
listPreference.setIcon(
ContentSettingsResources.getDisabledIcon(contentType, getResources()));
}
preference.setSummary("%s");
listPreference.setOnPreferenceChangeListener(this);
}
private void setUpLocationPreference(Preference preference) {
ContentSetting permission = mSite.getGeolocationPermission();
Context context = preference.getContext();
Object locationAllowed = getArguments().getSerializable(EXTRA_LOCATION);
if (permission == null && hasXGeoLocationPermission(context)) {
String origin = mSite.getAddress().getOrigin();
mSite.setGeolocationInfo(new GeolocationInfo(origin, origin, false));
setUpListPreference(preference, ContentSetting.ALLOW);
updateLocationPreferenceForXGeo(preference);
} else if (permission == null && locationAllowed != null) {
String origin = mSite.getAddress().getOrigin();
mSite.setGeolocationInfo(new GeolocationInfo(origin, origin, false));
setUpListPreference(preference, (boolean) locationAllowed
? ContentSetting.ALLOW : ContentSetting.BLOCK);
} else {
setUpListPreference(preference, permission);
}
}
/**
* Returns true if the current host matches the default search engine host and location for the
* default search engine is being granted via x-geo.
* @param context The current context.
*/
private boolean hasXGeoLocationPermission(Context context) {
String searchUrl = TemplateUrlService.getInstance().getUrlForSearchQuery("foo");
return mSite.getAddress().matches(searchUrl)
&& GeolocationHeader.isGeoHeaderEnabledForUrl(context, searchUrl, false);
}
/**
* Updates the location preference to indicate that the site has access to location (via X-Geo)
* for searches that happen from the omnibox.
* @param preference The Location preference to modify.
*/
private void updateLocationPreferenceForXGeo(Preference preference) {
ListPreference listPreference = (ListPreference) preference;
Resources res = getResources();
listPreference.setEntries(new String[] {
res.getString(R.string.website_settings_permissions_allow_dse),
res.getString(ContentSettingsResources.getSiteSummary(ContentSetting.BLOCK)),
});
listPreference.setEntryValues(new String[] {
ContentSetting.DEFAULT.toString(),
ContentSetting.BLOCK.toString(),
});
listPreference.setValueIndex(0);
}
private int getContentSettingsTypeFromPreferenceKey(String preferenceKey) {
switch (preferenceKey) {
case PREF_AUTOPLAY_PERMISSION:
return ContentSettingsType.CONTENT_SETTINGS_TYPE_AUTOPLAY;
case PREF_BACKGROUND_SYNC_PERMISSION:
return ContentSettingsType.CONTENT_SETTINGS_TYPE_BACKGROUND_SYNC;
case PREF_CAMERA_CAPTURE_PERMISSION:
return ContentSettingsType.CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA;
case PREF_COOKIES_PERMISSION:
return ContentSettingsType.CONTENT_SETTINGS_TYPE_COOKIES;
case PREF_FULLSCREEN_PERMISSION:
return ContentSettingsType.CONTENT_SETTINGS_TYPE_FULLSCREEN;
case PREF_JAVASCRIPT_PERMISSION:
return ContentSettingsType.CONTENT_SETTINGS_TYPE_JAVASCRIPT;
case PREF_KEYGEN_PERMISSION:
return ContentSettingsType.CONTENT_SETTINGS_TYPE_KEYGEN;
case PREF_LOCATION_ACCESS:
return ContentSettingsType.CONTENT_SETTINGS_TYPE_GEOLOCATION;
case PREF_MIC_CAPTURE_PERMISSION:
return ContentSettingsType.CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC;
case PREF_MIDI_SYSEX_PERMISSION:
return ContentSettingsType.CONTENT_SETTINGS_TYPE_MIDI_SYSEX;
case PREF_NOTIFICATIONS_PERMISSION:
return ContentSettingsType.CONTENT_SETTINGS_TYPE_NOTIFICATIONS;
case PREF_POPUP_PERMISSION:
return ContentSettingsType.CONTENT_SETTINGS_TYPE_POPUPS;
case PREF_PROTECTED_MEDIA_IDENTIFIER_PERMISSION:
return ContentSettingsType.CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER;
default:
return 0;
}
}
@Override
public void onClick(DialogInterface dialog, int which) {
clearStoredData();
}
private void clearStoredData() {
mSite.clearAllStoredData(
new Website.StoredDataClearedCallback() {
@Override
public void onStoredDataCleared() {
PreferenceScreen preferenceScreen = getPreferenceScreen();
preferenceScreen.removePreference(
preferenceScreen.findPreference(PREF_CLEAR_DATA));
if (!hasUsagePreferences()) {
preferenceScreen.removePreference(
preferenceScreen.findPreference(PREF_USAGE));
}
popBackIfNoSettings();
}
});
}
private void popBackIfNoSettings() {
if (!hasPermissionsPreferences() && !hasUsagePreferences()) {
if (getActivity() != null) {
getActivity().finish();
}
}
}
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
ContentSetting permission = ContentSetting.fromString((String) newValue);
if (PREF_AUTOPLAY_PERMISSION.equals(preference.getKey())) {
mSite.setAutoplayPermission(permission);
} else if (PREF_BACKGROUND_SYNC_PERMISSION.equals(preference.getKey())) {
mSite.setBackgroundSyncPermission(permission);
} else if (PREF_CAMERA_CAPTURE_PERMISSION.equals(preference.getKey())) {
mSite.setCameraPermission(permission);
} else if (PREF_COOKIES_PERMISSION.equals(preference.getKey())) {
mSite.setCookiePermission(permission);
} else if (PREF_FULLSCREEN_PERMISSION.equals(preference.getKey())) {
mSite.setFullscreenPermission(permission);
} else if (PREF_JAVASCRIPT_PERMISSION.equals(preference.getKey())) {
mSite.setJavaScriptPermission(permission);
} else if (PREF_KEYGEN_PERMISSION.equals(preference.getKey())) {
mSite.setKeygenPermission(permission);
} else if (PREF_LOCATION_ACCESS.equals(preference.getKey())) {
mSite.setGeolocationPermission(permission);
} else if (PREF_MIC_CAPTURE_PERMISSION.equals(preference.getKey())) {
mSite.setMicrophonePermission(permission);
} else if (PREF_MIDI_SYSEX_PERMISSION.equals(preference.getKey())) {
mSite.setMidiPermission(permission);
} else if (PREF_NOTIFICATIONS_PERMISSION.equals(preference.getKey())) {
mSite.setNotificationPermission(permission);
} else if (PREF_POPUP_PERMISSION.equals(preference.getKey())) {
mSite.setPopupPermission(permission);
} else if (PREF_PROTECTED_MEDIA_IDENTIFIER_PERMISSION.equals(preference.getKey())) {
mSite.setProtectedMediaIdentifierPermission(permission);
}
return true;
}
@Override
public boolean onPreferenceClick(Preference preference) {
Bundle extras = preference.peekExtras();
if (extras != null) {
UsbInfo usbInfo = (UsbInfo) extras.getSerializable(EXTRA_USB_INFO);
if (usbInfo != null) {
usbInfo.revoke();
PreferenceScreen preferenceScreen = getPreferenceScreen();
preferenceScreen.removePreference(preference);
mUsbPermissionCount--;
if (!hasPermissionsPreferences()) {
Preference heading = preferenceScreen.findPreference(PREF_PERMISSIONS);
preferenceScreen.removePreference(heading);
}
return true;
}
}
// Handle the Clear & Reset preference click by showing a confirmation.
new AlertDialog.Builder(getActivity(), R.style.AlertDialogTheme)
.setTitle(R.string.website_reset)
.setMessage(R.string.website_reset_confirmation)
.setPositiveButton(R.string.website_reset, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
resetSite();
}
})
.setNegativeButton(R.string.cancel, null)
.show();
return true;
}
/**
* Resets the current site, clearing all permissions and storage used (inc. cookies).
*/
@VisibleForTesting
protected void resetSite() {
if (getActivity() == null) return;
// Clear the screen.
// TODO(mvanouwerkerk): Refactor this class so that it does not depend on the screen state
// for its logic. This class should maintain its own data model, and only update the screen
// after a change is made.
PreferenceScreen screen = getPreferenceScreen();
for (String key : PERMISSION_PREFERENCE_KEYS) {
Preference preference = screen.findPreference(key);
if (preference != null) screen.removePreference(preference);
}
// Clear the permissions.
mSite.setAutoplayPermission(ContentSetting.DEFAULT);
mSite.setBackgroundSyncPermission(ContentSetting.DEFAULT);
mSite.setCameraPermission(ContentSetting.DEFAULT);
mSite.setCookiePermission(ContentSetting.DEFAULT);
WebsitePreferenceBridge.nativeClearCookieData(mSite.getAddress().getTitle());
mSite.setFullscreenPermission(ContentSetting.DEFAULT);
mSite.setGeolocationPermission(ContentSetting.DEFAULT);
mSite.setJavaScriptPermission(ContentSetting.DEFAULT);
mSite.setKeygenPermission(ContentSetting.DEFAULT);
mSite.setMicrophonePermission(ContentSetting.DEFAULT);
mSite.setMidiPermission(ContentSetting.DEFAULT);
mSite.setNotificationPermission(ContentSetting.DEFAULT);
mSite.setPopupPermission(ContentSetting.DEFAULT);
mSite.setProtectedMediaIdentifierPermission(ContentSetting.DEFAULT);
for (UsbInfo info : mSite.getUsbInfo()) info.revoke();
// Clear the storage and finish the activity if necessary.
if (mSite.getTotalUsage() > 0) {
clearStoredData();
} else {
// Clearing stored data implies popping back to parent menu if there
// is nothing left to show. Therefore, we only need to explicitly
// close the activity if there's no stored data to begin with.
getActivity().finish();
}
}
}