diff options
-rw-r--r-- | tools/aapt2/Android.bp | 1 | ||||
-rw-r--r-- | tools/aapt2/ConfigDescription.cpp | 6 | ||||
-rw-r--r-- | tools/aapt2/ConfigDescription.h | 3 | ||||
-rw-r--r-- | tools/aapt2/Configuration.proto | 207 | ||||
-rw-r--r-- | tools/aapt2/Locale.cpp | 137 | ||||
-rw-r--r-- | tools/aapt2/Locale.h | 5 | ||||
-rw-r--r-- | tools/aapt2/Resources.proto | 12 | ||||
-rw-r--r-- | tools/aapt2/ResourcesInternal.proto | 3 | ||||
-rw-r--r-- | tools/aapt2/proto/ProtoHelpers.cpp | 510 | ||||
-rw-r--r-- | tools/aapt2/proto/ProtoHelpers.h | 9 | ||||
-rw-r--r-- | tools/aapt2/proto/TableProtoDeserializer.cpp | 10 | ||||
-rw-r--r-- | tools/aapt2/proto/TableProtoSerializer.cpp | 12 | ||||
-rw-r--r-- | tools/aapt2/proto/TableProtoSerializer_test.cpp | 94 |
13 files changed, 906 insertions, 103 deletions
diff --git a/tools/aapt2/Android.bp b/tools/aapt2/Android.bp index 43918da75ad4..f0ebf10ec527 100644 --- a/tools/aapt2/Android.bp +++ b/tools/aapt2/Android.bp @@ -139,6 +139,7 @@ cc_library_host_static { "xml/XmlDom.cpp", "xml/XmlPullParser.cpp", "xml/XmlUtil.cpp", + "Configuration.proto", "Resources.proto", "ResourcesInternal.proto", ], diff --git a/tools/aapt2/ConfigDescription.cpp b/tools/aapt2/ConfigDescription.cpp index a9278c136cff..59a6e1281783 100644 --- a/tools/aapt2/ConfigDescription.cpp +++ b/tools/aapt2/ConfigDescription.cpp @@ -876,6 +876,12 @@ ConfigDescription ConfigDescription::CopyWithoutSdkVersion() const { return copy; } +std::string ConfigDescription::GetBcp47LanguageTag(bool canonicalize) const { + char locale[RESTABLE_MAX_LOCALE_LEN]; + getBcp47Locale(locale, canonicalize); + return std::string(locale); +} + bool ConfigDescription::Dominates(const ConfigDescription& o) const { if (*this == o) { return true; diff --git a/tools/aapt2/ConfigDescription.h b/tools/aapt2/ConfigDescription.h index 65c96175091c..c1d0e1084186 100644 --- a/tools/aapt2/ConfigDescription.h +++ b/tools/aapt2/ConfigDescription.h @@ -61,6 +61,9 @@ struct ConfigDescription : public android::ResTable_config { ConfigDescription CopyWithoutSdkVersion() const; + // Returns the BCP-47 language tag of this configuration's locale. + std::string GetBcp47LanguageTag(bool canonicalize = false) const; + /** * A configuration X dominates another configuration Y, if X has at least the * precedence of Y and X is strictly more general than Y: for any type defined diff --git a/tools/aapt2/Configuration.proto b/tools/aapt2/Configuration.proto new file mode 100644 index 000000000000..fc636a43ec40 --- /dev/null +++ b/tools/aapt2/Configuration.proto @@ -0,0 +1,207 @@ +/* + * Copyright (C) 2017 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. + */ + +syntax = "proto3"; + +package aapt.pb; + +option java_package = "com.android.aapt"; +option optimize_for = LITE_RUNTIME; + +// A description of the requirements a device must have in order for a +// resource to be matched and selected. +message Configuration { + enum LayoutDirection { + LAYOUT_DIRECTION_UNSET = 0; + LAYOUT_DIRECTION_LTR = 1; + LAYOUT_DIRECTION_RTL = 2; + } + + enum ScreenLayoutSize { + SCREEN_LAYOUT_SIZE_UNSET = 0; + SCREEN_LAYOUT_SIZE_SMALL = 1; + SCREEN_LAYOUT_SIZE_NORMAL = 2; + SCREEN_LAYOUT_SIZE_LARGE = 3; + SCREEN_LAYOUT_SIZE_XLARGE = 4; + } + + enum ScreenLayoutLong { + SCREEN_LAYOUT_LONG_UNSET = 0; + SCREEN_LAYOUT_LONG_LONG = 1; + SCREEN_LAYOUT_LONG_NOTLONG = 2; + } + + enum ScreenRound { + SCREEN_ROUND_UNSET = 0; + SCREEN_ROUND_ROUND = 1; + SCREEN_ROUND_NOTROUND = 2; + } + + enum WideColorGamut { + WIDE_COLOR_GAMUT_UNSET = 0; + WIDE_COLOR_GAMUT_WIDECG = 1; + WIDE_COLOR_GAMUT_NOWIDECG = 2; + } + + enum Hdr { + HDR_UNSET = 0; + HDR_HIGHDR = 1; + HDR_LOWDR = 2; + } + + enum Orientation { + ORIENTATION_UNSET = 0; + ORIENTATION_PORT = 1; + ORIENTATION_LAND = 2; + ORIENTATION_SQUARE = 3; + } + + enum UiModeType { + UI_MODE_TYPE_UNSET = 0; + UI_MODE_TYPE_NORMAL = 1; + UI_MODE_TYPE_DESK = 2; + UI_MODE_TYPE_CAR = 3; + UI_MODE_TYPE_TELEVISION = 4; + UI_MODE_TYPE_APPLIANCE = 5; + UI_MODE_TYPE_WATCH = 6; + UI_MODE_TYPE_VRHEADSET = 7; + } + + enum UiModeNight { + UI_MODE_NIGHT_UNSET = 0; + UI_MODE_NIGHT_NIGHT = 1; + UI_MODE_NIGHT_NOTNIGHT = 2; + } + + enum Touchscreen { + TOUCHSCREEN_UNSET = 0; + TOUCHSCREEN_NOTOUCH = 1; + TOUCHSCREEN_STYLUS = 2; + TOUCHSCREEN_FINGER = 3; + } + + enum KeysHidden { + KEYS_HIDDEN_UNSET = 0; + KEYS_HIDDEN_KEYSEXPOSED = 1; + KEYS_HIDDEN_KEYSHIDDEN = 2; + KEYS_HIDDEN_KEYSSOFT = 3; + } + + enum Keyboard { + KEYBOARD_UNSET = 0; + KEYBOARD_NOKEYS = 1; + KEYBOARD_QWERTY = 2; + KEYBOARD_TWELVEKEY = 3; + } + + enum NavHidden { + NAV_HIDDEN_UNSET = 0; + NAV_HIDDEN_NAVEXPOSED = 1; + NAV_HIDDEN_NAVHIDDEN = 2; + } + + enum Navigation { + NAVIGATION_UNSET = 0; + NAVIGATION_NONAV = 1; + NAVIGATION_DPAD = 2; + NAVIGATION_TRACKBALL = 3; + NAVIGATION_WHEEL = 4; + } + + // + // Axis/dimensions that are understood by the runtime. + // + + // Mobile country code. + uint32 mcc = 1; + + // Mobile network code. + uint32 mnc = 2; + + // BCP-47 locale tag. + string locale = 3; + + // Left-to-right, right-to-left... + LayoutDirection layout_direction = 4; + + // Screen width in pixels. Prefer screen_width_dp. + uint32 screen_width = 5; + + // Screen height in pixels. Prefer screen_height_dp. + uint32 screen_height = 6; + + // Screen width in density independent pixels (dp). + uint32 screen_width_dp = 7; + + // Screen height in density independent pixels (dp). + uint32 screen_height_dp = 8; + + // The smallest screen dimension, regardless of orientation, in dp. + uint32 smallest_screen_width_dp = 9; + + // Whether the device screen is classified as small, normal, large, xlarge. + ScreenLayoutSize screen_layout_size = 10; + + // Whether the device screen is long. + ScreenLayoutLong screen_layout_long = 11; + + // Whether the screen is round (Android Wear). + ScreenRound screen_round = 12; + + // Whether the screen supports wide color gamut. + WideColorGamut wide_color_gamut = 13; + + // Whether the screen has high dynamic range. + Hdr hdr = 14; + + // Which orientation the device is in (portrait, landscape). + Orientation orientation = 15; + + // Which type of UI mode the device is in (television, car, etc.). + UiModeType ui_mode_type = 16; + + // Whether the device is in night mode. + UiModeNight ui_mode_night = 17; + + // The device's screen density in dots-per-inch (dpi). + uint32 density = 18; + + // Whether a touchscreen exists, supports a stylus, or finger. + Touchscreen touchscreen = 19; + + // Whether the keyboard hardware keys are currently hidden, exposed, or + // if the keyboard is a software keyboard. + KeysHidden keys_hidden = 20; + + // The type of keyboard present (none, QWERTY, 12-key). + Keyboard keyboard = 21; + + // Whether the navigation is exposed or hidden. + NavHidden nav_hidden = 22; + + // The type of navigation present on the device + // (trackball, wheel, dpad, etc.). + Navigation navigation = 23; + + // The minimum SDK version of the device. + uint32 sdk_version = 24; + + // + // Build-time only dimensions. + // + + string product = 25; +} diff --git a/tools/aapt2/Locale.cpp b/tools/aapt2/Locale.cpp index 7664fac44be1..d81921f23904 100644 --- a/tools/aapt2/Locale.cpp +++ b/tools/aapt2/Locale.cpp @@ -24,9 +24,10 @@ #include "util/Util.h" -namespace aapt { +using ::android::ResTable_config; +using ::android::StringPiece; -using android::ResTable_config; +namespace aapt { void LocaleValue::set_language(const char* language_chars) { size_t i = 0; @@ -72,7 +73,7 @@ static inline bool is_number(const std::string& str) { return std::all_of(std::begin(str), std::end(str), ::isdigit); } -bool LocaleValue::InitFromFilterString(const android::StringPiece& str) { +bool LocaleValue::InitFromFilterString(const StringPiece& str) { // A locale (as specified in the filter) is an underscore separated name such // as "en_US", "en_Latn_US", or "en_US_POSIX". std::vector<std::string> parts = util::SplitAndLowercase(str, '_'); @@ -138,6 +139,71 @@ bool LocaleValue::InitFromFilterString(const android::StringPiece& str) { return true; } +bool LocaleValue::InitFromBcp47Tag(const StringPiece& bcp47tag) { + return InitFromBcp47TagImpl(bcp47tag, '-'); +} + +bool LocaleValue::InitFromBcp47TagImpl(const StringPiece& bcp47tag, const char separator) { + std::vector<std::string> subtags = util::SplitAndLowercase(bcp47tag, separator); + if (subtags.size() == 1) { + set_language(subtags[0].c_str()); + } else if (subtags.size() == 2) { + set_language(subtags[0].c_str()); + + // The second tag can either be a region, a variant or a script. + switch (subtags[1].size()) { + case 2: + case 3: + set_region(subtags[1].c_str()); + break; + case 4: + if ('0' <= subtags[1][0] && subtags[1][0] <= '9') { + // This is a variant: fall through + } else { + set_script(subtags[1].c_str()); + break; + } + case 5: + case 6: + case 7: + case 8: + set_variant(subtags[1].c_str()); + break; + default: + return false; + } + } else if (subtags.size() == 3) { + // The language is always the first subtag. + set_language(subtags[0].c_str()); + + // The second subtag can either be a script or a region code. + // If its size is 4, it's a script code, else it's a region code. + if (subtags[1].size() == 4) { + set_script(subtags[1].c_str()); + } else if (subtags[1].size() == 2 || subtags[1].size() == 3) { + set_region(subtags[1].c_str()); + } else { + return false; + } + + // The third tag can either be a region code (if the second tag was + // a script), else a variant code. + if (subtags[2].size() >= 4) { + set_variant(subtags[2].c_str()); + } else { + set_region(subtags[2].c_str()); + } + } else if (subtags.size() == 4) { + set_language(subtags[0].c_str()); + set_script(subtags[1].c_str()); + set_region(subtags[2].c_str()); + set_variant(subtags[3].c_str()); + } else { + return false; + } + return true; +} + ssize_t LocaleValue::InitFromParts(std::vector<std::string>::iterator iter, std::vector<std::string>::iterator end) { const std::vector<std::string>::iterator start_iter = iter; @@ -145,71 +211,13 @@ ssize_t LocaleValue::InitFromParts(std::vector<std::string>::iterator iter, std::string& part = *iter; if (part[0] == 'b' && part[1] == '+') { // This is a "modified" BCP 47 language tag. Same semantics as BCP 47 tags, - // except that the separator is "+" and not "-". - std::vector<std::string> subtags = util::SplitAndLowercase(part, '+'); - subtags.erase(subtags.begin()); - if (subtags.size() == 1) { - set_language(subtags[0].c_str()); - } else if (subtags.size() == 2) { - set_language(subtags[0].c_str()); - - // The second tag can either be a region, a variant or a script. - switch (subtags[1].size()) { - case 2: - case 3: - set_region(subtags[1].c_str()); - break; - case 4: - if ('0' <= subtags[1][0] && subtags[1][0] <= '9') { - // This is a variant: fall through - } else { - set_script(subtags[1].c_str()); - break; - } - case 5: - case 6: - case 7: - case 8: - set_variant(subtags[1].c_str()); - break; - default: - return -1; - } - } else if (subtags.size() == 3) { - // The language is always the first subtag. - set_language(subtags[0].c_str()); - - // The second subtag can either be a script or a region code. - // If its size is 4, it's a script code, else it's a region code. - if (subtags[1].size() == 4) { - set_script(subtags[1].c_str()); - } else if (subtags[1].size() == 2 || subtags[1].size() == 3) { - set_region(subtags[1].c_str()); - } else { - return -1; - } - - // The third tag can either be a region code (if the second tag was - // a script), else a variant code. - if (subtags[2].size() >= 4) { - set_variant(subtags[2].c_str()); - } else { - set_region(subtags[2].c_str()); - } - } else if (subtags.size() == 4) { - set_language(subtags[0].c_str()); - set_script(subtags[1].c_str()); - set_region(subtags[2].c_str()); - set_variant(subtags[3].c_str()); - } else { + // except that the separator is "+" and not "-". Skip the prefix 'b+'. + if (!InitFromBcp47TagImpl(StringPiece(part).substr(2), '+')) { return -1; } - ++iter; - } else { - if ((part.length() == 2 || part.length() == 3) && is_alpha(part) && - part != "car") { + if ((part.length() == 2 || part.length() == 3) && is_alpha(part) && part != "car") { set_language(part.c_str()); ++iter; @@ -222,7 +230,6 @@ ssize_t LocaleValue::InitFromParts(std::vector<std::string>::iterator iter, } } } - return static_cast<ssize_t>(iter - start_iter); } diff --git a/tools/aapt2/Locale.h b/tools/aapt2/Locale.h index 3d73b2eb17bf..6d8b598415cc 100644 --- a/tools/aapt2/Locale.h +++ b/tools/aapt2/Locale.h @@ -41,6 +41,9 @@ struct LocaleValue { */ bool InitFromFilterString(const android::StringPiece& config); + // Initializes this LocaleValue from a BCP-47 locale tag. + bool InitFromBcp47Tag(const android::StringPiece& bcp47tag); + /** * Initialize this LocaleValue from parts of a vector. */ @@ -67,6 +70,8 @@ struct LocaleValue { inline bool operator>(const LocaleValue& o) const; private: + bool InitFromBcp47TagImpl(const android::StringPiece& bcp47tag, const char separator); + void set_language(const char* language); void set_region(const char* language); void set_script(const char* script); diff --git a/tools/aapt2/Resources.proto b/tools/aapt2/Resources.proto index c1af88a1a74e..174b7f6b7c8c 100644 --- a/tools/aapt2/Resources.proto +++ b/tools/aapt2/Resources.proto @@ -16,19 +16,13 @@ syntax = "proto3"; +import "frameworks/base/tools/aapt2/Configuration.proto"; + package aapt.pb; option java_package = "com.android.aapt"; option optimize_for = LITE_RUNTIME; -// A configuration description that wraps the binary form of the C++ class -// aapt::ConfigDescription, with an added product definition. -// TODO(adamlesinski): Flesh this out to be represented in proto. -message ConfigDescription { - bytes data = 1; - string product = 2; -} - // A string pool that wraps the binary form of the C++ class android::ResStringPool. message StringPool { bytes data = 1; @@ -163,7 +157,7 @@ message Entry { // A Configuration/Value pair. message ConfigValue { - ConfigDescription config = 1; + Configuration config = 1; Value value = 2; } diff --git a/tools/aapt2/ResourcesInternal.proto b/tools/aapt2/ResourcesInternal.proto index 17604e4c6fe8..0b0a252a3452 100644 --- a/tools/aapt2/ResourcesInternal.proto +++ b/tools/aapt2/ResourcesInternal.proto @@ -16,6 +16,7 @@ syntax = "proto3"; +import "frameworks/base/tools/aapt2/Configuration.proto"; import "frameworks/base/tools/aapt2/Resources.proto"; package aapt.pb.internal; @@ -38,7 +39,7 @@ message CompiledFile { string resource_name = 1; // The configuration for which the resource is defined. - aapt.pb.ConfigDescription config = 2; + aapt.pb.Configuration config = 2; // The filesystem path to where the source file originated. // Mainly used to display helpful error messages. diff --git a/tools/aapt2/proto/ProtoHelpers.cpp b/tools/aapt2/proto/ProtoHelpers.cpp index 59ca8e484fbe..18f7e1d2ff7d 100644 --- a/tools/aapt2/proto/ProtoHelpers.cpp +++ b/tools/aapt2/proto/ProtoHelpers.cpp @@ -16,6 +16,8 @@ #include "proto/ProtoHelpers.h" +#include "Locale.h" + namespace aapt { void SerializeStringPoolToPb(const StringPool& pool, pb::StringPool* out_pb_pool) { @@ -70,27 +72,507 @@ SymbolState DeserializeVisibilityFromPb(pb::SymbolStatus_Visibility pb_visibilit return SymbolState::kUndefined; } -void SerializeConfig(const ConfigDescription& config, pb::ConfigDescription* out_pb_config) { - android::ResTable_config flat_config = config; - flat_config.size = sizeof(flat_config); - flat_config.swapHtoD(); - out_pb_config->set_data(&flat_config, sizeof(flat_config)); +void SerializeConfig(const ConfigDescription& config, pb::Configuration* out_pb_config) { + out_pb_config->set_mcc(config.mcc); + out_pb_config->set_mnc(config.mnc); + out_pb_config->set_locale(config.GetBcp47LanguageTag()); + + switch (config.screenLayout & ConfigDescription::MASK_LAYOUTDIR) { + case ConfigDescription::LAYOUTDIR_LTR: + out_pb_config->set_layout_direction(pb::Configuration_LayoutDirection_LAYOUT_DIRECTION_LTR); + break; + + case ConfigDescription::LAYOUTDIR_RTL: + out_pb_config->set_layout_direction(pb::Configuration_LayoutDirection_LAYOUT_DIRECTION_RTL); + break; + } + + out_pb_config->set_screen_width(config.screenWidth); + out_pb_config->set_screen_height(config.screenHeight); + out_pb_config->set_screen_width_dp(config.screenWidthDp); + out_pb_config->set_screen_height_dp(config.screenHeightDp); + out_pb_config->set_smallest_screen_width_dp(config.smallestScreenWidthDp); + + switch (config.screenLayout & ConfigDescription::MASK_SCREENSIZE) { + case ConfigDescription::SCREENSIZE_SMALL: + out_pb_config->set_screen_layout_size( + pb::Configuration_ScreenLayoutSize_SCREEN_LAYOUT_SIZE_SMALL); + break; + + case ConfigDescription::SCREENSIZE_NORMAL: + out_pb_config->set_screen_layout_size( + pb::Configuration_ScreenLayoutSize_SCREEN_LAYOUT_SIZE_NORMAL); + break; + + case ConfigDescription::SCREENSIZE_LARGE: + out_pb_config->set_screen_layout_size( + pb::Configuration_ScreenLayoutSize_SCREEN_LAYOUT_SIZE_LARGE); + break; + + case ConfigDescription::SCREENSIZE_XLARGE: + out_pb_config->set_screen_layout_size( + pb::Configuration_ScreenLayoutSize_SCREEN_LAYOUT_SIZE_XLARGE); + break; + } + + switch (config.screenLayout & ConfigDescription::MASK_SCREENLONG) { + case ConfigDescription::SCREENLONG_YES: + out_pb_config->set_screen_layout_long( + pb::Configuration_ScreenLayoutLong_SCREEN_LAYOUT_LONG_LONG); + break; + + case ConfigDescription::SCREENLONG_NO: + out_pb_config->set_screen_layout_long( + pb::Configuration_ScreenLayoutLong_SCREEN_LAYOUT_LONG_NOTLONG); + break; + } + + switch (config.screenLayout2 & ConfigDescription::MASK_SCREENROUND) { + case ConfigDescription::SCREENROUND_YES: + out_pb_config->set_screen_round(pb::Configuration_ScreenRound_SCREEN_ROUND_ROUND); + break; + + case ConfigDescription::SCREENROUND_NO: + out_pb_config->set_screen_round(pb::Configuration_ScreenRound_SCREEN_ROUND_NOTROUND); + break; + } + + switch (config.colorMode & ConfigDescription::MASK_WIDE_COLOR_GAMUT) { + case ConfigDescription::WIDE_COLOR_GAMUT_YES: + out_pb_config->set_wide_color_gamut(pb::Configuration_WideColorGamut_WIDE_COLOR_GAMUT_WIDECG); + break; + + case ConfigDescription::WIDE_COLOR_GAMUT_NO: + out_pb_config->set_wide_color_gamut( + pb::Configuration_WideColorGamut_WIDE_COLOR_GAMUT_NOWIDECG); + break; + } + + switch (config.colorMode & ConfigDescription::MASK_HDR) { + case ConfigDescription::HDR_YES: + out_pb_config->set_hdr(pb::Configuration_Hdr_HDR_HIGHDR); + break; + + case ConfigDescription::HDR_NO: + out_pb_config->set_hdr(pb::Configuration_Hdr_HDR_LOWDR); + break; + } + + switch (config.orientation) { + case ConfigDescription::ORIENTATION_PORT: + out_pb_config->set_orientation(pb::Configuration_Orientation_ORIENTATION_PORT); + break; + + case ConfigDescription::ORIENTATION_LAND: + out_pb_config->set_orientation(pb::Configuration_Orientation_ORIENTATION_LAND); + break; + + case ConfigDescription::ORIENTATION_SQUARE: + out_pb_config->set_orientation(pb::Configuration_Orientation_ORIENTATION_SQUARE); + break; + } + + switch (config.uiMode & ConfigDescription::MASK_UI_MODE_TYPE) { + case ConfigDescription::UI_MODE_TYPE_NORMAL: + out_pb_config->set_ui_mode_type(pb::Configuration_UiModeType_UI_MODE_TYPE_NORMAL); + break; + + case ConfigDescription::UI_MODE_TYPE_DESK: + out_pb_config->set_ui_mode_type(pb::Configuration_UiModeType_UI_MODE_TYPE_DESK); + break; + + case ConfigDescription::UI_MODE_TYPE_CAR: + out_pb_config->set_ui_mode_type(pb::Configuration_UiModeType_UI_MODE_TYPE_CAR); + break; + + case ConfigDescription::UI_MODE_TYPE_TELEVISION: + out_pb_config->set_ui_mode_type(pb::Configuration_UiModeType_UI_MODE_TYPE_TELEVISION); + break; + + case ConfigDescription::UI_MODE_TYPE_APPLIANCE: + out_pb_config->set_ui_mode_type(pb::Configuration_UiModeType_UI_MODE_TYPE_APPLIANCE); + break; + + case ConfigDescription::UI_MODE_TYPE_WATCH: + out_pb_config->set_ui_mode_type(pb::Configuration_UiModeType_UI_MODE_TYPE_WATCH); + break; + + case ConfigDescription::UI_MODE_TYPE_VR_HEADSET: + out_pb_config->set_ui_mode_type(pb::Configuration_UiModeType_UI_MODE_TYPE_VRHEADSET); + break; + } + + switch (config.uiMode & ConfigDescription::MASK_UI_MODE_NIGHT) { + case ConfigDescription::UI_MODE_NIGHT_YES: + out_pb_config->set_ui_mode_night(pb::Configuration_UiModeNight_UI_MODE_NIGHT_NIGHT); + break; + + case ConfigDescription::UI_MODE_NIGHT_NO: + out_pb_config->set_ui_mode_night(pb::Configuration_UiModeNight_UI_MODE_NIGHT_NOTNIGHT); + break; + } + + out_pb_config->set_density(config.density); + + switch (config.touchscreen) { + case ConfigDescription::TOUCHSCREEN_NOTOUCH: + out_pb_config->set_touchscreen(pb::Configuration_Touchscreen_TOUCHSCREEN_NOTOUCH); + break; + + case ConfigDescription::TOUCHSCREEN_STYLUS: + out_pb_config->set_touchscreen(pb::Configuration_Touchscreen_TOUCHSCREEN_STYLUS); + break; + + case ConfigDescription::TOUCHSCREEN_FINGER: + out_pb_config->set_touchscreen(pb::Configuration_Touchscreen_TOUCHSCREEN_FINGER); + break; + } + + switch (config.inputFlags & ConfigDescription::MASK_KEYSHIDDEN) { + case ConfigDescription::KEYSHIDDEN_NO: + out_pb_config->set_keys_hidden(pb::Configuration_KeysHidden_KEYS_HIDDEN_KEYSEXPOSED); + break; + + case ConfigDescription::KEYSHIDDEN_YES: + out_pb_config->set_keys_hidden(pb::Configuration_KeysHidden_KEYS_HIDDEN_KEYSHIDDEN); + break; + + case ConfigDescription::KEYSHIDDEN_SOFT: + out_pb_config->set_keys_hidden(pb::Configuration_KeysHidden_KEYS_HIDDEN_KEYSSOFT); + break; + } + + switch (config.keyboard) { + case ConfigDescription::KEYBOARD_NOKEYS: + out_pb_config->set_keyboard(pb::Configuration_Keyboard_KEYBOARD_NOKEYS); + break; + + case ConfigDescription::KEYBOARD_QWERTY: + out_pb_config->set_keyboard(pb::Configuration_Keyboard_KEYBOARD_QWERTY); + break; + + case ConfigDescription::KEYBOARD_12KEY: + out_pb_config->set_keyboard(pb::Configuration_Keyboard_KEYBOARD_TWELVEKEY); + break; + } + + switch (config.inputFlags & ConfigDescription::MASK_NAVHIDDEN) { + case ConfigDescription::NAVHIDDEN_NO: + out_pb_config->set_nav_hidden(pb::Configuration_NavHidden_NAV_HIDDEN_NAVEXPOSED); + break; + + case ConfigDescription::NAVHIDDEN_YES: + out_pb_config->set_nav_hidden(pb::Configuration_NavHidden_NAV_HIDDEN_NAVHIDDEN); + break; + } + + switch (config.navigation) { + case ConfigDescription::NAVIGATION_NONAV: + out_pb_config->set_navigation(pb::Configuration_Navigation_NAVIGATION_NONAV); + break; + + case ConfigDescription::NAVIGATION_DPAD: + out_pb_config->set_navigation(pb::Configuration_Navigation_NAVIGATION_DPAD); + break; + + case ConfigDescription::NAVIGATION_TRACKBALL: + out_pb_config->set_navigation(pb::Configuration_Navigation_NAVIGATION_TRACKBALL); + break; + + case ConfigDescription::NAVIGATION_WHEEL: + out_pb_config->set_navigation(pb::Configuration_Navigation_NAVIGATION_WHEEL); + break; + } + + out_pb_config->set_sdk_version(config.sdkVersion); } -bool DeserializeConfigDescriptionFromPb(const pb::ConfigDescription& pb_config, +bool DeserializeConfigDescriptionFromPb(const pb::Configuration& pb_config, ConfigDescription* out_config) { - // a ConfigDescription must be at least 4 bytes to store the size. - if (pb_config.data().size() < 4) { - return false; + out_config->mcc = static_cast<uint16_t>(pb_config.mcc()); + out_config->mnc = static_cast<uint16_t>(pb_config.mnc()); + + if (!pb_config.locale().empty()) { + LocaleValue lv; + if (!lv.InitFromBcp47Tag(pb_config.locale())) { + return false; + } + lv.WriteTo(out_config); + } + + switch (pb_config.layout_direction()) { + case pb::Configuration_LayoutDirection_LAYOUT_DIRECTION_LTR: + out_config->screenLayout = (out_config->screenLayout & ~ConfigDescription::MASK_LAYOUTDIR) | + ConfigDescription::LAYOUTDIR_LTR; + break; + + case pb::Configuration_LayoutDirection_LAYOUT_DIRECTION_RTL: + out_config->screenLayout = (out_config->screenLayout & ~ConfigDescription::MASK_LAYOUTDIR) | + ConfigDescription::LAYOUTDIR_RTL; + break; + + default: + break; } - const android::ResTable_config* config; - if (pb_config.data().size() > sizeof(*config)) { - return false; + out_config->smallestScreenWidthDp = static_cast<uint16_t>(pb_config.smallest_screen_width_dp()); + out_config->screenWidthDp = static_cast<uint16_t>(pb_config.screen_width_dp()); + out_config->screenHeightDp = static_cast<uint16_t>(pb_config.screen_height_dp()); + + switch (pb_config.screen_layout_size()) { + case pb::Configuration_ScreenLayoutSize_SCREEN_LAYOUT_SIZE_SMALL: + out_config->screenLayout = (out_config->screenLayout & ~ConfigDescription::MASK_SCREENSIZE) | + ConfigDescription::SCREENSIZE_SMALL; + break; + + case pb::Configuration_ScreenLayoutSize_SCREEN_LAYOUT_SIZE_NORMAL: + out_config->screenLayout = (out_config->screenLayout & ~ConfigDescription::MASK_SCREENSIZE) | + ConfigDescription::SCREENSIZE_NORMAL; + break; + + case pb::Configuration_ScreenLayoutSize_SCREEN_LAYOUT_SIZE_LARGE: + out_config->screenLayout = (out_config->screenLayout & ~ConfigDescription::MASK_SCREENSIZE) | + ConfigDescription::SCREENSIZE_LARGE; + break; + + case pb::Configuration_ScreenLayoutSize_SCREEN_LAYOUT_SIZE_XLARGE: + out_config->screenLayout = (out_config->screenLayout & ~ConfigDescription::MASK_SCREENSIZE) | + ConfigDescription::SCREENSIZE_XLARGE; + break; + + default: + break; + } + + switch (pb_config.screen_layout_long()) { + case pb::Configuration_ScreenLayoutLong_SCREEN_LAYOUT_LONG_LONG: + out_config->screenLayout = (out_config->screenLayout & ~ConfigDescription::MASK_SCREENLONG) | + ConfigDescription::SCREENLONG_YES; + break; + + case pb::Configuration_ScreenLayoutLong_SCREEN_LAYOUT_LONG_NOTLONG: + out_config->screenLayout = (out_config->screenLayout & ~ConfigDescription::MASK_SCREENLONG) | + ConfigDescription::SCREENLONG_NO; + break; + + default: + break; + } + + switch (pb_config.screen_round()) { + case pb::Configuration_ScreenRound_SCREEN_ROUND_ROUND: + out_config->screenLayout2 = + (out_config->screenLayout2 & ~ConfigDescription::MASK_SCREENROUND) | + ConfigDescription::SCREENROUND_YES; + break; + + case pb::Configuration_ScreenRound_SCREEN_ROUND_NOTROUND: + out_config->screenLayout2 = + (out_config->screenLayout2 & ~ConfigDescription::MASK_SCREENROUND) | + ConfigDescription::SCREENROUND_NO; + break; + + default: + break; + } + + switch (pb_config.wide_color_gamut()) { + case pb::Configuration_WideColorGamut_WIDE_COLOR_GAMUT_WIDECG: + out_config->colorMode = (out_config->colorMode & ~ConfigDescription::MASK_WIDE_COLOR_GAMUT) | + ConfigDescription::WIDE_COLOR_GAMUT_YES; + break; + + case pb::Configuration_WideColorGamut_WIDE_COLOR_GAMUT_NOWIDECG: + out_config->colorMode = (out_config->colorMode & ~ConfigDescription::MASK_WIDE_COLOR_GAMUT) | + ConfigDescription::WIDE_COLOR_GAMUT_NO; + break; + + default: + break; + } + + switch (pb_config.hdr()) { + case pb::Configuration_Hdr_HDR_HIGHDR: + out_config->colorMode = + (out_config->colorMode & ~ConfigDescription::MASK_HDR) | ConfigDescription::HDR_YES; + break; + + case pb::Configuration_Hdr_HDR_LOWDR: + out_config->colorMode = + (out_config->colorMode & ~ConfigDescription::MASK_HDR) | ConfigDescription::HDR_NO; + break; + + default: + break; + } + + switch (pb_config.orientation()) { + case pb::Configuration_Orientation_ORIENTATION_PORT: + out_config->orientation = ConfigDescription::ORIENTATION_PORT; + break; + + case pb::Configuration_Orientation_ORIENTATION_LAND: + out_config->orientation = ConfigDescription::ORIENTATION_LAND; + break; + + case pb::Configuration_Orientation_ORIENTATION_SQUARE: + out_config->orientation = ConfigDescription::ORIENTATION_SQUARE; + break; + + default: + break; + } + + switch (pb_config.ui_mode_type()) { + case pb::Configuration_UiModeType_UI_MODE_TYPE_NORMAL: + out_config->uiMode = (out_config->uiMode & ~ConfigDescription::MASK_UI_MODE_TYPE) | + ConfigDescription::UI_MODE_TYPE_NORMAL; + break; + + case pb::Configuration_UiModeType_UI_MODE_TYPE_DESK: + out_config->uiMode = (out_config->uiMode & ~ConfigDescription::MASK_UI_MODE_TYPE) | + ConfigDescription::UI_MODE_TYPE_DESK; + break; + + case pb::Configuration_UiModeType_UI_MODE_TYPE_CAR: + out_config->uiMode = (out_config->uiMode & ~ConfigDescription::MASK_UI_MODE_TYPE) | + ConfigDescription::UI_MODE_TYPE_CAR; + break; + + case pb::Configuration_UiModeType_UI_MODE_TYPE_TELEVISION: + out_config->uiMode = (out_config->uiMode & ~ConfigDescription::MASK_UI_MODE_TYPE) | + ConfigDescription::UI_MODE_TYPE_TELEVISION; + break; + + case pb::Configuration_UiModeType_UI_MODE_TYPE_APPLIANCE: + out_config->uiMode = (out_config->uiMode & ~ConfigDescription::MASK_UI_MODE_TYPE) | + ConfigDescription::UI_MODE_TYPE_APPLIANCE; + break; + + case pb::Configuration_UiModeType_UI_MODE_TYPE_WATCH: + out_config->uiMode = (out_config->uiMode & ~ConfigDescription::MASK_UI_MODE_TYPE) | + ConfigDescription::UI_MODE_TYPE_WATCH; + break; + + case pb::Configuration_UiModeType_UI_MODE_TYPE_VRHEADSET: + out_config->uiMode = (out_config->uiMode & ~ConfigDescription::MASK_UI_MODE_TYPE) | + ConfigDescription::UI_MODE_TYPE_VR_HEADSET; + break; + + default: + break; + } + + switch (pb_config.ui_mode_night()) { + case pb::Configuration_UiModeNight_UI_MODE_NIGHT_NIGHT: + out_config->uiMode = (out_config->uiMode & ~ConfigDescription::MASK_UI_MODE_NIGHT) | + ConfigDescription::UI_MODE_NIGHT_YES; + break; + + case pb::Configuration_UiModeNight_UI_MODE_NIGHT_NOTNIGHT: + out_config->uiMode = (out_config->uiMode & ~ConfigDescription::MASK_UI_MODE_NIGHT) | + ConfigDescription::UI_MODE_NIGHT_NO; + break; + + default: + break; + } + + out_config->density = static_cast<uint16_t>(pb_config.density()); + + switch (pb_config.touchscreen()) { + case pb::Configuration_Touchscreen_TOUCHSCREEN_NOTOUCH: + out_config->touchscreen = ConfigDescription::TOUCHSCREEN_NOTOUCH; + break; + + case pb::Configuration_Touchscreen_TOUCHSCREEN_STYLUS: + out_config->touchscreen = ConfigDescription::TOUCHSCREEN_STYLUS; + break; + + case pb::Configuration_Touchscreen_TOUCHSCREEN_FINGER: + out_config->touchscreen = ConfigDescription::TOUCHSCREEN_FINGER; + break; + + default: + break; + } + + switch (pb_config.keys_hidden()) { + case pb::Configuration_KeysHidden_KEYS_HIDDEN_KEYSEXPOSED: + out_config->inputFlags = (out_config->inputFlags & ~ConfigDescription::MASK_KEYSHIDDEN) | + ConfigDescription::KEYSHIDDEN_NO; + break; + + case pb::Configuration_KeysHidden_KEYS_HIDDEN_KEYSHIDDEN: + out_config->inputFlags = (out_config->inputFlags & ~ConfigDescription::MASK_KEYSHIDDEN) | + ConfigDescription::KEYSHIDDEN_YES; + break; + + case pb::Configuration_KeysHidden_KEYS_HIDDEN_KEYSSOFT: + out_config->inputFlags = (out_config->inputFlags & ~ConfigDescription::MASK_KEYSHIDDEN) | + ConfigDescription::KEYSHIDDEN_SOFT; + break; + + default: + break; + } + + switch (pb_config.keyboard()) { + case pb::Configuration_Keyboard_KEYBOARD_NOKEYS: + out_config->keyboard = ConfigDescription::KEYBOARD_NOKEYS; + break; + + case pb::Configuration_Keyboard_KEYBOARD_QWERTY: + out_config->keyboard = ConfigDescription::KEYBOARD_QWERTY; + break; + + case pb::Configuration_Keyboard_KEYBOARD_TWELVEKEY: + out_config->keyboard = ConfigDescription::KEYBOARD_12KEY; + break; + + default: + break; + } + + switch (pb_config.nav_hidden()) { + case pb::Configuration_NavHidden_NAV_HIDDEN_NAVEXPOSED: + out_config->inputFlags = (out_config->inputFlags & ~ConfigDescription::MASK_NAVHIDDEN) | + ConfigDescription::NAVHIDDEN_NO; + break; + + case pb::Configuration_NavHidden_NAV_HIDDEN_NAVHIDDEN: + out_config->inputFlags = (out_config->inputFlags & ~ConfigDescription::MASK_NAVHIDDEN) | + ConfigDescription::NAVHIDDEN_YES; + break; + + default: + break; + } + + switch (pb_config.navigation()) { + case pb::Configuration_Navigation_NAVIGATION_NONAV: + out_config->navigation = ConfigDescription::NAVIGATION_NONAV; + break; + + case pb::Configuration_Navigation_NAVIGATION_DPAD: + out_config->navigation = ConfigDescription::NAVIGATION_DPAD; + break; + + case pb::Configuration_Navigation_NAVIGATION_TRACKBALL: + out_config->navigation = ConfigDescription::NAVIGATION_TRACKBALL; + break; + + case pb::Configuration_Navigation_NAVIGATION_WHEEL: + out_config->navigation = ConfigDescription::NAVIGATION_WHEEL; + break; + + default: + break; } - config = reinterpret_cast<const android::ResTable_config*>(pb_config.data().data()); - out_config->copyFromDtoH(*config); + out_config->screenWidth = static_cast<uint16_t>(pb_config.screen_width()); + out_config->screenHeight = static_cast<uint16_t>(pb_config.screen_height()); + out_config->sdkVersion = static_cast<uint16_t>(pb_config.sdk_version()); return true; } diff --git a/tools/aapt2/proto/ProtoHelpers.h b/tools/aapt2/proto/ProtoHelpers.h index 2f268f44752c..714a2b27bf7f 100644 --- a/tools/aapt2/proto/ProtoHelpers.h +++ b/tools/aapt2/proto/ProtoHelpers.h @@ -20,11 +20,12 @@ #include "androidfw/ResourceTypes.h" #include "ConfigDescription.h" +#include "Configuration.pb.h" #include "ResourceTable.h" -#include "Source.h" -#include "StringPool.h" #include "Resources.pb.h" #include "ResourcesInternal.pb.h" +#include "Source.h" +#include "StringPool.h" namespace aapt { @@ -39,9 +40,9 @@ pb::SymbolStatus_Visibility SerializeVisibilityToPb(SymbolState state); SymbolState DeserializeVisibilityFromPb(pb::SymbolStatus_Visibility pb_visibility); -void SerializeConfig(const ConfigDescription& config, pb::ConfigDescription* out_pb_config); +void SerializeConfig(const ConfigDescription& config, pb::Configuration* out_pb_config); -bool DeserializeConfigDescriptionFromPb(const pb::ConfigDescription& pb_config, +bool DeserializeConfigDescriptionFromPb(const pb::Configuration& pb_config, ConfigDescription* out_config); pb::Reference_Type SerializeReferenceTypeToPb(Reference::Type type); diff --git a/tools/aapt2/proto/TableProtoDeserializer.cpp b/tools/aapt2/proto/TableProtoDeserializer.cpp index f4a2b1e19331..4a88d61ef84c 100644 --- a/tools/aapt2/proto/TableProtoDeserializer.cpp +++ b/tools/aapt2/proto/TableProtoDeserializer.cpp @@ -123,7 +123,7 @@ class PackagePbDeserializer { } for (const pb::ConfigValue& pb_config_value : pb_entry.config_value()) { - const pb::ConfigDescription& pb_config = pb_config_value.config(); + const pb::Configuration& pb_config = pb_config_value.config(); ConfigDescription config; if (!DeserializeConfigDescriptionFromPb(pb_config, &config)) { @@ -395,14 +395,16 @@ std::unique_ptr<ResourceFile> DeserializeCompiledFileFromPb( } file->name = name_ref.ToResourceName(); file->source.path = pb_file.source_path(); - DeserializeConfigDescriptionFromPb(pb_file.config(), &file->config); + if (!DeserializeConfigDescriptionFromPb(pb_file.config(), &file->config)) { + diag->Error(DiagMessage(source) << "invalid resource configuration in compiled file header"); + return {}; + } for (const pb::internal::CompiledFile_Symbol& pb_symbol : pb_file.exported_symbol()) { // Need to create an lvalue here so that nameRef can point to something real. if (!ResourceUtils::ParseResourceName(pb_symbol.resource_name(), &name_ref)) { diag->Error(DiagMessage(source) - << "invalid resource name for exported symbol in " - "compiled file header: " + << "invalid resource name for exported symbol in compiled file header: " << pb_file.resource_name()); return {}; } diff --git a/tools/aapt2/proto/TableProtoSerializer.cpp b/tools/aapt2/proto/TableProtoSerializer.cpp index 981b72ab7221..3d5407c137b1 100644 --- a/tools/aapt2/proto/TableProtoSerializer.cpp +++ b/tools/aapt2/proto/TableProtoSerializer.cpp @@ -282,10 +282,10 @@ CompiledFileOutputStream::CompiledFileOutputStream(ZeroCopyOutputStream* out) : } void CompiledFileOutputStream::EnsureAlignedWrite() { - const int padding = out_.ByteCount() % 4; - if (padding > 0) { + const int overflow = out_.ByteCount() % 4; + if (overflow > 0) { uint32_t zero = 0u; - out_.WriteRaw(&zero, padding); + out_.WriteRaw(&zero, 4 - overflow); } } @@ -322,10 +322,10 @@ CompiledFileInputStream::CompiledFileInputStream(const void* data, size_t size) : in_(static_cast<const uint8_t*>(data), size) {} void CompiledFileInputStream::EnsureAlignedRead() { - const int padding = in_.CurrentPosition() % 4; - if (padding > 0) { + const int overflow = in_.CurrentPosition() % 4; + if (overflow > 0) { // Reads are always 4 byte aligned. - in_.Skip(padding); + in_.Skip(4 - overflow); } } diff --git a/tools/aapt2/proto/TableProtoSerializer_test.cpp b/tools/aapt2/proto/TableProtoSerializer_test.cpp index 80608b3d9c05..8f6414c68a43 100644 --- a/tools/aapt2/proto/TableProtoSerializer_test.cpp +++ b/tools/aapt2/proto/TableProtoSerializer_test.cpp @@ -19,6 +19,7 @@ #include "ResourceTable.h" #include "test/Test.h" +using ::android::StringPiece; using ::google::protobuf::io::StringOutputStream; using ::testing::Eq; using ::testing::NotNull; @@ -239,4 +240,97 @@ TEST(TableProtoSerializer, DeserializeCorruptHeaderSafely) { EXPECT_FALSE(in_file_stream.ReadDataMetaData(&offset, &len)); } +static void ExpectConfigSerializes(const StringPiece& config_str) { + const ConfigDescription expected_config = test::ParseConfigOrDie(config_str); + pb::Configuration pb_config; + SerializeConfig(expected_config, &pb_config); + + ConfigDescription actual_config; + ASSERT_TRUE(DeserializeConfigDescriptionFromPb(pb_config, &actual_config)); + EXPECT_EQ(expected_config, actual_config); +} + +TEST(TableProtoSerializer, SerializeDeserializeConfiguration) { + ExpectConfigSerializes(""); + + ExpectConfigSerializes("mcc123"); + + ExpectConfigSerializes("mnc123"); + + ExpectConfigSerializes("en"); + ExpectConfigSerializes("en-rGB"); + ExpectConfigSerializes("b+en+GB"); + + ExpectConfigSerializes("ldltr"); + ExpectConfigSerializes("ldrtl"); + + ExpectConfigSerializes("sw3600dp"); + + ExpectConfigSerializes("w300dp"); + + ExpectConfigSerializes("h400dp"); + + ExpectConfigSerializes("small"); + ExpectConfigSerializes("normal"); + ExpectConfigSerializes("large"); + ExpectConfigSerializes("xlarge"); + + ExpectConfigSerializes("long"); + ExpectConfigSerializes("notlong"); + + ExpectConfigSerializes("round"); + ExpectConfigSerializes("notround"); + + ExpectConfigSerializes("widecg"); + ExpectConfigSerializes("nowidecg"); + + ExpectConfigSerializes("highdr"); + ExpectConfigSerializes("lowdr"); + + ExpectConfigSerializes("port"); + ExpectConfigSerializes("land"); + ExpectConfigSerializes("square"); + + ExpectConfigSerializes("desk"); + ExpectConfigSerializes("car"); + ExpectConfigSerializes("television"); + ExpectConfigSerializes("appliance"); + ExpectConfigSerializes("watch"); + ExpectConfigSerializes("vrheadset"); + + ExpectConfigSerializes("night"); + ExpectConfigSerializes("notnight"); + + ExpectConfigSerializes("300dpi"); + ExpectConfigSerializes("hdpi"); + + ExpectConfigSerializes("notouch"); + ExpectConfigSerializes("stylus"); + ExpectConfigSerializes("finger"); + + ExpectConfigSerializes("keysexposed"); + ExpectConfigSerializes("keyshidden"); + ExpectConfigSerializes("keyssoft"); + + ExpectConfigSerializes("nokeys"); + ExpectConfigSerializes("qwerty"); + ExpectConfigSerializes("12key"); + + ExpectConfigSerializes("navhidden"); + ExpectConfigSerializes("navexposed"); + + ExpectConfigSerializes("nonav"); + ExpectConfigSerializes("dpad"); + ExpectConfigSerializes("trackball"); + ExpectConfigSerializes("wheel"); + + ExpectConfigSerializes("300x200"); + + ExpectConfigSerializes("v8"); + + ExpectConfigSerializes( + "mcc123-mnc456-b+en+GB-ldltr-sw300dp-w300dp-h400dp-large-long-round-widecg-highdr-land-car-" + "night-xhdpi-stylus-keysexposed-qwerty-navhidden-dpad-300x200-v23"); +} + } // namespace aapt |