Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d5022f97 authored by Kevin's avatar Kevin
Browse files

Fix heads up views freeing too early.

In the previous CL, heads up views were freed while they were still
animating away.  As a result, there could be a sudden shift in the view
the notification uses (most easily reproducible if you tap on a HUN with
actions as the actions disappear).  This CL introduces an API to set a
a listener for when the content view becomes inactive and remove it then.

Bug: 111809944
Test: runtest systemui, manual (HUN with full screen intent, tap, see
that it goes away without visual jank)

Change-Id: Ib27bcf993f6be41aa4fde50b39817004610f5fd4
parent d4660b27
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@

package com.android.systemui.statusbar;

import static com.android.systemui.statusbar.notification.row.NotificationInflater.FLAG_CONTENT_VIEW_AMBIENT;

import android.annotation.NonNull;
import android.content.Context;
import android.content.res.Resources;
@@ -85,6 +87,7 @@ public final class AmbientPulseManager extends AlertingNotificationManager {
        for (OnAmbientChangedListener listener : mListeners) {
            listener.onAmbientStateChanged(entry, false);
        }
        entry.row.freeContentViewWhenSafe(FLAG_CONTENT_VIEW_AMBIENT);
    }

    @Override
+8 −8
Original line number Diff line number Diff line
@@ -19,9 +19,9 @@ import static com.android.systemui.statusbar.NotificationRemoteInputManager.ENAB
import static com.android.systemui.statusbar.NotificationRemoteInputManager
        .FORCE_REMOTE_INPUT_HISTORY;
import static com.android.systemui.statusbar.notification.row.NotificationInflater
        .FLAG_REINFLATE_AMBIENT_VIEW;
        .FLAG_CONTENT_VIEW_AMBIENT;
import static com.android.systemui.statusbar.notification.row.NotificationInflater
        .FLAG_REINFLATE_HEADS_UP_VIEW;
        .FLAG_CONTENT_VIEW_HEADS_UP;

