OSDN Git Service

Moving the inflation to the background
authorSelim Cinek <cinek@google.com>
Fri, 28 Apr 2017 22:03:48 +0000 (15:03 -0700)
committerSelim Cinek <cinek@google.com>
Mon, 1 May 2017 19:53:57 +0000 (12:53 -0700)
The inflation of the notifications is moved to
the background. This should improve the general
performance when adding / removing groups and alike.

Test: runtest systemui
Fixes: 34888292
Change-Id: Ieb19a09a5a97d496d9319d917a5e317a3ad76fc4

packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInflater.java
packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationInflaterTest.java

index 540c391..64f36c6 100644 (file)
@@ -86,7 +86,7 @@ public class NotificationData {
         public List<SnoozeCriterion> snoozeCriteria;
         private int mCachedContrastColor = COLOR_INVALID;
         private int mCachedContrastColorIsFor = COLOR_INVALID;
-        private ArraySet<AsyncTask> mRunningTasks = new ArraySet();
+        private NotificationInflater.AsyncInflationTask mRunningTask = null;
 
         public Entry(StatusBarNotification n) {
             this.key = n.getKey();
@@ -219,23 +219,25 @@ public class NotificationData {
          * Abort all existing inflation tasks
          */
         public void abortInflation() {
-            for (AsyncTask task : mRunningTasks) {
-                task.cancel(true /* mayInterruptIfRunning */);
+            if (mRunningTask != null) {
+                mRunningTask.abort();
+                mRunningTask = null;
             }
-            mRunningTasks.clear();
         }
 
-        public void addInflationTask(AsyncTask asyncInflationTask) {
-            mRunningTasks.add(asyncInflationTask);
+        public void setInflationTask(NotificationInflater.AsyncInflationTask asyncInflationTask) {
+            // abort any existing inflation
+            abortInflation();
+            mRunningTask = asyncInflationTask;
         }
 
-        public void onInflationTaskFinished(AsyncTask asyncInflationTask) {
-            mRunningTasks.remove(asyncInflationTask);
+        public void onInflationTaskFinished() {
+           mRunningTask = null;
         }
 
         @VisibleForTesting
-        public ArraySet<AsyncTask> getRunningTasks() {
-            return mRunningTasks;
+        public AsyncTask getRunningTask() {
+            return mRunningTask;
         }
     }
 
index 7cfc767..a7034c6 100644 (file)
 
 package com.android.systemui.statusbar.notification;
 
+import android.annotation.Nullable;
 import android.app.Notification;
 import android.content.Context;
 import android.os.AsyncTask;
+import android.os.CancellationSignal;
 import android.service.notification.StatusBarNotification;
 import android.util.Log;
 import android.view.View;
@@ -29,6 +31,9 @@ import com.android.systemui.statusbar.ExpandableNotificationRow;
 import com.android.systemui.statusbar.NotificationContentView;
 import com.android.systemui.statusbar.NotificationData;
 import com.android.systemui.statusbar.phone.StatusBar;
+import com.android.systemui.util.Assert;
+
+import java.util.HashMap;
 
 /**
  * A utility that inflates the right kind of contentView based on the state
@@ -116,126 +121,303 @@ public class NotificationInflater {
     @VisibleForTesting
     void inflateNotificationViews(int reInflateFlags) {
         StatusBarNotification sbn = mRow.getEntry().notification;
-        new AsyncInflationTask(mRow.getContext(), sbn, reInflateFlags).execute();
+        new AsyncInflationTask(sbn, reInflateFlags, mRow, mIsLowPriority,
+                mIsChildInGroup, mUsesIncreasedHeight, mUsesIncreasedHeadsUpHeight, mRedactAmbient,
+                mCallback, mRemoteViewClickHandler).execute();
     }
 
     @VisibleForTesting
-    void inflateNotificationViews(int reInflateFlags,
+    InflationProgress inflateNotificationViews(int reInflateFlags,
             Notification.Builder builder, Context packageContext) {
-        NotificationData.Entry entry = mRow.getEntry();
-        NotificationContentView privateLayout = mRow.getPrivateLayout();
-        NotificationContentView publicLayout = mRow.getPublicLayout();
+        InflationProgress result = createRemoteViews(reInflateFlags, builder, mIsLowPriority,
+                mIsChildInGroup, mUsesIncreasedHeight, mUsesIncreasedHeadsUpHeight,
+                mRedactAmbient, packageContext);
+        apply(result, reInflateFlags, mRow, mRedactAmbient, mRemoteViewClickHandler, null);
+        return result;
+    }
 
-        boolean isLowPriority = mIsLowPriority && !mIsChildInGroup;
+    private static InflationProgress createRemoteViews(int reInflateFlags,
+            Notification.Builder builder, boolean isLowPriority, boolean isChildInGroup,
+            boolean usesIncreasedHeight, boolean usesIncreasedHeadsUpHeight, boolean redactAmbient,
+            Context packageContext) {
+        InflationProgress result = new InflationProgress();
+        isLowPriority = isLowPriority && !isChildInGroup;
         if ((reInflateFlags & FLAG_REINFLATE_CONTENT_VIEW) != 0) {
-            final RemoteViews newContentView = createContentView(builder,
-                    isLowPriority, mUsesIncreasedHeight);
-            if (!compareRemoteViews(newContentView,
-                    entry.cachedContentView)) {
-                View contentViewLocal = newContentView.apply(
-                        packageContext,
-                        privateLayout,
-                        mRemoteViewClickHandler);
-                contentViewLocal.setIsRootNamespace(true);
-                privateLayout.setContractedChild(contentViewLocal);
-            } else {
-                newContentView.reapply(packageContext,
-                        privateLayout.getContractedChild(),
-                        mRemoteViewClickHandler);
-            }
-            entry.cachedContentView = newContentView;
+            result.newContentView = createContentView(builder, isLowPriority, usesIncreasedHeight);
         }
 
         if ((reInflateFlags & FLAG_REINFLATE_EXPANDED_VIEW) != 0) {
-            final RemoteViews newBigContentView = createBigContentView(
-                    builder, isLowPriority);
-            if (newBigContentView != null) {
-                if (!compareRemoteViews(newBigContentView, entry.cachedBigContentView)) {
-                    View bigContentViewLocal = newBigContentView.apply(
-                            packageContext,
-                            privateLayout,
-                            mRemoteViewClickHandler);
-                    bigContentViewLocal.setIsRootNamespace(true);
-                    privateLayout.setExpandedChild(bigContentViewLocal);
-                } else {
-                    newBigContentView.reapply(packageContext,
-                            privateLayout.getExpandedChild(),
-                            mRemoteViewClickHandler);
-                }
-            } else if (entry.cachedBigContentView != null) {
-                privateLayout.setExpandedChild(null);
-            }
-            entry.cachedBigContentView = newBigContentView;
-            mRow.setExpandable(newBigContentView != null);
+            result.newExpandedView = createExpandedView(builder, isLowPriority);
         }
 
         if ((reInflateFlags & FLAG_REINFLATE_HEADS_UP_VIEW) != 0) {
-            final RemoteViews newHeadsUpContentView =
-                    builder.createHeadsUpContentView(mUsesIncreasedHeadsUpHeight);
-            if (newHeadsUpContentView != null) {
-                if (!compareRemoteViews(newHeadsUpContentView,
-                        entry.cachedHeadsUpContentView)) {
-                    View headsUpContentViewLocal = newHeadsUpContentView.apply(
-                            packageContext,
-                            privateLayout,
-                            mRemoteViewClickHandler);
-                    headsUpContentViewLocal.setIsRootNamespace(true);
-                    privateLayout.setHeadsUpChild(headsUpContentViewLocal);
-                } else {
-                    newHeadsUpContentView.reapply(packageContext,
-                            privateLayout.getHeadsUpChild(),
-                            mRemoteViewClickHandler);
-                }
-            } else if (entry.cachedHeadsUpContentView != null) {
-                privateLayout.setHeadsUpChild(null);
-            }
-            entry.cachedHeadsUpContentView = newHeadsUpContentView;
+            result.newHeadsUpView = builder.createHeadsUpContentView(usesIncreasedHeadsUpHeight);
         }
 
         if ((reInflateFlags & FLAG_REINFLATE_PUBLIC_VIEW) != 0) {
-            final RemoteViews newPublicNotification
-                    = builder.makePublicContentView();
-            if (!compareRemoteViews(newPublicNotification, entry.cachedPublicContentView)) {
-                View publicContentView = newPublicNotification.apply(
-                        packageContext,
-                        publicLayout,
-                        mRemoteViewClickHandler);
-                publicContentView.setIsRootNamespace(true);
-                publicLayout.setContractedChild(publicContentView);
-            } else {
-                newPublicNotification.reapply(packageContext,
-                        publicLayout.getContractedChild(),
-                        mRemoteViewClickHandler);
-            }
-            entry.cachedPublicContentView = newPublicNotification;
+            result.newPublicView = builder.makePublicContentView();
         }
 
         if ((reInflateFlags & FLAG_REINFLATE_AMBIENT_VIEW) != 0) {
-            final RemoteViews newAmbientNotification = mRedactAmbient
-                    ? builder.makePublicAmbientNotification()
+            result.newAmbientView = redactAmbient ? builder.makePublicAmbientNotification()
                     : builder.makeAmbientNotification();
-            NotificationContentView newParent = mRedactAmbient ? publicLayout : privateLayout;
-            NotificationContentView otherParent = !mRedactAmbient ? publicLayout : privateLayout;
-
-            if (newParent.getAmbientChild() == null ||
-                    !compareRemoteViews(newAmbientNotification, entry.cachedAmbientContentView)) {
-                View ambientContentView = newAmbientNotification.apply(
-                        packageContext,
-                        newParent,
-                        mRemoteViewClickHandler);
-                ambientContentView.setIsRootNamespace(true);
-                newParent.setAmbientChild(ambientContentView);
-                otherParent.setAmbientChild(null);
-            } else {
-                newAmbientNotification.reapply(packageContext,
-                        newParent.getAmbientChild(),
-                        mRemoteViewClickHandler);
+        }
+        result.packageContext = packageContext;
+        return result;
+    }
+
+    public static CancellationSignal apply(InflationProgress result, int reInflateFlags,
+            ExpandableNotificationRow row, boolean redactAmbient,
+            RemoteViews.OnClickHandler remoteViewClickHandler,
+            @Nullable InflationCallback callback) {
+        NotificationData.Entry entry = row.getEntry();
+        NotificationContentView privateLayout = row.getPrivateLayout();
+        NotificationContentView publicLayout = row.getPublicLayout();
+        final HashMap<Integer, CancellationSignal> runningInflations = new HashMap<>();
+
+        int flag = FLAG_REINFLATE_CONTENT_VIEW;
+        if ((reInflateFlags & flag) != 0) {
+            boolean isNewView = !compareRemoteViews(result.newContentView, entry.cachedContentView);
+            ApplyCallback applyCallback = new ApplyCallback() {
+                @Override
+                public void setResultView(View v) {
+                    result.inflatedContentView = v;
+                }
+
+                @Override
+                public RemoteViews getRemoteView() {
+                    return result.newContentView;
+                }
+            };
+            applyRemoteView(result, reInflateFlags, flag, row, redactAmbient,
+                    isNewView, remoteViewClickHandler, callback, entry, privateLayout,
+                    privateLayout.getContractedChild(),
+                    runningInflations, applyCallback);
+        }
+
+        flag = FLAG_REINFLATE_EXPANDED_VIEW;
+        if ((reInflateFlags & flag) != 0) {
+            if (result.newExpandedView != null) {
+                boolean isNewView = !compareRemoteViews(result.newExpandedView,
+                        entry.cachedBigContentView);
+                ApplyCallback applyCallback = new ApplyCallback() {
+                    @Override
+                    public void setResultView(View v) {
+                        result.inflatedExpandedView = v;
+                    }
+
+                    @Override
+                    public RemoteViews getRemoteView() {
+                        return result.newExpandedView;
+                    }
+                };
+                applyRemoteView(result, reInflateFlags, flag, row,
+                        redactAmbient, isNewView, remoteViewClickHandler, callback, entry,
+                        privateLayout, privateLayout.getExpandedChild(), runningInflations,
+                        applyCallback);
+            }
+        }
+
+        flag = FLAG_REINFLATE_HEADS_UP_VIEW;
+        if ((reInflateFlags & flag) != 0) {
+            if (result.newHeadsUpView != null) {
+                boolean isNewView = !compareRemoteViews(result.newHeadsUpView,
+                        entry.cachedHeadsUpContentView);
+                ApplyCallback applyCallback = new ApplyCallback() {
+                    @Override
+                    public void setResultView(View v) {
+                        result.inflatedHeadsUpView = v;
+                    }
+
+                    @Override
+                    public RemoteViews getRemoteView() {
+                        return result.newHeadsUpView;
+                    }
+                };
+                applyRemoteView(result, reInflateFlags, flag, row,
+                        redactAmbient, isNewView, remoteViewClickHandler, callback, entry,
+                        privateLayout, privateLayout.getHeadsUpChild(), runningInflations,
+                        applyCallback);
             }
-            entry.cachedAmbientContentView = newAmbientNotification;
         }
+
+        flag = FLAG_REINFLATE_PUBLIC_VIEW;
+        if ((reInflateFlags & flag) != 0) {
+            boolean isNewView = !compareRemoteViews(result.newPublicView,
+                    entry.cachedPublicContentView);
+            ApplyCallback applyCallback = new ApplyCallback() {
+                @Override
+                public void setResultView(View v) {
+                    result.inflatedPublicView = v;
+                }
+
+                @Override
+                public RemoteViews getRemoteView() {
+                    return result.newPublicView;
+                }
+            };
+            applyRemoteView(result, reInflateFlags, flag, row,
+                    redactAmbient, isNewView, remoteViewClickHandler, callback, entry,
+                    publicLayout, publicLayout.getContractedChild(), runningInflations,
+                    applyCallback);
+        }
+
+        flag = FLAG_REINFLATE_AMBIENT_VIEW;
+        if ((reInflateFlags & flag) != 0) {
+            NotificationContentView newParent = redactAmbient ? publicLayout : privateLayout;
+            boolean isNewView = !canReapplyAmbient(row, redactAmbient) ||
+                    !compareRemoteViews(result.newAmbientView, entry.cachedAmbientContentView);
+            ApplyCallback applyCallback = new ApplyCallback() {
+                @Override
+                public void setResultView(View v) {
+                    result.inflatedAmbientView = v;
+                }
+
+                @Override
+                public RemoteViews getRemoteView() {
+                    return result.newAmbientView;
+                }
+            };
+            applyRemoteView(result, reInflateFlags, flag, row,
+                    redactAmbient, isNewView, remoteViewClickHandler, callback, entry,
+                    newParent, newParent.getAmbientChild(), runningInflations,
+                    applyCallback);
+        }
+
+        // Let's try to finish, maybe nobody is even inflating anything
+        finishIfDone(result, reInflateFlags, runningInflations, callback, row,
+                redactAmbient);
+        CancellationSignal cancellationSignal = new CancellationSignal();
+        cancellationSignal.setOnCancelListener(
+                () -> runningInflations.values().forEach(CancellationSignal::cancel));
+        return cancellationSignal;
+    }
+
+    private static void applyRemoteView(final InflationProgress result,
+            final int reInflateFlags, int inflationId,
+            final ExpandableNotificationRow row,
+            final boolean redactAmbient, boolean isNewView,
+            RemoteViews.OnClickHandler remoteViewClickHandler,
+            @Nullable final InflationCallback callback, NotificationData.Entry entry,
+            NotificationContentView parentLayout, View existingView,
+            final HashMap<Integer, CancellationSignal> runningInflations,
+            ApplyCallback applyCallback) {
+        RemoteViews.OnViewAppliedListener listener
+                = new RemoteViews.OnViewAppliedListener() {
+
+            @Override
+            public void onViewApplied(View v) {
+                if (isNewView) {
+                    v.setIsRootNamespace(true);
+                    applyCallback.setResultView(v);
+                }
+                runningInflations.remove(inflationId);
+                finishIfDone(result, reInflateFlags, runningInflations, callback, row,
+                        redactAmbient);
+            }
+
+            @Override
+            public void onError(Exception e) {
+                runningInflations.remove(inflationId);
+                handleInflationError(runningInflations, e, entry.notification, callback);
+            }
+        };
+        CancellationSignal cancellationSignal;
+        RemoteViews newContentView = applyCallback.getRemoteView();
+        if (isNewView) {
+            cancellationSignal = newContentView.applyAsync(
+                    result.packageContext,
+                    parentLayout,
+                    null /* executor */,
+                    listener,
+                    remoteViewClickHandler);
+        } else {
+            cancellationSignal = newContentView.reapplyAsync(
+                    result.packageContext,
+                    existingView,
+                    null /* executor */,
+                    listener,
+                    remoteViewClickHandler);
+        }
+        runningInflations.put(inflationId, cancellationSignal);
     }
 
-    private RemoteViews createBigContentView(Notification.Builder builder,
+    private static void handleInflationError(HashMap<Integer, CancellationSignal> runningInflations,
+            Exception e, StatusBarNotification notification, @Nullable InflationCallback callback) {
+        Assert.isMainThread();
+        runningInflations.values().forEach(CancellationSignal::cancel);
+        if (callback != null) {
+            callback.handleInflationException(notification, e);
+        }
+    }
+
+    /**
+     * Finish the inflation of the views
+     *
+     * @return true if the inflation was finished
+     */
+    private static boolean finishIfDone(InflationProgress result, int reInflateFlags,
+            HashMap<Integer, CancellationSignal> runningInflations,
+            @Nullable InflationCallback endListener, ExpandableNotificationRow row,
+            boolean redactAmbient) {
+        Assert.isMainThread();
+        NotificationData.Entry entry = row.getEntry();
+        NotificationContentView privateLayout = row.getPrivateLayout();
+        NotificationContentView publicLayout = row.getPublicLayout();
+        if (runningInflations.isEmpty()) {
+            if ((reInflateFlags & FLAG_REINFLATE_CONTENT_VIEW) != 0) {
+                if (result.inflatedContentView != null) {
+                    privateLayout.setContractedChild(result.inflatedContentView);
+                }
+                entry.cachedContentView = result.newContentView;
+            }
+
+            if ((reInflateFlags & FLAG_REINFLATE_EXPANDED_VIEW) != 0) {
+                if (result.inflatedExpandedView != null) {
+                    privateLayout.setExpandedChild(result.inflatedExpandedView);
+                } else if (result.newExpandedView == null) {
+                    privateLayout.setExpandedChild(null);
+                }
+                entry.cachedBigContentView = result.newExpandedView;
+                row.setExpandable(result.newExpandedView != null);
+            }
+
+            if ((reInflateFlags & FLAG_REINFLATE_HEADS_UP_VIEW) != 0) {
+                if (result.inflatedHeadsUpView != null) {
+                    privateLayout.setHeadsUpChild(result.inflatedHeadsUpView);
+                } else if (result.newHeadsUpView == null) {
+                    privateLayout.setHeadsUpChild(null);
+                }
+                entry.cachedHeadsUpContentView = result.newHeadsUpView;
+            }
+
+            if ((reInflateFlags & FLAG_REINFLATE_PUBLIC_VIEW) != 0) {
+                if (result.inflatedPublicView != null) {
+                    publicLayout.setContractedChild(result.inflatedPublicView);
+                }
+                entry.cachedPublicContentView = result.newPublicView;
+            }
+
+            if ((reInflateFlags & FLAG_REINFLATE_AMBIENT_VIEW) != 0) {
+                if (result.inflatedAmbientView != null) {
+                    NotificationContentView newParent = redactAmbient
+                            ? publicLayout : privateLayout;
+                    NotificationContentView otherParent = !redactAmbient
+                            ? publicLayout : privateLayout;
+                    newParent.setAmbientChild(result.inflatedAmbientView);
+                    otherParent.setAmbientChild(null);
+                }
+                entry.cachedAmbientContentView = result.newAmbientView;
+            }
+            if (endListener != null) {
+                endListener.onAsyncInflationFinished(row.getEntry());
+            }
+            return true;
+        }
+        return false;
+    }
+
+    private static RemoteViews createExpandedView(Notification.Builder builder,
             boolean isLowPriority) {
         RemoteViews bigContentView = builder.createBigContentView();
         if (bigContentView != null) {
@@ -249,7 +431,7 @@ public class NotificationInflater {
         return null;
     }
 
-    private RemoteViews createContentView(Notification.Builder builder,
+    private static RemoteViews createContentView(Notification.Builder builder,
             boolean isLowPriority, boolean useLarge) {
         if (isLowPriority) {
             return builder.makeLowPriorityContentView(false /* useRegularSubtext */);
@@ -258,7 +440,7 @@ public class NotificationInflater {
     }
 
     // Returns true if the RemoteViews are the same.
-    private boolean compareRemoteViews(final RemoteViews a, final RemoteViews b) {
+    private static boolean compareRemoteViews(final RemoteViews a, final RemoteViews b) {
         return (a == null && b == null) ||
                 (a != null && b != null
                         && b.getPackage() != null
@@ -272,7 +454,7 @@ public class NotificationInflater {
     }
 
     public interface InflationCallback {
-        void handleInflationException(StatusBarNotification notification, InflationException e);
+        void handleInflationException(StatusBarNotification notification, Exception e);
         void onAsyncInflationFinished(NotificationData.Entry entry);
     }
 
@@ -286,37 +468,68 @@ public class NotificationInflater {
         inflateNotificationViews();
     }
 
-    private class AsyncInflationTask extends AsyncTask<Void, Void, Notification.Builder> {
+    private static boolean canReapplyAmbient(ExpandableNotificationRow row, boolean redactAmbient) {
+        NotificationContentView ambientView = redactAmbient ? row.getPublicLayout()
+                : row.getPrivateLayout();            ;
+        return ambientView.getAmbientChild() != null;
+    }
+
+    public static class AsyncInflationTask extends AsyncTask<Void, Void, InflationProgress>
+            implements InflationCallback {
 
         private final StatusBarNotification mSbn;
         private final Context mContext;
         private final int mReInflateFlags;
-        private Context mPackageContext = null;
+        private final boolean mIsLowPriority;
+        private final boolean mIsChildInGroup;
+        private final boolean mUsesIncreasedHeight;
+        private final InflationCallback mCallback;
+        private final boolean mUsesIncreasedHeadsUpHeight;
+        private final boolean mRedactAmbient;
+        private ExpandableNotificationRow mRow;
         private Exception mError;
-
-        private AsyncInflationTask(Context context, StatusBarNotification notification,
-                int reInflateFlags) {
+        private RemoteViews.OnClickHandler mRemoteViewClickHandler;
+        private CancellationSignal mCancellationSignal;
+
+        private AsyncInflationTask(StatusBarNotification notification,
+                int reInflateFlags, ExpandableNotificationRow row, boolean isLowPriority,
+                boolean isChildInGroup, boolean usesIncreasedHeight,
+                boolean usesIncreasedHeadsUpHeight, boolean redactAmbient,
+                InflationCallback callback,
+                RemoteViews.OnClickHandler remoteViewClickHandler) {
+            mRow = row;
+            NotificationData.Entry entry = row.getEntry();
+            entry.setInflationTask(this);
             mSbn = notification;
-            mContext = context;
             mReInflateFlags = reInflateFlags;
-            mRow.getEntry().addInflationTask(this);
+            mContext = mRow.getContext();
+            mIsLowPriority = isLowPriority;
+            mIsChildInGroup = isChildInGroup;
+            mUsesIncreasedHeight = usesIncreasedHeight;
+            mUsesIncreasedHeadsUpHeight = usesIncreasedHeadsUpHeight;
+            mRedactAmbient = redactAmbient;
+            mRemoteViewClickHandler = remoteViewClickHandler;
+            mCallback = callback;
         }
 
         @Override
-        protected Notification.Builder doInBackground(Void... params) {
+        protected InflationProgress doInBackground(Void... params) {
             try {
                 final Notification.Builder recoveredBuilder
                         = Notification.Builder.recoverBuilder(mContext,
                         mSbn.getNotification());
-                mPackageContext = mSbn.getPackageContext(mContext);
+                Context packageContext = mSbn.getPackageContext(mContext);
                 Notification notification = mSbn.getNotification();
                 if (notification.isMediaNotification()) {
                     MediaNotificationProcessor processor = new MediaNotificationProcessor(mContext,
-                            mPackageContext);
+                            packageContext);
                     processor.setIsLowPriority(mIsLowPriority);
                     processor.processNotification(notification, recoveredBuilder);
                 }
-                return recoveredBuilder;
+                return createRemoteViews(mReInflateFlags,
+                        recoveredBuilder, mIsLowPriority, mIsChildInGroup,
+                        mUsesIncreasedHeight, mUsesIncreasedHeadsUpHeight, mRedactAmbient,
+                        packageContext);
             } catch (Exception e) {
                 mError = e;
                 return null;
@@ -324,34 +537,63 @@ public class NotificationInflater {
         }
 
         @Override
-        protected void onPostExecute(Notification.Builder builder) {
-            mRow.getEntry().onInflationTaskFinished(this);
+        protected void onPostExecute(InflationProgress result) {
             if (mError == null) {
-                finishInflation(mReInflateFlags, builder, mPackageContext);
+                mCancellationSignal = apply(result, mReInflateFlags, mRow, mRedactAmbient,
+                        mRemoteViewClickHandler, this);
             } else {
                 handleError(mError);
             }
         }
-    }
 
-    private void finishInflation(int reinflationFlags, Notification.Builder builder,
-            Context context) {
-        try {
-            inflateNotificationViews(reinflationFlags, builder, context);
-        } catch (RuntimeException e){
+        private void handleError(Exception e) {
+            mRow.getEntry().onInflationTaskFinished();
+            StatusBarNotification sbn = mRow.getStatusBarNotification();
+            final String ident = sbn.getPackageName() + "/0x"
+                    + Integer.toHexString(sbn.getId());
+            Log.e(StatusBar.TAG, "couldn't inflate view for notification " + ident, e);
+            mCallback.handleInflationException(sbn,
+                    new InflationException("Couldn't inflate contentViews" + e));
+        }
+
+        public void abort() {
+            cancel(true /* mayInterruptIfRunning */);
+            if (mCancellationSignal != null) {
+                mCancellationSignal.cancel();
+            }
+        }
+
+        @Override
+        public void handleInflationException(StatusBarNotification notification, Exception e) {
             handleError(e);
-            return;
         }
-        mRow.onNotificationUpdated();
-        mCallback.onAsyncInflationFinished(mRow.getEntry());
+
+        @Override
+        public void onAsyncInflationFinished(NotificationData.Entry entry) {
+            mRow.getEntry().onInflationTaskFinished();
+            mRow.onNotificationUpdated();
+            mCallback.onAsyncInflationFinished(mRow.getEntry());
+        }
+    }
+
+    private static class InflationProgress {
+        private RemoteViews newContentView;
+        private RemoteViews newHeadsUpView;
+        private RemoteViews newExpandedView;
+        private RemoteViews newAmbientView;
+        private RemoteViews newPublicView;
+
+        private Context packageContext;
+
+        private View inflatedContentView;
+        private View inflatedHeadsUpView;
+        private View inflatedExpandedView;
+        private View inflatedAmbientView;
+        private View inflatedPublicView;
     }
 
-    private void handleError(Exception e) {
-        StatusBarNotification sbn = mRow.getStatusBarNotification();
-        final String ident = sbn.getPackageName() + "/0x"
-                + Integer.toHexString(sbn.getId());
-        Log.e(StatusBar.TAG, "couldn't inflate view for notification " + ident, e);
-        mCallback.handleInflationException(sbn,
-                new InflationException("Couldn't inflate contentViews" + e));
+    private abstract static class ApplyCallback {
+        public abstract void setResultView(View v);
+        public abstract RemoteViews getRemoteView();
     }
 }
index c1859fe..2e6af75 100644 (file)
@@ -1610,7 +1610,7 @@ public class StatusBar extends SystemUI implements DemoMode,
     }
 
     @Override
-    public void handleInflationException(StatusBarNotification notification, InflationException e) {
+    public void handleInflationException(StatusBarNotification notification, Exception e) {
         handleNotificationError(notification, e.getMessage());
     }
 
index fbb25e5..5e8ea9c 100644 (file)
@@ -26,6 +26,7 @@ import android.app.Notification;
 import android.content.Context;
 import android.service.notification.StatusBarNotification;
 import android.support.test.InstrumentationRegistry;
+import android.support.test.annotation.UiThreadTest;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
 import android.widget.RemoteViews;
@@ -41,7 +42,6 @@ import org.junit.Test;
 import org.junit.runner.RunWith;
 
 import java.util.concurrent.CountDownLatch;
-import java.util.function.Function;
 
 @SmallTest
 @RunWith(AndroidJUnit4.class)
@@ -67,7 +67,7 @@ public class NotificationInflaterTest {
         mNotificationInflater.setInflationCallback(new NotificationInflater.InflationCallback() {
             @Override
             public void handleInflationException(StatusBarNotification notification,
-                    InflationException e) {
+                    Exception e) {
             }
 
             @Override
@@ -77,6 +77,7 @@ public class NotificationInflaterTest {
     }
 
     @Test
+    @UiThreadTest
     public void testIncreasedHeadsUpBeingUsed() {
         mNotificationInflater.setUsesIncreasedHeadsUpHeight(true);
         Notification.Builder builder = spy(mBuilder);
@@ -85,6 +86,7 @@ public class NotificationInflaterTest {
     }
 
     @Test
+    @UiThreadTest
     public void testIncreasedHeightBeingUsed() {
         mNotificationInflater.setUsesIncreasedHeight(true);
         Notification.Builder builder = spy(mBuilder);
@@ -127,7 +129,7 @@ public class NotificationInflaterTest {
         mRow.getEntry().abortInflation();
         runThenWaitForInflation(() -> mNotificationInflater.inflateNotificationViews(),
                 mNotificationInflater);
-        Assert.assertTrue(mRow.getEntry().getRunningTasks().size() == 0);
+        Assert.assertNull(mRow.getEntry().getRunningTask() );
     }
 
     public static void runThenWaitForInflation(Runnable block,
@@ -143,7 +145,7 @@ public class NotificationInflaterTest {
         inflater.setInflationCallback(new NotificationInflater.InflationCallback() {
             @Override
             public void handleInflationException(StatusBarNotification notification,
-                    InflationException e) {
+                    Exception e) {
                 if (!expectingException) {
                     exceptionHolder.setException(e);
                 }