diff options
18 files changed, 247 insertions, 22 deletions
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index c012ff34bfab..4e7734c5471d 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -19039,6 +19039,14 @@ public final class Settings { public static final int BATTERY_SAVER_MODE_CUSTOM = 4; /** + Whether 1P apps vote for enabling data during different modes, + i.e. BTM, BBSM + * @hide + */ + @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE) + public static final String CONNECTIVITY_KEEP_DATA_ON = "wear_connectivity_keep_data_on"; + + /** * The maximum ambient mode duration when an activity is allowed to auto resume. * @hide */ diff --git a/core/res/res/xml/sms_short_codes.xml b/core/res/res/xml/sms_short_codes.xml index 709646b00e5c..3a2e50aa06e8 100644 --- a/core/res/res/xml/sms_short_codes.xml +++ b/core/res/res/xml/sms_short_codes.xml @@ -34,7 +34,7 @@ http://smscoin.net/software/engine/WordPress/Paid+SMS-registration/ --> <!-- Arab Emirates --> - <shortcode country="ae" pattern="\\d{1,5}" free="1017|1355|3214|6253" /> + <shortcode country="ae" pattern="\\d{1,5}" free="1017|1355|3214" /> <!-- Albania: 5 digits, known short codes listed --> <shortcode country="al" pattern="\\d{5}" premium="15191|55[56]00" /> @@ -155,7 +155,7 @@ <shortcode country="ie" pattern="\\d{5}" premium="5[3-9]\\d{3}" free="50\\d{3}|116\\d{3}" standard="5[12]\\d{3}" /> <!-- Israel: 4 digits, known premium codes listed --> - <shortcode country="il" pattern="\\d{1,5}" premium="4422|4545" free="37477" /> + <shortcode country="il" pattern="\\d{4}" premium="4422|4545" /> <!-- Italy: 5 digits (premium=41xxx,42xxx), plus EU: https://www.itu.int/dms_pub/itu-t/oth/02/02/T020200006B0001PDFE.pdf --> @@ -198,9 +198,6 @@ <!-- Malaysia: 5 digits: http://www.skmm.gov.my/attachment/Consumer_Regulation/Mobile_Content_Services_FAQs.pdf --> <shortcode country="my" pattern="\\d{5}" premium="32298|33776" free="22099|28288|66668" /> - <!-- Namibia: 5 digits --> - <shortcode country="na" pattern="\\d{1,5}" free="40005" /> - <!-- The Netherlands, 4 digits, known premium codes listed, plus EU --> <shortcode country="nl" pattern="\\d{4}" premium="4466|5040" free="116\\d{3}|2223|6225|2223|1662" /> diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java index 7e8fe7e09d74..d9fe7335dbcb 100644 --- a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java +++ b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java @@ -445,5 +445,6 @@ public class GlobalSettingsValidators { VALIDATORS.put(Global.Wearable.PHONE_SWITCHING_SUPPORTED, BOOLEAN_VALIDATOR); VALIDATORS.put(Global.Wearable.WEAR_LAUNCHER_UI_MODE, ANY_INTEGER_VALIDATOR); VALIDATORS.put(Global.Wearable.WEAR_POWER_ANOMALY_SERVICE_ENABLED, BOOLEAN_VALIDATOR); + VALIDATORS.put(Global.Wearable.CONNECTIVITY_KEEP_DATA_ON, BOOLEAN_VALIDATOR); } } diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java index 2e174e267bde..c0d83c4c08d5 100644 --- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java +++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java @@ -686,7 +686,8 @@ public class SettingsBackupTest { Settings.Global.Wearable.PHONE_SWITCHING_SUPPORTED, Settings.Global.Wearable.WEAR_MEDIA_CONTROLS_PACKAGE, Settings.Global.Wearable.WEAR_MEDIA_SESSIONS_PACKAGE, - Settings.Global.Wearable.WEAR_POWER_ANOMALY_SERVICE_ENABLED); + Settings.Global.Wearable.WEAR_POWER_ANOMALY_SERVICE_ENABLED, + Settings.Global.Wearable.CONNECTIVITY_KEEP_DATA_ON); private static final Set<String> BACKUP_DENY_LIST_SECURE_SETTINGS = newHashSet( diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinBouncer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinBouncer.kt index fb50f69f7d9b..243751fafe5d 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinBouncer.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinBouncer.kt @@ -76,6 +76,8 @@ fun PinPad( val backspaceButtonAppearance by viewModel.backspaceButtonAppearance.collectAsState() val confirmButtonAppearance by viewModel.confirmButtonAppearance.collectAsState() val animateFailure: Boolean by viewModel.animateFailure.collectAsState() + val isDigitButtonAnimationEnabled: Boolean by + viewModel.isDigitButtonAnimationEnabled.collectAsState() val buttonScaleAnimatables = remember { List(12) { Animatable(1f) } } LaunchedEffect(animateFailure) { @@ -94,10 +96,11 @@ fun PinPad( ) { repeat(9) { index -> DigitButton( - index + 1, - isInputEnabled, - viewModel::onPinButtonClicked, - buttonScaleAnimatables[index]::value, + digit = index + 1, + isInputEnabled = isInputEnabled, + onClicked = viewModel::onPinButtonClicked, + scaling = buttonScaleAnimatables[index]::value, + isAnimationEnabled = isDigitButtonAnimationEnabled, ) } @@ -116,10 +119,11 @@ fun PinPad( ) DigitButton( - 0, - isInputEnabled, - viewModel::onPinButtonClicked, - buttonScaleAnimatables[10]::value, + digit = 0, + isInputEnabled = isInputEnabled, + onClicked = viewModel::onPinButtonClicked, + scaling = buttonScaleAnimatables[10]::value, + isAnimationEnabled = isDigitButtonAnimationEnabled, ) ActionButton( @@ -143,15 +147,17 @@ private fun DigitButton( isInputEnabled: Boolean, onClicked: (Int) -> Unit, scaling: () -> Float, + isAnimationEnabled: Boolean, ) { PinPadButton( onClicked = { onClicked(digit) }, isEnabled = isInputEnabled, backgroundColor = MaterialTheme.colorScheme.surfaceVariant, foregroundColor = MaterialTheme.colorScheme.onSurfaceVariant, + isAnimationEnabled = isAnimationEnabled, modifier = Modifier.graphicsLayer { - val scale = scaling() + val scale = if (isAnimationEnabled) scaling() else 1f scaleX = scale scaleY = scale } @@ -195,6 +201,7 @@ private fun ActionButton( isEnabled = isInputEnabled && !isHidden, backgroundColor = backgroundColor, foregroundColor = foregroundColor, + isAnimationEnabled = true, modifier = Modifier.graphicsLayer { alpha = hiddenAlpha @@ -216,6 +223,7 @@ private fun PinPadButton( isEnabled: Boolean, backgroundColor: Color, foregroundColor: Color, + isAnimationEnabled: Boolean, modifier: Modifier = Modifier, onLongPressed: (() -> Unit)? = null, content: @Composable (contentColor: () -> Color) -> Unit, @@ -243,7 +251,7 @@ private fun PinPadButton( val cornerRadius: Dp by animateDpAsState( - if (isPressed) 24.dp else pinButtonSize / 2, + if (isAnimationEnabled && isPressed) 24.dp else pinButtonSize / 2, label = "PinButton round corners", animationSpec = tween(animDurationMillis, easing = animEasing) ) @@ -251,7 +259,7 @@ private fun PinPadButton( val containerColor: Color by animateColorAsState( when { - isPressed -> MaterialTheme.colorScheme.primary + isAnimationEnabled && isPressed -> MaterialTheme.colorScheme.primary else -> backgroundColor }, label = "Pin button container color", @@ -260,7 +268,7 @@ private fun PinPadButton( val contentColor = animateColorAsState( when { - isPressed -> MaterialTheme.colorScheme.onPrimary + isAnimationEnabled && isPressed -> MaterialTheme.colorScheme.onPrimary else -> foregroundColor }, label = "Pin button container color", diff --git a/packages/SystemUI/src/com/android/systemui/authentication/data/repository/AuthenticationRepository.kt b/packages/SystemUI/src/com/android/systemui/authentication/data/repository/AuthenticationRepository.kt index ee3a55f51679..7769dd9dc9ab 100644 --- a/packages/SystemUI/src/com/android/systemui/authentication/data/repository/AuthenticationRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/authentication/data/repository/AuthenticationRepository.kt @@ -108,6 +108,9 @@ interface AuthenticationRepository { /** The minimal length of a pattern. */ val minPatternLength: Int + /** Whether the "enhanced PIN privacy" setting is enabled for the current user. */ + val isPinEnhancedPrivacyEnabled: StateFlow<Boolean> + /** * Returns the currently-configured authentication method. This determines how the * authentication challenge needs to be completed in order to unlock an otherwise locked device. @@ -212,6 +215,12 @@ constructor( override val minPatternLength: Int = LockPatternUtils.MIN_LOCK_PATTERN_SIZE + override val isPinEnhancedPrivacyEnabled: StateFlow<Boolean> = + refreshingFlow( + initialValue = true, + getFreshValue = { userId -> lockPatternUtils.isPinEnhancedPrivacyEnabled(userId) }, + ) + override suspend fun getAuthenticationMethod(): AuthenticationMethodModel { return withContext(backgroundDispatcher) { blockingAuthenticationMethodInternal(userRepository.selectedUserId) diff --git a/packages/SystemUI/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractor.kt b/packages/SystemUI/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractor.kt index 1ede5301e751..5eefbf5353d3 100644 --- a/packages/SystemUI/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractor.kt @@ -145,6 +145,9 @@ constructor( val authenticationChallengeResult: SharedFlow<Boolean> = repository.authenticationChallengeResult + /** Whether the "enhanced PIN privacy" setting is enabled for the current user. */ + val isPinEnhancedPrivacyEnabled: StateFlow<Boolean> = repository.isPinEnhancedPrivacyEnabled + private var throttlingCountdownJob: Job? = null init { diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractor.kt b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractor.kt index 4e1cddc63530..ff36839460be 100644 --- a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractor.kt @@ -92,6 +92,10 @@ constructor( /** Whether the pattern should be visible for the currently-selected user. */ val isPatternVisible: StateFlow<Boolean> = authenticationInteractor.isPatternVisible + /** Whether the "enhanced PIN privacy" setting is enabled for the current user. */ + val isPinEnhancedPrivacyEnabled: StateFlow<Boolean> = + authenticationInteractor.isPinEnhancedPrivacyEnabled + /** Whether the user switcher should be displayed within the bouncer UI on large screens. */ val isUserSwitcherVisible: Boolean get() = repository.isUserSwitcherVisible diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModel.kt index 2ed0d5d2f6c1..b2b8049e3cff 100644 --- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModel.kt @@ -84,6 +84,19 @@ class PinBouncerViewModel( override val throttlingMessageId = R.string.kg_too_many_failed_pin_attempts_dialog_message + /** + * Whether the digit buttons should be animated when touched. Note that this doesn't affect the + * delete or enter buttons; those should always animate. + */ + val isDigitButtonAnimationEnabled: StateFlow<Boolean> = + interactor.isPinEnhancedPrivacyEnabled + .map { !it } + .stateIn( + scope = viewModelScope, + started = SharingStarted.WhileSubscribed(), + initialValue = !interactor.isPinEnhancedPrivacyEnabled.value, + ) + /** Notifies that the user clicked on a PIN button with the given digit value. */ fun onPinButtonClicked(input: Int) { val pinInput = mutablePinInput.value diff --git a/packages/SystemUI/tests/src/com/android/systemui/authentication/data/repository/AuthenticationRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/authentication/data/repository/AuthenticationRepositoryTest.kt index ae2ec2ca1fe9..87ab5b0d157f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/authentication/data/repository/AuthenticationRepositoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/authentication/data/repository/AuthenticationRepositoryTest.kt @@ -143,6 +143,23 @@ class AuthenticationRepositoryTest : SysuiTestCase() { assertThat(authenticationChallengeResults).isEqualTo(listOf(true, false, true)) } + @Test + fun isPinEnhancedPrivacyEnabled() = + testScope.runTest { + whenever(lockPatternUtils.isPinEnhancedPrivacyEnabled(USER_INFOS[0].id)) + .thenReturn(false) + whenever(lockPatternUtils.isPinEnhancedPrivacyEnabled(USER_INFOS[1].id)) + .thenReturn(true) + + val values by collectValues(underTest.isPinEnhancedPrivacyEnabled) + assertThat(values.first()).isTrue() + assertThat(values.last()).isFalse() + + userRepository.setSelectedUserInfo(USER_INFOS[1]) + assertThat(values.last()).isTrue() + + } + private fun setSecurityModeAndDispatchBroadcast( securityMode: KeyguardSecurityModel.SecurityMode, ) { diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt index 6da69519000c..7a9cb6cc18c2 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt @@ -354,6 +354,18 @@ class PinBouncerViewModelTest : SysuiTestCase() { assertThat(confirmButtonAppearance).isEqualTo(ActionButtonAppearance.Hidden) } + @Test + fun isDigitButtonAnimationEnabled() = + testScope.runTest { + val isAnimationEnabled by collectLastValue(underTest.isDigitButtonAnimationEnabled) + + utils.authenticationRepository.setPinEnhancedPrivacyEnabled(true) + assertThat(isAnimationEnabled).isFalse() + + utils.authenticationRepository.setPinEnhancedPrivacyEnabled(false) + assertThat(isAnimationEnabled).isTrue() + } + private fun TestScope.lockDeviceAndOpenPinBouncer() { utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin) utils.deviceEntryRepository.setUnlocked(false) diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/data/repository/FakeAuthenticationRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/data/repository/FakeAuthenticationRepository.kt index 6e9363b744ab..af1930ef143e 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/data/repository/FakeAuthenticationRepository.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/data/repository/FakeAuthenticationRepository.kt @@ -60,6 +60,10 @@ class FakeAuthenticationRepository( override val minPatternLength: Int = 4 + private val _isPinEnhancedPrivacyEnabled = MutableStateFlow(false) + override val isPinEnhancedPrivacyEnabled: StateFlow<Boolean> = + _isPinEnhancedPrivacyEnabled.asStateFlow() + private var failedAttemptCount = 0 private var throttlingEndTimestamp = 0L private var credentialOverride: List<Any>? = null @@ -138,6 +142,10 @@ class FakeAuthenticationRepository( } } + fun setPinEnhancedPrivacyEnabled(isEnabled: Boolean) { + _isPinEnhancedPrivacyEnabled.value = isEnabled + } + private fun getExpectedCredential(securityMode: SecurityMode): List<Any> { return when (val credentialType = getCurrentCredentialType(securityMode)) { LockPatternUtils.CREDENTIAL_TYPE_PIN -> credentialOverride ?: DEFAULT_PIN diff --git a/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp index 159c6fd9ef58..c638873873dc 100644 --- a/tools/aapt2/cmd/Link.cpp +++ b/tools/aapt2/cmd/Link.cpp @@ -2514,6 +2514,28 @@ int LinkCommand::Action(const std::vector<std::string>& args) { } } + // Parse the feature flag values. An argument that starts with '@' points to a file to read flag + // values from. + std::vector<std::string> all_feature_flags_args; + for (const std::string& arg : feature_flags_args_) { + if (util::StartsWith(arg, "@")) { + const std::string path = arg.substr(1, arg.size() - 1); + std::string error; + if (!file::AppendArgsFromFile(path, &all_feature_flags_args, &error)) { + context.GetDiagnostics()->Error(android::DiagMessage(path) << error); + return 1; + } + } else { + all_feature_flags_args.push_back(arg); + } + } + + for (const std::string& arg : all_feature_flags_args) { + if (ParseFeatureFlagsParameter(arg, context.GetDiagnostics(), &options_.feature_flag_values)) { + return 1; + } + } + if (context.GetPackageType() != PackageType::kStaticLib && stable_id_file_path_) { if (!LoadStableIdMap(context.GetDiagnostics(), stable_id_file_path_.value(), &options_.stable_id_map)) { diff --git a/tools/aapt2/cmd/Link.h b/tools/aapt2/cmd/Link.h index a08f385b2270..26713fd92264 100644 --- a/tools/aapt2/cmd/Link.h +++ b/tools/aapt2/cmd/Link.h @@ -17,11 +17,17 @@ #ifndef AAPT2_LINK_H #define AAPT2_LINK_H +#include <optional> #include <regex> +#include <string> +#include <unordered_map> +#include <unordered_set> +#include <vector> #include "Command.h" #include "Resource.h" #include "androidfw/IDiagnostics.h" +#include "cmd/Util.h" #include "format/binary/TableFlattener.h" #include "format/proto/ProtoSerialize.h" #include "link/ManifestFixer.h" @@ -72,6 +78,7 @@ struct LinkOptions { bool use_sparse_encoding = false; std::unordered_set<std::string> extensions_to_not_compress; std::optional<std::regex> regex_to_not_compress; + FeatureFlagValues feature_flag_values; // Static lib options. bool no_static_lib_packages = false; diff --git a/tools/aapt2/cmd/Util.cpp b/tools/aapt2/cmd/Util.cpp index a92f24b82547..678d84628015 100644 --- a/tools/aapt2/cmd/Util.cpp +++ b/tools/aapt2/cmd/Util.cpp @@ -113,6 +113,56 @@ std::unique_ptr<IConfigFilter> ParseConfigFilterParameters(const std::vector<std return std::move(filter); } +bool ParseFeatureFlagsParameter(StringPiece arg, android::IDiagnostics* diag, + FeatureFlagValues* out_feature_flag_values) { + if (arg.empty()) { + return true; + } + + for (StringPiece flag_and_value : util::Tokenize(arg, ',')) { + std::vector<std::string> parts = util::Split(flag_and_value, '='); + if (parts.empty()) { + continue; + } + + if (parts.size() > 2) { + diag->Error(android::DiagMessage() + << "Invalid feature flag and optional value '" << flag_and_value + << "'. Must be in the format 'flag_name[=true|false]"); + return false; + } + + StringPiece flag_name = util::TrimWhitespace(parts[0]); + if (flag_name.empty()) { + diag->Error(android::DiagMessage() << "No name given for one or more flags in: " << arg); + return false; + } + + std::optional<bool> flag_value = {}; + if (parts.size() == 2) { + StringPiece str_flag_value = util::TrimWhitespace(parts[1]); + if (!str_flag_value.empty()) { + flag_value = ResourceUtils::ParseBool(parts[1]); + if (!flag_value.has_value()) { + diag->Error(android::DiagMessage() << "Invalid value for feature flag '" << flag_and_value + << "'. Value must be 'true' or 'false'"); + return false; + } + } + } + + if (auto [it, inserted] = + out_feature_flag_values->try_emplace(std::string(flag_name), flag_value); + !inserted) { + // We are allowing the same flag to appear multiple times, last value wins. + diag->Note(android::DiagMessage() + << "Value for feature flag '" << flag_name << "' was given more than once"); + it->second = flag_value; + } + } + return true; +} + // Adjust the SplitConstraints so that their SDK version is stripped if it // is less than or equal to the minSdk. Otherwise the resources that have had // their SDK version stripped due to minSdk won't ever match. diff --git a/tools/aapt2/cmd/Util.h b/tools/aapt2/cmd/Util.h index 712c07b71695..9ece5dd4d720 100644 --- a/tools/aapt2/cmd/Util.h +++ b/tools/aapt2/cmd/Util.h @@ -17,8 +17,13 @@ #ifndef AAPT_SPLIT_UTIL_H #define AAPT_SPLIT_UTIL_H +#include <functional> +#include <map> +#include <memory> +#include <optional> #include <regex> #include <set> +#include <string> #include <unordered_set> #include "AppInfo.h" @@ -32,6 +37,8 @@ namespace aapt { +using FeatureFlagValues = std::map<std::string, std::optional<bool>, std::less<>>; + // Parses a configuration density (ex. hdpi, xxhdpi, 234dpi, anydpi, etc). // Returns Nothing and logs a human friendly error message if the string was not legal. std::optional<uint16_t> ParseTargetDensityParameter(android::StringPiece arg, @@ -48,6 +55,13 @@ bool ParseSplitParameter(android::StringPiece arg, android::IDiagnostics* diag, std::unique_ptr<IConfigFilter> ParseConfigFilterParameters(const std::vector<std::string>& args, android::IDiagnostics* diag); +// Parses a feature flags parameter, which can contain one or more pairs of flag names and optional +// values, and fills in `out_feature_flag_values` with the parsed values. The pairs in the argument +// are separated by ',' and the name is separated from the value by '=' if there is a value given. +// Example arg: "flag1=true,flag2=false,flag3=,flag4" where flag3 and flag4 have no given value. +bool ParseFeatureFlagsParameter(android::StringPiece arg, android::IDiagnostics* diag, + FeatureFlagValues* out_feature_flag_values); + // Adjust the SplitConstraints so that their SDK version is stripped if it // is less than or equal to the min_sdk. Otherwise the resources that have had // their SDK version stripped due to min_sdk won't ever match. diff --git a/tools/aapt2/cmd/Util_test.cpp b/tools/aapt2/cmd/Util_test.cpp index 139bfbcd0f41..723d87ed0af3 100644 --- a/tools/aapt2/cmd/Util_test.cpp +++ b/tools/aapt2/cmd/Util_test.cpp @@ -25,6 +25,7 @@ #include "util/Files.h" using ::android::ConfigDescription; +using testing::Pair; using testing::UnorderedElementsAre; namespace aapt { @@ -354,6 +355,51 @@ TEST (UtilTest, ParseSplitParameters) { EXPECT_CONFIG_EQ(constraints, expected_configuration); } +TEST(UtilTest, ParseFeatureFlagsParameter_Empty) { + auto diagnostics = test::ContextBuilder().Build()->GetDiagnostics(); + FeatureFlagValues feature_flag_values; + ASSERT_TRUE(ParseFeatureFlagsParameter("", diagnostics, &feature_flag_values)); + EXPECT_TRUE(feature_flag_values.empty()); +} + +TEST(UtilTest, ParseFeatureFlagsParameter_TooManyParts) { + auto diagnostics = test::ContextBuilder().Build()->GetDiagnostics(); + FeatureFlagValues feature_flag_values; + ASSERT_FALSE(ParseFeatureFlagsParameter("foo=bar=baz", diagnostics, &feature_flag_values)); +} + +TEST(UtilTest, ParseFeatureFlagsParameter_NoNameGiven) { + auto diagnostics = test::ContextBuilder().Build()->GetDiagnostics(); + FeatureFlagValues feature_flag_values; + ASSERT_FALSE(ParseFeatureFlagsParameter("foo=true,=false", diagnostics, &feature_flag_values)); +} + +TEST(UtilTest, ParseFeatureFlagsParameter_InvalidValue) { + auto diagnostics = test::ContextBuilder().Build()->GetDiagnostics(); + FeatureFlagValues feature_flag_values; + ASSERT_FALSE(ParseFeatureFlagsParameter("foo=true,bar=42", diagnostics, &feature_flag_values)); +} + +TEST(UtilTest, ParseFeatureFlagsParameter_DuplicateFlag) { + auto diagnostics = test::ContextBuilder().Build()->GetDiagnostics(); + FeatureFlagValues feature_flag_values; + ASSERT_TRUE( + ParseFeatureFlagsParameter("foo=true,bar=true,foo=false", diagnostics, &feature_flag_values)); + EXPECT_THAT(feature_flag_values, UnorderedElementsAre(Pair("foo", std::optional<bool>(false)), + Pair("bar", std::optional<bool>(true)))); +} + +TEST(UtilTest, ParseFeatureFlagsParameter_Valid) { + auto diagnostics = test::ContextBuilder().Build()->GetDiagnostics(); + FeatureFlagValues feature_flag_values; + ASSERT_TRUE(ParseFeatureFlagsParameter("foo= true, bar =FALSE,baz=, quux", diagnostics, + &feature_flag_values)); + EXPECT_THAT(feature_flag_values, + UnorderedElementsAre(Pair("foo", std::optional<bool>(true)), + Pair("bar", std::optional<bool>(false)), + Pair("baz", std::nullopt), Pair("quux", std::nullopt))); +} + TEST (UtilTest, AdjustSplitConstraintsForMinSdk) { std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build(); diff --git a/tools/lint/README.md b/tools/lint/README.md index b235ad60c799..ff8e44229189 100644 --- a/tools/lint/README.md +++ b/tools/lint/README.md @@ -103,10 +103,15 @@ out/soong/.intermediates/frameworks/base/services/autofill/services.autofill/and As noted above, this baseline file contains warnings too, which might be undesirable. For example, CI tools might surface these warnings in code reviews. In order to create this file without -warnings, we need to pass another flag to lint: `--nowarn`. The easiest way to do this is to -locally change the soong code in -[lint.go](http://cs/aosp-master/build/soong/java/lint.go;l=451;rcl=2e778d5bc4a8d1d77b4f4a3029a4a254ad57db75) -adding `cmd.Flag("--nowarn")` and running lint again. +warnings, we need to pass another flag to lint: `--nowarn`. One option is to add the flag to your +Android.bp file and then run lint again: + +``` + lint: { + extra_check_modules: ["AndroidFrameworkLintChecker"], + flags: ["--nowarn"], + } +``` # Documentation |