diff --git a/core/tests/coretests/res/values/overlayable_icons_test.xml b/core/tests/coretests/res/values/overlayable_icons_test.xml
index ce209ce909056..6503f3ee6d577 100644
--- a/core/tests/coretests/res/values/overlayable_icons_test.xml
+++ b/core/tests/coretests/res/values/overlayable_icons_test.xml
@@ -70,6 +70,7 @@
- @*android:drawable/ic_wifi_signal_3
- @*android:drawable/ic_wifi_signal_4
- @*android:drawable/perm_group_activity_recognition
+ - @*android:drawable/perm_group_aural
- @*android:drawable/perm_group_calendar
- @*android:drawable/perm_group_call_log
- @*android:drawable/perm_group_camera
diff --git a/packages/SystemUI/tests/src/com/android/systemui/IconPackOverlayTest.java b/packages/SystemUI/tests/src/com/android/systemui/IconPackOverlayTest.java
new file mode 100644
index 0000000000000..ccc9afcd4296b
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/IconPackOverlayTest.java
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 2019 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.systemui;
+
+import static junit.framework.Assert.fail;
+
+import static org.junit.Assert.assertEquals;
+
+import android.annotation.DrawableRes;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.content.res.XmlResourceParser;
+import android.text.TextUtils;
+import android.util.TypedValue;
+
+import androidx.test.filters.MediumTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.internal.util.XmlUtils;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+
+@RunWith(AndroidJUnit4.class)
+@MediumTest
+public class IconPackOverlayTest extends SysuiTestCase {
+
+ private static final String[] ICON_PACK_OVERLAY_PACKAGES = {
+ "com.android.theme.icon_pack.circular.systemui",
+ "com.android.theme.icon_pack.rounded.systemui",
+ "com.android.theme.icon_pack.filled.systemui",
+ };
+
+ private static final int[] VECTOR_ATTRIBUTES = {
+ android.R.attr.tint,
+ android.R.attr.height,
+ android.R.attr.width,
+ android.R.attr.alpha,
+ android.R.attr.autoMirrored,
+ };
+
+ private final TypedValue mTargetTypedValue = new TypedValue();
+ private final TypedValue mOverlayTypedValue = new TypedValue();
+
+ private Resources mResources;
+ private TypedArray mOverlayableIcons;
+
+ @Before
+ public void setup() {
+ mResources = mContext.getResources();
+ mOverlayableIcons = mResources.obtainTypedArray(R.array.overlayable_icons);
+ }
+
+ @After
+ public void teardown() {
+ mOverlayableIcons.recycle();
+ }
+
+ /**
+ * Ensure that all icons contained in overlayable_icons_test.xml exist in all 3 overlay icon
+ * packs for systemui. This test fails if you remove or rename an overlaid icon. If so,
+ * make the same change to the corresponding drawables in {@link #ICON_PACK_OVERLAY_PACKAGES}.
+ */
+ @Test
+ public void testIconPack_containAllOverlayedIcons() {
+ StringBuilder errors = new StringBuilder();
+
+ for (String overlayPackage : ICON_PACK_OVERLAY_PACKAGES) {
+ Resources overlayResources;
+ try {
+ overlayResources = mContext.getPackageManager()
+ .getResourcesForApplication(overlayPackage);
+ } catch (PackageManager.NameNotFoundException e) {
+ continue; // No need to test overlay resources if apk is not on the system.
+ }
+
+ for (int i = 0; i < mOverlayableIcons.length(); i++) {
+ int sysuiRid = mOverlayableIcons.getResourceId(i, 0);
+ String sysuiResourceName = mResources.getResourceName(sysuiRid);
+ String overlayResourceName = sysuiResourceName
+ .replace(mContext.getPackageName(), overlayPackage);
+ if (overlayResources.getIdentifier(overlayResourceName, null, null)
+ == Resources.ID_NULL) {
+ errors.append(String.format("[%s] is not contained in overlay package [%s]",
+ overlayResourceName, overlayPackage));
+ }
+ }
+ }
+
+ if (!TextUtils.isEmpty(errors)) {
+ fail(errors.toString());
+ }
+ }
+
+ /**
+ * Ensures that all overlay icons have the same values for {@link #VECTOR_ATTRIBUTES} as the
+ * underlying drawable in systemui. To fix this test, make the attribute change to all of the
+ * corresponding drawables in {@link #ICON_PACK_OVERLAY_PACKAGES}.
+ */
+ @Test
+ public void testIconPacks_haveEqualVectorDrawableAttributes() {
+ StringBuilder errors = new StringBuilder();
+
+ for (String overlayPackage : ICON_PACK_OVERLAY_PACKAGES) {
+ Resources overlayResources;
+ try {
+ overlayResources = mContext.getPackageManager()
+ .getResourcesForApplication(overlayPackage);
+ } catch (PackageManager.NameNotFoundException e) {
+ continue; // No need to test overlay resources if apk is not on the system.
+ }
+
+ for (int i = 0; i < mOverlayableIcons.length(); i++) {
+ int sysuiRid = mOverlayableIcons.getResourceId(i, 0);
+ String sysuiResourceName = mResources.getResourceName(sysuiRid);
+ TypedArray sysuiAttrs = getAVDAttributes(mResources, sysuiRid);
+ if (sysuiAttrs == null) {
+ errors.append(String.format("[%s] does not exist or is not a valid AVD.",
+ sysuiResourceName));
+ continue;
+ }
+
+ String overlayResourceName = sysuiResourceName
+ .replace(mContext.getPackageName(), overlayPackage);
+ int overlayRid = overlayResources.getIdentifier(overlayResourceName, null, null);
+ TypedArray overlayAttrs = getAVDAttributes(overlayResources, overlayRid);
+ if (overlayAttrs == null) {
+ errors.append(String.format("[%s] does not exist or is not a valid AVD.",
+ overlayResourceName));
+ continue;
+ }
+
+ if (!attributesEquals(sysuiAttrs, overlayAttrs)) {
+ errors.append(String.format("[%s] AVD attributes do not match [%s]\n",
+ sysuiResourceName, overlayResourceName));
+ }
+ sysuiAttrs.recycle();
+ overlayAttrs.recycle();
+ }
+ }
+
+ if (!TextUtils.isEmpty(errors)) {
+ fail(errors.toString());
+ }
+ }
+
+ private TypedArray getAVDAttributes(Resources resources, @DrawableRes int rid) {
+ try {
+ XmlResourceParser parser = resources.getXml(rid);
+ XmlUtils.nextElement(parser);
+ return resources.obtainAttributes(parser, VECTOR_ATTRIBUTES);
+ } catch (XmlPullParserException | IOException | Resources.NotFoundException e) {
+ return null;
+ }
+ }
+
+ private boolean attributesEquals(TypedArray target, TypedArray overlay) {
+ assertEquals(target.length(), overlay.length());
+ for (int i = 0; i < target.length(); i++) {
+ target.getValue(i, mTargetTypedValue);
+ overlay.getValue(i, mOverlayTypedValue);
+ if (!attributesEquals(mTargetTypedValue, mOverlayTypedValue)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private boolean attributesEquals(TypedValue target, TypedValue overlay) {
+ return target.type == overlay.type && target.data == overlay.data;
+ }
+}
diff --git a/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/perm_group_aural.xml b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/perm_group_aural.xml
new file mode 100644
index 0000000000000..64802640a9ec5
--- /dev/null
+++ b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/perm_group_aural.xml
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_settings_disable.xml b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_settings_disable.xml
new file mode 100644
index 0000000000000..0572fb72f82e8
--- /dev/null
+++ b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_settings_disable.xml
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_settings_enable.xml b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_settings_enable.xml
new file mode 100644
index 0000000000000..41962b27b2702
--- /dev/null
+++ b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_settings_enable.xml
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_sync_problem_24dp.xml b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_sync_problem_24dp.xml
new file mode 100644
index 0000000000000..a0233ba8acc9a
--- /dev/null
+++ b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_sync_problem_24dp.xml
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/perm_group_aural.xml b/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/perm_group_aural.xml
new file mode 100644
index 0000000000000..3f5c75b66f4cd
--- /dev/null
+++ b/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/perm_group_aural.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_settings_disable.xml b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_settings_disable.xml
new file mode 100644
index 0000000000000..b816e4e838fe9
--- /dev/null
+++ b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_settings_disable.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_settings_enable.xml b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_settings_enable.xml
new file mode 100644
index 0000000000000..d0b6209b38ad5
--- /dev/null
+++ b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_settings_enable.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_sync_problem_24dp.xml b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_sync_problem_24dp.xml
new file mode 100644
index 0000000000000..f2dd9e818fc40
--- /dev/null
+++ b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_sync_problem_24dp.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/perm_group_aural.xml b/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/perm_group_aural.xml
new file mode 100644
index 0000000000000..8cd240d47b2d1
--- /dev/null
+++ b/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/perm_group_aural.xml
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_settings_disable.xml b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_settings_disable.xml
new file mode 100644
index 0000000000000..0572fb72f82e8
--- /dev/null
+++ b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_settings_disable.xml
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_settings_enable.xml b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_settings_enable.xml
new file mode 100644
index 0000000000000..ec608cdf67dd1
--- /dev/null
+++ b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_settings_enable.xml
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_sync_problem_24dp.xml b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_sync_problem_24dp.xml
new file mode 100644
index 0000000000000..e9a07cc3b9883
--- /dev/null
+++ b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_sync_problem_24dp.xml
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
\ No newline at end of file