Merge "[Notif] Cache bool instead of manager/info" into pi-dev
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index 3ece2f9..58bc4dd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -35,6 +35,7 @@
 import android.graphics.drawable.AnimationDrawable;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
+import android.os.AsyncTask;
 import android.os.Build;
 import android.os.Bundle;
 import android.service.notification.StatusBarNotification;
@@ -100,13 +101,17 @@
 public class ExpandableNotificationRow extends ActivatableNotificationView
         implements PluginListener<NotificationMenuRowPlugin> {
 
+    private static final boolean DEBUG = false;
     private static final int DEFAULT_DIVIDER_ALPHA = 0x29;
     private static final int COLORED_DIVIDER_ALPHA = 0x7B;
     private static final int MENU_VIEW_INDEX = 0;
     private static final String TAG = "ExpandableNotifRow";
 
+    /**
+     * Listener for when {@link ExpandableNotificationRow} is laid out.
+     */
     public interface LayoutListener {
-        public void onLayout();
+        void onLayout();
     }
 
     private LayoutListener mLayoutListener;
@@ -174,8 +179,11 @@
     private NotificationGuts mGuts;
     private NotificationData.Entry mEntry;
     private StatusBarNotification mStatusBarNotification;
-    private PackageManager mCachedPackageManager;
-    private PackageInfo mCachedPackageInfo;
+    /**
+     * Whether or not this row represents a system notification. Note that if this is {@code null},
+     * that means we were either unable to retrieve the info or have yet to retrieve the info.
+     */
+    private Boolean mIsSystemNotification;
     private String mAppName;
     private boolean mIsHeadsUp;
     private boolean mLastChronometerRunning = true;
@@ -271,7 +279,7 @@
                 public Float get(ExpandableNotificationRow object) {
                     return object.getTranslation();
                 }
-    };
+            };
     private OnClickListener mOnClickListener;
     private boolean mHeadsupDisappearRunning;
     private View mChildAfterViewWhenDismissed;
@@ -292,6 +300,33 @@
     private int mNotificationColorAmbient;
     private NotificationViewState mNotificationViewState;
 
