Bug 706876 - Create "Clear Site Settings" menuitem. r=mfinkle

This commit is contained in:
Margaret Leibovic 2011-12-17 13:50:09 -08:00
Родитель ddf6778a19
Коммит 3ed223571b
8 изменённых файлов: 306 добавлений и 0 удалений

Просмотреть файл

@ -544,6 +544,9 @@ abstract public class GeckoApp
intent = new Intent(this, GeckoPreferences.class);
startActivity(intent);
return true;
case R.id.site_settings:
GeckoAppShell.sendEventToGecko(new GeckoEvent("Permissions:Get", null));
return true;
case R.id.addons:
GeckoAppShell.sendEventToGecko(new GeckoEvent("about:addons"));
return true;
@ -976,6 +979,10 @@ abstract public class GeckoApp
tab.setAgentMode(agentMode);
if (tab == Tabs.getInstance().getSelectedTab())
updateAgentModeMenuItem(tab, agentMode);
} else if (event.equals("Permissions:Data")) {
String host = message.getString("host");
JSONArray permissions = message.getJSONArray("permissions");
showSiteSettingsDialog(host, permissions);
}
} catch (Exception e) {
Log.e(LOGTAG, "Exception handling message \"" + event + "\":", e);
@ -1030,6 +1037,73 @@ abstract public class GeckoApp
});
}
/**
* @param aPermissions
* Array of JSON objects to represent site permissions.
* Example: { type: "offline-app", setting: "Store Offline Data: Allow" }
*/
private void showSiteSettingsDialog(String aHost, JSONArray aPermissions) {
final AlertDialog.Builder builder = new AlertDialog.Builder(this);
View customTitleView = getLayoutInflater().inflate(R.layout.site_setting_title, null);
((TextView) customTitleView.findViewById(R.id.title)).setText(R.string.site_settings_title);
((TextView) customTitleView.findViewById(R.id.host)).setText(aHost);
builder.setCustomTitle(customTitleView);
// If there are no permissions to clear, show the user a message about that.
// In the future, we want to disable the menu item if there are no permissions to clear.
if (aPermissions.length() == 0) {
builder.setMessage(R.string.site_settings_no_settings);
} else {
// Eventually we should use a list adapter and custom checkable list items
// to make a two-line UI to match the mock-ups
CharSequence[] items = new CharSequence[aPermissions.length()];
boolean[] states = new boolean[aPermissions.length()];
for (int i = 0; i < aPermissions.length(); i++) {
try {
items[i] = aPermissions.getJSONObject(i).
getString("setting");
// Make all the items checked by default
states[i] = true;
} catch (JSONException e) {
Log.i(LOGTAG, "JSONException: " + e);
}
}
builder.setMultiChoiceItems(items, states, new DialogInterface.OnMultiChoiceClickListener(){
public void onClick(DialogInterface dialog, int item, boolean state) {
// Do nothing
}
});
builder.setPositiveButton(R.string.site_settings_clear, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
ListView listView = ((AlertDialog) dialog).getListView();
SparseBooleanArray checkedItemPositions = listView.getCheckedItemPositions();
// An array of the indices of the permissions we want to clear
JSONArray permissionsToClear = new JSONArray();
for (int i = 0; i < checkedItemPositions.size(); i++) {
boolean checked = checkedItemPositions.get(i);
if (checked)
permissionsToClear.put(i);
}
GeckoAppShell.sendEventToGecko(new GeckoEvent("Permissions:Clear", permissionsToClear.toString()));
}
});
}
builder.setNegativeButton(R.string.site_settings_cancel, new DialogInterface.OnClickListener(){
public void onClick(DialogInterface dialog, int id) {
dialog.cancel();
}
});
mMainHandler.post(new Runnable() {
public void run() {
builder.create().show();
}
});
}
void handleDoorHanger(JSONObject geckoObject) throws JSONException {
final String message = geckoObject.getString("message");
final String value = geckoObject.getString("value");
@ -1463,6 +1537,7 @@ abstract public class GeckoApp
GeckoAppShell.registerGeckoEventListener("ToggleChrome:Show", GeckoApp.mAppContext);
GeckoAppShell.registerGeckoEventListener("AgentMode:Changed", GeckoApp.mAppContext);
GeckoAppShell.registerGeckoEventListener("FormAssist:AutoComplete", GeckoApp.mAppContext);
GeckoAppShell.registerGeckoEventListener("Permissions:Data", GeckoApp.mAppContext);
mConnectivityFilter = new IntentFilter();
mConnectivityFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
@ -1693,6 +1768,7 @@ abstract public class GeckoApp
GeckoAppShell.unregisterGeckoEventListener("ToggleChrome:Show", GeckoApp.mAppContext);
GeckoAppShell.unregisterGeckoEventListener("AgentMode:Changed", GeckoApp.mAppContext);
GeckoAppShell.unregisterGeckoEventListener("FormAssist:AutoComplete", GeckoApp.mAppContext);
GeckoAppShell.unregisterGeckoEventListener("Permissions:Data", GeckoApp.mAppContext);
mFavicons.close();

Просмотреть файл

@ -192,6 +192,7 @@ RES_LAYOUT = \
res/layout/notification_icon_text.xml \
res/layout/notification_progress.xml \
res/layout/notification_progress_text.xml \
res/layout/site_setting_title.xml \
res/layout/tabs_row.xml \
res/layout/tabs_tray.xml \
res/layout/list_item_header.xml \

Просмотреть файл

@ -80,3 +80,8 @@
<!ENTITY save_as_pdf "Save as PDF">
<!ENTITY agent_request_desktop "Request Desktop Site">
<!ENTITY agent_request_mobile "Request Mobile Site">
<!ENTITY site_settings_title "Clear Site Settings">
<!ENTITY site_settings_cancel "Cancel">
<!ENTITY site_settings_clear "Clear">
<!ENTITY site_settings_no_settings "There are no settings to clear.">

Просмотреть файл

@ -27,6 +27,9 @@
<item android:id="@+id/preferences"
android:title="@string/preferences" />
<item android:id="@+id/site_settings"
android:title="@string/site_settings_title" />
<item android:id="@+id/addons"
android:title="@string/addons"/>

Просмотреть файл

@ -0,0 +1,28 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical"
android:gravity="center_vertical">
<TextView android:id="@+id/title"
style="?android:attr/windowTitleStyle"
android:textAppearance="?android:attr/textAppearanceLarge"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="6dip"
android:paddingBottom="0dip"
android:paddingLeft="10dip"
android:paddingRight="10dip"/>
<TextView android:id="@+id/host"
style="?android:attr/windowTitleStyle"
android:textAppearance="?android:attr/textAppearanceMedium"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="2dip"
android:paddingBottom="6dip"
android:paddingLeft="10dip"
android:paddingRight="10dip"/>
</LinearLayout>

Просмотреть файл

@ -82,4 +82,9 @@
<string name="forward">&forward;</string>
<string name="new_tab">&new_tab;</string>
<string name="addons">&addons;</string>
<string name="site_settings_title">&site_settings_title;</string>
<string name="site_settings_cancel">&site_settings_cancel;</string>
<string name="site_settings_clear">&site_settings_clear;</string>
<string name="site_settings_no_settings">&site_settings_no_settings;</string>
</resources>

Просмотреть файл

@ -207,6 +207,7 @@ var BrowserApp = {
XPInstallObserver.init();
ConsoleAPI.init();
ClipboardHelper.init();
PermissionsHelper.init();
// Init LoginManager
Cc["@mozilla.org/login-manager;1"].getService(Ci.nsILoginManager);
@ -3259,3 +3260,159 @@ var PluginHelper = {
return overflows;
}
};
var PermissionsHelper = {
_permissonTypes: ["password", "geo", "popup", "indexedDB",
"offline-app", "desktop-notification"],
_permissionStrings: {
"password": {
label: "password.rememberPassword",
allowed: "password.remember",
denied: "password.never"
},
"geo": {
label: "geolocation.shareLocation",
allowed: "geolocation.alwaysShare",
denied: "geolocation.neverShare"
},
"popup": {
label: "blockPopups.label",
allowed: "popupButtonAlwaysAllow2",
denied: "popupButtonNeverWarn2"
},
"indexedDB": {
label: "offlineApps.storeOfflineData",
allowed: "offlineApps.allow",
denied: "offlineApps.never"
},
"offline-app": {
label: "offlineApps.storeOfflineData",
allowed: "offlineApps.allow",
denied: "offlineApps.never"
},
"desktop-notification": {
label: "desktopNotification.useNotifications",
allowed: "desktopNotification.allow",
denied: "desktopNotification.dontAllow"
}
},
init: function init() {
Services.obs.addObserver(this, "Permissions:Get", false);
Services.obs.addObserver(this, "Permissions:Clear", false);
},
observe: function observe(aSubject, aTopic, aData) {
let uri = BrowserApp.selectedBrowser.currentURI;
switch (aTopic) {
case "Permissions:Get":
let permissions = [];
for (let i = 0; i < this._permissonTypes.length; i++) {
let type = this._permissonTypes[i];
let value = this.getPermission(uri, type);
// Only add the permission if it was set by the user
if (value == Services.perms.UNKNOWN_ACTION)
continue;
// Get the strings that correspond to the permission type
let typeStrings = this._permissionStrings[type];
let label = Strings.browser.GetStringFromName(typeStrings["label"]);
// Get the key to look up the appropriate string entity
let valueKey = value == Services.perms.ALLOW_ACTION ?
"allowed" : "denied";
let valueString = Strings.browser.GetStringFromName(typeStrings[valueKey]);
// If we implement a two-line UI, we will need to pass the label and
// value individually and let java handle the formatting
let setting = Strings.browser.formatStringFromName("siteSettings.labelToValue",
[ label, valueString ], 2)
permissions.push({
type: type,
setting: setting
});
}
// Keep track of permissions, so we know which ones to clear
this._currentPermissions = permissions;
sendMessageToJava({
gecko: {
type: "Permissions:Data",
host: uri.host,
permissions: permissions
}
});
break;
case "Permissions:Clear":
// An array of the indices of the permissions we want to clear
let permissionsToClear = JSON.parse(aData);
for (let i = 0; i < permissionsToClear.length; i++) {
let indexToClear = permissionsToClear[i];
let permissionType = this._currentPermissions[indexToClear]["type"];
this.clearPermission(uri, permissionType);
}
break;
}
},
/**
* Gets the permission value stored for a specified permission type.
*
* @param aType
* The permission type string stored in permission manager.
* e.g. "cookie", "geo", "indexedDB", "popup", "image"
*
* @return A permission value defined in nsIPermissionManager.
*/
getPermission: function getPermission(aURI, aType) {
// Password saving isn't a nsIPermissionManager permission type, so handle
// it seperately.
if (aType == "password") {
// By default, login saving is enabled, so if it is disabled, the
// user selected the never remember option
if (!Services.logins.getLoginSavingEnabled(aURI.prePath))
return Services.perms.DENY_ACTION;
// Check to see if the user ever actually saved a login
if (Services.logins.countLogins(aURI.prePath, "", ""))
return Services.perms.ALLOW_ACTION;
return Services.perms.UNKNOWN_ACTION;
}
// Geolocation consumers use testExactPermission
if (aType == "geo")
return Services.perms.testExactPermission(aURI, aType);
return Services.perms.testPermission(aURI, aType);
},
/**
* Clears a user-set permission value for the site given a permission type.
*
* @param aType
* The permission type string stored in permission manager.
* e.g. "cookie", "geo", "indexedDB", "popup", "image"
*/
clearPermission: function clearPermission(aURI, aType) {
// Password saving isn't a nsIPermissionManager permission type, so handle
// it seperately.
if (aType == "password") {
// Get rid of exisiting stored logings
let logins = Services.logins.findLogins({}, aURI.prePath, "", "");
for (let i = 0; i < logins.length; i++) {
Services.logins.removeLogin(logins[i]);
}
// Re-set login saving to enabled
Services.logins.setLoginSavingEnabled(aURI.prePath, true);
} else {
Services.perms.remove(aURI.host, aType);
}
}
}

Просмотреть файл

@ -122,6 +122,10 @@ popupButtonAllowOnce=Show
popupButtonAlwaysAllow2=Always Show
popupButtonNeverWarn2=Never Show
# LOCALIZATION NOTE (blockPopups.label): Label that will be used in
# site settings dialog.
blockPopups.label=Block Popups
# Telemetry
telemetry.optin.message=Help improve %S by sending anonymous usage information to Mozilla?
telemetry.optin.yes=Yes
@ -147,12 +151,20 @@ identity.ownerUnknown2=(unknown)
# Geolocation UI
geolocation.allow=Share
geolocation.dontAllow=Don't share
geolocation.alwaysAllow=Always Share
geolocation.neverAllow=Never Share
geolocation.wantsTo=%S wants your location.
# LOCALIZATION NOTE (geolocation.shareLocation): Label that will be used in
# site settings dialog.
geolocation.shareLocation=Share Location
# Desktop notification UI
desktopNotification.allow=Allow
desktopNotification.dontAllow=Don't allow
desktopNotification.wantsTo=%S wants to use notifications.
# LOCALIZATION NOTE (desktopNotification.useNotifications): Label that will be
# used in site settings dialog.
desktopNotification.useNotifications=Use Notifications
# New Tab Popup
# LOCALIZATION NOTE (newtabpopup): Semi-colon list of plural forms.
@ -169,6 +181,9 @@ offlineApps.available2=%S wants to store data on your device for offline use.
offlineApps.allow=Allow
offlineApps.never=Don't Allow
offlineApps.notNow=Not Now
# LOCALIZATION NOTE (offlineApps.storeOfflineData): Label that will be used in
# site settings dialog.
offlineApps.storeOfflineData=Store Offline Data
# New-style ContentPermissionPrompt values
offlineApps.dontAllow=Don't Allow
@ -184,6 +199,16 @@ openWebappsManage.allow=Allow
openWebappsManage.dontAllow=Don't Allow
openWebappsManage.wantsTo=%S wants to manage applications on your device.
# LOCALIZATION NOTE (password.rememberPassword): Label that will be used in
# site settings dialog.
password.rememberPassword=Remember Password
# LOCALIZATION NOTE (password.remember): This should match
# promptRememberButtonText in passwordmgr.properties
password.remember=Remember
# LOCALIZATION NOTE (password.never): This should match
# promptNeverForSiteButtonText in passwordmgr.properties
password.never=Never
# Bookmark List
bookmarkList.desktop=Desktop Bookmarks
@ -278,3 +303,9 @@ timer.end=%1$S: %2$Sms
clickToPlayFlash.message=This page contains flash content. Would you like to play it?
clickToPlayFlash.yes=Yes
clickToPlayFlash.no=No
# Site settings dialog
# LOCALIZATION NOTE (siteSettings.labelToValue): This string will be used to
# dislay a list of current permissions settings for a site.
# Example: "Store Offline Data: Allow"
siteSettings.labelToValue=%S: %S