Bug 936756 - Switch locales via pref, not via system locale setting. r=mfinkle,sriram (relanded as one patch)

This commit is contained in:
Richard Newman 2013-12-03 15:05:43 -08:00
parent ddc7ad74e3
commit c34e10b816
19 changed files with 552 additions and 227 deletions

View File

@ -124,7 +124,7 @@ abstract public class BrowserApp extends GeckoApp
private static final int GECKO_TOOLS_MENU = -1; private static final int GECKO_TOOLS_MENU = -1;
private static final int ADDON_MENU_OFFSET = 1000; private static final int ADDON_MENU_OFFSET = 1000;
private class MenuItemInfo { private static class MenuItemInfo {
public int id; public int id;
public String label; public String label;
public String icon; public String icon;
@ -133,6 +133,7 @@ abstract public class BrowserApp extends GeckoApp
public boolean enabled = true; public boolean enabled = true;
public boolean visible = true; public boolean visible = true;
public int parent; public int parent;
public boolean added = false; // So we can re-add after a locale change.
} }
// The types of guest mdoe dialogs we show // The types of guest mdoe dialogs we show
@ -1639,6 +1640,20 @@ abstract public class BrowserApp extends GeckoApp
showHomePagerWithAnimator(page, null); showHomePagerWithAnimator(page, null);
} }
@Override
public void onLocaleReady(final String locale) {
super.onLocaleReady(locale);
if (mHomePager != null) {
// Blow it away and rebuild it with the right strings.
mHomePager.redisplay(getSupportFragmentManager());
}
if (mMenu != null) {
mMenu.clear();
onCreateOptionsMenu(mMenu);
}
}
private void showHomePagerWithAnimator(HomePager.Page page, PropertyAnimator animator) { private void showHomePagerWithAnimator(HomePager.Page page, PropertyAnimator animator) {
if (isHomePagerVisible()) { if (isHomePagerVisible()) {
return; return;
@ -1811,7 +1826,7 @@ abstract public class BrowserApp extends GeckoApp
} }
} }
private Menu findParentMenu(Menu menu, MenuItem item) { private static Menu findParentMenu(Menu menu, MenuItem item) {
final int itemId = item.getItemId(); final int itemId = item.getItemId();
final int count = (menu != null) ? menu.size() : 0; final int count = (menu != null) ? menu.size() : 0;
@ -1831,54 +1846,58 @@ abstract public class BrowserApp extends GeckoApp
return null; return null;
} }
private void addAddonMenuItem(final MenuItemInfo info) { /**
if (mMenu == null) { * Add the provided item to the provided menu, which should be
if (mAddonMenuItemsCache == null) * the root (mMenu).
mAddonMenuItemsCache = new Vector<MenuItemInfo>(); */
private void addAddonMenuItemToMenu(final Menu menu, final MenuItemInfo info) {
mAddonMenuItemsCache.add(info); info.added = true;
return;
} final Menu destination;
Menu menu;
if (info.parent == 0) { if (info.parent == 0) {
menu = mMenu; destination = menu;
} else if (info.parent == GECKO_TOOLS_MENU) { } else if (info.parent == GECKO_TOOLS_MENU) {
MenuItem tools = mMenu.findItem(R.id.tools); MenuItem tools = menu.findItem(R.id.tools);
menu = tools != null ? tools.getSubMenu() : mMenu; destination = tools != null ? tools.getSubMenu() : menu;
} else { } else {
MenuItem parent = mMenu.findItem(info.parent); MenuItem parent = menu.findItem(info.parent);
if (parent == null) if (parent == null) {
return; return;
}
Menu parentMenu = findParentMenu(mMenu, parent); Menu parentMenu = findParentMenu(menu, parent);
if (!parent.hasSubMenu()) { if (!parent.hasSubMenu()) {
parentMenu.removeItem(parent.getItemId()); parentMenu.removeItem(parent.getItemId());
menu = parentMenu.addSubMenu(Menu.NONE, parent.getItemId(), Menu.NONE, parent.getTitle()); destination = parentMenu.addSubMenu(Menu.NONE, parent.getItemId(), Menu.NONE, parent.getTitle());
if (parent.getIcon() != null) if (parent.getIcon() != null) {
((SubMenu) menu).getItem().setIcon(parent.getIcon()); ((SubMenu) destination).getItem().setIcon(parent.getIcon());
}
} else { } else {
menu = parent.getSubMenu(); destination = parent.getSubMenu();
} }
} }
MenuItem item = menu.add(Menu.NONE, info.id, Menu.NONE, info.label); MenuItem item = destination.add(Menu.NONE, info.id, Menu.NONE, info.label);
item.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() { item.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
@Override @Override
public boolean onMenuItemClick(MenuItem item) { public boolean onMenuItemClick(MenuItem item) {
Log.i(LOGTAG, "menu item clicked"); Log.i(LOGTAG, "Menu item clicked");
GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Menu:Clicked", Integer.toString(info.id - ADDON_MENU_OFFSET))); GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Menu:Clicked", Integer.toString(info.id - ADDON_MENU_OFFSET)));
return true; return true;
} }
}); });
if (info.icon != null) { if (info.icon == null) {
item.setIcon(R.drawable.ic_menu_addons_filler);
} else {
final int id = info.id; final int id = info.id;
BitmapUtils.getDrawable(this, info.icon, new BitmapUtils.BitmapLoader() { BitmapUtils.getDrawable(this, info.icon, new BitmapUtils.BitmapLoader() {
@Override @Override
public void onBitmapFound(Drawable d) { public void onBitmapFound(Drawable d) {
MenuItem item = mMenu.findItem(id); // TODO: why do we re-find the item?
MenuItem item = destination.findItem(id);
if (item == null) { if (item == null) {
return; return;
} }
@ -1889,8 +1908,6 @@ abstract public class BrowserApp extends GeckoApp
item.setIcon(d); item.setIcon(d);
} }
}); });
} else {
item.setIcon(R.drawable.ic_menu_addons_filler);
} }
item.setCheckable(info.checkable); item.setCheckable(info.checkable);
@ -1899,6 +1916,24 @@ abstract public class BrowserApp extends GeckoApp
item.setVisible(info.visible); item.setVisible(info.visible);
} }
private void addAddonMenuItem(final MenuItemInfo info) {
if (mAddonMenuItemsCache == null) {
mAddonMenuItemsCache = new Vector<MenuItemInfo>();
}
// Mark it as added if the menu was ready.
info.added = (mMenu != null);
// Always cache so we can rebuild after a locale switch.
mAddonMenuItemsCache.add(info);
if (mMenu == null) {
return;
}
addAddonMenuItemToMenu(mMenu, info);
}
private void removeAddonMenuItem(int id) { private void removeAddonMenuItem(int id) {
// Remove add-on menu item from cache, if available. // Remove add-on menu item from cache, if available.
if (mAddonMenuItemsCache != null && !mAddonMenuItemsCache.isEmpty()) { if (mAddonMenuItemsCache != null && !mAddonMenuItemsCache.isEmpty()) {
@ -1928,13 +1963,15 @@ abstract public class BrowserApp extends GeckoApp
item.checked = options.optBoolean("checked", item.checked); item.checked = options.optBoolean("checked", item.checked);
item.enabled = options.optBoolean("enabled", item.enabled); item.enabled = options.optBoolean("enabled", item.enabled);
item.visible = options.optBoolean("visible", item.visible); item.visible = options.optBoolean("visible", item.visible);
item.added = (mMenu != null);
break; break;
} }
} }
} }
if (mMenu == null) if (mMenu == null) {
return; return;
}
MenuItem menuItem = mMenu.findItem(id); MenuItem menuItem = mMenu.findItem(id);
if (menuItem != null) { if (menuItem != null) {
@ -1948,22 +1985,23 @@ abstract public class BrowserApp extends GeckoApp
@Override @Override
public boolean onCreateOptionsMenu(Menu menu) { public boolean onCreateOptionsMenu(Menu menu) {
// Sets mMenu = menu.
super.onCreateOptionsMenu(menu); super.onCreateOptionsMenu(menu);
// Inform the menu about the action-items bar. // Inform the menu about the action-items bar.
if (menu instanceof GeckoMenu && HardwareUtils.isTablet()) if (menu instanceof GeckoMenu &&
HardwareUtils.isTablet()) {
((GeckoMenu) menu).setActionItemBarPresenter(mBrowserToolbar); ((GeckoMenu) menu).setActionItemBarPresenter(mBrowserToolbar);
}
MenuInflater inflater = getMenuInflater(); MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.browser_app_menu, mMenu); inflater.inflate(R.menu.browser_app_menu, mMenu);
// Add add-on menu items if any. // Add add-on menu items, if any exist.
if (mAddonMenuItemsCache != null && !mAddonMenuItemsCache.isEmpty()) { if (mAddonMenuItemsCache != null && !mAddonMenuItemsCache.isEmpty()) {
for (MenuItemInfo item : mAddonMenuItemsCache) { for (MenuItemInfo item : mAddonMenuItemsCache) {
addAddonMenuItem(item); addAddonMenuItemToMenu(mMenu, item);
} }
mAddonMenuItemsCache.clear();
} }
// Action providers are available only ICS+. // Action providers are available only ICS+.

View File

@ -1,6 +1,15 @@
package org.mozilla.gecko; /* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
import android.content.Context; * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
interface ContextGetter { package org.mozilla.gecko;
Context getContext();
import android.content.Context;
import android.content.SharedPreferences;
public interface ContextGetter {
Context getContext();
SharedPreferences getSharedPreferences();
} }

View File

@ -12,6 +12,15 @@ public class GeckoActivity extends FragmentActivity implements GeckoActivityStat
// has this activity recently started another Gecko activity? // has this activity recently started another Gecko activity?
private boolean mGeckoActivityOpened = false; private boolean mGeckoActivityOpened = false;
/**
* Display any resources that show strings or encompass locale-specific
* representations.
*
* onLocaleReady must always be called on the UI thread.
*/
public void onLocaleReady(final String locale) {
}
@Override @Override
public void onPause() { public void onPause() {
super.onPause(); super.onPause();

View File

@ -126,12 +126,18 @@ import java.util.Set;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
abstract public class GeckoApp public abstract class GeckoApp
extends GeckoActivity extends GeckoActivity
implements GeckoEventListener, SensorEventListener, LocationListener, implements
Tabs.OnTabsChangedListener, GeckoEventResponder, ContextGetter,
GeckoMenu.Callback, GeckoMenu.MenuPresenter, GeckoAppShell.GeckoInterface,
ContextGetter, GeckoAppShell.GeckoInterface GeckoEventListener,
GeckoEventResponder,
GeckoMenu.Callback,
GeckoMenu.MenuPresenter,
LocationListener,
SensorEventListener,
Tabs.OnTabsChangedListener
{ {
private static final String LOGTAG = "GeckoApp"; private static final String LOGTAG = "GeckoApp";
@ -233,10 +239,20 @@ abstract public class GeckoApp
void focusChrome() { } void focusChrome() { }
@Override
public Context getContext() { public Context getContext() {
return sAppContext; return sAppContext;
} }
@Override
public SharedPreferences getSharedPreferences() {
return GeckoApp.getAppSharedPreferences();
}
public static SharedPreferences getAppSharedPreferences() {
return GeckoApp.sAppContext.getSharedPreferences(GeckoApp.PREFS_NAME, 0);
}
public Activity getActivity() { public Activity getActivity() {
return this; return this;
} }
@ -258,10 +274,6 @@ abstract public class GeckoApp
return this; return this;
} }
public static SharedPreferences getAppSharedPreferences() {
return GeckoApp.sAppContext.getSharedPreferences(PREFS_NAME, 0);
}
public View getCameraView() { public View getCameraView() {
return mCameraView; return mCameraView;
} }
@ -703,6 +715,8 @@ abstract public class GeckoApp
GeckoAppShell.openUriExternal(message.optString("url"), GeckoAppShell.openUriExternal(message.optString("url"),
message.optString("mime"), message.optString("packageName"), message.optString("mime"), message.optString("packageName"),
message.optString("className"), message.optString("action"), message.optString("title")); message.optString("className"), message.optString("action"), message.optString("title"));
} else if (event.equals("Locale:Set")) {
setLocale(message.getString("locale"));
} }
} catch (Exception e) { } catch (Exception e) {
Log.e(LOGTAG, "Exception handling message \"" + event + "\":", e); Log.e(LOGTAG, "Exception handling message \"" + event + "\":", e);
@ -1179,7 +1193,7 @@ abstract public class GeckoApp
} }
BrowserDB.initialize(getProfile().getName()); BrowserDB.initialize(getProfile().getName());
((GeckoApplication)getApplication()).initialize(); ((GeckoApplication) getApplication()).initialize();
sAppContext = this; sAppContext = this;
GeckoAppShell.setContextGetter(this); GeckoAppShell.setContextGetter(this);
@ -1193,12 +1207,13 @@ abstract public class GeckoApp
Log.e(LOGTAG, "Exception starting favicon cache. Corrupt resources?", e); Log.e(LOGTAG, "Exception starting favicon cache. Corrupt resources?", e);
} }
// When we detect a locale change, we need to restart Gecko, which // Did the OS locale change while we were backgrounded? If so,
// actually means restarting the entire application. This logic should // we need to die so that Gecko will re-init add-ons that touch
// actually be handled elsewhere since GeckoApp may not be alive to // the UI.
// handle this event if "Don't keep activities" is enabled (filed as // This is using a sledgehammer to crack a nut, but it'll do for
// bug 889082). // now.
if (((GeckoApplication)getApplication()).needsRestart()) { if (LocaleManager.systemLocaleDidChange()) {
Log.i(LOGTAG, "System locale changed. Restarting.");
doRestart(); doRestart();
System.exit(0); System.exit(0);
return; return;
@ -1279,6 +1294,11 @@ abstract public class GeckoApp
public void run() { public void run() {
final SharedPreferences prefs = GeckoApp.getAppSharedPreferences(); final SharedPreferences prefs = GeckoApp.getAppSharedPreferences();
// Wait until now to set this, because we'd rather throw an exception than
// have a caller of LocaleManager regress startup.
LocaleManager.setContextGetter(GeckoApp.this);
LocaleManager.initialize();
SessionInformation previousSession = SessionInformation.fromSharedPrefs(prefs); SessionInformation previousSession = SessionInformation.fromSharedPrefs(prefs);
if (previousSession.wasKilled()) { if (previousSession.wasKilled()) {
Telemetry.HistogramAdd("FENNEC_WAS_KILLED", 1); Telemetry.HistogramAdd("FENNEC_WAS_KILLED", 1);
@ -1299,17 +1319,29 @@ abstract public class GeckoApp
final String profilePath = getProfile().getDir().getAbsolutePath(); final String profilePath = getProfile().getDir().getAbsolutePath();
final EventDispatcher dispatcher = GeckoAppShell.getEventDispatcher(); final EventDispatcher dispatcher = GeckoAppShell.getEventDispatcher();
Log.i(LOGTAG, "Creating BrowserHealthRecorder."); Log.i(LOGTAG, "Creating BrowserHealthRecorder.");
final String osLocale = Locale.getDefault().toString();
Log.d(LOGTAG, "Locale is " + osLocale);
// Replace the duplicate `osLocale` argument when we support switchable final String osLocale = Locale.getDefault().toString();
// application locales. String appLocale = LocaleManager.getAndApplyPersistedLocale();
Log.d(LOGTAG, "OS locale is " + osLocale + ", app locale is " + appLocale);
if (appLocale == null) {
appLocale = osLocale;
}
mHealthRecorder = new BrowserHealthRecorder(GeckoApp.this, mHealthRecorder = new BrowserHealthRecorder(GeckoApp.this,
profilePath, profilePath,
dispatcher, dispatcher,
osLocale, osLocale,
osLocale, // Placeholder. appLocale,
previousSession); previousSession);
final String uiLocale = appLocale;
ThreadUtils.postToUiThread(new Runnable() {
@Override
public void run() {
GeckoApp.this.onLocaleReady(uiLocale);
}
});
} }
}); });
@ -1317,6 +1349,30 @@ abstract public class GeckoApp
NotificationHelper.init(getApplicationContext()); NotificationHelper.init(getApplicationContext());
} }
/**
* At this point, the resource system and the rest of the browser are
* aware of the locale.
*
* Now we can display strings!
*/
@Override
public void onLocaleReady(final String locale) {
if (!ThreadUtils.isOnUiThread()) {
throw new RuntimeException("onLocaleReady must always be called from the UI thread.");
}
// The URL bar hint needs to be populated.
TextView urlBar = (TextView) findViewById(R.id.url_bar_title);
if (urlBar == null) {
return;
}
final String hint = getResources().getString(R.string.url_bar_default_text);
urlBar.setHint(hint);
// Allow onConfigurationChanged to take care of the rest.
onConfigurationChanged(getResources().getConfiguration());
}
protected void initializeChrome() { protected void initializeChrome() {
mDoorHangerPopup = new DoorHangerPopup(this, null); mDoorHangerPopup = new DoorHangerPopup(this, null);
mPluginContainer = (AbsoluteLayout) findViewById(R.id.plugin_container); mPluginContainer = (AbsoluteLayout) findViewById(R.id.plugin_container);
@ -1526,6 +1582,7 @@ abstract public class GeckoApp
registerEventListener("Contact:Add"); registerEventListener("Contact:Add");
registerEventListener("Intent:Open"); registerEventListener("Intent:Open");
registerEventListener("Intent:GetHandlers"); registerEventListener("Intent:GetHandlers");
registerEventListener("Locale:Set");
if (SmsManager.getInstance() != null) { if (SmsManager.getInstance() != null) {
SmsManager.getInstance().start(); SmsManager.getInstance().start();
@ -1579,23 +1636,6 @@ abstract public class GeckoApp
// intervals. // intervals.
GeckoPreferences.broadcastAnnouncementsPref(context); GeckoPreferences.broadcastAnnouncementsPref(context);
GeckoPreferences.broadcastHealthReportUploadPref(context); GeckoPreferences.broadcastHealthReportUploadPref(context);
/*
XXXX see Bug 635342.
We want to disable this code if possible. It is about 145ms in runtime.
If this code ever becomes live again, you'll need to chain the
new locale into BrowserHealthRecorder correctly. See
GeckoAppShell.setSelectedLocale.
We pass the OS locale into the BHR constructor: we need to grab
that *before* we modify the current locale!
SharedPreferences settings = getPreferences(Activity.MODE_PRIVATE);
String localeCode = settings.getString(getPackageName() + ".locale", "");
if (localeCode != null && localeCode.length() > 0)
GeckoAppShell.setSelectedLocale(localeCode);
*/
if (!GeckoThread.checkLaunchState(GeckoThread.LaunchState.Launched)) { if (!GeckoThread.checkLaunchState(GeckoThread.LaunchState.Launched)) {
return; return;
} }
@ -2140,6 +2180,8 @@ abstract public class GeckoApp
@Override @Override
public void onConfigurationChanged(Configuration newConfig) { public void onConfigurationChanged(Configuration newConfig) {
Log.d(LOGTAG, "onConfigurationChanged: " + newConfig.locale);
LocaleManager.correctLocale(getResources(), newConfig);
super.onConfigurationChanged(newConfig); super.onConfigurationChanged(newConfig);
if (mOrientation != newConfig.orientation) { if (mOrientation != newConfig.orientation) {
@ -2725,4 +2767,52 @@ abstract public class GeckoApp
} }
return versionCode; return versionCode;
} }
// FHR reason code for a session end prior to a restart for a
// locale change.
private static final String SESSION_END_LOCALE_CHANGED = "L";
/**
* Use LocaleManager to change our persisted and current locales,
* and poke BrowserHealthRecorder to tell it of our changed state.
*/
private void setLocale(final String locale) {
if (locale == null) {
return;
}
final String resultant = LocaleManager.setSelectedLocale(locale);
if (resultant == null) {
return;
}
final BrowserHealthRecorder rec = mHealthRecorder;
if (rec == null) {
return;
}
final boolean startNewSession = true;
final boolean shouldRestart = false;
rec.onAppLocaleChanged(resultant);
rec.onEnvironmentChanged(startNewSession, SESSION_END_LOCALE_CHANGED);
if (!shouldRestart) {
ThreadUtils.postToUiThread(new Runnable() {
@Override
public void run() {
GeckoApp.this.onLocaleReady(resultant);
}
});
return;
}
// Do this in the background so that the health recorder has its
// time to finish.
ThreadUtils.postToBackgroundThread(new Runnable() {
@Override
public void run() {
GeckoApp.this.doRestart();
GeckoApp.this.finish();
}
});
}
} }

View File

@ -229,8 +229,7 @@ public class GeckoAppShell
} }
if (e instanceof OutOfMemoryError) { if (e instanceof OutOfMemoryError) {
SharedPreferences prefs = SharedPreferences prefs = getSharedPreferences();
getContext().getSharedPreferences(GeckoApp.PREFS_NAME, 0);
SharedPreferences.Editor editor = prefs.edit(); SharedPreferences.Editor editor = prefs.edit();
editor.putBoolean(GeckoApp.PREFS_OOM_EXCEPTION, true); editor.putBoolean(GeckoApp.PREFS_OOM_EXCEPTION, true);
editor.commit(); editor.commit();
@ -1587,45 +1586,6 @@ public class GeckoAppShell
} }
} }
@WrapElementForJNI
public static void setSelectedLocale(String localeCode) {
/* Bug 713464: This method is still called from Gecko side.
Earlier we had an option to run Firefox in a language other than system's language.
However, this is not supported as of now.
Gecko resets the locale to en-US by calling this function with an empty string.
This affects GeckoPreferences activity in multi-locale builds.
N.B., if this code ever becomes live again, you need to hook it up to locale
recording in BrowserHealthRecorder: we track the current app and OS locales
as part of the recorded environment.
See similar note in GeckoApp.java for the startup path.
//We're not using this, not need to save it (see bug 635342)
SharedPreferences settings =
getContext().getPreferences(Activity.MODE_PRIVATE);
settings.edit().putString(getContext().getPackageName() + ".locale",
localeCode).commit();
Locale locale;
int index;
if ((index = localeCode.indexOf('-')) != -1 ||
(index = localeCode.indexOf('_')) != -1) {
String langCode = localeCode.substring(0, index);
String countryCode = localeCode.substring(index + 1);
locale = new Locale(langCode, countryCode);
} else {
locale = new Locale(localeCode);
}
Locale.setDefault(locale);
Resources res = getContext().getBaseContext().getResources();
Configuration config = res.getConfiguration();
config.locale = locale;
res.updateConfiguration(config, res.getDisplayMetrics());
*/
}
@WrapElementForJNI(stubName = "GetSystemColoursWrapper") @WrapElementForJNI(stubName = "GetSystemColoursWrapper")
public static int[] getSystemColors() { public static int[] getSystemColors() {
// attrsAppearance[] must correspond to AndroidSystemColors structure in android/AndroidBridge.h // attrsAppearance[] must correspond to AndroidSystemColors structure in android/AndroidBridge.h
@ -2146,6 +2106,13 @@ public class GeckoAppShell
sContextGetter = cg; sContextGetter = cg;
} }
public static SharedPreferences getSharedPreferences() {
if (sContextGetter == null) {
throw new IllegalStateException("No ContextGetter; cannot fetch prefs.");
}
return sContextGetter.getSharedPreferences();
}
public interface AppStateListener { public interface AppStateListener {
public void onPause(); public void onPause();
public void onResume(); public void onResume();

View File

@ -12,20 +12,39 @@ import org.mozilla.gecko.util.HardwareUtils;
import org.mozilla.gecko.util.ThreadUtils; import org.mozilla.gecko.util.ThreadUtils;
import android.app.Application; import android.app.Application;
import android.content.BroadcastReceiver; import android.content.res.Configuration;
import android.content.Context; import android.util.Log;
import android.content.Intent;
import android.content.IntentFilter;
public class GeckoApplication extends Application { public class GeckoApplication extends Application {
private boolean mInited; private boolean mInited;
private boolean mInBackground; private boolean mInBackground;
private boolean mPausedGecko; private boolean mPausedGecko;
private boolean mNeedsRestart;
private LightweightTheme mLightweightTheme; private LightweightTheme mLightweightTheme;
/**
* We need to do locale work here, because we need to intercept
* each hit to onConfigurationChanged.
*/
@Override
public void onConfigurationChanged(Configuration config) {
Log.d("GeckoApplication", "onConfigurationChanged: " + config.locale +
", background: " + mInBackground);
// Do nothing if we're in the background. It'll simply cause a loop
// (Bug 936756 Comment 11), and it's not necessary.
if (mInBackground) {
super.onConfigurationChanged(config);
return;
}
// Otherwise, correct the locale. This catches some cases that GeckoApp
// doesn't get a chance to.
LocaleManager.correctLocale(getResources(), config);
super.onConfigurationChanged(config);
}
protected void initialize() { protected void initialize() {
if (mInited) if (mInited)
return; return;
@ -43,14 +62,6 @@ public class GeckoApplication extends Application {
GeckoNetworkManager.getInstance().init(getApplicationContext()); GeckoNetworkManager.getInstance().init(getApplicationContext());
MemoryMonitor.getInstance().init(getApplicationContext()); MemoryMonitor.getInstance().init(getApplicationContext());
BroadcastReceiver receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
mNeedsRestart = true;
}
};
registerReceiver(receiver, new IntentFilter(Intent.ACTION_LOCALE_CHANGED));
mInited = true; mInited = true;
} }
@ -90,10 +101,6 @@ public class GeckoApplication extends Application {
mInBackground = false; mInBackground = false;
} }
protected boolean needsRestart() {
return mNeedsRestart;
}
@Override @Override
public void onCreate() { public void onCreate() {
HardwareUtils.init(getApplicationContext()); HardwareUtils.init(getApplicationContext());

View File

@ -19,6 +19,7 @@ import org.json.JSONObject;
import android.app.Activity; import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.TypedArray; import android.content.res.TypedArray;
import android.os.Handler; import android.os.Handler;
import android.util.AttributeSet; import android.util.AttributeSet;
@ -30,6 +31,7 @@ import java.util.List;
public class GeckoView extends LayerView public class GeckoView extends LayerView
implements GeckoEventListener, ContextGetter { implements GeckoEventListener, ContextGetter {
private static final String DEFAULT_SHARED_PREFERENCES_FILE = "GeckoView";
private static final String LOGTAG = "GeckoView"; private static final String LOGTAG = "GeckoView";
private ChromeDelegate mChromeDelegate; private ChromeDelegate mChromeDelegate;
@ -305,6 +307,14 @@ public class GeckoView extends LayerView
return GeckoAppShell.getGeckoInterface(); return GeckoAppShell.getGeckoInterface();
} }
protected String getSharedPreferencesFile() {
return DEFAULT_SHARED_PREFERENCES_FILE;
}
public SharedPreferences getSharedPreferences() {
return getContext().getSharedPreferences(getSharedPreferencesFile(), 0);
}
/** /**
* Wrapper for a browser in the GeckoView container. Associated with a browser * Wrapper for a browser in the GeckoView container. Associated with a browser
* element in the Gecko system. * element in the Gecko system.

View File

@ -0,0 +1,215 @@
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.gecko;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.util.Log;
import java.util.Locale;
/**
* This class manages persistence, application, and otherwise handling of
* user-specified locales.
*
* Of note:
*
* * It's a singleton, because its scope extends to that of the application,
* and definitionally all changes to the locale of the app must go through
* this.
* * It's lazy.
* * It has ties into the Gecko event system, because it has to tell Gecko when
* to switch locale.
* * It relies on using the SharedPreferences file owned by the browser (in
* Fennec's case, "GeckoApp") for performance.
*/
public class LocaleManager {
private static final String LOG_TAG = "GeckoLocales";
// These are both volatile because we don't impose restrictions
// over which thread calls our methods.
private static volatile ContextGetter getter = null;
private static volatile Locale currentLocale = null;
private static volatile boolean inited = false;
private static boolean systemLocaleDidChange = false;
private static BroadcastReceiver receiver;
public static void setContextGetter(ContextGetter getter) {
LocaleManager.getter = getter;
}
public static void initialize() {
if (inited) {
return;
}
receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
systemLocaleDidChange = true;
}
};
getContext().registerReceiver(receiver, new IntentFilter(Intent.ACTION_LOCALE_CHANGED));
inited = true;
}
public static boolean systemLocaleDidChange() {
return systemLocaleDidChange;
}
private static Context getContext() {
if (getter == null) {
throw new IllegalStateException("No ContextGetter; cannot fetch context.");
}
return getter.getContext();
}
private static SharedPreferences getSharedPreferences() {
if (getter == null) {
throw new IllegalStateException("No ContextGetter; cannot fetch prefs.", new RuntimeException("No prefs."));
}
return getter.getSharedPreferences();
}
/**
* Every time the system gives us a new configuration, it
* carries the external locale. Fix it.
*/
public static void correctLocale(Resources res, Configuration config) {
Locale current = getCurrentLocale();
if (current == null) {
return;
}
// I know it's tempting to short-circuit here if the config seems to be
// up-to-date, but the rest is necessary.
config.locale = current;
// The following two lines are heavily commented in case someone
// decides to chase down performance improvements and decides to
// question what's going on here.
// Both lines should be cheap, *but*...
// This is unnecessary for basic string choice, but it almost
// certainly comes into play when rendering numbers, deciding on RTL,
// etc. Take it out if you can prove that's not the case.
Locale.setDefault(current);
// This seems to be a no-op, but every piece of documentation under the
// sun suggests that it's necessary, and it certainly makes sense.
res.updateConfiguration(config, res.getDisplayMetrics());
}
private static Locale parseLocaleCode(final String localeCode) {
int index;
if ((index = localeCode.indexOf('-')) != -1 ||
(index = localeCode.indexOf('_')) != -1) {
final String langCode = localeCode.substring(0, index);
final String countryCode = localeCode.substring(index + 1);
return new Locale(langCode, countryCode);
} else {
return new Locale(localeCode);
}
}
public static Locale getCurrentLocale() {
if (currentLocale != null) {
return currentLocale;
}
final String current = getPersistedLocale();
if (current == null) {
return null;
}
return currentLocale = parseLocaleCode(current);
}
/**
* Returns the persisted locale if it differed from the current.
*/
public static String updateLocale(String localeCode) {
// Fast path.
final Locale defaultLocale = Locale.getDefault();
if (defaultLocale.toString().equals(localeCode)) {
return null;
}
final Locale locale = parseLocaleCode(localeCode);
// Fast path.
if (defaultLocale.equals(locale)) {
return null;
}
Locale.setDefault(locale);
currentLocale = locale;
// Update resources.
Resources res = getContext().getResources();
Configuration config = res.getConfiguration();
config.locale = locale;
res.updateConfiguration(config, res.getDisplayMetrics());
// Tell Gecko.
GeckoEvent ev = GeckoEvent.createBroadcastEvent("Locale:Changed", locale.toString());
GeckoAppShell.sendEventToGecko(ev);
return locale.toString();
}
private static String getPrefName() {
return getContext().getPackageName() + ".locale";
}
public static String getPersistedLocale() {
final SharedPreferences settings = getSharedPreferences();
// N.B., it is expected that any per-profile settings will be
// implemented via SharedPreferences multiplexing in ContextGetter, not
// via profile-annotated preference names.
final String locale = settings.getString(getPrefName(), "");
if ("".equals(locale)) {
return null;
}
return locale;
}
private static void persistLocale(String localeCode) {
final SharedPreferences settings = getSharedPreferences();
settings.edit().putString(getPrefName(), localeCode).commit();
}
public static String getAndApplyPersistedLocale() {
final long t1 = android.os.SystemClock.uptimeMillis();
final String localeCode = getPersistedLocale();
if (localeCode == null) {
return null;
}
updateLocale(localeCode);
final long t2 = android.os.SystemClock.uptimeMillis();
Log.i(LOG_TAG, "Locale read and update took: " + (t2 - t1) + "ms.");
return localeCode;
}
/**
* Returns the set locale if it changed. Always persists.
*/
public static String setSelectedLocale(String localeCode) {
final String resultant = updateLocale(localeCode);
persistLocale(localeCode);
return resultant;
}
}

View File

@ -319,6 +319,7 @@ public class BrowserHealthRecorder implements GeckoEventListener {
} }
public void onAppLocaleChanged(String to) { public void onAppLocaleChanged(String to) {
Log.d(LOG_TAG, "Setting health recorder app locale to " + to);
this.profileCache.beginInitialization(); this.profileCache.beginInitialization();
this.profileCache.setAppLocale(to); this.profileCache.setAppLocale(to);
} }
@ -349,10 +350,19 @@ public class BrowserHealthRecorder implements GeckoEventListener {
* Invoke this method after calls that mutate the environment. * Invoke this method after calls that mutate the environment.
* *
* If this change resulted in a transition between two environments, {@link * If this change resulted in a transition between two environments, {@link
* #onEnvironmentTransition(int, int)} will be invoked on the background * #onEnvironmentTransition(int, int, boolean, String)} will be invoked on the background
* thread. * thread.
*/ */
public synchronized void onEnvironmentChanged() { public synchronized void onEnvironmentChanged() {
onEnvironmentChanged(true, "E");
}
/**
* If `startNewSession` is false, it means no new session should begin
* (e.g., because we're about to restart, and we don't want to create
* an orphan).
*/
public synchronized void onEnvironmentChanged(final boolean startNewSession, final String sessionEndReason) {
final int previousEnv = this.env; final int previousEnv = this.env;
this.env = -1; this.env = -1;
try { try {
@ -374,7 +384,7 @@ public class BrowserHealthRecorder implements GeckoEventListener {
@Override @Override
public void run() { public void run() {
try { try {
onEnvironmentTransition(previousEnv, updatedEnv); onEnvironmentTransition(previousEnv, updatedEnv, startNewSession, sessionEndReason);
} catch (Exception e) { } catch (Exception e) {
Log.w(LOG_TAG, "Could not record environment transition.", e); Log.w(LOG_TAG, "Could not record environment transition.", e);
} }
@ -643,7 +653,7 @@ public class BrowserHealthRecorder implements GeckoEventListener {
* Invoked in the background whenever the environment transitions between * Invoked in the background whenever the environment transitions between
* two valid values. * two valid values.
*/ */
protected void onEnvironmentTransition(int prev, int env) { protected void onEnvironmentTransition(int prev, int env, boolean startNewSession, String sessionEndReason) {
if (this.state != State.INITIALIZED) { if (this.state != State.INITIALIZED) {
Log.d(LOG_TAG, "Not initialized: not recording env transition (" + prev + " => " + env + ")."); Log.d(LOG_TAG, "Not initialized: not recording env transition (" + prev + " => " + env + ").");
return; return;
@ -652,7 +662,12 @@ public class BrowserHealthRecorder implements GeckoEventListener {
final SharedPreferences prefs = GeckoApp.getAppSharedPreferences(); final SharedPreferences prefs = GeckoApp.getAppSharedPreferences();
final SharedPreferences.Editor editor = prefs.edit(); final SharedPreferences.Editor editor = prefs.edit();
recordSessionEnd("E", editor, prev); recordSessionEnd(sessionEndReason, editor, prev);
if (!startNewSession) {
editor.commit();
return;
}
final SessionInformation newSession = SessionInformation.forRuntimeTransition(); final SessionInformation newSession = SessionInformation.forRuntimeTransition();
setCurrentSession(newSession); setCurrentSession(newSession);

View File

@ -129,6 +129,11 @@ public class HomePager extends ViewPager {
super.addView(child, index, params); super.addView(child, index, params);
} }
public void redisplay(FragmentManager fm) {
final TabsAdapter adapter = (TabsAdapter) getAdapter();
show(fm, adapter.getCurrentPage(), null);
}
/** /**
* Loads and initializes the pager. * Loads and initializes the pager.
* *
@ -281,6 +286,12 @@ public class HomePager extends ViewPager {
return -1; return -1;
} }
public Page getCurrentPage() {
int currentItem = getCurrentItem();
TabInfo info = mTabs.get(currentItem);
return info.page;
}
@Override @Override
public int getCount() { public int getCount() {
return mTabs.size(); return mTabs.size();

View File

@ -95,7 +95,7 @@ public class TabMenuStrip extends LinearLayout
} }
} }
// Page scroll animates the drawable and it's bounds from the previous to next child view. // Page scroll animates the drawable and its bounds from the previous to next child view.
@Override @Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
if (mStrip == null) { if (mStrip == null) {

View File

@ -10,6 +10,7 @@ import android.content.ComponentName;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.util.Log;
import android.view.ActionProvider; import android.view.ActionProvider;
import android.view.KeyEvent; import android.view.KeyEvent;
import android.view.LayoutInflater; import android.view.LayoutInflater;
@ -114,7 +115,7 @@ public class GeckoMenu extends ListView
mItems = new ArrayList<GeckoMenuItem>(); mItems = new ArrayList<GeckoMenuItem>();
mActionItems = new HashMap<GeckoMenuItem, View>(); mActionItems = new HashMap<GeckoMenuItem, View>();
mActionItemBarPresenter = (DefaultActionItemBar) LayoutInflater.from(context).inflate(R.layout.menu_action_bar, null); mActionItemBarPresenter = (DefaultActionItemBar) LayoutInflater.from(context).inflate(R.layout.menu_action_bar, null);
} }
@Override @Override
@ -219,14 +220,26 @@ public class GeckoMenu extends ListView
public void clear() { public void clear() {
for (GeckoMenuItem menuItem : mItems) { for (GeckoMenuItem menuItem : mItems) {
if (menuItem.hasSubMenu()) { if (menuItem.hasSubMenu()) {
menuItem.getSubMenu().clear(); SubMenu sub = menuItem.getSubMenu();
if (sub == null) {
continue;
}
try {
sub.clear();
} catch (Exception ex) {
Log.e(LOGTAG, "Couldn't clear submenu.", ex);
}
} }
} }
mAdapter.clear(); mAdapter.clear();
mItems.clear(); mItems.clear();
/*
* Reinflating the menu will re-add any action items to the toolbar, so
* remove the old ones. This also ensures that any text associated with
* these is switched to the correct locale.
*/
if (mActionItemBarPresenter != null) { if (mActionItemBarPresenter != null) {
for (View item : mActionItems.values()) { for (View item : mActionItems.values()) {
mActionItemBarPresenter.removeActionItem(item); mActionItemBarPresenter.removeActionItem(item);

View File

@ -142,7 +142,11 @@ public class GeckoMenuItem implements MenuItem {
@Override @Override
public SubMenu getSubMenu() { public SubMenu getSubMenu() {
return mSubMenu; // For consistency with hasSubMenu.
if (mActionProvider == null) {
return mSubMenu;
}
return null;
} }
@Override @Override

View File

@ -232,6 +232,7 @@ gbjar.sources += [
'JavaAddonManager.java', 'JavaAddonManager.java',
'LightweightTheme.java', 'LightweightTheme.java',
'LightweightThemeDrawable.java', 'LightweightThemeDrawable.java',
'LocaleManager.java',
'MemoryMonitor.java', 'MemoryMonitor.java',
'menu/GeckoMenu.java', 'menu/GeckoMenu.java',
'menu/GeckoMenuInflater.java', 'menu/GeckoMenuInflater.java',

View File

@ -104,7 +104,6 @@
android:textColor="@color/url_bar_title" android:textColor="@color/url_bar_title"
android:textColorHint="@color/url_bar_title_hint" android:textColorHint="@color/url_bar_title_hint"
android:gravity="center_vertical|left" android:gravity="center_vertical|left"
android:hint="@string/url_bar_default_text"
android:layout_gravity="center_vertical" android:layout_gravity="center_vertical"
gecko:autoUpdateTheme="false"/> gecko:autoUpdateTheme="false"/>

View File

@ -274,6 +274,7 @@ var BrowserApp = {
Services.androidBridge.browserApp = this; Services.androidBridge.browserApp = this;
Services.obs.addObserver(this, "Locale:Changed", false);
Services.obs.addObserver(this, "Tab:Load", false); Services.obs.addObserver(this, "Tab:Load", false);
Services.obs.addObserver(this, "Tab:Selected", false); Services.obs.addObserver(this, "Tab:Selected", false);
Services.obs.addObserver(this, "Tab:Closed", false); Services.obs.addObserver(this, "Tab:Closed", false);
@ -410,6 +411,14 @@ var BrowserApp = {
return ""; return "";
}, },
/**
* Pass this a locale string, such as "fr" or "es_ES".
*/
setLocale: function (locale) {
console.log("browser.js: requesting locale set: " + locale);
sendMessageToJava({ type: "Locale:Set", locale: locale });
},
initContextMenu: function ba_initContextMenu() { initContextMenu: function ba_initContextMenu() {
// TODO: These should eventually move into more appropriate classes // TODO: These should eventually move into more appropriate classes
NativeWindow.contextmenus.add(Strings.browser.GetStringFromName("contextmenu.openInNewTab"), NativeWindow.contextmenus.add(Strings.browser.GetStringFromName("contextmenu.openInNewTab"),
@ -1496,6 +1505,13 @@ var BrowserApp = {
this.notifyPrefObservers(aData); this.notifyPrefObservers(aData);
break; break;
case "Locale:Changed":
// TODO: do we need to be more nuanced here -- e.g., checking for the
// OS locale -- or should it always be false on Fennec?
Services.prefs.setBoolPref("intl.locale.matchOS", false);
Services.prefs.setCharPref("general.useragent.locale", aData);
break;
default: default:
dump('BrowserApp.observe: unexpected topic "' + aTopic + '"\n'); dump('BrowserApp.observe: unexpected topic "' + aTopic + '"\n');
break; break;

View File

@ -77,7 +77,6 @@ jmethodID GeckoAppShell::jScheduleRestart = 0;
jmethodID GeckoAppShell::jSendMessageWrapper = 0; jmethodID GeckoAppShell::jSendMessageWrapper = 0;
jmethodID GeckoAppShell::jSetFullScreen = 0; jmethodID GeckoAppShell::jSetFullScreen = 0;
jmethodID GeckoAppShell::jSetKeepScreenOn = 0; jmethodID GeckoAppShell::jSetKeepScreenOn = 0;
jmethodID GeckoAppShell::jSetSelectedLocale = 0;
jmethodID GeckoAppShell::jSetURITitle = 0; jmethodID GeckoAppShell::jSetURITitle = 0;
jmethodID GeckoAppShell::jShowAlertNotificationWrapper = 0; jmethodID GeckoAppShell::jShowAlertNotificationWrapper = 0;
jmethodID GeckoAppShell::jShowFilePickerAsyncWrapper = 0; jmethodID GeckoAppShell::jShowFilePickerAsyncWrapper = 0;
@ -158,7 +157,6 @@ void GeckoAppShell::InitStubs(JNIEnv *jEnv) {
jSendMessageWrapper = getStaticMethod("sendMessage", "(Ljava/lang/String;Ljava/lang/String;I)V"); jSendMessageWrapper = getStaticMethod("sendMessage", "(Ljava/lang/String;Ljava/lang/String;I)V");
jSetFullScreen = getStaticMethod("setFullScreen", "(Z)V"); jSetFullScreen = getStaticMethod("setFullScreen", "(Z)V");
jSetKeepScreenOn = getStaticMethod("setKeepScreenOn", "(Z)V"); jSetKeepScreenOn = getStaticMethod("setKeepScreenOn", "(Z)V");
jSetSelectedLocale = getStaticMethod("setSelectedLocale", "(Ljava/lang/String;)V");
jSetURITitle = getStaticMethod("setUriTitle", "(Ljava/lang/String;Ljava/lang/String;)V"); jSetURITitle = getStaticMethod("setUriTitle", "(Ljava/lang/String;Ljava/lang/String;)V");
jShowAlertNotificationWrapper = getStaticMethod("showAlertNotification", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"); jShowAlertNotificationWrapper = getStaticMethod("showAlertNotification", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
jShowFilePickerAsyncWrapper = getStaticMethod("showFilePickerAsync", "(Ljava/lang/String;J)V"); jShowFilePickerAsyncWrapper = getStaticMethod("showFilePickerAsync", "(Ljava/lang/String;J)V");
@ -2055,35 +2053,6 @@ void GeckoAppShell::SetKeepScreenOn(bool a0) {
env->PopLocalFrame(NULL); env->PopLocalFrame(NULL);
} }
void GeckoAppShell::SetSelectedLocale(const nsAString& a0) {
JNIEnv *env = AndroidBridge::GetJNIEnv();
if (!env) {
ALOG_BRIDGE("Aborted: No env - %s", __PRETTY_FUNCTION__);
return;
}
if (env->PushLocalFrame(1) != 0) {
ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
env->ExceptionDescribe();
env->ExceptionClear();
return;
}
jstring j0 = AndroidBridge::NewJavaString(env, a0);
env->CallStaticVoidMethod(mGeckoAppShellClass, jSetSelectedLocale, j0);
if (env->ExceptionCheck()) {
ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
env->ExceptionDescribe();
env->ExceptionClear();
env->PopLocalFrame(NULL);
return;
}
env->PopLocalFrame(NULL);
}
void GeckoAppShell::SetURITitle(const nsAString& a0, const nsAString& a1) { void GeckoAppShell::SetURITitle(const nsAString& a0, const nsAString& a1) {
JNIEnv *env = AndroidBridge::GetJNIEnv(); JNIEnv *env = AndroidBridge::GetJNIEnv();
if (!env) { if (!env) {

View File

@ -84,7 +84,6 @@ public:
static void SendMessageWrapper(const nsAString& a0, const nsAString& a1, int32_t a2); static void SendMessageWrapper(const nsAString& a0, const nsAString& a1, int32_t a2);
static void SetFullScreen(bool a0); static void SetFullScreen(bool a0);
static void SetKeepScreenOn(bool a0); static void SetKeepScreenOn(bool a0);
static void SetSelectedLocale(const nsAString& a0);
static void SetURITitle(const nsAString& a0, const nsAString& a1); static void SetURITitle(const nsAString& a0, const nsAString& a1);
static void ShowAlertNotificationWrapper(const nsAString& a0, const nsAString& a1, const nsAString& a2, const nsAString& a3, const nsAString& a4); static void ShowAlertNotificationWrapper(const nsAString& a0, const nsAString& a1, const nsAString& a2, const nsAString& a3, const nsAString& a4);
static void ShowFilePickerAsyncWrapper(const nsAString& a0, int64_t a1); static void ShowFilePickerAsyncWrapper(const nsAString& a0, int64_t a1);

View File

@ -163,12 +163,8 @@ nsAppShell::NotifyNativeEvent()
mQueueCond.Notify(); mQueueCond.Notify();
} }
#define PREFNAME_MATCH_OS "intl.locale.matchOS"
#define PREFNAME_UA_LOCALE "general.useragent.locale"
#define PREFNAME_COALESCE_TOUCHES "dom.event.touch.coalescing.enabled" #define PREFNAME_COALESCE_TOUCHES "dom.event.touch.coalescing.enabled"
static const char* kObservedPrefs[] = { static const char* kObservedPrefs[] = {
PREFNAME_MATCH_OS,
PREFNAME_UA_LOCALE,
PREFNAME_COALESCE_TOUCHES, PREFNAME_COALESCE_TOUCHES,
nullptr nullptr
}; };
@ -182,8 +178,6 @@ nsAppShell::Init()
#endif #endif
nsresult rv = nsBaseAppShell::Init(); nsresult rv = nsBaseAppShell::Init();
AndroidBridge* bridge = AndroidBridge::Bridge();
nsCOMPtr<nsIObserverService> obsServ = nsCOMPtr<nsIObserverService> obsServ =
mozilla::services::GetObserverService(); mozilla::services::GetObserverService();
if (obsServ) { if (obsServ) {
@ -193,27 +187,7 @@ nsAppShell::Init()
if (sPowerManagerService) if (sPowerManagerService)
sPowerManagerService->AddWakeLockListener(sWakeLockListener); sPowerManagerService->AddWakeLockListener(sWakeLockListener);
if (!bridge)
return rv;
Preferences::AddStrongObservers(this, kObservedPrefs); Preferences::AddStrongObservers(this, kObservedPrefs);
bool match;
rv = Preferences::GetBool(PREFNAME_MATCH_OS, &match);
NS_ENSURE_SUCCESS(rv, rv);
if (match) {
GeckoAppShell::SetSelectedLocale(EmptyString());
return NS_OK;
}
nsAutoString locale;
rv = Preferences::GetLocalizedString(PREFNAME_UA_LOCALE, &locale);
if (NS_FAILED(rv)) {
rv = Preferences::GetString(PREFNAME_UA_LOCALE, &locale);
}
GeckoAppShell::SetSelectedLocale(locale);
mAllowCoalescingTouches = Preferences::GetBool(PREFNAME_COALESCE_TOUCHES, true); mAllowCoalescingTouches = Preferences::GetBool(PREFNAME_COALESCE_TOUCHES, true);
return rv; return rv;
} }
@ -228,30 +202,9 @@ nsAppShell::Observe(nsISupports* aSubject,
// or we'll see crashes, as the app shell outlives XPConnect. // or we'll see crashes, as the app shell outlives XPConnect.
mObserversHash.Clear(); mObserversHash.Clear();
return nsBaseAppShell::Observe(aSubject, aTopic, aData); return nsBaseAppShell::Observe(aSubject, aTopic, aData);
} else if (!strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID) && aData && ( } else if (!strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID) &&
nsDependentString(aData).Equals( aData &&
NS_LITERAL_STRING(PREFNAME_UA_LOCALE)) || nsDependentString(aData).Equals(NS_LITERAL_STRING(PREFNAME_COALESCE_TOUCHES))) {
nsDependentString(aData).Equals(
NS_LITERAL_STRING(PREFNAME_COALESCE_TOUCHES)) ||
nsDependentString(aData).Equals(
NS_LITERAL_STRING(PREFNAME_MATCH_OS)))) {
bool match;
nsresult rv = Preferences::GetBool(PREFNAME_MATCH_OS, &match);
NS_ENSURE_SUCCESS(rv, rv);
if (match) {
GeckoAppShell::SetSelectedLocale(EmptyString());
return NS_OK;
}
nsAutoString locale;
if (NS_FAILED(Preferences::GetLocalizedString(PREFNAME_UA_LOCALE,
&locale))) {
locale = Preferences::GetString(PREFNAME_UA_LOCALE);
}
GeckoAppShell::SetSelectedLocale(locale);
mAllowCoalescingTouches = Preferences::GetBool(PREFNAME_COALESCE_TOUCHES, true); mAllowCoalescingTouches = Preferences::GetBool(PREFNAME_COALESCE_TOUCHES, true);
return NS_OK; return NS_OK;
} }