+    private SystemNotificationAsyncTask mSystemNotificationAsyncTask =
+            new SystemNotificationAsyncTask();
+
+    /**
+     * Returns whether the given {@code statusBarNotification} is a system notification.
+     * <b>Note</b>, this should be run in the background thread if possible as it makes multiple IPC
+     * calls.
+     */
+    private static Boolean isSystemNotification(
+            Context context, StatusBarNotification statusBarNotification) {
+        PackageManager packageManager = StatusBar.getPackageManagerForUser(
+                context, statusBarNotification.getUser().getIdentifier());
+        Boolean isSystemNotification = null;
+
+        try {
+            PackageInfo packageInfo = packageManager.getPackageInfo(
+                    statusBarNotification.getPackageName(), PackageManager.GET_SIGNATURES);
+
+            isSystemNotification =
+                    com.android.settingslib.Utils.isSystemPackage(
+                            context.getResources(), packageManager, packageInfo);
+        } catch (PackageManager.NameNotFoundException e) {
+            Log.e(TAG, "cacheIsSystemNotification: Could not find package info");
+        }
+        return isSystemNotification;
+    }
+
     @Override
     public boolean isGroupExpansionChanging() {
         if (isChildInGroup()) {
@@ -383,21 +418,19 @@
         mStatusBarNotification = entry.notification;
         mNotificationInflater.inflateNotificationViews();
 
-        perhapsCachePackageInfo();
+        cacheIsSystemNotification();
     }
 
     /**
-     * Caches the package manager and info objects which are expensive to obtain.
+     * Caches whether or not this row contains a system notification. Note, this is only cached
+     * once per notification as the packageInfo can't technically change for a notification row.
      */
-    private void perhapsCachePackageInfo() {
-        if (mCachedPackageInfo == null) {
-            mCachedPackageManager = StatusBar.getPackageManagerForUser(
-                    mContext, mStatusBarNotification.getUser().getIdentifier());
-            try {
-                mCachedPackageInfo = mCachedPackageManager.getPackageInfo(
-                        mStatusBarNotification.getPackageName(), PackageManager.GET_SIGNATURES);
-            } catch (PackageManager.NameNotFoundException e) {
-                Log.e(TAG, "perhapsCachePackageInfo: Could not find package info");
+    private void cacheIsSystemNotification() {
+        if (mIsSystemNotification == null) {
+            if (mSystemNotificationAsyncTask.getStatus() == AsyncTask.Status.PENDING) {
+                // Run async task once, only if it hasn't already been executed. Note this is
+                // executed in serial - no need to parallelize this small task.
+                mSystemNotificationAsyncTask.execute();
             }
         }
     }
@@ -407,9 +440,7 @@
      * covers multiple channels, or is in a whitelist).
      */
     public boolean getIsNonblockable() {
-        boolean isNonblockable;
-
-        isNonblockable = Dependency.get(NotificationBlockingHelperManager.class)
+        boolean isNonblockable = Dependency.get(NotificationBlockingHelperManager.class)
                 .isNonblockablePackage(mStatusBarNotification.getPackageName());
 
         // Only bother with going through the children if the row is still blockable based on the
@@ -418,10 +449,18 @@
             isNonblockable = getNumUniqueChannels() > 1;
         }
 
-        // Only bother with IPC if the package is still blockable.
-        if (!isNonblockable && mCachedPackageManager != null && mCachedPackageInfo != null) {
-            if (com.android.settingslib.Utils.isSystemPackage(
-                    mContext.getResources(), mCachedPackageManager, mCachedPackageInfo)) {
+        // If the SystemNotifAsyncTask hasn't finished running or retrieved a value, we'll try once
+        // again, but in-place on the main thread this time. This should rarely ever get called.
+        if (mIsSystemNotification == null) {
+            if (DEBUG) {
+                Log.d(TAG, "Retrieving isSystemNotification on main thread");
+            }
+            mSystemNotificationAsyncTask.cancel(true /* mayInterruptIfRunning */);
+            mIsSystemNotification = isSystemNotification(mContext, mStatusBarNotification);
+        }
+
+        if (!isNonblockable && mIsSystemNotification != null) {
+            if (mIsSystemNotification) {
                 if (mEntry.channel != null
                         && !mEntry.channel.isBlockableSystem()) {
                     isNonblockable = true;
@@ -2828,4 +2867,21 @@
          */
         boolean onClick(View v, int x, int y, MenuItem item);
     }
+
+    /**
+     * Background task for executing IPCs to check if the notification is a system notification. The
+     * output is used for both the blocking helper and the notification info.
+     */
+    private class SystemNotificationAsyncTask extends AsyncTask<Void, Void, Boolean> {
+
+        @Override
+        protected Boolean doInBackground(Void... voids) {
+            return isSystemNotification(mContext, mStatusBarNotification);
+        }
+
+        @Override
+        protected void onPostExecute(Boolean result) {
+            mIsSystemNotification = result;
+        }
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationBlockingHelperManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationBlockingHelperManagerTest.java
index 78cceeb..b3dddd5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationBlockingHelperManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationBlockingHelperManagerTest.java
@@ -65,6 +65,8 @@
     @Before
     public void setUp() {
         mBlockingHelperManager = new NotificationBlockingHelperManager(mContext);
+        // By default, have the shade visible/expanded.
+        mBlockingHelperManager.setNotificationShadeExpanded(1f);
 
         mHelper = new NotificationTestHelper(mContext);
         when(mGutsManager.openGuts(
@@ -115,7 +117,6 @@
     public void testPerhapsShowBlockingHelper_shown() throws Exception {
         ExpandableNotificationRow row = createBlockableRowSpy();
         row.getEntry().userSentiment = USER_SENTIMENT_NEGATIVE;
-        mBlockingHelperManager.setNotificationShadeExpanded(1f);
 
         assertTrue(mBlockingHelperManager.perhapsShowBlockingHelper(row, mMenuRow));
 
@@ -127,7 +128,6 @@
     public void testPerhapsShowBlockingHelper_shownForLargeGroup() throws Exception {
         ExpandableNotificationRow groupRow = createBlockableGroupRowSpy(10);
         groupRow.getEntry().userSentiment = USER_SENTIMENT_NEGATIVE;
-        mBlockingHelperManager.setNotificationShadeExpanded(1f);
 
         assertTrue(mBlockingHelperManager.perhapsShowBlockingHelper(groupRow, mMenuRow));
 
@@ -143,7 +143,6 @@
         // of the child row.
         ExpandableNotificationRow childRow = groupRow.getChildrenContainer().getViewAtPosition(0);
         childRow.getEntry().userSentiment = USER_SENTIMENT_NEGATIVE;
-        mBlockingHelperManager.setNotificationShadeExpanded(1f);
 
         assertTrue(mBlockingHelperManager.perhapsShowBlockingHelper(childRow, mMenuRow));
 
@@ -154,7 +153,6 @@
     public void testPerhapsShowBlockingHelper_notShownDueToNeutralUserSentiment() throws Exception {
         ExpandableNotificationRow row = createBlockableRowSpy();
         row.getEntry().userSentiment = USER_SENTIMENT_NEUTRAL;
-        mBlockingHelperManager.setNotificationShadeExpanded(1f);
 
         assertFalse(mBlockingHelperManager.perhapsShowBlockingHelper(row, mMenuRow));
     }
@@ -164,7 +162,6 @@
             throws Exception {
         ExpandableNotificationRow row = createBlockableRowSpy();
         row.getEntry().userSentiment = USER_SENTIMENT_POSITIVE;
-        mBlockingHelperManager.setNotificationShadeExpanded(1f);
 
         assertFalse(mBlockingHelperManager.perhapsShowBlockingHelper(row, mMenuRow));
     }
@@ -184,7 +181,6 @@
         ExpandableNotificationRow row = createBlockableRowSpy();
         when(row.getIsNonblockable()).thenReturn(true);
         row.getEntry().userSentiment = USER_SENTIMENT_NEGATIVE;
-        mBlockingHelperManager.setNotificationShadeExpanded(1f);
 
         assertFalse(mBlockingHelperManager.perhapsShowBlockingHelper(row, mMenuRow));
     }
@@ -198,7 +194,6 @@
         // of the child row.
         ExpandableNotificationRow childRow = groupRow.getChildrenContainer().getViewAtPosition(0);
         childRow.getEntry().userSentiment = USER_SENTIMENT_NEGATIVE;
-        mBlockingHelperManager.setNotificationShadeExpanded(1f);
 
         assertFalse(mBlockingHelperManager.perhapsShowBlockingHelper(childRow, mMenuRow));
     }
@@ -208,7 +203,6 @@
         ExpandableNotificationRow row = spy(createBlockableRowSpy());
         row.getEntry().userSentiment = USER_SENTIMENT_NEGATIVE;
         when(row.isAttachedToWindow()).thenReturn(true);
-        mBlockingHelperManager.setNotificationShadeExpanded(1f);
 
         // Show check
         assertTrue(mBlockingHelperManager.perhapsShowBlockingHelper(row, mMenuRow));