import android.annotation.Nullable;
import android.app.Notification;
@@ -458,7 +458,7 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater.
     */
    private void showAlertingView(NotificationData.Entry entry,
            @InflationFlag int inflatedFlags) {
        if ((inflatedFlags & FLAG_REINFLATE_HEADS_UP_VIEW) != 0) {
        if ((inflatedFlags & FLAG_CONTENT_VIEW_HEADS_UP) != 0) {
            // Possible for shouldHeadsUp to change between the inflation starting and ending.
            // If it does and we no longer need to heads up, we should free the view.
            if (shouldHeadsUp(entry)) {
@@ -466,14 +466,14 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater.
                // Mark as seen immediately
                setNotificationShown(entry.notification);
            } else {
                entry.row.updateInflationFlag(FLAG_REINFLATE_HEADS_UP_VIEW, false);
                entry.row.freeContentViewWhenSafe(FLAG_CONTENT_VIEW_HEADS_UP);
            }
        }
        if ((inflatedFlags & FLAG_REINFLATE_AMBIENT_VIEW) != 0) {
        if ((inflatedFlags & FLAG_CONTENT_VIEW_AMBIENT) != 0) {
            if (shouldPulse(entry)) {
                mAmbientPulseManager.showNotification(entry);
            } else {
                entry.row.updateInflationFlag(FLAG_REINFLATE_AMBIENT_VIEW, false);
                entry.row.freeContentViewWhenSafe(FLAG_CONTENT_VIEW_AMBIENT);
            }
        }
    }
@@ -666,8 +666,8 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater.
        row.setSmartActions(entry.smartActions);
        row.setEntry(entry);

        row.updateInflationFlag(FLAG_REINFLATE_HEADS_UP_VIEW, shouldHeadsUp(entry));
        row.updateInflationFlag(FLAG_REINFLATE_AMBIENT_VIEW, shouldPulse(entry));
        row.updateInflationFlag(FLAG_CONTENT_VIEW_HEADS_UP, shouldHeadsUp(entry));
        row.updateInflationFlag(FLAG_CONTENT_VIEW_AMBIENT, shouldPulse(entry));
        row.inflateViews();
    }

+34 −13
Original line number Diff line number Diff line
@@ -17,10 +17,12 @@
package com.android.systemui.statusbar.notification.row;

import static com.android.systemui.statusbar.notification.ActivityLaunchAnimator.ExpandAnimationParameters;
import static com.android.systemui.statusbar.notification.row.NotificationContentView.VISIBLE_TYPE_AMBIENT;
import static com.android.systemui.statusbar.notification.row.NotificationContentView.VISIBLE_TYPE_HEADSUP;
import static com.android.systemui.statusbar.notification.row.NotificationInflater
        .FLAG_REINFLATE_AMBIENT_VIEW;
        .FLAG_CONTENT_VIEW_AMBIENT;
import static com.android.systemui.statusbar.notification.row.NotificationInflater
        .FLAG_REINFLATE_HEADS_UP_VIEW;
        .FLAG_CONTENT_VIEW_HEADS_UP;
import static com.android.systemui.statusbar.notification.row.NotificationInflater.InflationCallback;

import android.animation.Animator;
@@ -453,6 +455,33 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
        mNotificationInflater.inflateNotificationViews();
    }

    /**
     * Marks a content view as freeable, setting it so that future inflations do not reinflate
     * and ensuring that the view is freed when it is safe to remove.
     *
     * @param inflationFlag flag corresponding to the content view to be freed
     */
    public void freeContentViewWhenSafe(@InflationFlag int inflationFlag) {
        // View should not be reinflated in the future
        updateInflationFlag(inflationFlag, false);
        Runnable freeViewRunnable = () ->
                mNotificationInflater.freeNotificationView(inflationFlag);
        switch (inflationFlag) {
            case FLAG_CONTENT_VIEW_HEADS_UP:
                getPrivateLayout().performWhenContentInactive(VISIBLE_TYPE_HEADSUP,
                        freeViewRunnable);
                break;
            case FLAG_CONTENT_VIEW_AMBIENT:
                getPrivateLayout().performWhenContentInactive(VISIBLE_TYPE_AMBIENT,
                        freeViewRunnable);
                getPublicLayout().performWhenContentInactive(VISIBLE_TYPE_AMBIENT,
                        freeViewRunnable);
                break;
            default:
                break;
        }
    }

    /**
     * Update whether or not a content view should be inflated.
     *
@@ -607,7 +636,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
            headsUpHeight = mMaxHeadsUpHeight;
        }
        NotificationViewWrapper headsUpWrapper = layout.getVisibleWrapper(
                NotificationContentView.VISIBLE_TYPE_HEADSUP);
                VISIBLE_TYPE_HEADSUP);
        if (headsUpWrapper != null) {
            headsUpHeight = Math.max(headsUpHeight, headsUpWrapper.getMinLayoutHeight());
        }
@@ -642,13 +671,9 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
        if (isHeadsUp) {
            mMustStayOnScreen = true;
            setAboveShelf(true);
        } else {
            if (isAboveShelf() != wasAboveShelf) {
        } else if (isAboveShelf() != wasAboveShelf) {
            mAboveShelfChangedListener.onAboveShelfStateChanged(!wasAboveShelf);
        }
            updateInflationFlag(FLAG_REINFLATE_HEADS_UP_VIEW, false);
            mNotificationInflater.freeNotificationView(FLAG_REINFLATE_HEADS_UP_VIEW);
        }
    }

    public boolean isAmbientPulsing() {
@@ -657,10 +682,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView

    public void setAmbientPulsing(boolean isAmbientPulsing) {
        mIsAmbientPulsing = isAmbientPulsing;
        if (!isAmbientPulsing) {
            updateInflationFlag(FLAG_REINFLATE_AMBIENT_VIEW, false);
            mNotificationInflater.freeNotificationView(FLAG_REINFLATE_AMBIENT_VIEW);
        }
    }

    public void setGroupManager(NotificationGroupManager groupManager) {
+58 −0
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ import android.content.Context;
import android.graphics.Rect;
import android.os.Build;
import android.service.notification.StatusBarNotification;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.AttributeSet;
import android.util.Log;
@@ -108,6 +109,10 @@ public class NotificationContentView extends FrameLayout {
    private NotificationGroupManager mGroupManager;
    private RemoteInputController mRemoteInputController;
    private Runnable mExpandedVisibleListener;
    /**
     * List of listeners for when content views become inactive (i.e. not the showing view).
     */
    private final ArrayMap<View, Runnable> mOnContentViewInactiveListeners = new ArrayMap<>();

    private final ViewTreeObserver.OnPreDrawListener mEnableAnimationPredrawListener
            = new ViewTreeObserver.OnPreDrawListener() {
@@ -1171,6 +1176,7 @@ public class NotificationContentView extends FrameLayout {

    public void onNotificationUpdated(NotificationData.Entry entry) {
        mStatusBarNotification = entry.notification;
        mOnContentViewInactiveListeners.clear();
        mBeforeN = entry.targetSdk < Build.VERSION_CODES.N;
        updateAllSingleLineViews();
        if (mContractedChild != null) {
@@ -1628,6 +1634,58 @@ public class NotificationContentView extends FrameLayout {
        fireExpandedVisibleListenerIfVisible();
    }

    /**
     * Set a one-shot listener to run when a given content view becomes inactive.
     *
     * @param visibleType visible type corresponding to the content view to listen
     * @param listener runnable to run once when the content view becomes inactive
     */
    public void performWhenContentInactive(int visibleType, Runnable listener) {
        View view = getViewForVisibleType(visibleType);
        // View is already inactive
        if (view == null || isContentViewInactive(visibleType)) {
            listener.run();
            return;
        }
        mOnContentViewInactiveListeners.put(view, listener);
    }

    /**
     * Whether or not the content view is inactive.  This means it should not be visible
     * or the showing content as removing it would cause visual jank.
     *
     * @param visibleType visible type corresponding to the content view to be removed
     * @return true if the content view is inactive, false otherwise
     */
    public boolean isContentViewInactive(int visibleType) {
        View view = getViewForVisibleType(visibleType);
        return isContentViewInactive(view);
    }

    /**
     * Whether or not the content view is inactive.
     *
     * @param view view to see if its inactive
     * @return true if the view is inactive, false o/w
     */
    private boolean isContentViewInactive(View view) {
        if (view == null) {
            return true;
        }
        return view.getVisibility() != VISIBLE && getViewForVisibleType(mVisibleType) != view;
    }

    @Override
    protected void onChildVisibilityChanged(View child, int oldVisibility, int newVisibility) {
        super.onChildVisibilityChanged(child, oldVisibility, newVisibility);
        if (isContentViewInactive(child)) {
            Runnable listener = mOnContentViewInactiveListeners.remove(child);
            if (listener != null) {
                listener.run();
            }
        }
    }

    public void setIsLowPriority(boolean isLowPriority) {
        mIsLowPriority = isLowPriority;
    }
+75 −54
Original line number Diff line number Diff line
@@ -16,6 +16,9 @@

package com.android.systemui.statusbar.notification.row;

import static com.android.systemui.statusbar.notification.row.NotificationContentView.VISIBLE_TYPE_AMBIENT;
import static com.android.systemui.statusbar.notification.row.NotificationContentView.VISIBLE_TYPE_HEADSUP;

import android.annotation.IntDef;
import android.annotation.Nullable;
import android.app.Notification;
@@ -59,54 +62,54 @@ public class NotificationInflater {

    @Retention(RetentionPolicy.SOURCE)
    @IntDef(flag = true,
            prefix = {"FLAG_REINFLATE_"},
            prefix = {"FLAG_CONTENT_VIEW_"},
            value = {
                FLAG_REINFLATE_CONTENT_VIEW,
                FLAG_REINFLATE_EXPANDED_VIEW,
                FLAG_REINFLATE_HEADS_UP_VIEW,
                FLAG_REINFLATE_AMBIENT_VIEW,
                FLAG_REINFLATE_PUBLIC_VIEW,
                FLAG_REINFLATE_ALL})
                FLAG_CONTENT_VIEW_CONTRACTED,
                FLAG_CONTENT_VIEW_EXPANDED,
                FLAG_CONTENT_VIEW_HEADS_UP,
                FLAG_CONTENT_VIEW_AMBIENT,
                FLAG_CONTENT_VIEW_PUBLIC,
                FLAG_CONTENT_VIEW_ALL})
    public @interface InflationFlag {}
    /**
     * The default, contracted view.  Seen when the shade is pulled down and in the lock screen
     * if there is no worry about content sensitivity.
     */
    public static final int FLAG_REINFLATE_CONTENT_VIEW = 1;
    public static final int FLAG_CONTENT_VIEW_CONTRACTED = 1;

    /**
     * The expanded view.  Seen when the user expands a notification.
     */
    public static final int FLAG_REINFLATE_EXPANDED_VIEW = 1 << 1;
    public static final int FLAG_CONTENT_VIEW_EXPANDED = 1 << 1;

    /**
     * The heads up view.  Seen when a high priority notification peeks in from the top.
     */
    public static final int FLAG_REINFLATE_HEADS_UP_VIEW = 1 << 2;
    public static final int FLAG_CONTENT_VIEW_HEADS_UP = 1 << 2;

    /**
     * The ambient view.  Seen when a high priority notification is received and the phone
     * is dozing.
     */
    public static final int FLAG_REINFLATE_AMBIENT_VIEW = 1 << 3;
    public static final int FLAG_CONTENT_VIEW_AMBIENT = 1 << 3;

    /**
     * The public view.  This is a version of the contracted view that hides sensitive
     * information and is used on the lock screen if we determine that the notification's
     * content should be hidden.
     */
    public static final int FLAG_REINFLATE_PUBLIC_VIEW = 1 << 4;
    public static final int FLAG_CONTENT_VIEW_PUBLIC = 1 << 4;

    public static final int FLAG_REINFLATE_ALL = ~0;
    public static final int FLAG_CONTENT_VIEW_ALL = ~0;

    /**
     * Content views that must be inflated at all times.
     */
    @InflationFlag
    private static final int REQUIRED_INFLATION_FLAGS =
            FLAG_REINFLATE_CONTENT_VIEW
            | FLAG_REINFLATE_EXPANDED_VIEW
            | FLAG_REINFLATE_PUBLIC_VIEW;
            FLAG_CONTENT_VIEW_CONTRACTED
            | FLAG_CONTENT_VIEW_EXPANDED
            | FLAG_CONTENT_VIEW_PUBLIC;

    /**
     * The set of content views to inflate.
@@ -144,7 +147,7 @@ public class NotificationInflater {
        if (childInGroup != mIsChildInGroup) {
            mIsChildInGroup = childInGroup;
            if (mIsLowPriority) {
                int flags = FLAG_REINFLATE_CONTENT_VIEW | FLAG_REINFLATE_EXPANDED_VIEW;
                int flags = FLAG_CONTENT_VIEW_CONTRACTED | FLAG_CONTENT_VIEW_EXPANDED;
                inflateNotificationViews(flags);
            }
        }
@@ -172,7 +175,7 @@ public class NotificationInflater {
            if (mRow.getEntry() == null) {
                return;
            }
            inflateNotificationViews(FLAG_REINFLATE_AMBIENT_VIEW);
            inflateNotificationViews(FLAG_CONTENT_VIEW_AMBIENT);
        }
    }

@@ -252,23 +255,41 @@ public class NotificationInflater {
    }

    /**
     * Frees the content view associated with the inflation flag.
     * Frees the content view associated with the inflation flag.  Will only succeed if the
     * view is safe to remove.
     *
     * @param inflateFlag the flag corresponding to the content view which should be freed
     */
    public void freeNotificationView(@InflationFlag int inflateFlag) {
        if ((mInflationFlags & inflateFlag) != 0) {
            // The view should still be inflated.
            return;
        }
        switch (inflateFlag) {
            case FLAG_REINFLATE_HEADS_UP_VIEW:
            case FLAG_CONTENT_VIEW_HEADS_UP:
                if (mRow.getPrivateLayout().isContentViewInactive(VISIBLE_TYPE_HEADSUP)) {
                    mRow.getPrivateLayout().setHeadsUpChild(null);
                mCachedContentViews.remove(FLAG_REINFLATE_HEADS_UP_VIEW);
                    mCachedContentViews.remove(FLAG_CONTENT_VIEW_HEADS_UP);
                }
                break;
            case FLAG_REINFLATE_AMBIENT_VIEW:
                mRow.getShowingLayout().setAmbientChild(null);
                mCachedContentViews.remove(FLAG_REINFLATE_AMBIENT_VIEW);
            case FLAG_CONTENT_VIEW_AMBIENT:
                boolean privateSafeToRemove = mRow.getPrivateLayout().isContentViewInactive(
                        VISIBLE_TYPE_AMBIENT);
                boolean publicSafeToRemove = mRow.getPublicLayout().isContentViewInactive(
                        VISIBLE_TYPE_AMBIENT);
                if (privateSafeToRemove) {
                    mRow.getPrivateLayout().setAmbientChild(null);
                }
                if (publicSafeToRemove) {
                    mRow.getPublicLayout().setAmbientChild(null);
                }
                if (privateSafeToRemove && publicSafeToRemove) {
                    mCachedContentViews.remove(FLAG_CONTENT_VIEW_AMBIENT);
                }
                break;
            case FLAG_REINFLATE_CONTENT_VIEW:
            case FLAG_REINFLATE_EXPANDED_VIEW:
            case FLAG_REINFLATE_PUBLIC_VIEW:
            case FLAG_CONTENT_VIEW_CONTRACTED:
            case FLAG_CONTENT_VIEW_EXPANDED:
            case FLAG_CONTENT_VIEW_PUBLIC:
            default:
                break;
        }
@@ -280,23 +301,23 @@ public class NotificationInflater {
            Context packageContext) {
        InflationProgress result = new InflationProgress();
        isLowPriority = isLowPriority && !isChildInGroup;
        if ((reInflateFlags & FLAG_REINFLATE_CONTENT_VIEW) != 0) {
        if ((reInflateFlags & FLAG_CONTENT_VIEW_CONTRACTED) != 0) {
            result.newContentView = createContentView(builder, isLowPriority, usesIncreasedHeight);
        }

        if ((reInflateFlags & FLAG_REINFLATE_EXPANDED_VIEW) != 0) {
        if ((reInflateFlags & FLAG_CONTENT_VIEW_EXPANDED) != 0) {
            result.newExpandedView = createExpandedView(builder, isLowPriority);
        }

        if ((reInflateFlags & FLAG_REINFLATE_HEADS_UP_VIEW) != 0) {
        if ((reInflateFlags & FLAG_CONTENT_VIEW_HEADS_UP) != 0) {
            result.newHeadsUpView = builder.createHeadsUpContentView(usesIncreasedHeadsUpHeight);
        }

        if ((reInflateFlags & FLAG_REINFLATE_PUBLIC_VIEW) != 0) {
        if ((reInflateFlags & FLAG_CONTENT_VIEW_PUBLIC) != 0) {
            result.newPublicView = builder.makePublicContentView();
        }

        if ((reInflateFlags & FLAG_REINFLATE_AMBIENT_VIEW) != 0) {
        if ((reInflateFlags & FLAG_CONTENT_VIEW_AMBIENT) != 0) {
            result.newAmbientView = redactAmbient ? builder.makePublicAmbientNotification()
                    : builder.makeAmbientNotification();
        }
@@ -316,11 +337,11 @@ public class NotificationInflater {
        NotificationContentView publicLayout = row.getPublicLayout();
        final HashMap<Integer, CancellationSignal> runningInflations = new HashMap<>();

        int flag = FLAG_REINFLATE_CONTENT_VIEW;
        int flag = FLAG_CONTENT_VIEW_CONTRACTED;
        if ((reInflateFlags & flag) != 0) {
            boolean isNewView =
                    !canReapplyRemoteView(result.newContentView,
                            cachedContentViews.get(FLAG_REINFLATE_CONTENT_VIEW));
                            cachedContentViews.get(FLAG_CONTENT_VIEW_CONTRACTED));
            ApplyCallback applyCallback = new ApplyCallback() {
                @Override
                public void setResultView(View v) {
@@ -339,12 +360,12 @@ public class NotificationInflater {
                    runningInflations, applyCallback);
        }

        flag = FLAG_REINFLATE_EXPANDED_VIEW;
        flag = FLAG_CONTENT_VIEW_EXPANDED;
        if ((reInflateFlags & flag) != 0) {
            if (result.newExpandedView != null) {
                boolean isNewView =
                        !canReapplyRemoteView(result.newExpandedView,
                                cachedContentViews.get(FLAG_REINFLATE_EXPANDED_VIEW));
                                cachedContentViews.get(FLAG_CONTENT_VIEW_EXPANDED));
                ApplyCallback applyCallback = new ApplyCallback() {
                    @Override
                    public void setResultView(View v) {
@@ -365,12 +386,12 @@ public class NotificationInflater {
            }
        }

        flag = FLAG_REINFLATE_HEADS_UP_VIEW;
        flag = FLAG_CONTENT_VIEW_HEADS_UP;
        if ((reInflateFlags & flag) != 0) {
            if (result.newHeadsUpView != null) {
                boolean isNewView =
                        !canReapplyRemoteView(result.newHeadsUpView,
                                cachedContentViews.get(FLAG_REINFLATE_HEADS_UP_VIEW));
                                cachedContentViews.get(FLAG_CONTENT_VIEW_HEADS_UP));
                ApplyCallback applyCallback = new ApplyCallback() {
                    @Override
                    public void setResultView(View v) {
@@ -386,16 +407,16 @@ public class NotificationInflater {
                        redactAmbient, isNewView, remoteViewClickHandler, callback,
                        privateLayout, privateLayout.getHeadsUpChild(),
                        privateLayout.getVisibleWrapper(
                                NotificationContentView.VISIBLE_TYPE_HEADSUP), runningInflations,
                                VISIBLE_TYPE_HEADSUP), runningInflations,
                        applyCallback);
            }
        }

        flag = FLAG_REINFLATE_PUBLIC_VIEW;
        flag = FLAG_CONTENT_VIEW_PUBLIC;
        if ((reInflateFlags & flag) != 0) {
            boolean isNewView =
                    !canReapplyRemoteView(result.newPublicView,
                            cachedContentViews.get(FLAG_REINFLATE_PUBLIC_VIEW));
                            cachedContentViews.get(FLAG_CONTENT_VIEW_PUBLIC));
            ApplyCallback applyCallback = new ApplyCallback() {
                @Override
                public void setResultView(View v) {
@@ -414,12 +435,12 @@ public class NotificationInflater {
                    runningInflations, applyCallback);
        }

        flag = FLAG_REINFLATE_AMBIENT_VIEW;
        flag = FLAG_CONTENT_VIEW_AMBIENT;
        if ((reInflateFlags & flag) != 0) {
            NotificationContentView newParent = redactAmbient ? publicLayout : privateLayout;
            boolean isNewView = (!canReapplyAmbient(row, redactAmbient)
                    || !canReapplyRemoteView(result.newAmbientView,
                            cachedContentViews.get(FLAG_REINFLATE_AMBIENT_VIEW)));
                            cachedContentViews.get(FLAG_CONTENT_VIEW_AMBIENT)));
            ApplyCallback applyCallback = new ApplyCallback() {
                @Override
                public void setResultView(View v) {
@@ -570,40 +591,40 @@ public class NotificationInflater {
        NotificationContentView privateLayout = row.getPrivateLayout();
        NotificationContentView publicLayout = row.getPublicLayout();
        if (runningInflations.isEmpty()) {
            if ((reInflateFlags & FLAG_REINFLATE_CONTENT_VIEW) != 0) {
            if ((reInflateFlags & FLAG_CONTENT_VIEW_CONTRACTED) != 0) {
                if (result.inflatedContentView != null) {
                    privateLayout.setContractedChild(result.inflatedContentView);
                }
                cachedContentViews.put(FLAG_REINFLATE_CONTENT_VIEW, result.newContentView);
                cachedContentViews.put(FLAG_CONTENT_VIEW_CONTRACTED, result.newContentView);
            }

            if ((reInflateFlags & FLAG_REINFLATE_EXPANDED_VIEW) != 0) {
            if ((reInflateFlags & FLAG_CONTENT_VIEW_EXPANDED) != 0) {
                if (result.inflatedExpandedView != null) {
                    privateLayout.setExpandedChild(result.inflatedExpandedView);
                } else if (result.newExpandedView == null) {
                    privateLayout.setExpandedChild(null);
                }
                cachedContentViews.put(FLAG_REINFLATE_EXPANDED_VIEW, result.newExpandedView);
                cachedContentViews.put(FLAG_CONTENT_VIEW_EXPANDED, result.newExpandedView);
                row.setExpandable(result.newExpandedView != null);
            }

            if ((reInflateFlags & FLAG_REINFLATE_HEADS_UP_VIEW) != 0) {
            if ((reInflateFlags & FLAG_CONTENT_VIEW_HEADS_UP) != 0) {
                if (result.inflatedHeadsUpView != null) {
                    privateLayout.setHeadsUpChild(result.inflatedHeadsUpView);
                } else if (result.newHeadsUpView == null) {
                    privateLayout.setHeadsUpChild(null);
                }
                cachedContentViews.put(FLAG_REINFLATE_HEADS_UP_VIEW, result.newHeadsUpView);
                cachedContentViews.put(FLAG_CONTENT_VIEW_HEADS_UP, result.newHeadsUpView);
            }

            if ((reInflateFlags & FLAG_REINFLATE_PUBLIC_VIEW) != 0) {
            if ((reInflateFlags & FLAG_CONTENT_VIEW_PUBLIC) != 0) {
                if (result.inflatedPublicView != null) {
                    publicLayout.setContractedChild(result.inflatedPublicView);
                }
                cachedContentViews.put(FLAG_REINFLATE_PUBLIC_VIEW, result.newPublicView);
                cachedContentViews.put(FLAG_CONTENT_VIEW_PUBLIC, result.newPublicView);
            }

            if ((reInflateFlags & FLAG_REINFLATE_AMBIENT_VIEW) != 0) {
            if ((reInflateFlags & FLAG_CONTENT_VIEW_AMBIENT) != 0) {
                if (result.inflatedAmbientView != null) {
                    NotificationContentView newParent = redactAmbient
                            ? publicLayout : privateLayout;
@@ -612,7 +633,7 @@ public class NotificationInflater {
                    newParent.setAmbientChild(result.inflatedAmbientView);
                    otherParent.setAmbientChild(null);
                }
                cachedContentViews.put(FLAG_REINFLATE_AMBIENT_VIEW, result.newAmbientView);
                cachedContentViews.put(FLAG_CONTENT_VIEW_AMBIENT, result.newAmbientView);
            }
            entry.headsUpStatusBarText = result.headsUpStatusBarText;
            entry.headsUpStatusBarTextPublic = result.headsUpStatusBarTextPublic;
Loading