diff options
-rw-r--r-- | base/android/java/org/chromium/base/LocaleUtils.java | 26 | ||||
-rw-r--r-- | base/android/locale_utils.cc | 94 | ||||
-rw-r--r-- | base/android/locale_utils.h | 29 | ||||
-rw-r--r-- | base/base.gyp | 2 | ||||
-rw-r--r-- | base/base.gypi | 3 | ||||
-rw-r--r-- | build/all_android.gyp | 2 | ||||
-rw-r--r-- | build/android/gtest_filter/ui_unittests_disabled | 2 | ||||
-rw-r--r-- | chrome/browser/autofill/autofill_country.cc | 37 | ||||
-rw-r--r-- | testing/android/native_test_launcher.cc | 2 | ||||
-rw-r--r-- | ui/base/l10n/l10n_util.cc | 47 | ||||
-rw-r--r-- | ui/base/l10n/l10n_util.h | 6 | ||||
-rw-r--r-- | ui/base/l10n/l10n_util_unittest.cc | 21 | ||||
-rw-r--r-- | ui/ui_unittests.gypi | 52 |
13 files changed, 282 insertions, 41 deletions
diff --git a/base/android/java/org/chromium/base/LocaleUtils.java b/base/android/java/org/chromium/base/LocaleUtils.java new file mode 100644 index 0000000..6bca1f7 --- /dev/null +++ b/base/android/java/org/chromium/base/LocaleUtils.java @@ -0,0 +1,26 @@ +// Copyright (c) 2012 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.base; + +import java.util.Locale; + +/** + * This class provides the locale related methods for the native library. + */ +class LocaleUtils { + + private LocaleUtils() { /* cannot be instantiated */ } + + /** + * @return the default locale. + */ + @CalledByNative + public static String getDefaultLocale() { + Locale locale = Locale.getDefault(); + String language = locale.getLanguage(); + String country = locale.getCountry(); + return country.isEmpty() ? language : language + "-" + country; + } +} diff --git a/base/android/locale_utils.cc b/base/android/locale_utils.cc new file mode 100644 index 0000000..c2a88cf --- /dev/null +++ b/base/android/locale_utils.cc @@ -0,0 +1,94 @@ +// Copyright (c) 2012 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. + +#include "base/android/locale_utils.h" + +#include "base/android/jni_android.h" +#include "base/android/jni_string.h" +#include "base/android/scoped_java_ref.h" +#include "base/logging.h" +#include "base/string_util.h" +#include "jni/locale_utils_jni.h" +#include "unicode/uloc.h" + +namespace base { +namespace android { + +std::string GetDefaultLocale() { + JNIEnv* env = AttachCurrentThread(); + ScopedJavaLocalRef<jstring> locale = Java_LocaleUtils_getDefaultLocale(env); + return ConvertJavaStringToUTF8(locale); +} + +namespace { + +// Common prototype of ICU uloc_getXXX() functions. +typedef int32_t (*UlocGetComponentFunc)(const char*, char*, int32_t, + UErrorCode*); + +std::string GetLocaleComponent(const std::string& locale, + UlocGetComponentFunc uloc_func, + int32_t max_capacity) { + std::string result; + UErrorCode error = U_ZERO_ERROR; + int32_t actual_length = uloc_func(locale.c_str(), + WriteInto(&result, max_capacity), + max_capacity, + &error); + DCHECK(U_SUCCESS(error)); + DCHECK(actual_length < max_capacity); + result.resize(actual_length); + return result; +} + +ScopedJavaLocalRef<jobject> NewJavaLocale( + JNIEnv* env, + ScopedJavaLocalRef<jclass> locale_class, + jmethodID constructor_id, + const std::string& locale) { + // TODO(wangxianzhu): Use new Locale API once Android supports scripts. + std::string language = GetLocaleComponent( + locale, uloc_getLanguage, ULOC_LANG_CAPACITY); + std::string country = GetLocaleComponent( + locale, uloc_getCountry, ULOC_COUNTRY_CAPACITY); + std::string variant = GetLocaleComponent( + locale, uloc_getVariant, ULOC_FULLNAME_CAPACITY); + return ScopedJavaLocalRef<jobject>( + env, env->NewObject( + locale_class.obj(), constructor_id, + ConvertUTF8ToJavaString(env, language).obj(), + ConvertUTF8ToJavaString(env, country).obj(), + ConvertUTF8ToJavaString(env, variant).obj())); +} + +} // namespace + +string16 GetDisplayNameForLocale(const std::string& locale, + const std::string& display_locale) { + JNIEnv* env = AttachCurrentThread(); + + ScopedJavaLocalRef<jclass> locale_class = GetClass(env, "java/util/Locale"); + jmethodID constructor_id = GetMethodID( + env, locale_class, "<init>", + "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"); + ScopedJavaLocalRef<jobject> java_locale = NewJavaLocale( + env, locale_class, constructor_id, locale); + ScopedJavaLocalRef<jobject> java_display_locale = NewJavaLocale( + env, locale_class, constructor_id, display_locale); + + jmethodID method_id = GetMethodID(env, locale_class, "getDisplayName", + "(Ljava/util/Locale;)Ljava/lang/String;"); + ScopedJavaLocalRef<jstring> java_result( + env, + static_cast<jstring>(env->CallObjectMethod(java_locale.obj(), method_id, + java_display_locale.obj()))); + return ConvertJavaStringToUTF16(java_result); +} + +bool RegisterLocaleUtils(JNIEnv* env) { + return RegisterNativesImpl(env); +} + +} // namespace android +} // namespace base diff --git a/base/android/locale_utils.h b/base/android/locale_utils.h new file mode 100644 index 0000000..35d0015 --- /dev/null +++ b/base/android/locale_utils.h @@ -0,0 +1,29 @@ +// Copyright (c) 2012 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. + +#ifndef BASE_ANDROID_LOCALE_UTILS_H_ +#define BASE_ANDROID_LOCALE_UTILS_H_ +#pragma once + +#include <jni.h> + +#include <string> + +#include "base/string16.h" + +namespace base { +namespace android { + +// Return the current default locale of the device. +std::string GetDefaultLocale(); + +string16 GetDisplayNameForLocale(const std::string& locale, + const std::string& display_locale); + +bool RegisterLocaleUtils(JNIEnv* env); + +} // namespace android +} // namespace base + +#endif // BASE_ANDROID_LOCALE_UTILS_H_ diff --git a/base/base.gyp b/base/base.gyp index e048d09..8de65df 100644 --- a/base/base.gyp +++ b/base/base.gyp @@ -538,11 +538,13 @@ 'variables': { 'java_sources': [ 'android/java/org/chromium/base/BuildInfo.java', + 'android/java/org/chromium/base/LocaleUtils.java', 'android/java/org/chromium/base/PathUtils.java', 'android/java/org/chromium/base/SystemMessageHandler.java', ], 'jni_headers': [ '<(SHARED_INTERMEDIATE_DIR)/base/jni/build_info_jni.h', + '<(SHARED_INTERMEDIATE_DIR)/base/jni/locale_utils_jni.h', '<(SHARED_INTERMEDIATE_DIR)/base/jni/path_utils_jni.h', '<(SHARED_INTERMEDIATE_DIR)/base/jni/system_message_handler_jni.h', ], diff --git a/base/base.gypi b/base/base.gypi index 4c96ebd..c19658f 100644 --- a/base/base.gypi +++ b/base/base.gypi @@ -39,6 +39,8 @@ 'android/jni_registrar.h', 'android/jni_string.cc', 'android/jni_string.h', + 'android/locale_utils.cc', + 'android/locale_utils.h', 'android/path_utils.cc', 'android/path_utils.h', 'at_exit.cc', @@ -696,6 +698,7 @@ 'dependencies': [ 'symbolize', '../third_party/ashmem/ashmem.gyp:ashmem', + '../third_party/icu/icu.gyp:icuuc', 'base_java', 'base_jni_headers', ], diff --git a/build/all_android.gyp b/build/all_android.gyp index 424425a..ad99339 100644 --- a/build/all_android.gyp +++ b/build/all_android.gyp @@ -60,6 +60,7 @@ # Unit test bundles packaged as an apk. '../base/base.gyp:base_unittests_apk', '../ipc/ipc.gyp:ipc_tests_apk', + '../ui/ui.gyp:ui_unittests_apk', ], }] ], @@ -81,7 +82,6 @@ 'type': 'none', 'dependencies': [ '../content/content.gyp:content_browsertests', - '../ui/ui.gyp:gfx_unittests', ], }, ], # targets diff --git a/build/android/gtest_filter/ui_unittests_disabled b/build/android/gtest_filter/ui_unittests_disabled index 4f4406f..f0a6c2b 100644 --- a/build/android/gtest_filter/ui_unittests_disabled +++ b/build/android/gtest_filter/ui_unittests_disabled @@ -41,6 +41,8 @@ ImageTest.SkiaToSkia ImageTest.SkiaToSkiaRef ImageTest.SwapRepresentations L10nUtilTest.GetAppLocale +L10nUtilTest.GetDisplayNameForCountry +L10nUtilTest.GetDisplayNameForLocale TextEliderTest.ElideEmail TextEliderTest.ElideEmailMoreSpace TextEliderTest.ElideRectangleText diff --git a/chrome/browser/autofill/autofill_country.cc b/chrome/browser/autofill/autofill_country.cc index 4a83bd0..2dea6af 100644 --- a/chrome/browser/autofill/autofill_country.cc +++ b/chrome/browser/autofill/autofill_country.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 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. @@ -390,7 +390,7 @@ class CountryNames { // effect. |buffer_size| should specify the |buffer|'s size, and is updated if // the |buffer| is resized. const std::string GetSortKey(const icu::Collator& collator, - const icu::UnicodeString& str, + const string16& str, scoped_array<uint8_t>* buffer, int32_t* buffer_size) const; @@ -482,10 +482,7 @@ void CountryNames::AddLocalizedNamesForLocale(const std::string& locale) { return; std::map<std::string, std::string> localized_names; - - icu::Locale icu_locale(locale.c_str()); const icu::Collator* collator = GetCollatorForLocale(locale); - int32_t buffer_size = 1000; scoped_array<uint8_t> buffer(new uint8_t[buffer_size]); @@ -493,10 +490,8 @@ void CountryNames::AddLocalizedNamesForLocale(const std::string& locale) { it != CountryDataMap::End(); ++it) { const std::string& country_code = it->first; - - icu::Locale country_locale(NULL, country_code.c_str()); - icu::UnicodeString country_name; - country_locale.getDisplayName(icu_locale, country_name); + string16 country_name = l10n_util::GetDisplayNameForCountry(country_code, + locale); std::string sort_key = GetSortKey(*collator, country_name, &buffer, @@ -521,7 +516,7 @@ const std::string CountryNames::GetCountryCodeForLocalizedName( int32_t buffer_size = country_name.size() * 4; scoped_array<uint8_t> buffer(new uint8_t[buffer_size]); std::string sort_key = GetSortKey(*collator, - country_name.c_str(), + country_name, &buffer, &buffer_size); @@ -555,38 +550,28 @@ icu::Collator* CountryNames::GetCollatorForLocale(const std::string& locale) { } const std::string CountryNames::GetSortKey(const icu::Collator& collator, - const icu::UnicodeString& str, + const string16& str, scoped_array<uint8_t>* buffer, int32_t* buffer_size) const { DCHECK(buffer); DCHECK(buffer_size); - int32_t expected_size = collator.getSortKey(str, buffer->get(), *buffer_size); + icu::UnicodeString icu_str(str.c_str(), str.length()); + int32_t expected_size = collator.getSortKey(icu_str, buffer->get(), + *buffer_size); if (expected_size > *buffer_size) { // If there wasn't enough space, grow the buffer and try again. *buffer_size = expected_size; buffer->reset(new uint8_t[*buffer_size]); DCHECK(buffer->get()); - expected_size = collator.getSortKey(str, buffer->get(), *buffer_size); + expected_size = collator.getSortKey(icu_str, buffer->get(), *buffer_size); DCHECK_EQ(*buffer_size, expected_size); } return std::string(reinterpret_cast<const char*>(buffer->get())); } -// Returns the country name corresponding to |country_code|, localized to the -// |display_locale|. -string16 GetDisplayName(const std::string& country_code, - const icu::Locale& display_locale) { - icu::Locale country_locale(NULL, country_code.c_str()); - icu::UnicodeString name; - country_locale.getDisplayName(display_locale, name); - - DCHECK_GT(name.length(), 0); - return string16(name.getBuffer(), name.length()); -} - } // namespace AutofillCountry::AutofillCountry(const std::string& country_code, @@ -596,7 +581,7 @@ AutofillCountry::AutofillCountry(const std::string& country_code, const CountryData& data = result->second; country_code_ = country_code; - name_ = GetDisplayName(country_code, icu::Locale(locale.c_str())); + name_ = l10n_util::GetDisplayNameForCountry(country_code, locale); postal_code_label_ = l10n_util::GetStringUTF16(data.postal_code_label_id); state_label_ = l10n_util::GetStringUTF16(data.state_label_id); } diff --git a/testing/android/native_test_launcher.cc b/testing/android/native_test_launcher.cc index 1555fbe..5e600b8 100644 --- a/testing/android/native_test_launcher.cc +++ b/testing/android/native_test_launcher.cc @@ -6,6 +6,7 @@ #include "base/android/jni_android.h" #include "base/android/jni_string.h" +#include "base/android/locale_utils.h" #include "base/android/path_utils.h" #include "base/android/scoped_java_ref.h" #include "base/at_exit.h" @@ -150,6 +151,7 @@ void LibraryLoadedOnMainThread(JNIEnv* env) { false); // Tick count VLOG(0) << "Chromium logging enabled: level = " << logging::GetMinLogLevel() << ", default verbosity = " << logging::GetVlogVerbosity(); + base::android::RegisterLocaleUtils(env); base::android::RegisterPathUtils(env); } diff --git a/ui/base/l10n/l10n_util.cc b/ui/base/l10n/l10n_util.cc index 6cf4608..f6c1b32 100644 --- a/ui/base/l10n/l10n_util.cc +++ b/ui/base/l10n/l10n_util.cc @@ -27,6 +27,10 @@ #include "unicode/rbbi.h" #include "unicode/uloc.h" +#if defined(OS_ANDROID) +#include "base/android/locale_utils.h" +#endif + #if defined(OS_LINUX) #include <glib.h> #endif @@ -474,26 +478,49 @@ string16 GetDisplayNameForLocale(const std::string& locale, // #1 and #2 wouldn't work if display_locale != current UI locale although // we can think of additional hack to work around the problem. // #3 can be potentially expensive. - if (locale_code == "zh-CN") + bool is_zh = false; + if (locale_code == "zh-CN") { locale_code = "zh-Hans"; - else if (locale_code == "zh-TW") + is_zh = true; + } else if (locale_code == "zh-TW") { locale_code = "zh-Hant"; - - UErrorCode error = U_ZERO_ERROR; - const int kBufferSize = 1024; + is_zh = true; + } string16 display_name; - int actual_size = uloc_getDisplayName(locale_code.c_str(), - display_locale.c_str(), - WriteInto(&display_name, kBufferSize), kBufferSize - 1, &error); - DCHECK(U_SUCCESS(error)); - display_name.resize(actual_size); +#if defined(OS_ANDROID) + // Use Java API to get locale display name so that we can remove most of + // the lang data from icu data to reduce binary size, except for zh-Hans and + // zh-Hant because the current Android Java API doesn't support scripts. + // TODO(wangxianzhu): remove the special handling of zh-Hans and zh-Hant once + // Android Java API supports scripts. + if (!is_zh) { + display_name = base::android::GetDisplayNameForLocale(locale_code, + display_locale); + } else +#endif + { + UErrorCode error = U_ZERO_ERROR; + const int kBufferSize = 1024; + + int actual_size = uloc_getDisplayName(locale_code.c_str(), + display_locale.c_str(), + WriteInto(&display_name, kBufferSize), kBufferSize - 1, &error); + DCHECK(U_SUCCESS(error)); + display_name.resize(actual_size); + } + // Add an RTL mark so parentheses are properly placed. if (is_for_ui && base::i18n::IsRTL()) display_name.push_back(static_cast<char16>(base::i18n::kRightToLeftMark)); return display_name; } +string16 GetDisplayNameForCountry(const std::string& country_code, + const std::string& display_locale) { + return GetDisplayNameForLocale("_" + country_code, display_locale, false); +} + std::string NormalizeLocale(const std::string& locale) { std::string normalized_locale(locale); std::replace(normalized_locale.begin(), normalized_locale.end(), '-', '_'); diff --git a/ui/base/l10n/l10n_util.h b/ui/base/l10n/l10n_util.h index 48ec68a..2eae6de 100644 --- a/ui/base/l10n/l10n_util.h +++ b/ui/base/l10n/l10n_util.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 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. @@ -51,6 +51,10 @@ UI_EXPORT string16 GetDisplayNameForLocale(const std::string& locale, const std::string& display_locale, bool is_for_ui); +// Returns the display name of the |country_code| in |display_locale|. +UI_EXPORT string16 GetDisplayNameForCountry(const std::string& country_code, + const std::string& display_locale); + // Converts all - into _, to be consistent with ICU and file system names. UI_EXPORT std::string NormalizeLocale(const std::string& locale); diff --git a/ui/base/l10n/l10n_util_unittest.cc b/ui/base/l10n/l10n_util_unittest.cc index 971d7ce..a9b51fd 100644 --- a/ui/base/l10n/l10n_util_unittest.cc +++ b/ui/base/l10n/l10n_util_unittest.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 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. @@ -303,7 +303,7 @@ TEST_F(L10nUtilTest, SortStringsUsingFunction) { STLDeleteElements(&strings); } -TEST_F(L10nUtilTest, LocaleDisplayName) { +TEST_F(L10nUtilTest, GetDisplayNameForLocale) { // TODO(jungshik): Make this test more extensive. // Test zh-CN and zh-TW are treated as zh-Hans and zh-Hant. string16 result = l10n_util::GetDisplayNameForLocale("zh-CN", "en", false); @@ -318,6 +318,12 @@ TEST_F(L10nUtilTest, LocaleDisplayName) { result = l10n_util::GetDisplayNameForLocale("es-419", "en", false); EXPECT_EQ(ASCIIToUTF16("Spanish (Latin America)"), result); + result = l10n_util::GetDisplayNameForLocale("-BR", "en", false); + EXPECT_EQ(ASCIIToUTF16("Brazil"), result); + + result = l10n_util::GetDisplayNameForLocale("xyz-xyz", "en", false); + EXPECT_EQ(ASCIIToUTF16("xyz (XYZ)"), result); + // ToUpper and ToLower should work with embedded NULLs. const size_t length_with_null = 4; char16 buf_with_null[length_with_null] = { 0, 'a', 0, 'b' }; @@ -334,6 +340,17 @@ TEST_F(L10nUtilTest, LocaleDisplayName) { lower_with_null[2] == 0 && lower_with_null[3] == 'b'); } +TEST_F(L10nUtilTest, GetDisplayNameForCountry) { + string16 result = l10n_util::GetDisplayNameForCountry("BR", "en"); + EXPECT_EQ(ASCIIToUTF16("Brazil"), result); + + result = l10n_util::GetDisplayNameForCountry("419", "en"); + EXPECT_EQ(ASCIIToUTF16("Latin America"), result); + + result = l10n_util::GetDisplayNameForCountry("xyz", "en"); + EXPECT_EQ(ASCIIToUTF16("XYZ"), result); +} + TEST_F(L10nUtilTest, GetParentLocales) { std::vector<std::string> locales; const std::string top_locale("sr_Cyrl_RS"); diff --git a/ui/ui_unittests.gypi b/ui/ui_unittests.gypi index 77965dc..1b68db7 100644 --- a/ui/ui_unittests.gypi +++ b/ui/ui_unittests.gypi @@ -29,7 +29,7 @@ }, { 'target_name': 'ui_unittests', - 'type': 'executable', + 'type': '<(gtest_target_type)', 'includes': [ 'base/ime/ime_unittests.gypi', ], @@ -154,6 +154,11 @@ 'gfx/interpolated_transform_unittest.cc', ], }], + ['OS=="android" and "<(gtest_target_type)"=="shared_library"', { + 'dependencies': [ + '../testing/android/native_test.gyp:native_test_native_code', + ], + }], ['use_glib == 1', { 'dependencies': [ '../build/linux/system.gyp:pangocairo', @@ -206,4 +211,49 @@ ], }, ], + 'conditions': [ + # Special target to wrap a <(gtest_target_type)==shared_library + # ui_unittests into an android apk for execution. + # See base.gyp for TODO(jrg)s about this strategy. + ['OS=="android" and "<(gtest_target_type)"=="shared_library"', { + 'targets': [ + { + 'target_name': 'ui_unittests_apk', + 'type': 'none', + 'dependencies': [ + 'ui_unittests', + ], + 'actions': [ + { + # Generate apk files (including source and antfile) from + # a template, and builds them. + 'action_name': 'generate_and_build', + 'inputs': [ + '../testing/android/generate_native_test.py', + '<(PRODUCT_DIR)/lib.target/libui_unittests.so', + '<(PRODUCT_DIR)/chromium_base.jar', + ], + 'outputs': [ + '<(PRODUCT_DIR)/ChromeNativeTests_ui_unittests-debug.apk', + ], + 'action': [ + '../testing/android/generate_native_test.py', + '--native_library', + '<(PRODUCT_DIR)/lib.target/libui_unittests.so', + # TODO(jrg): find a better way to specify jar + # dependencies. Hard coding seems fragile. + '--jar', + '<(PRODUCT_DIR)/chromium_base.jar', + '--output', + '<(PRODUCT_DIR)/ui_unittests_apk', + '--ant-args', + '-DPRODUCT_DIR=<(PRODUCT_DIR)', + '--ant-compile' + ], + }, + ] + }, + ], + }], + ], } |