Adam Lesinski | 6a00817 | 2016-02-02 17:02:58 -0800 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2016 The Android Open Source Project |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | |
Adam Lesinski | 6a00817 | 2016-02-02 17:02:58 -0800 | [diff] [blame] | 17 | #include "filter/ConfigFilter.h" |
| 18 | |
Mårten Kongstad | 5c541f6 | 2018-06-20 08:46:41 +0200 | [diff] [blame] | 19 | #include "androidfw/ConfigDescription.h" |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 20 | #include "androidfw/ResourceTypes.h" |
| 21 | |
Mårten Kongstad | 5c541f6 | 2018-06-20 08:46:41 +0200 | [diff] [blame] | 22 | using ::android::ConfigDescription; |
Adam Lesinski | 6a00817 | 2016-02-02 17:02:58 -0800 | [diff] [blame] | 23 | |
| 24 | namespace aapt { |
| 25 | |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 26 | void AxisConfigFilter::AddConfig(ConfigDescription config) { |
| 27 | uint32_t diff_mask = ConfigDescription::DefaultConfig().diff(config); |
Adam Lesinski | 6a00817 | 2016-02-02 17:02:58 -0800 | [diff] [blame] | 28 | |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 29 | // Ignore the version |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 30 | diff_mask &= ~android::ResTable_config::CONFIG_VERSION; |
Adam Lesinski | 6a00817 | 2016-02-02 17:02:58 -0800 | [diff] [blame] | 31 | |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 32 | // Ignore any densities. Those are best handled in --preferred-density |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 33 | if ((diff_mask & android::ResTable_config::CONFIG_DENSITY) != 0) { |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 34 | config.density = 0; |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 35 | diff_mask &= ~android::ResTable_config::CONFIG_DENSITY; |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 36 | } |
Adam Lesinski | 6a00817 | 2016-02-02 17:02:58 -0800 | [diff] [blame] | 37 | |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 38 | configs_.insert(std::make_pair(config, diff_mask)); |
| 39 | config_mask_ |= diff_mask; |
Adam Lesinski | 6a00817 | 2016-02-02 17:02:58 -0800 | [diff] [blame] | 40 | } |
| 41 | |
Adam Lesinski | 13308bc | 2017-05-16 15:26:54 -0700 | [diff] [blame] | 42 | // Returns true if the locale script of the config should be considered matching |
| 43 | // the locale script of entry. |
| 44 | // |
| 45 | // If both the scripts are empty, the scripts are considered matching for |
| 46 | // backward compatibility reasons. |
| 47 | // |
| 48 | // If only one script is empty, we try to compute it based on the provided |
| 49 | // language and country. If we could not compute it, we assume it's either a |
| 50 | // new language we don't know about, or a private use language. We return true |
| 51 | // since we don't know any better and they might as well be a match. |
| 52 | // |
| 53 | // Finally, when we have two scripts (one of which could be computed), we return |
| 54 | // true if and only if they are an exact match. |
| 55 | static bool ScriptsMatch(const ConfigDescription& config, const ConfigDescription& entry) { |
| 56 | const char* config_script = config.localeScript; |
| 57 | const char* entry_script = entry.localeScript; |
| 58 | if (config_script[0] == '\0' && entry_script[0] == '\0') { |
| 59 | return true; // both scripts are empty. We match for backward compatibility reasons. |
| 60 | } |
| 61 | |
| 62 | char script_buffer[sizeof(config.localeScript)]; |
| 63 | if (config_script[0] == '\0') { |
| 64 | android::localeDataComputeScript(script_buffer, config.language, config.country); |
| 65 | if (script_buffer[0] == '\0') { // We can't compute the script, so we match. |
| 66 | return true; |
| 67 | } |
| 68 | config_script = script_buffer; |
| 69 | } else if (entry_script[0] == '\0') { |
| 70 | android::localeDataComputeScript(script_buffer, entry.language, entry.country); |
| 71 | if (script_buffer[0] == '\0') { // We can't compute the script, so we match. |
| 72 | return true; |
| 73 | } |
| 74 | entry_script = script_buffer; |
| 75 | } |
| 76 | return memcmp(config_script, entry_script, sizeof(config.localeScript)) == 0; |
| 77 | } |
| 78 | |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 79 | bool AxisConfigFilter::Match(const ConfigDescription& config) const { |
| 80 | const uint32_t mask = ConfigDescription::DefaultConfig().diff(config); |
| 81 | if ((config_mask_ & mask) == 0) { |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 82 | // The two configurations don't have any common axis. |
| 83 | return true; |
| 84 | } |
Adam Lesinski | 6a00817 | 2016-02-02 17:02:58 -0800 | [diff] [blame] | 85 | |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 86 | uint32_t matched_axis = 0; |
| 87 | for (const auto& entry : configs_) { |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 88 | const ConfigDescription& target = entry.first; |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 89 | const uint32_t diff_mask = entry.second; |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 90 | uint32_t diff = target.diff(config); |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 91 | if ((diff & diff_mask) == 0) { |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 92 | // Mark the axis that was matched. |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 93 | matched_axis |= diff_mask; |
| 94 | } else if ((diff & diff_mask) == android::ResTable_config::CONFIG_LOCALE) { |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 95 | // If the locales differ, but the languages are the same and |
| 96 | // the locale we are matching only has a language specified, |
| 97 | // we match. |
Adam Lesinski | 13308bc | 2017-05-16 15:26:54 -0700 | [diff] [blame] | 98 | // |
| 99 | // Exception: we won't match if a script is specified for at least |
| 100 | // one of the locales and it's different from the other locale's |
| 101 | // script. (We will compute the other script if at least one of the |
| 102 | // scripts were explicitly set. In cases we can't compute an script, |
| 103 | // we match.) |
| 104 | if (config.language[0] != '\0' && config.country[0] == '\0' && |
| 105 | config.localeVariant[0] == '\0' && config.language[0] == entry.first.language[0] && |
| 106 | config.language[1] == entry.first.language[1] && ScriptsMatch(config, entry.first)) { |
| 107 | matched_axis |= android::ResTable_config::CONFIG_LOCALE; |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 108 | } |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 109 | } else if ((diff & diff_mask) == |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 110 | android::ResTable_config::CONFIG_SMALLEST_SCREEN_SIZE) { |
| 111 | // Special case if the smallest screen width doesn't match. We check that |
| 112 | // the |
| 113 | // config being matched has a smaller screen width than the filter |
| 114 | // specified. |
| 115 | if (config.smallestScreenWidthDp != 0 && |
| 116 | config.smallestScreenWidthDp < target.smallestScreenWidthDp) { |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 117 | matched_axis |= android::ResTable_config::CONFIG_SMALLEST_SCREEN_SIZE; |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 118 | } |
Adam Lesinski | 6a00817 | 2016-02-02 17:02:58 -0800 | [diff] [blame] | 119 | } |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 120 | } |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 121 | return matched_axis == (config_mask_ & mask); |
Adam Lesinski | 6a00817 | 2016-02-02 17:02:58 -0800 | [diff] [blame] | 122 | } |
| 123 | |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 124 | } // namespace aapt |