AssetManager support for 3 letter lang/country codes.

- 3 letter codes are packed into the existing 32 bit locale
  field in ResTable_config
- We introduce new fields for script / variant information.

Note that we define a "match" between two ResTable_config
structures to be purely on the basis of their language &
country (disregarding the script and the variant). However,
configs with scripts and variants are considered to be more
specific than those without.

Change-Id: I3c2e909ebbebdbbd0ab72a639d531b2b9fdbd9b9
diff --git a/libs/androidfw/tests/Android.mk b/libs/androidfw/tests/Android.mk
index 6e6522c..9e9649c 100644
--- a/libs/androidfw/tests/Android.mk
+++ b/libs/androidfw/tests/Android.mk
@@ -6,7 +6,8 @@
 test_src_files := \
     BackupData_test.cpp \
     ObbFile_test.cpp \
-    ZipUtils_test.cpp
+    ZipUtils_test.cpp \
+    ResourceTypes_test.cpp
 
 shared_libraries := \
     libandroidfw \
diff --git a/libs/androidfw/tests/ResourceTypes_test.cpp b/libs/androidfw/tests/ResourceTypes_test.cpp
new file mode 100644
index 0000000..eadfe00
--- /dev/null
+++ b/libs/androidfw/tests/ResourceTypes_test.cpp
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <androidfw/ResourceTypes.h>
+#include <utils/Log.h>
+#include <utils/String8.h>
+
+#include <gtest/gtest.h>
+namespace android {
+
+TEST(ResourceTypesTest, ResourceConfig_packAndUnpack2LetterLanguage) {
+     ResTable_config config;
+     config.packLanguage("en");
+
+     EXPECT_EQ('e', config.language[0]);
+     EXPECT_EQ('n', config.language[1]);
+
+     char out[4] = { 1, 1, 1, 1};
+     config.unpackLanguage(out);
+     EXPECT_EQ('e', out[0]);
+     EXPECT_EQ('n', out[1]);
+     EXPECT_EQ(0, out[2]);
+     EXPECT_EQ(0, out[3]);
+
+     memset(out, 1, sizeof(out));
+     config.locale = 0;
+     config.unpackLanguage(out);
+     EXPECT_EQ(0, out[0]);
+     EXPECT_EQ(0, out[1]);
+     EXPECT_EQ(0, out[2]);
+     EXPECT_EQ(0, out[3]);
+}
+
+TEST(ResourceTypesTest, ResourceConfig_packAndUnpack2LetterRegion) {
+     ResTable_config config;
+     config.packRegion("US");
+
+     EXPECT_EQ('U', config.country[0]);
+     EXPECT_EQ('S', config.country[1]);
+
+     char out[4] = { 1, 1, 1, 1};
+     config.unpackRegion(out);
+     EXPECT_EQ('U', out[0]);
+     EXPECT_EQ('S', out[1]);
+     EXPECT_EQ(0, out[2]);
+     EXPECT_EQ(0, out[3]);
+}
+
+TEST(ResourceTypesTest, ResourceConfig_packAndUnpack3LetterLanguage) {
+     ResTable_config config;
+     config.packLanguage("eng");
+
+     // 1-00110-01 101-00100
+     EXPECT_EQ(0x99, config.language[0]);
+     EXPECT_EQ(0xa4, config.language[1]);
+
+     char out[4] = { 1, 1, 1, 1};
+     config.unpackLanguage(out);
+     EXPECT_EQ('e', out[0]);
+     EXPECT_EQ('n', out[1]);
+     EXPECT_EQ('g', out[2]);
+     EXPECT_EQ(0, out[3]);
+}
+
+TEST(ResourceTypesTest, ResourceConfig_packAndUnpack3LetterRegion) {
+     ResTable_config config;
+     config.packRegion("419");
+
+     char out[4] = { 1, 1, 1, 1};
+     config.unpackRegion(out);
+
+     EXPECT_EQ('4', out[0]);
+     EXPECT_EQ('1', out[1]);
+     EXPECT_EQ('9', out[2]);
+}
+
+/* static */ void fillIn(const char* lang, const char* country,
+        const char* script, const char* variant, ResTable_config* out) {
+     memset(out, 0, sizeof(ResTable_config));
+     if (lang != NULL) {
+         out->packLanguage(lang);
+     }
+
+     if (country != NULL) {
+         out->packRegion(country);
+     }
+
+     if (script != NULL) {
+         memcpy(out->localeScript, script, 4);
+     }
+
+     if (variant != NULL) {
+         memcpy(out->localeVariant, variant, strlen(variant));
+     }
+}
+
+TEST(ResourceTypesTest, IsMoreSpecificThan) {
+    ResTable_config l;
+    ResTable_config r;
+
+    fillIn("en", NULL, NULL, NULL, &l);
+    fillIn(NULL, NULL, NULL, NULL, &r);
+
+    EXPECT_TRUE(l.isMoreSpecificThan(r));
+    EXPECT_FALSE(r.isMoreSpecificThan(l));
+
+    fillIn("eng", NULL, NULL, NULL, &l);
+    EXPECT_TRUE(l.isMoreSpecificThan(r));
+    EXPECT_FALSE(r.isMoreSpecificThan(l));
+
+    fillIn("eng", "419", NULL, NULL, &r);
+    EXPECT_FALSE(l.isMoreSpecificThan(r));
+    EXPECT_TRUE(r.isMoreSpecificThan(l));
+
+    fillIn("en", NULL, NULL, NULL, &l);
+    fillIn("en", "US", NULL, NULL, &r);
+    EXPECT_FALSE(l.isMoreSpecificThan(r));
+    EXPECT_TRUE(r.isMoreSpecificThan(l));
+
+    fillIn("en", "US", NULL, NULL, &l);
+    fillIn("en", "US", "Latn", NULL, &r);
+    EXPECT_FALSE(l.isMoreSpecificThan(r));
+    EXPECT_TRUE(r.isMoreSpecificThan(l));
+
+    fillIn("en", "US", NULL, NULL, &l);
+    fillIn("en", "US", NULL, "POSIX", &r);
+    EXPECT_FALSE(l.isMoreSpecificThan(r));
+    EXPECT_TRUE(r.isMoreSpecificThan(l));
+
+    fillIn("en", "US", "Latn", NULL, &l);
+    fillIn("en", "US", NULL, "POSIX", &r);
+    EXPECT_FALSE(l.isMoreSpecificThan(r));
+    EXPECT_TRUE(r.isMoreSpecificThan(l));
+}
+
+
+}  // namespace android.