Adding API to check if an icon returned by PackageManager
is a fallback icon

Bug: 141588119
Test: atest PackageManagerTest
Change-Id: I9ae5a74dd0b0c0c49a078d46914986ecb0d27a94
diff --git a/api/current.txt b/api/current.txt
index d5ece2e..6d0c510 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -11842,6 +11842,7 @@
     method public boolean hasSigningCertificate(int, @NonNull byte[], int);
     method public abstract boolean hasSystemFeature(@NonNull String);
     method public abstract boolean hasSystemFeature(@NonNull String, int);
+    method public boolean isDefaultApplicationIcon(@NonNull android.graphics.drawable.Drawable);
     method public boolean isDeviceUpgrading();
     method public abstract boolean isInstantApp();
     method public abstract boolean isInstantApp(@NonNull String);
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 1f502a1..05e42bf 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -50,6 +50,7 @@
 import android.content.res.Resources;
 import android.content.res.XmlResourceParser;
 import android.graphics.Rect;
+import android.graphics.drawable.AdaptiveIconDrawable;
 import android.graphics.drawable.Drawable;
 import android.net.wifi.WifiManager;
 import android.os.Build;
@@ -7619,4 +7620,19 @@
             "sendDeviceCustomizationReadyBroadcast not implemented in subclass");
     }
 
+    /**
+     * Returns if the provided drawable represents the default activity icon provided by the system.
+     *
+     * PackageManager provides a default icon for any package/activity if the app itself does not
+     * define one or if the system encountered any error when loading the icon.
+     *
+     * @return true if the drawable represents the default activity icon, false otherwise
+     * @see #getDefaultActivityIcon()
+     */
+    public boolean isDefaultApplicationIcon(@NonNull Drawable drawable) {
+        int resId = drawable instanceof AdaptiveIconDrawable
+                ? ((AdaptiveIconDrawable) drawable).getSourceDrawableResId() : Resources.ID_NULL;
+        return resId == com.android.internal.R.drawable.sym_def_app_icon
+                || resId == com.android.internal.R.drawable.sym_app_on_sd_unavailable_icon;
+    }
 }
diff --git a/graphics/java/android/graphics/drawable/AdaptiveIconDrawable.java b/graphics/java/android/graphics/drawable/AdaptiveIconDrawable.java
index fab96a1..928e607 100644
--- a/graphics/java/android/graphics/drawable/AdaptiveIconDrawable.java
+++ b/graphics/java/android/graphics/drawable/AdaptiveIconDrawable.java
@@ -16,6 +16,7 @@
 
 package android.graphics.drawable;
 
+import android.annotation.DrawableRes;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.TestApi;
@@ -223,6 +224,7 @@
         final int deviceDensity = Drawable.resolveDensity(r, 0);
         state.setDensity(deviceDensity);
         state.mSrcDensityOverride = mSrcDensityOverride;
+        state.mSourceDrawableId = Resources.getAttributeSetSourceResId(attrs);
 
         final ChildDrawable[] array = state.mChildren;
         for (int i = 0; i < state.mChildren.length; i++) {
@@ -446,6 +448,17 @@
     }
 
     /**
+     * If the drawable was inflated from XML, this returns the resource ID for the drawable
+     *
+     * @hide
+     */
+    @DrawableRes
+    public int getSourceDrawableResId() {
+        final LayerState state = mLayerState;
+        return state == null ? Resources.ID_NULL : state.mSourceDrawableId;
+    }
+
+    /**
      * Inflates child layers using the specified parser.
      */
     private void inflateLayers(@NonNull Resources r, @NonNull XmlPullParser parser,
@@ -944,6 +957,8 @@
         @Config int mChangingConfigurations;
         @Config int mChildrenChangingConfigurations;
 
+        @DrawableRes int mSourceDrawableId = Resources.ID_NULL;
+
         private boolean mCheckedOpacity;
         private int mOpacity;