Fall back to persist.sys.language/country if locale isn't set.

This will prevent users from losing their language setting when they
take an OTA to M.

bug: 23021286
Change-Id: Ifb66f6bf6a940ab745edac709321f3009ec6eab4
This commit is contained in:
Narayan Kamath
2015-08-11 15:40:34 +01:00
parent e19b76cbb5
commit bf88205bef
2 changed files with 78 additions and 28 deletions

View File

@@ -43,6 +43,9 @@
#include <dirent.h>
#include <assert.h>
#include <string>
#include <vector>
using namespace android;
@@ -357,38 +360,66 @@ static bool hasFile(const char* file) {
return false;
}
// Convenience wrapper over the property API that returns an
// std::string.
std::string getProperty(const char* key, const char* defaultValue) {
std::vector<char> temp(PROPERTY_VALUE_MAX);
const int len = property_get(key, &temp[0], defaultValue);
if (len < 0) {
return "";
}
return std::string(&temp[0], len);
}
/*
* Read the persistent locale. Attempts to read to persist.sys.locale
* and falls back to the default locale (ro.product.locale) if
* persist.sys.locale is empty.
* Read the persistent locale. Inspects the following system properties
* (in order) and returns the first non-empty property in the list :
*
* (1) persist.sys.locale
* (2) persist.sys.language/country/localevar (country and localevar are
* inspected iff. language is non-empty.
* (3) ro.product.locale
* (4) ro.product.locale.language/region
*
* Note that we need to inspect persist.sys.language/country/localevar to
* preserve language settings for devices that are upgrading from Lollipop
* to M. The same goes for ro.product.locale.language/region as well.
*/
static void readLocale(char* locale)
const std::string readLocale()
{
// Allocate 4 extra bytes because we might read a property into
// this array at offset 4.
char propLocale[PROPERTY_VALUE_MAX + 4];
property_get("persist.sys.locale", propLocale, "");
if (propLocale[0] == 0) {
property_get("ro.product.locale", propLocale, "");
if (propLocale[0] == 0) {
// If persist.sys.locale and ro.product.locale are missing,
// construct a locale value from the individual locale components.
property_get("ro.product.locale.language", propLocale, "en");
// The language code is either two or three chars in length. If it
// isn't 2 chars long, assume three. Anything else is an error
// anyway.
const int offset = (propLocale[2] == 0) ? 2 : 3;
propLocale[offset] = '-';
property_get("ro.product.locale.region", propLocale + offset + 1, "US");
}
const std::string locale = getProperty("persist.sys.locale", "");
if (!locale.empty()) {
return locale;
}
strncat(locale, propLocale, PROPERTY_VALUE_MAX);
// ALOGD("[DEBUG] locale=%s", locale);
const std::string language = getProperty("persist.sys.language", "");
if (!language.empty()) {
const std::string country = getProperty("persist.sys.country", "");
const std::string variant = getProperty("persist.sys.localevar", "");
std::string out = language;
if (!country.empty()) {
out = out + "-" + country;
}
if (!variant.empty()) {
out = out + "-" + variant;
}
return out;
}
const std::string productLocale = getProperty("ro.product.locale", "");
if (!productLocale.empty()) {
return productLocale;
}
// If persist.sys.locale and ro.product.locale are missing,
// construct a locale value from the individual locale components.
const std::string productLanguage = getProperty("ro.product.locale.language", "en");
const std::string productRegion = getProperty("ro.product.locale.region", "US");
return productLanguage + "-" + productRegion;
}
void AndroidRuntime::addOption(const char* optionString, void* extraInfo)
@@ -793,7 +824,8 @@ int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv)
/* Set the properties for locale */
{
strcpy(localeOption, "-Duser.locale=");
readLocale(localeOption);
const std::string locale = readLocale();
strncat(localeOption, locale.c_str(), PROPERTY_VALUE_MAX);
addOption(localeOption);
}

View File

@@ -95,6 +95,7 @@ import com.android.server.wm.WindowManagerService;
import dalvik.system.VMRuntime;
import java.io.File;
import java.util.Locale;
import java.util.Timer;
import java.util.TimerTask;
@@ -182,6 +183,23 @@ public final class SystemServer {
SystemClock.setCurrentTimeMillis(EARLIEST_SUPPORTED_TIME);
}
// If the system has "persist.sys.language" and friends set, replace them with
// "persist.sys.locale". Note that the default locale at this point is calculated
// using the "-Duser.locale" command line flag. That flag is usually populated by
// AndroidRuntime using the same set of system properties, but only the system_server
// and system apps are allowed to set them.
//
// NOTE: Most changes made here will need an equivalent change to
// core/jni/AndroidRuntime.cpp
if (!SystemProperties.get("persist.sys.language").isEmpty()) {
final String languageTag = Locale.getDefault().toLanguageTag();
SystemProperties.set("persist.sys.locale", languageTag);
SystemProperties.set("persist.sys.language", "");
SystemProperties.set("persist.sys.country", "");
SystemProperties.set("persist.sys.localevar", "");
}
// Here we go!
Slog.i(TAG, "Entered the Android system server!");
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_SYSTEM_RUN, SystemClock.uptimeMillis());