diff options
author | 2022-10-27 16:14:25 +0000 | |
---|---|---|
committer | 2022-11-09 12:47:07 +0000 | |
commit | f0e1e76072150fb1eb22dda7b19cb852c01cb989 (patch) | |
tree | e6cdc9de40297b1f65225e028537cc3f54a8cd36 | |
parent | c1283cff6a7e2751451692dcaea728820578c218 (diff) |
Add SafetySource.areNotificationsAllowed config
This will work with the notification behavior added separately in
ag/20299585
Test: atest SafetySourceTest SafetyCenterConfigTests
Fix: 255939073
Change-Id: Ic2922ee6ccd2414208bd7978fd2d73fd712c2a68
13 files changed, 344 insertions, 52 deletions
diff --git a/SafetyCenter/Config/Android.bp b/SafetyCenter/Config/Android.bp index 6615dd1c4..78480bf55 100644 --- a/SafetyCenter/Config/Android.bp +++ b/SafetyCenter/Config/Android.bp @@ -36,6 +36,7 @@ java_library { "androidx.annotation_annotation", "framework-annotations-lib", "framework-permission-s", + "modules-utils-build", ], apex_available: [ "com.android.permission", diff --git a/SafetyCenter/Config/java/com/android/safetycenter/config/SafetyCenterConfigParser.java b/SafetyCenter/Config/java/com/android/safetycenter/config/SafetyCenterConfigParser.java index 8081ae472..5c8da1ed6 100644 --- a/SafetyCenter/Config/java/com/android/safetycenter/config/SafetyCenterConfigParser.java +++ b/SafetyCenter/Config/java/com/android/safetycenter/config/SafetyCenterConfigParser.java @@ -37,6 +37,8 @@ import android.safetycenter.config.SafetySourcesGroup; import androidx.annotation.RequiresApi; +import com.android.modules.utils.build.SdkLevel; + import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlPullParserFactory; @@ -71,6 +73,7 @@ public final class SafetyCenterConfigParser { private static final String ATTR_SAFETY_SOURCE_LOGGING_ALLOWED = "loggingAllowed"; private static final String ATTR_SAFETY_SOURCE_REFRESH_ON_PAGE_OPEN_ALLOWED = "refreshOnPageOpenAllowed"; + private static final String ATTR_SAFETY_SOURCE_NOTIFICATIONS_ALLOWED = "notificationsAllowed"; private static final String ENUM_STATELESS_ICON_TYPE_NONE = "none"; private static final String ENUM_STATELESS_ICON_TYPE_PRIVACY = "privacy"; private static final String ENUM_PROFILE_PRIMARY = "primary_profile_only"; @@ -321,6 +324,18 @@ public final class SafetyCenterConfigParser { parser.getAttributeName(i), resources)); break; + case ATTR_SAFETY_SOURCE_NOTIFICATIONS_ALLOWED: + if (SdkLevel.isAtLeastU()) { + builder.setNotificationsAllowed( + parseBoolean( + parser.getAttributeValue(i), + name, + parser.getAttributeName(i), + resources)); + } else { + throw attributeUnexpected(name, parser.getAttributeName(i)); + } + break; default: throw attributeUnexpected(name, parser.getAttributeName(i)); } diff --git a/SafetyCenter/Config/tests/java/com/android/safetycenter/config/ParserConfigInvalidTest.kt b/SafetyCenter/Config/tests/java/com/android/safetycenter/config/ParserConfigInvalidTest.kt index 140da54d3..06c390ebc 100644 --- a/SafetyCenter/Config/tests/java/com/android/safetycenter/config/ParserConfigInvalidTest.kt +++ b/SafetyCenter/Config/tests/java/com/android/safetycenter/config/ParserConfigInvalidTest.kt @@ -17,7 +17,10 @@ package com.android.safetycenter.config import android.content.Context +import android.os.Build +import androidx.annotation.RequiresApi import androidx.test.core.app.ApplicationProvider.getApplicationContext +import com.android.modules.utils.build.SdkLevel import com.android.safetycenter.config.tests.R import com.google.common.truth.Truth.assertThat import org.junit.Assert.assertThrows @@ -59,6 +62,23 @@ class ParserConfigInvalidTest { @JvmStatic @Parameterized.Parameters(name = "{0}") fun parameters() = + if (SdkLevel.isAtLeastU()) { + parametersUpsideDownCake() + } else { + parametersTiramisu() + } + + @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE) + fun parametersUpsideDownCake(): Array<Params> = + parametersTiramisu() + + arrayOf( + Params( + "ConfigStaticSafetySourceWithNotifications", + R.raw.config_static_safety_source_with_notifications, + "Element static-safety-source invalid", + "Prohibited attribute notificationsAllowed present")) + + fun parametersTiramisu(): Array<Params> = arrayOf( Params( "ConfigDynamicSafetySourceAllDisabledNoWork", diff --git a/SafetyCenter/Config/tests/java/com/android/safetycenter/config/ParserConfigValidTest.kt b/SafetyCenter/Config/tests/java/com/android/safetycenter/config/ParserConfigValidTest.kt index a8be2cdf0..02fbb5950 100644 --- a/SafetyCenter/Config/tests/java/com/android/safetycenter/config/ParserConfigValidTest.kt +++ b/SafetyCenter/Config/tests/java/com/android/safetycenter/config/ParserConfigValidTest.kt @@ -22,6 +22,7 @@ import android.safetycenter.config.SafetySource import android.safetycenter.config.SafetySourcesGroup import androidx.test.core.app.ApplicationProvider.getApplicationContext import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.android.modules.utils.build.SdkLevel import com.android.safetycenter.config.tests.R import com.google.common.truth.Truth.assertThat import org.junit.Test @@ -68,6 +69,7 @@ class ParserConfigValidTest { .setSearchTermsResId(R.string.reference) .setLoggingAllowed(false) .setRefreshOnPageOpenAllowed(true) + .apply { if (SdkLevel.isAtLeastU()) setNotificationsAllowed(true) } .build()) .addSafetySource( SafetySource.Builder(SafetySource.SAFETY_SOURCE_TYPE_DYNAMIC) @@ -152,6 +154,7 @@ class ParserConfigValidTest { .setMaxSeverityLevel(300) .setLoggingAllowed(false) .setRefreshOnPageOpenAllowed(true) + .apply { if (SdkLevel.isAtLeastU()) setNotificationsAllowed(true) } .build()) .build()) .addSafetySourcesGroup( diff --git a/SafetyCenter/Config/tests/res/raw-v34/config_static_safety_source_with_notifications.xml b/SafetyCenter/Config/tests/res/raw-v34/config_static_safety_source_with_notifications.xml new file mode 100644 index 000000000..920f5c44b --- /dev/null +++ b/SafetyCenter/Config/tests/res/raw-v34/config_static_safety_source_with_notifications.xml @@ -0,0 +1,16 @@ +<safety-center-config> + <safety-sources-config> + <safety-sources-group + id="id" + title="@com.android.safetycenter.config.tests:string/reference" + summary="@com.android.safetycenter.config.tests:string/reference"> + <static-safety-source + id="id" + title="@com.android.safetycenter.config.tests:string/reference" + summary="@com.android.safetycenter.config.tests:string/reference" + intentAction="intent" + profile="primary_profile_only" + notificationsAllowed="true"/> + </safety-sources-group> + </safety-sources-config> +</safety-center-config> diff --git a/SafetyCenter/Config/tests/res/raw-v34/config_valid.xml b/SafetyCenter/Config/tests/res/raw-v34/config_valid.xml new file mode 100644 index 000000000..8d9e3aa24 --- /dev/null +++ b/SafetyCenter/Config/tests/res/raw-v34/config_valid.xml @@ -0,0 +1,118 @@ +<safety-center-config> + <safety-sources-config> + <safety-sources-group + id="dynamic" + title="@com.android.safetycenter.config.tests:string/reference" + summary="@com.android.safetycenter.config.tests:string/reference" + statelessIconType="privacy"> + <dynamic-safety-source + id="dynamic_barebone" + packageName="package" + title="@com.android.safetycenter.config.tests:string/reference" + summary="@com.android.safetycenter.config.tests:string/reference" + intentAction="intent" + profile="primary_profile_only"/> + <dynamic-safety-source + id="dynamic_all_optional" + packageName="package" + title="@com.android.safetycenter.config.tests:string/reference" + titleForWork="@com.android.safetycenter.config.tests:string/reference" + summary="@com.android.safetycenter.config.tests:string/reference" + intentAction="intent" + profile="all_profiles" + initialDisplayState="disabled" + maxSeverityLevel="300" + searchTerms="@com.android.safetycenter.config.tests:string/reference" + loggingAllowed="false" + refreshOnPageOpenAllowed="true" + notificationsAllowed="true"/> + <dynamic-safety-source + id="@com.android.safetycenter.config.tests:string/dynamic_all_references_id" + packageName="@com.android.safetycenter.config.tests:string/dynamic_all_references_package_name" + title="@com.android.safetycenter.config.tests:string/reference" + titleForWork="@com.android.safetycenter.config.tests:string/reference" + summary="@com.android.safetycenter.config.tests:string/reference" + intentAction="@com.android.safetycenter.config.tests:string/dynamic_all_references_intent_action" + profile="@com.android.safetycenter.config.tests:string/dynamic_all_references_profile" + initialDisplayState="@com.android.safetycenter.config.tests:string/dynamic_all_references_initial_display_state" + maxSeverityLevel="@com.android.safetycenter.config.tests:string/dynamic_all_references_max_severity_level" + searchTerms="@com.android.safetycenter.config.tests:string/reference" + loggingAllowed="@com.android.safetycenter.config.tests:string/dynamic_all_references_logging_allowed" + refreshOnPageOpenAllowed="@com.android.safetycenter.config.tests:string/dynamic_all_references_refresh_on_page_open_allowed"/> + <dynamic-safety-source + id="dynamic_disabled" + packageName="package" + title="@com.android.safetycenter.config.tests:string/reference" + summary="@com.android.safetycenter.config.tests:string/reference" + profile="primary_profile_only" + initialDisplayState="disabled"/> + <dynamic-safety-source + id="dynamic_hidden" + packageName="package" + profile="all_profiles" + initialDisplayState="hidden"/> + <dynamic-safety-source + id="dynamic_hidden_with_search" + packageName="package" + title="@com.android.safetycenter.config.tests:string/reference" + titleForWork="@com.android.safetycenter.config.tests:string/reference" + summary="@com.android.safetycenter.config.tests:string/reference" + intentAction="intent" + profile="all_profiles" + initialDisplayState="hidden" + searchTerms="@com.android.safetycenter.config.tests:string/reference"/> + </safety-sources-group> + <safety-sources-group + id="static" + title="@com.android.safetycenter.config.tests:string/reference"> + <static-safety-source + id="static_barebone" + title="@com.android.safetycenter.config.tests:string/reference" + intentAction="intent" + profile="primary_profile_only"/> + <static-safety-source + id="static_all_optional" + title="@com.android.safetycenter.config.tests:string/reference" + titleForWork="@com.android.safetycenter.config.tests:string/reference" + summary="@com.android.safetycenter.config.tests:string/reference" + intentAction="intent" + profile="all_profiles" + searchTerms="@com.android.safetycenter.config.tests:string/reference"/> + </safety-sources-group> + <safety-sources-group + id="issue_only"> + <issue-only-safety-source + id="issue_only_barebone" + packageName="package" + profile="primary_profile_only"/> + <issue-only-safety-source + id="issue_only_all_optional" + packageName="package" + profile="all_profiles" + maxSeverityLevel="300" + loggingAllowed="false" + refreshOnPageOpenAllowed="true" + notificationsAllowed="true"/> + </safety-sources-group> + <safety-sources-group + id="mixed" + title="@com.android.safetycenter.config.tests:string/reference"> + <dynamic-safety-source + id="mixed_dynamic_barebone" + packageName="package" + title="@com.android.safetycenter.config.tests:string/reference" + summary="@com.android.safetycenter.config.tests:string/reference" + intentAction="intent" + profile="primary_profile_only"/> + <issue-only-safety-source + id="mixed_issue_only_barebone" + packageName="package" + profile="primary_profile_only"/> + <static-safety-source + id="mixed_static_barebone" + title="@com.android.safetycenter.config.tests:string/reference" + intentAction="intent" + profile="primary_profile_only"/> + </safety-sources-group> + </safety-sources-config> +</safety-center-config> diff --git a/SafetyCenter/ConfigLintChecker/java/android/os/Build.java b/SafetyCenter/ConfigLintChecker/java/android/os/Build.java index abe5d49d3..820be5db3 100644 --- a/SafetyCenter/ConfigLintChecker/java/android/os/Build.java +++ b/SafetyCenter/ConfigLintChecker/java/android/os/Build.java @@ -24,5 +24,7 @@ public final class Build { public static final class VERSION_CODES { /** Constant used in the Safety Center config files. */ public static final int TIRAMISU = 10000; + /** Constant used in the Safety Center config files. */ + public static final int UPSIDE_DOWN_CAKE = 10001; } } diff --git a/SafetyCenter/ConfigLintChecker/java/com/android/modules/utils/build/SdkLevel.java b/SafetyCenter/ConfigLintChecker/java/com/android/modules/utils/build/SdkLevel.java new file mode 100644 index 000000000..d5a5935d6 --- /dev/null +++ b/SafetyCenter/ConfigLintChecker/java/com/android/modules/utils/build/SdkLevel.java @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2022 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. + */ + +package com.android.modules.utils.build; + +/** Stub class to compile the linter for host execution. */ +public final class SdkLevel { + private SdkLevel() {} + + /** Method used in Safety Center code. */ + public static boolean isAtLeastU() { + return true; + } +} diff --git a/framework-s/api/system-current.txt b/framework-s/api/system-current.txt index 360896f9c..c54ea8f29 100644 --- a/framework-s/api/system-current.txt +++ b/framework-s/api/system-current.txt @@ -470,6 +470,7 @@ package android.safetycenter.config { } public final class SafetySource implements android.os.Parcelable { + method public boolean areNotificationsAllowed(); method public int describeContents(); method @NonNull public String getId(); method public int getInitialDisplayState(); @@ -505,6 +506,7 @@ package android.safetycenter.config { method @NonNull public android.safetycenter.config.SafetySource.Builder setIntentAction(@Nullable String); method @NonNull public android.safetycenter.config.SafetySource.Builder setLoggingAllowed(boolean); method @NonNull public android.safetycenter.config.SafetySource.Builder setMaxSeverityLevel(int); + method @NonNull public android.safetycenter.config.SafetySource.Builder setNotificationsAllowed(boolean); method @NonNull public android.safetycenter.config.SafetySource.Builder setPackageName(@Nullable String); method @NonNull public android.safetycenter.config.SafetySource.Builder setProfile(int); method @NonNull public android.safetycenter.config.SafetySource.Builder setRefreshOnPageOpenAllowed(boolean); diff --git a/framework-s/java/android/safetycenter/config/SafetySource.java b/framework-s/java/android/safetycenter/config/SafetySource.java index e5008bfea..a249c12af 100644 --- a/framework-s/java/android/safetycenter/config/SafetySource.java +++ b/framework-s/java/android/safetycenter/config/SafetySource.java @@ -17,6 +17,7 @@ package android.safetycenter.config; import static android.os.Build.VERSION_CODES.TIRAMISU; +import static android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE; import android.annotation.IntDef; import android.annotation.NonNull; @@ -29,6 +30,8 @@ import android.os.Parcelable; import androidx.annotation.RequiresApi; +import com.android.modules.utils.build.SdkLevel; + import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.Objects; @@ -152,20 +155,24 @@ public final class SafetySource implements Parcelable { @Override public SafetySource createFromParcel(Parcel in) { int type = in.readInt(); - return new Builder(type) - .setId(in.readString()) - .setPackageName(in.readString()) - .setTitleResId(in.readInt()) - .setTitleForWorkResId(in.readInt()) - .setSummaryResId(in.readInt()) - .setIntentAction(in.readString()) - .setProfile(in.readInt()) - .setInitialDisplayState(in.readInt()) - .setMaxSeverityLevel(in.readInt()) - .setSearchTermsResId(in.readInt()) - .setLoggingAllowed(in.readBoolean()) - .setRefreshOnPageOpenAllowed(in.readBoolean()) - .build(); + Builder builder = + new Builder(type) + .setId(in.readString()) + .setPackageName(in.readString()) + .setTitleResId(in.readInt()) + .setTitleForWorkResId(in.readInt()) + .setSummaryResId(in.readInt()) + .setIntentAction(in.readString()) + .setProfile(in.readInt()) + .setInitialDisplayState(in.readInt()) + .setMaxSeverityLevel(in.readInt()) + .setSearchTermsResId(in.readInt()) + .setLoggingAllowed(in.readBoolean()) + .setRefreshOnPageOpenAllowed(in.readBoolean()); + if (SdkLevel.isAtLeastU()) { + builder.setNotificationsAllowed(in.readBoolean()); + } + return builder.build(); } @Override @@ -187,6 +194,7 @@ public final class SafetySource implements Parcelable { @StringRes private final int mSearchTermsResId; private final boolean mLoggingAllowed; private final boolean mRefreshOnPageOpenAllowed; + private final boolean mNotificationsAllowed; private SafetySource( @SafetySourceType int type, @@ -201,7 +209,8 @@ public final class SafetySource implements Parcelable { int maxSeverityLevel, @StringRes int searchTermsResId, boolean loggingAllowed, - boolean refreshOnPageOpenAllowed) { + boolean refreshOnPageOpenAllowed, + boolean notificationsAllowed) { mType = type; mId = id; mPackageName = packageName; @@ -215,6 +224,7 @@ public final class SafetySource implements Parcelable { mSearchTermsResId = searchTermsResId; mLoggingAllowed = loggingAllowed; mRefreshOnPageOpenAllowed = refreshOnPageOpenAllowed; + mNotificationsAllowed = notificationsAllowed; } /** Returns the type of this safety source. */ @@ -418,6 +428,20 @@ public final class SafetySource implements Parcelable { return mRefreshOnPageOpenAllowed; } + /** + * Returns whether Safety Center may post Notifications about issues reported by this {@link + * SafetySource}. + * + * @see Builder#setNotificationsAllowed(boolean) + */ + @RequiresApi(UPSIDE_DOWN_CAKE) + public boolean areNotificationsAllowed() { + if (!SdkLevel.isAtLeastU()) { + throw new UnsupportedOperationException(); + } + return mNotificationsAllowed; + } + @Override public boolean equals(Object o) { if (this == o) return true; @@ -435,7 +459,8 @@ public final class SafetySource implements Parcelable { && mMaxSeverityLevel == that.mMaxSeverityLevel && mSearchTermsResId == that.mSearchTermsResId && mLoggingAllowed == that.mLoggingAllowed - && mRefreshOnPageOpenAllowed == that.mRefreshOnPageOpenAllowed; + && mRefreshOnPageOpenAllowed == that.mRefreshOnPageOpenAllowed + && mNotificationsAllowed == that.mNotificationsAllowed; } @Override @@ -453,7 +478,8 @@ public final class SafetySource implements Parcelable { mMaxSeverityLevel, mSearchTermsResId, mLoggingAllowed, - mRefreshOnPageOpenAllowed); + mRefreshOnPageOpenAllowed, + mNotificationsAllowed); } @Override @@ -485,6 +511,8 @@ public final class SafetySource implements Parcelable { + mLoggingAllowed + ", mRefreshOnPageOpenAllowed=" + mRefreshOnPageOpenAllowed + + ", mNotificationsAllowed" + + mNotificationsAllowed + '}'; } @@ -508,6 +536,9 @@ public final class SafetySource implements Parcelable { dest.writeInt(mSearchTermsResId); dest.writeBoolean(mLoggingAllowed); dest.writeBoolean(mRefreshOnPageOpenAllowed); + if (SdkLevel.isAtLeastU()) { + dest.writeBoolean(mNotificationsAllowed); + } } /** Builder class for {@link SafetySource}. */ @@ -526,6 +557,7 @@ public final class SafetySource implements Parcelable { @Nullable @StringRes private Integer mSearchTermsResId; @Nullable private Boolean mLoggingAllowed; @Nullable private Boolean mRefreshOnPageOpenAllowed; + @Nullable private Boolean mNotificationsAllowed; /** Creates a {@link Builder} for a {@link SafetySource}. */ public Builder(@SafetySourceType int type) { @@ -714,6 +746,26 @@ public final class SafetySource implements Parcelable { } /** + * Sets the {@link #areNotificationsAllowed()} property of this {@link SafetySource}. + * + * <p>If set to {@code true} Safety Center may post Notifications about issues reported by + * this source. + * + * <p>The default value is {@code false}. + * + * @see #areNotificationsAllowed() + */ + @NonNull + @RequiresApi(UPSIDE_DOWN_CAKE) + public Builder setNotificationsAllowed(boolean notificationsAllowed) { + if (!SdkLevel.isAtLeastU()) { + throw new UnsupportedOperationException(); + } + mNotificationsAllowed = notificationsAllowed; + return this; + } + + /** * Creates the {@link SafetySource} defined by this {@link Builder}. * * <p>Throws an {@link IllegalStateException} if any constraint on the safety source is @@ -807,6 +859,17 @@ public final class SafetySource implements Parcelable { isStatic, false); + boolean notificationsAllowed = false; + if (SdkLevel.isAtLeastU()) { + notificationsAllowed = + BuilderUtils.validateBoolean( + mNotificationsAllowed, + "notificationsAllowed", + false, + isStatic, + false); + } + return new SafetySource( mType, mId, @@ -820,7 +883,8 @@ public final class SafetySource implements Parcelable { maxSeverityLevel, searchTermsResId, loggingAllowed, - refreshOnPageOpenAllowed); + refreshOnPageOpenAllowed, + notificationsAllowed); } } } diff --git a/framework-s/java/android/safetycenter/config/safety_center_config.xsd b/framework-s/java/android/safetycenter/config/safety_center_config.xsd index 88cfcfec7..8d9903e16 100644 --- a/framework-s/java/android/safetycenter/config/safety_center_config.xsd +++ b/framework-s/java/android/safetycenter/config/safety_center_config.xsd @@ -70,6 +70,8 @@ <xsd:attribute name="loggingAllowed" type="booleanOrStringResourceName" default="true"/> <xsd:attribute name="refreshOnPageOpenAllowed" type="booleanOrStringResourceName" default="false"/> + <xsd:attribute name="notificationsAllowed" type="booleanOrStringResourceName" + default="false"/> </xsd:complexType> <xsd:complexType name="issue-only-safety-source"> @@ -81,6 +83,8 @@ <xsd:attribute name="loggingAllowed" type="booleanOrStringResourceName" default="true"/> <xsd:attribute name="refreshOnPageOpenAllowed" type="booleanOrStringResourceName" default="false"/> + <xsd:attribute name="notificationsAllowed" type="booleanOrStringResourceName" + default="false"/> </xsd:complexType> <xsd:complexType name="static-safety-source"> diff --git a/tests/cts/safetycenter/Android.bp b/tests/cts/safetycenter/Android.bp index 5c85ea3a9..b7519201f 100644 --- a/tests/cts/safetycenter/Android.bp +++ b/tests/cts/safetycenter/Android.bp @@ -43,6 +43,7 @@ android_test { "safety-center-config", "safety-center-internal-data", "safety-center-resources-lib", + "modules-utils-build", "truth-prebuilt", "Nene", "Harrier", diff --git a/tests/cts/safetycenter/src/android/safetycenter/cts/config/SafetySourceTest.kt b/tests/cts/safetycenter/src/android/safetycenter/cts/config/SafetySourceTest.kt index 60c09fc86..ca21636c1 100644 --- a/tests/cts/safetycenter/src/android/safetycenter/cts/config/SafetySourceTest.kt +++ b/tests/cts/safetycenter/src/android/safetycenter/cts/config/SafetySourceTest.kt @@ -17,9 +17,12 @@ package android.safetycenter.cts.config import android.content.res.Resources +import android.os.Build import android.safetycenter.config.SafetySource import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.ext.truth.os.ParcelableSubject.assertThat +import androidx.test.filters.SdkSuppress +import com.android.modules.utils.build.SdkLevel import com.android.permission.testing.EqualsHashCodeToStringTester import com.google.common.truth.Truth.assertThat import org.junit.Assert.assertThrows @@ -33,7 +36,7 @@ class SafetySourceTest { @Test fun getType_returnsType() { assertThat(DYNAMIC_BAREBONE.type).isEqualTo(SafetySource.SAFETY_SOURCE_TYPE_DYNAMIC) - assertThat(DYNAMIC_ALL_OPTIONAL.type).isEqualTo(SafetySource.SAFETY_SOURCE_TYPE_DYNAMIC) + assertThat(dynamicAllOptional().type).isEqualTo(SafetySource.SAFETY_SOURCE_TYPE_DYNAMIC) assertThat(DYNAMIC_HIDDEN.type).isEqualTo(SafetySource.SAFETY_SOURCE_TYPE_DYNAMIC) assertThat(DYNAMIC_HIDDEN_WITH_SEARCH.type) .isEqualTo(SafetySource.SAFETY_SOURCE_TYPE_DYNAMIC) @@ -41,40 +44,40 @@ class SafetySourceTest { assertThat(STATIC_BAREBONE.type).isEqualTo(SafetySource.SAFETY_SOURCE_TYPE_STATIC) assertThat(STATIC_ALL_OPTIONAL.type).isEqualTo(SafetySource.SAFETY_SOURCE_TYPE_STATIC) assertThat(ISSUE_ONLY_BAREBONE.type).isEqualTo(SafetySource.SAFETY_SOURCE_TYPE_ISSUE_ONLY) - assertThat(ISSUE_ONLY_ALL_OPTIONAL.type) + assertThat(issueOnlyAllOptional().type) .isEqualTo(SafetySource.SAFETY_SOURCE_TYPE_ISSUE_ONLY) } @Test fun getId_returnsId() { assertThat(DYNAMIC_BAREBONE.id).isEqualTo(DYNAMIC_BAREBONE_ID) - assertThat(DYNAMIC_ALL_OPTIONAL.id).isEqualTo(DYNAMIC_ALL_OPTIONAL_ID) + assertThat(dynamicAllOptional().id).isEqualTo(DYNAMIC_ALL_OPTIONAL_ID) assertThat(DYNAMIC_HIDDEN.id).isEqualTo(DYNAMIC_HIDDEN_ID) assertThat(DYNAMIC_HIDDEN_WITH_SEARCH.id).isEqualTo(DYNAMIC_HIDDEN_WITH_SEARCH_ID) assertThat(DYNAMIC_DISABLED.id).isEqualTo(DYNAMIC_DISABLED_ID) assertThat(STATIC_BAREBONE.id).isEqualTo(STATIC_BAREBONE_ID) assertThat(STATIC_ALL_OPTIONAL.id).isEqualTo(STATIC_ALL_OPTIONAL_ID) assertThat(ISSUE_ONLY_BAREBONE.id).isEqualTo(ISSUE_ONLY_BAREBONE_ID) - assertThat(ISSUE_ONLY_ALL_OPTIONAL.id).isEqualTo(ISSUE_ONLY_ALL_OPTIONAL_ID) + assertThat(issueOnlyAllOptional().id).isEqualTo(ISSUE_ONLY_ALL_OPTIONAL_ID) } @Test fun getPackageName_returnsPackageNameOrThrows() { assertThat(DYNAMIC_BAREBONE.packageName).isEqualTo(PACKAGE_NAME) - assertThat(DYNAMIC_ALL_OPTIONAL.packageName).isEqualTo(PACKAGE_NAME) + assertThat(dynamicAllOptional().packageName).isEqualTo(PACKAGE_NAME) assertThat(DYNAMIC_HIDDEN.packageName).isEqualTo(PACKAGE_NAME) assertThat(DYNAMIC_HIDDEN_WITH_SEARCH.packageName).isEqualTo(PACKAGE_NAME) assertThat(DYNAMIC_DISABLED.packageName).isEqualTo(PACKAGE_NAME) assertThrows(UnsupportedOperationException::class.java) { STATIC_BAREBONE.packageName } assertThrows(UnsupportedOperationException::class.java) { STATIC_ALL_OPTIONAL.packageName } assertThat(ISSUE_ONLY_BAREBONE.packageName).isEqualTo(PACKAGE_NAME) - assertThat(ISSUE_ONLY_ALL_OPTIONAL.packageName).isEqualTo(PACKAGE_NAME) + assertThat(issueOnlyAllOptional().packageName).isEqualTo(PACKAGE_NAME) } @Test fun getTitleResId_returnsTitleResIdOrThrows() { assertThat(DYNAMIC_BAREBONE.titleResId).isEqualTo(REFERENCE_RES_ID) - assertThat(DYNAMIC_ALL_OPTIONAL.titleResId).isEqualTo(REFERENCE_RES_ID) + assertThat(dynamicAllOptional().titleResId).isEqualTo(REFERENCE_RES_ID) assertThat(DYNAMIC_DISABLED.titleResId).isEqualTo(REFERENCE_RES_ID) assertThat(DYNAMIC_HIDDEN.titleResId).isEqualTo(Resources.ID_NULL) assertThat(DYNAMIC_HIDDEN_WITH_SEARCH.titleResId).isEqualTo(REFERENCE_RES_ID) @@ -82,7 +85,7 @@ class SafetySourceTest { assertThat(STATIC_ALL_OPTIONAL.titleResId).isEqualTo(REFERENCE_RES_ID) assertThrows(UnsupportedOperationException::class.java) { ISSUE_ONLY_BAREBONE.titleResId } assertThrows(UnsupportedOperationException::class.java) { - ISSUE_ONLY_ALL_OPTIONAL.titleResId + issueOnlyAllOptional().titleResId } } @@ -91,7 +94,7 @@ class SafetySourceTest { assertThrows(UnsupportedOperationException::class.java) { DYNAMIC_BAREBONE.titleForWorkResId } - assertThat(DYNAMIC_ALL_OPTIONAL.titleForWorkResId).isEqualTo(REFERENCE_RES_ID) + assertThat(dynamicAllOptional().titleForWorkResId).isEqualTo(REFERENCE_RES_ID) assertThrows(UnsupportedOperationException::class.java) { DYNAMIC_DISABLED.titleForWorkResId } @@ -105,14 +108,14 @@ class SafetySourceTest { ISSUE_ONLY_BAREBONE.titleForWorkResId } assertThrows(UnsupportedOperationException::class.java) { - ISSUE_ONLY_ALL_OPTIONAL.titleForWorkResId + issueOnlyAllOptional().titleForWorkResId } } @Test fun getSummaryResId_returnsSummaryResIdOrThrows() { assertThat(DYNAMIC_BAREBONE.summaryResId).isEqualTo(REFERENCE_RES_ID) - assertThat(DYNAMIC_ALL_OPTIONAL.summaryResId).isEqualTo(REFERENCE_RES_ID) + assertThat(dynamicAllOptional().summaryResId).isEqualTo(REFERENCE_RES_ID) assertThat(DYNAMIC_DISABLED.summaryResId).isEqualTo(REFERENCE_RES_ID) assertThat(DYNAMIC_HIDDEN.summaryResId).isEqualTo(Resources.ID_NULL) assertThat(DYNAMIC_HIDDEN_WITH_SEARCH.summaryResId).isEqualTo(REFERENCE_RES_ID) @@ -120,14 +123,14 @@ class SafetySourceTest { assertThat(STATIC_ALL_OPTIONAL.summaryResId).isEqualTo(REFERENCE_RES_ID) assertThrows(UnsupportedOperationException::class.java) { ISSUE_ONLY_BAREBONE.summaryResId } assertThrows(UnsupportedOperationException::class.java) { - ISSUE_ONLY_ALL_OPTIONAL.summaryResId + issueOnlyAllOptional().summaryResId } } @Test fun getIntentAction_returnsIntentActionOrThrows() { assertThat(DYNAMIC_BAREBONE.intentAction).isEqualTo(INTENT_ACTION) - assertThat(DYNAMIC_ALL_OPTIONAL.intentAction).isEqualTo(INTENT_ACTION) + assertThat(dynamicAllOptional().intentAction).isEqualTo(INTENT_ACTION) assertThat(DYNAMIC_DISABLED.intentAction).isNull() assertThat(DYNAMIC_HIDDEN.intentAction).isNull() assertThat(DYNAMIC_HIDDEN_WITH_SEARCH.intentAction).isEqualTo(INTENT_ACTION) @@ -135,28 +138,28 @@ class SafetySourceTest { assertThat(STATIC_ALL_OPTIONAL.intentAction).isEqualTo(INTENT_ACTION) assertThrows(UnsupportedOperationException::class.java) { ISSUE_ONLY_BAREBONE.intentAction } assertThrows(UnsupportedOperationException::class.java) { - ISSUE_ONLY_ALL_OPTIONAL.intentAction + issueOnlyAllOptional().intentAction } } @Test fun getProfile_returnsProfile() { assertThat(DYNAMIC_BAREBONE.profile).isEqualTo(SafetySource.PROFILE_PRIMARY) - assertThat(DYNAMIC_ALL_OPTIONAL.profile).isEqualTo(SafetySource.PROFILE_ALL) + assertThat(dynamicAllOptional().profile).isEqualTo(SafetySource.PROFILE_ALL) assertThat(DYNAMIC_DISABLED.profile).isEqualTo(SafetySource.PROFILE_PRIMARY) assertThat(DYNAMIC_HIDDEN.profile).isEqualTo(SafetySource.PROFILE_ALL) assertThat(DYNAMIC_HIDDEN_WITH_SEARCH.profile).isEqualTo(SafetySource.PROFILE_ALL) assertThat(STATIC_BAREBONE.profile).isEqualTo(SafetySource.PROFILE_PRIMARY) assertThat(STATIC_ALL_OPTIONAL.profile).isEqualTo(SafetySource.PROFILE_ALL) assertThat(ISSUE_ONLY_BAREBONE.profile).isEqualTo(SafetySource.PROFILE_PRIMARY) - assertThat(ISSUE_ONLY_ALL_OPTIONAL.profile).isEqualTo(SafetySource.PROFILE_ALL) + assertThat(issueOnlyAllOptional().profile).isEqualTo(SafetySource.PROFILE_ALL) } @Test fun getInitialDisplayState_returnsInitialDisplayStateOrThrows() { assertThat(DYNAMIC_BAREBONE.initialDisplayState) .isEqualTo(SafetySource.INITIAL_DISPLAY_STATE_ENABLED) - assertThat(DYNAMIC_ALL_OPTIONAL.initialDisplayState) + assertThat(dynamicAllOptional().initialDisplayState) .isEqualTo(SafetySource.INITIAL_DISPLAY_STATE_DISABLED) assertThat(DYNAMIC_DISABLED.initialDisplayState) .isEqualTo(SafetySource.INITIAL_DISPLAY_STATE_DISABLED) @@ -174,14 +177,14 @@ class SafetySourceTest { ISSUE_ONLY_BAREBONE.initialDisplayState } assertThrows(UnsupportedOperationException::class.java) { - ISSUE_ONLY_ALL_OPTIONAL.initialDisplayState + issueOnlyAllOptional().initialDisplayState } } @Test fun getMaxSeverityLevel_returnsMaxSeverityLevelOrThrows() { assertThat(DYNAMIC_BAREBONE.maxSeverityLevel).isEqualTo(Integer.MAX_VALUE) - assertThat(DYNAMIC_ALL_OPTIONAL.maxSeverityLevel).isEqualTo(MAX_SEVERITY_LEVEL) + assertThat(dynamicAllOptional().maxSeverityLevel).isEqualTo(MAX_SEVERITY_LEVEL) assertThat(DYNAMIC_DISABLED.maxSeverityLevel).isEqualTo(Integer.MAX_VALUE) assertThat(DYNAMIC_HIDDEN.maxSeverityLevel).isEqualTo(Integer.MAX_VALUE) assertThat(DYNAMIC_HIDDEN_WITH_SEARCH.maxSeverityLevel).isEqualTo(Integer.MAX_VALUE) @@ -190,13 +193,13 @@ class SafetySourceTest { STATIC_ALL_OPTIONAL.maxSeverityLevel } assertThat(ISSUE_ONLY_BAREBONE.maxSeverityLevel).isEqualTo(Integer.MAX_VALUE) - assertThat(ISSUE_ONLY_ALL_OPTIONAL.maxSeverityLevel).isEqualTo(MAX_SEVERITY_LEVEL) + assertThat(issueOnlyAllOptional().maxSeverityLevel).isEqualTo(MAX_SEVERITY_LEVEL) } @Test fun getSearchTermsResId_returnsSearchTermsResIdOrThrows() { assertThat(DYNAMIC_BAREBONE.searchTermsResId).isEqualTo(Resources.ID_NULL) - assertThat(DYNAMIC_ALL_OPTIONAL.searchTermsResId).isEqualTo(REFERENCE_RES_ID) + assertThat(dynamicAllOptional().searchTermsResId).isEqualTo(REFERENCE_RES_ID) assertThat(DYNAMIC_DISABLED.searchTermsResId).isEqualTo(Resources.ID_NULL) assertThat(DYNAMIC_HIDDEN.searchTermsResId).isEqualTo(Resources.ID_NULL) assertThat(DYNAMIC_HIDDEN_WITH_SEARCH.searchTermsResId).isEqualTo(REFERENCE_RES_ID) @@ -206,14 +209,14 @@ class SafetySourceTest { ISSUE_ONLY_BAREBONE.searchTermsResId } assertThrows(UnsupportedOperationException::class.java) { - ISSUE_ONLY_ALL_OPTIONAL.searchTermsResId + issueOnlyAllOptional().searchTermsResId } } @Test fun isLoggingAllowed_returnsLoggingAllowedOrThrows() { assertThat(DYNAMIC_BAREBONE.isLoggingAllowed).isEqualTo(true) - assertThat(DYNAMIC_ALL_OPTIONAL.isLoggingAllowed).isEqualTo(false) + assertThat(dynamicAllOptional().isLoggingAllowed).isEqualTo(false) assertThat(DYNAMIC_DISABLED.isLoggingAllowed).isEqualTo(true) assertThat(DYNAMIC_HIDDEN.isLoggingAllowed).isEqualTo(true) assertThat(DYNAMIC_HIDDEN_WITH_SEARCH.isLoggingAllowed).isEqualTo(true) @@ -222,13 +225,13 @@ class SafetySourceTest { STATIC_ALL_OPTIONAL.isLoggingAllowed } assertThat(ISSUE_ONLY_BAREBONE.isLoggingAllowed).isEqualTo(true) - assertThat(ISSUE_ONLY_ALL_OPTIONAL.isLoggingAllowed).isEqualTo(false) + assertThat(issueOnlyAllOptional().isLoggingAllowed).isEqualTo(false) } @Test fun isRefreshOnPageOpenAllowed_returnsRefreshOnPageOpenAllowedOrThrows() { assertThat(DYNAMIC_BAREBONE.isRefreshOnPageOpenAllowed).isEqualTo(false) - assertThat(DYNAMIC_ALL_OPTIONAL.isRefreshOnPageOpenAllowed).isEqualTo(true) + assertThat(dynamicAllOptional().isRefreshOnPageOpenAllowed).isEqualTo(true) assertThat(DYNAMIC_DISABLED.isRefreshOnPageOpenAllowed).isEqualTo(false) assertThat(DYNAMIC_HIDDEN.isRefreshOnPageOpenAllowed).isEqualTo(false) assertThat(DYNAMIC_HIDDEN_WITH_SEARCH.isRefreshOnPageOpenAllowed).isEqualTo(false) @@ -239,33 +242,47 @@ class SafetySourceTest { STATIC_ALL_OPTIONAL.isRefreshOnPageOpenAllowed } assertThat(ISSUE_ONLY_BAREBONE.isRefreshOnPageOpenAllowed).isEqualTo(false) - assertThat(ISSUE_ONLY_ALL_OPTIONAL.isRefreshOnPageOpenAllowed).isEqualTo(true) + assertThat(issueOnlyAllOptional().isRefreshOnPageOpenAllowed).isEqualTo(true) + } + + @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake") + @Test + fun areNotificationsAllowed_returnsNotificationsAllowed() { + assertThat(DYNAMIC_BAREBONE.areNotificationsAllowed()).isFalse() + assertThat(dynamicAllOptional().areNotificationsAllowed()).isTrue() + assertThat(DYNAMIC_DISABLED.areNotificationsAllowed()).isFalse() + assertThat(DYNAMIC_HIDDEN.areNotificationsAllowed()).isFalse() + assertThat(DYNAMIC_HIDDEN_WITH_SEARCH.areNotificationsAllowed()).isFalse() + assertThat(STATIC_BAREBONE.areNotificationsAllowed()).isFalse() + assertThat(STATIC_ALL_OPTIONAL.areNotificationsAllowed()).isFalse() + assertThat(ISSUE_ONLY_BAREBONE.areNotificationsAllowed()).isFalse() + assertThat(issueOnlyAllOptional().areNotificationsAllowed()).isTrue() } @Test fun describeContents_returns0() { assertThat(DYNAMIC_BAREBONE.describeContents()).isEqualTo(0) - assertThat(DYNAMIC_ALL_OPTIONAL.describeContents()).isEqualTo(0) + assertThat(dynamicAllOptional().describeContents()).isEqualTo(0) assertThat(DYNAMIC_DISABLED.describeContents()).isEqualTo(0) assertThat(DYNAMIC_HIDDEN.describeContents()).isEqualTo(0) assertThat(DYNAMIC_HIDDEN_WITH_SEARCH.describeContents()).isEqualTo(0) assertThat(STATIC_BAREBONE.describeContents()).isEqualTo(0) assertThat(STATIC_ALL_OPTIONAL.describeContents()).isEqualTo(0) assertThat(ISSUE_ONLY_BAREBONE.describeContents()).isEqualTo(0) - assertThat(ISSUE_ONLY_ALL_OPTIONAL.describeContents()).isEqualTo(0) + assertThat(issueOnlyAllOptional().describeContents()).isEqualTo(0) } @Test fun parcelRoundTrip_recreatesEqual() { assertThat(DYNAMIC_BAREBONE).recreatesEqual(SafetySource.CREATOR) - assertThat(DYNAMIC_ALL_OPTIONAL).recreatesEqual(SafetySource.CREATOR) + assertThat(dynamicAllOptional()).recreatesEqual(SafetySource.CREATOR) assertThat(DYNAMIC_DISABLED).recreatesEqual(SafetySource.CREATOR) assertThat(DYNAMIC_HIDDEN).recreatesEqual(SafetySource.CREATOR) assertThat(DYNAMIC_HIDDEN_WITH_SEARCH).recreatesEqual(SafetySource.CREATOR) assertThat(STATIC_BAREBONE).recreatesEqual(SafetySource.CREATOR) assertThat(STATIC_ALL_OPTIONAL).recreatesEqual(SafetySource.CREATOR) assertThat(ISSUE_ONLY_BAREBONE).recreatesEqual(SafetySource.CREATOR) - assertThat(ISSUE_ONLY_ALL_OPTIONAL).recreatesEqual(SafetySource.CREATOR) + assertThat(issueOnlyAllOptional()).recreatesEqual(SafetySource.CREATOR) } @Test @@ -273,7 +290,7 @@ class SafetySourceTest { EqualsHashCodeToStringTester() .addEqualityGroup(DYNAMIC_BAREBONE) .addEqualityGroup( - DYNAMIC_ALL_OPTIONAL, + dynamicAllOptional(), SafetySource.Builder(SafetySource.SAFETY_SOURCE_TYPE_DYNAMIC) .setId(DYNAMIC_ALL_OPTIONAL_ID) .setPackageName(PACKAGE_NAME) @@ -294,7 +311,7 @@ class SafetySourceTest { .addEqualityGroup(STATIC_BAREBONE) .addEqualityGroup(STATIC_ALL_OPTIONAL) .addEqualityGroup(ISSUE_ONLY_BAREBONE) - .addEqualityGroup(ISSUE_ONLY_ALL_OPTIONAL) + .addEqualityGroup(issueOnlyAllOptional()) .addEqualityGroup( SafetySource.Builder(SafetySource.SAFETY_SOURCE_TYPE_DYNAMIC) .setId("other") @@ -496,7 +513,7 @@ class SafetySourceTest { .setProfile(SafetySource.PROFILE_PRIMARY) .build() - private val DYNAMIC_ALL_OPTIONAL = + private fun dynamicAllOptional(): SafetySource = SafetySource.Builder(SafetySource.SAFETY_SOURCE_TYPE_DYNAMIC) .setId(DYNAMIC_ALL_OPTIONAL_ID) .setPackageName(PACKAGE_NAME) @@ -510,6 +527,7 @@ class SafetySourceTest { .setSearchTermsResId(REFERENCE_RES_ID) .setLoggingAllowed(false) .setRefreshOnPageOpenAllowed(true) + .apply { if (SdkLevel.isAtLeastU()) setNotificationsAllowed(true) } .build() private val DYNAMIC_DISABLED = @@ -569,7 +587,7 @@ class SafetySourceTest { .setProfile(SafetySource.PROFILE_PRIMARY) .build() - private val ISSUE_ONLY_ALL_OPTIONAL = + private fun issueOnlyAllOptional(): SafetySource = SafetySource.Builder(SafetySource.SAFETY_SOURCE_TYPE_ISSUE_ONLY) .setId(ISSUE_ONLY_ALL_OPTIONAL_ID) .setPackageName(PACKAGE_NAME) @@ -577,6 +595,7 @@ class SafetySourceTest { .setMaxSeverityLevel(MAX_SEVERITY_LEVEL) .setLoggingAllowed(false) .setRefreshOnPageOpenAllowed(true) + .apply { if (SdkLevel.isAtLeastU()) setNotificationsAllowed(true) } .build() } } |