diff --git a/mobile/android/base/GeckoApp.java b/mobile/android/base/GeckoApp.java index e5d9001d9cd..ac62ba35c47 100644 --- a/mobile/android/base/GeckoApp.java +++ b/mobile/android/base/GeckoApp.java @@ -440,6 +440,7 @@ abstract public class GeckoApp MenuItem share = aMenu.findItem(R.id.share); MenuItem saveAsPDF = aMenu.findItem(R.id.save_as_pdf); MenuItem downloads = aMenu.findItem(R.id.downloads); + MenuItem charEncoding = aMenu.findItem(R.id.char_encoding); if (tab == null) { bookmark.setEnabled(false); @@ -476,6 +477,8 @@ abstract public class GeckoApp if (Build.VERSION.SDK_INT < 12) downloads.setVisible(false); + charEncoding.setVisible(GeckoPreferences.getCharEncodingState()); + return true; } @@ -538,6 +541,9 @@ abstract public class GeckoApp intent = new Intent(DownloadManager.ACTION_VIEW_DOWNLOADS); startActivity(intent); return true; + case R.id.char_encoding: + GeckoAppShell.sendEventToGecko(new GeckoEvent("CharEncoding:Get", null)); + return true; default: return super.onOptionsItemSelected(item); } @@ -985,6 +991,51 @@ abstract public class GeckoApp int size = message.getInt("size"); handleDownloadDone(displayName, path, mimeType, size); + } else if (event.equals("CharEncoding:Data")) { + final JSONArray charsets = message.getJSONArray("charsets"); + int selected = message.getInt("selected"); + + final int len = charsets.length(); + final String[] titleArray = new String[len]; + for (int i = 0; i < len; i++) { + JSONObject charset = charsets.getJSONObject(i); + titleArray[i] = charset.getString("title"); + } + + final AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(this); + dialogBuilder.setSingleChoiceItems(titleArray, selected, new AlertDialog.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + try { + JSONObject charset = charsets.getJSONObject(which); + GeckoAppShell.sendEventToGecko(new GeckoEvent("CharEncoding:Set", charset.getString("code"))); + dialog.dismiss(); + } catch (JSONException e) { + Log.e(LOGTAG, "error parsing json", e); + } + } + }); + dialogBuilder.setNegativeButton(R.string.button_cancel, new AlertDialog.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + dialog.dismiss(); + } + }); + mMainHandler.post(new Runnable() { + public void run() { + dialogBuilder.show(); + } + }); + } else if (event.equals("CharEncoding:State")) { + final boolean visible = message.getString("visible").equals("true"); + GeckoPreferences.setCharEncodingState(visible); + if (sMenu != null) { + mMainHandler.post(new Runnable() { + public void run() { + sMenu.findItem(R.id.char_encoding).setVisible(visible); + } + }); + } } } catch (Exception e) { Log.e(LOGTAG, "Exception handling message \"" + event + "\":", e); @@ -1598,6 +1649,8 @@ abstract public class GeckoApp GeckoAppShell.registerGeckoEventListener("FormAssist:AutoComplete", GeckoApp.mAppContext); GeckoAppShell.registerGeckoEventListener("Permissions:Data", GeckoApp.mAppContext); GeckoAppShell.registerGeckoEventListener("Downloads:Done", GeckoApp.mAppContext); + GeckoAppShell.registerGeckoEventListener("CharEncoding:Data", GeckoApp.mAppContext); + GeckoAppShell.registerGeckoEventListener("CharEncoding:State", GeckoApp.mAppContext); mConnectivityFilter = new IntentFilter(); mConnectivityFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); @@ -1926,6 +1979,8 @@ abstract public class GeckoApp GeckoAppShell.unregisterGeckoEventListener("FormAssist:AutoComplete", GeckoApp.mAppContext); GeckoAppShell.unregisterGeckoEventListener("Permissions:Data", GeckoApp.mAppContext); GeckoAppShell.unregisterGeckoEventListener("Downloads:Done", GeckoApp.mAppContext); + GeckoAppShell.unregisterGeckoEventListener("CharEncoding:Data", GeckoApp.mAppContext); + GeckoAppShell.unregisterGeckoEventListener("CharEncoding:State", GeckoApp.mAppContext); mFavicons.close(); diff --git a/mobile/android/base/GeckoPreferences.java b/mobile/android/base/GeckoPreferences.java index 731bb698783..5da6e81e435 100644 --- a/mobile/android/base/GeckoPreferences.java +++ b/mobile/android/base/GeckoPreferences.java @@ -73,6 +73,7 @@ public class GeckoPreferences private ArrayList mPreferencesList = new ArrayList(); private PreferenceScreen mPreferenceScreen; + private static boolean sIsCharEncodingEnabled = false; @Override protected void onCreate(Bundle savedInstanceState) { @@ -140,12 +141,22 @@ public class GeckoPreferences final private int DIALOG_CREATE_MASTER_PASSWORD = 0; final private int DIALOG_REMOVE_MASTER_PASSWORD = 1; + public static void setCharEncodingState(boolean enabled) { + sIsCharEncodingEnabled = enabled; + } + + public static boolean getCharEncodingState() { + return sIsCharEncodingEnabled; + } + @Override public boolean onPreferenceChange(Preference preference, Object newValue) { String prefName = preference.getKey(); if (prefName != null && prefName.equals("privacy.masterpassword.enabled")) { showDialog((Boolean)newValue ? DIALOG_CREATE_MASTER_PASSWORD : DIALOG_REMOVE_MASTER_PASSWORD); return false; + } else if (prefName != null && prefName.equals("browser.menu.showCharacterEncoding")) { + setCharEncodingState(((String) newValue).equals("true")); } setPreference(prefName, newValue); diff --git a/mobile/android/base/locales/en-US/android_strings.dtd b/mobile/android/base/locales/en-US/android_strings.dtd index 58acc9e92e3..f5dfeaf6390 100644 --- a/mobile/android/base/locales/en-US/android_strings.dtd +++ b/mobile/android/base/locales/en-US/android_strings.dtd @@ -51,7 +51,9 @@ - + + + @@ -72,6 +74,7 @@ + diff --git a/mobile/android/base/resources/layout/gecko_menu.xml b/mobile/android/base/resources/layout/gecko_menu.xml index 292fe7bd4f9..2d0a0eb22c6 100644 --- a/mobile/android/base/resources/layout/gecko_menu.xml +++ b/mobile/android/base/resources/layout/gecko_menu.xml @@ -30,6 +30,10 @@ + + diff --git a/mobile/android/base/resources/values/arrays.xml b/mobile/android/base/resources/values/arrays.xml index 58b665e6351..75408d7bc1a 100644 --- a/mobile/android/base/resources/values/arrays.xml +++ b/mobile/android/base/resources/values/arrays.xml @@ -25,4 +25,12 @@ 160 240 + + @string/pref_char_encoding_on + @string/pref_char_encoding_off + + + true + false + diff --git a/mobile/android/base/resources/xml/preferences.xml b/mobile/android/base/resources/xml/preferences.xml index 2bbce810e57..384c01b4b99 100644 --- a/mobile/android/base/resources/xml/preferences.xml +++ b/mobile/android/base/resources/xml/preferences.xml @@ -15,8 +15,10 @@ - &pref_remember_signons; &pref_cookies; &pref_char_encoding; + &pref_char_encoding_on; + &pref_char_encoding_off; &pref_clear_history; &pref_clear_history_confirm; &pref_clear_private_data; @@ -78,6 +80,7 @@ &new_tab; &addons; &downloads; + &char_encoding; &site_settings_title; &site_settings_cancel; diff --git a/mobile/android/chrome/content/browser.js b/mobile/android/chrome/content/browser.js index 7ed4860b6d6..e915df9052c 100644 --- a/mobile/android/chrome/content/browser.js +++ b/mobile/android/chrome/content/browser.js @@ -146,7 +146,8 @@ function resolveGeckoURI(aURI) { var Strings = {}; [ ["brand", "chrome://branding/locale/brand.properties"], - ["browser", "chrome://browser/locale/browser.properties"] + ["browser", "chrome://browser/locale/browser.properties"], + ["charset", "chrome://global/locale/charsetTitles.properties"] ].forEach(function (aStringBundle) { let [name, bundle] = aStringBundle; XPCOMUtils.defineLazyGetter(Strings, name, function() { @@ -252,6 +253,7 @@ var BrowserApp = { ConsoleAPI.init(); ClipboardHelper.init(); PermissionsHelper.init(); + CharacterEncoding.init(); // Init LoginManager Cc["@mozilla.org/login-manager;1"].getService(Ci.nsILoginManager); @@ -357,6 +359,7 @@ var BrowserApp = { ViewportHandler.uninit(); XPInstallObserver.uninit(); ConsoleAPI.uninit(); + CharacterEncoding.uninit(); }, get tabs() { @@ -638,10 +641,6 @@ var BrowserApp = { pref.type = "bool"; pref.value = pref.value == 0; break; - case "browser.menu.showCharacterEncoding": - pref.type = "bool"; - pref.value = pref.value == "true"; - break; case "font.size.inflation.minTwips": pref.type = "string"; pref.value = pref.value.toString(); @@ -683,10 +682,6 @@ var BrowserApp = { json.type = "int"; json.value = (json.value ? 0 : 2); break; - case "browser.menu.showCharacterEncoding": - json.type = "string"; - json.value = (json.value ? "true" : "false"); - break; case "font.size.inflation.minTwips": json.type = "int"; json.value = parseInt(json.value); @@ -3819,7 +3814,7 @@ var PermissionsHelper = { Services.contentPrefs.removePref(aURI, aType + ".request.remember"); } } -} +}; var MasterPassword = { pref: "privacy.masterpassword.enabled", @@ -3899,4 +3894,99 @@ var MasterPassword = { } }); } -} +}; + +var CharacterEncoding = { + _charsets: [], + + init: function init() { + Services.obs.addObserver(this, "CharEncoding:Get", false); + Services.obs.addObserver(this, "CharEncoding:Set", false); + this.sendState(); + }, + + uninit: function uninit() { + Services.obs.removeObserver(this, "CharEncoding:Get", false); + Services.obs.removeObserver(this, "CharEncoding:Set", false); + }, + + observe: function observe(aSubject, aTopic, aData) { + switch (aTopic) { + case "CharEncoding:Get": + this.getEncoding(); + break; + case "CharEncoding:Set": + this.setEncoding(aData); + break; + } + }, + + sendState: function sendState() { + let showCharEncoding = "false"; + try { + showCharEncoding = Services.prefs.getComplexValue("browser.menu.showCharacterEncoding", Ci.nsIPrefLocalizedString).data; + } catch (e) { /* Optional */ } + + sendMessageToJava({ + gecko: { + type: "CharEncoding:State", + visible: showCharEncoding + } + }); + }, + + getEncoding: function getEncoding() { + function normalizeCharsetCode(charsetCode) { + return charsetCode.trim().toLowerCase(); + } + + function getTitle(charsetCode) { + let charsetTitle = charsetCode; + try { + charsetTitle = Strings.charset.GetStringFromName(charsetCode + ".title"); + } catch (e) { + dump("error: title not found for " + charsetCode); + } + return charsetTitle; + } + + if (!this._charsets.length) { + let charsets = Services.prefs.getComplexValue("intl.charsetmenu.browser.static", Ci.nsIPrefLocalizedString).data; + this._charsets = charsets.split(",").map(function (charset) { + return { + code: normalizeCharsetCode(charset), + title: getTitle(charset) + }; + }); + } + + // if document charset is not in charset options, add it + let docCharset = normalizeCharsetCode(BrowserApp.selectedBrowser.contentDocument.characterSet); + let selected = 0; + let charsetCount = this._charsets.length; + for (; selected < charsetCount && this._charsets[selected].code != docCharset; selected++); + if (selected == charsetCount) { + this._charsets.push({ + code: docCharset, + title: getTitle(docCharset) + }); + } + + sendMessageToJava({ + gecko: { + type: "CharEncoding:Data", + charsets: this._charsets, + selected: selected + } + }); + }, + + setEncoding: function setEncoding(aEncoding) { + let browser = BrowserApp.selectedBrowser; + let docCharset = browser.docShell.QueryInterface(Ci.nsIDocCharset); + docCharset.charset = aEncoding; + browser.reload(Ci.nsIWebNavigation.LOAD_FLAGS_CHARSET_CHANGE); + }, + +}; + diff --git a/mobile/android/locales/en-US/chrome/browser.properties b/mobile/android/locales/en-US/chrome/browser.properties index 6cb6d3321aa..78801141c6e 100644 --- a/mobile/android/locales/en-US/chrome/browser.properties +++ b/mobile/android/locales/en-US/chrome/browser.properties @@ -172,7 +172,7 @@ browser.menu.showCharacterEncoding=false # LOCALIZATION NOTE (intl.charsetmenu.browser.static): Set to a series of comma separated # values for charsets that the user can select from in the Character Encoding menu. -intl.charsetmenu.browser.static=iso-8859-1,utf-8,x-gbk,big5,iso-2022-jp,shift_jis,euc-jp +intl.charsetmenu.browser.static=iso-8859-1,utf-8,big5,iso-2022-jp,shift_jis,euc-jp # Application Menu appMenu.more=More