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

Commit d4660b27 authored by Kevin's avatar Kevin
Browse files

Inflate ambient + heads up view as necessary

In order to save memory, this CL introduces API to set a subset of the
content views of a notification to inflate instead of all of them.
It also changes the default views to inflate to the contracted,
expanded, and public views.  Heads up and ambient views are only
inflated if the respective notification will heads up or pulse.  In
addition, these views are freed up once the heads up/pulse ends.

This saves a significant amount of memory.  While 50 notifications would
take up around 50 MB before, they take up around 27 MB after this
change.

Bug: 111809944
Test: runtest systemui, manual
Change-Id: I970420943a3ecfac3e53d83a342b29636e32a51d
parent 20c6621d
Loading
Loading
Loading
Loading
+3 −3
Original line number Original line Diff line number Diff line
@@ -256,9 +256,9 @@ public class NotificationMediaManager implements Dumpable {


    private boolean isMediaNotification(NotificationData.Entry entry) {
    private boolean isMediaNotification(NotificationData.Entry entry) {
        // TODO: confirm that there's a valid media key
        // TODO: confirm that there's a valid media key
        return entry.getExpandedContentView() != null &&
        return entry.row.getExpandedContentView() != null
                entry.getExpandedContentView()
                && entry.row.getExpandedContentView().findViewById(
                        .findViewById(com.android.internal.R.id.media_actions) != null;
                        com.android.internal.R.id.media_actions) != null;
    }
    }


    private void clearCurrentMediaNotificationSession() {
    private void clearCurrentMediaNotificationSession() {
+0 −14
Original line number Original line Diff line number Diff line
@@ -50,7 +50,6 @@ import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.ArraySet;
import android.view.View;
import android.view.View;
import android.widget.ImageView;
import android.widget.ImageView;
import android.widget.RemoteViews;


import androidx.annotation.Nullable;
import androidx.annotation.Nullable;


@@ -102,11 +101,6 @@ public class NotificationData {
        public boolean autoRedacted; // whether the redacted notification was generated by us
        public boolean autoRedacted; // whether the redacted notification was generated by us
        public int targetSdk;
        public int targetSdk;
        private long lastFullScreenIntentLaunchTime = NOT_LAUNCHED_YET;
        private long lastFullScreenIntentLaunchTime = NOT_LAUNCHED_YET;
        public RemoteViews cachedContentView;
        public RemoteViews cachedBigContentView;
        public RemoteViews cachedHeadsUpContentView;
        public RemoteViews cachedPublicContentView;
        public RemoteViews cachedAmbientContentView;
        public CharSequence remoteInputText;
        public CharSequence remoteInputText;
        public List<SnoozeCriterion> snoozeCriteria;
        public List<SnoozeCriterion> snoozeCriteria;
        public int userSentiment = Ranking.USER_SENTIMENT_NEUTRAL;
        public int userSentiment = Ranking.USER_SENTIMENT_NEUTRAL;
@@ -178,14 +172,6 @@ public class NotificationData {
            }
            }
        }
        }


        public View getExpandedContentView() {
            return row.getPrivateLayout().getExpandedChild();
        }

        public View getPublicContentView() {
            return row.getPublicLayout().getContractedChild();
        }

        public void notifyFullScreenIntentLaunched() {
        public void notifyFullScreenIntentLaunched() {
            setInterruption();
            setInterruption();
            lastFullScreenIntentLaunchTime = SystemClock.elapsedRealtime();
            lastFullScreenIntentLaunchTime = SystemClock.elapsedRealtime();
+42 −10
Original line number Original line Diff line number Diff line
@@ -18,6 +18,10 @@ package com.android.systemui.statusbar.notification;
import static com.android.systemui.statusbar.NotificationRemoteInputManager.ENABLE_REMOTE_INPUT;
import static com.android.systemui.statusbar.NotificationRemoteInputManager.ENABLE_REMOTE_INPUT;
import static com.android.systemui.statusbar.NotificationRemoteInputManager
import static com.android.systemui.statusbar.NotificationRemoteInputManager
        .FORCE_REMOTE_INPUT_HISTORY;
        .FORCE_REMOTE_INPUT_HISTORY;
import static com.android.systemui.statusbar.notification.row.NotificationInflater
        .FLAG_REINFLATE_AMBIENT_VIEW;
import static com.android.systemui.statusbar.notification.row.NotificationInflater
        .FLAG_REINFLATE_HEADS_UP_VIEW;


import android.annotation.Nullable;
import android.annotation.Nullable;
import android.app.Notification;
import android.app.Notification;
@@ -71,6 +75,7 @@ import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.NotificationUiAdjustment;
import com.android.systemui.statusbar.NotificationUiAdjustment;
import com.android.systemui.statusbar.NotificationUpdateHandler;
import com.android.systemui.statusbar.NotificationUpdateHandler;
import com.android.systemui.statusbar.notification.row.NotificationInflater;
import com.android.systemui.statusbar.notification.row.NotificationInflater;
import com.android.systemui.statusbar.notification.row.NotificationInflater.InflationFlag;
import com.android.systemui.statusbar.notification.row.RowInflaterTask;
import com.android.systemui.statusbar.notification.row.RowInflaterTask;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
@@ -440,25 +445,48 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater.
    }
    }


    private void addEntry(NotificationData.Entry shadeEntry) {
    private void addEntry(NotificationData.Entry shadeEntry) {
        if (shouldHeadsUp(shadeEntry)) {
        addNotificationViews(shadeEntry);
            mHeadsUpManager.showNotification(shadeEntry);
        mCallback.onNotificationAdded(shadeEntry);
    }

    /**
     * Adds the entry to the respective alerting manager if the content view was inflated and
     * the entry should still alert.
     *
     * @param entry entry to add
     * @param inflatedFlags flags representing content views that were inflated
     */
    private void showAlertingView(NotificationData.Entry entry,
            @InflationFlag int inflatedFlags) {
        if ((inflatedFlags & FLAG_REINFLATE_HEADS_UP_VIEW) != 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)) {
                mHeadsUpManager.showNotification(entry);
                // Mark as seen immediately
                // Mark as seen immediately
            setNotificationShown(shadeEntry.notification);
                setNotificationShown(entry.notification);
            } else {
                entry.row.updateInflationFlag(FLAG_REINFLATE_HEADS_UP_VIEW, false);
            }
        }
        if ((inflatedFlags & FLAG_REINFLATE_AMBIENT_VIEW) != 0) {
            if (shouldPulse(entry)) {
                mAmbientPulseManager.showNotification(entry);
            } else {
                entry.row.updateInflationFlag(FLAG_REINFLATE_AMBIENT_VIEW, false);
            }
            }
        if (shouldPulse(shadeEntry)) {
            mAmbientPulseManager.showNotification(shadeEntry);
        }
        }
        addNotificationViews(shadeEntry);
        mCallback.onNotificationAdded(shadeEntry);
    }
    }


    @Override
    @Override
    public void onAsyncInflationFinished(NotificationData.Entry entry) {
    public void onAsyncInflationFinished(NotificationData.Entry entry,
            @InflationFlag int inflatedFlags) {
        mPendingNotifications.remove(entry.key);
        mPendingNotifications.remove(entry.key);
        // If there was an async task started after the removal, we don't want to add it back to
        // If there was an async task started after the removal, we don't want to add it back to
        // the list, otherwise we might get leaks.
        // the list, otherwise we might get leaks.
        boolean isNew = mNotificationData.get(entry.key) == null;
        boolean isNew = mNotificationData.get(entry.key) == null;
        if (isNew && !entry.row.isRemoved()) {
        if (isNew && !entry.row.isRemoved()) {
            showAlertingView(entry, inflatedFlags);
            addEntry(entry);
            addEntry(entry);
        } else if (!isNew && entry.row.hasLowPriorityStateUpdated()) {
        } else if (!isNew && entry.row.hasLowPriorityStateUpdated()) {
            mVisualStabilityManager.onLowPriorityUpdated(entry);
            mVisualStabilityManager.onLowPriorityUpdated(entry);
@@ -636,7 +664,11 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater.
        row.setUseIncreasedCollapsedHeight(useIncreasedCollapsedHeight);
        row.setUseIncreasedCollapsedHeight(useIncreasedCollapsedHeight);
        row.setUseIncreasedHeadsUpHeight(useIncreasedHeadsUp);
        row.setUseIncreasedHeadsUpHeight(useIncreasedHeadsUp);
        row.setSmartActions(entry.smartActions);
        row.setSmartActions(entry.smartActions);
        row.updateNotification(entry);
        row.setEntry(entry);

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


    protected void addNotificationViews(NotificationData.Entry entry) {
    protected void addNotificationViews(NotificationData.Entry entry) {
+42 −4
Original line number Original line Diff line number Diff line
@@ -17,12 +17,17 @@
package com.android.systemui.statusbar.notification.row;
package com.android.systemui.statusbar.notification.row;


import static com.android.systemui.statusbar.notification.ActivityLaunchAnimator.ExpandAnimationParameters;
import static com.android.systemui.statusbar.notification.ActivityLaunchAnimator.ExpandAnimationParameters;
import static com.android.systemui.statusbar.notification.row.NotificationInflater
        .FLAG_REINFLATE_AMBIENT_VIEW;
import static com.android.systemui.statusbar.notification.row.NotificationInflater
        .FLAG_REINFLATE_HEADS_UP_VIEW;
import static com.android.systemui.statusbar.notification.row.NotificationInflater.InflationCallback;
import static com.android.systemui.statusbar.notification.row.NotificationInflater.InflationCallback;


import android.animation.Animator;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.Nullable;
import android.app.Notification;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationChannel;
@@ -83,6 +88,7 @@ import com.android.systemui.statusbar.notification.AboveShelfChangedListener;
import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
import com.android.systemui.statusbar.notification.logging.NotificationCounters;
import com.android.systemui.statusbar.notification.logging.NotificationCounters;
import com.android.systemui.statusbar.notification.NotificationUtils;
import com.android.systemui.statusbar.notification.NotificationUtils;
import com.android.systemui.statusbar.notification.row.NotificationInflater.InflationFlag;
import com.android.systemui.statusbar.notification.row.wrapper.NotificationViewWrapper;
import com.android.systemui.statusbar.notification.row.wrapper.NotificationViewWrapper;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
@@ -429,12 +435,32 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
        }
        }
    }
    }


    public void updateNotification(NotificationData.Entry entry) {
    /**
     * Set the entry for the row.
     *
     * @param entry the entry this row is tied to
     */
    public void setEntry(@NonNull NotificationData.Entry entry) {
        mEntry = entry;
        mEntry = entry;
        mStatusBarNotification = entry.notification;
        mStatusBarNotification = entry.notification;
        cacheIsSystemNotification();
    }

    /**
     * Inflate views based off the inflation flags set.  Inflation happens asynchronously.
     */
    public void inflateViews() {
        mNotificationInflater.inflateNotificationViews();
        mNotificationInflater.inflateNotificationViews();
    }


        cacheIsSystemNotification();
    /**
     * Update whether or not a content view should be inflated.
     *
     * @param flag the flag corresponding to the content view
     * @param shouldInflate true if it should be inflated, false if it should not
     */
    public void updateInflationFlag(@InflationFlag int flag, boolean shouldInflate) {
        mNotificationInflater.updateInflationFlag(flag, shouldInflate);
    }
    }


    /**
    /**
@@ -616,9 +642,13 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
        if (isHeadsUp) {
        if (isHeadsUp) {
            mMustStayOnScreen = true;
            mMustStayOnScreen = true;
            setAboveShelf(true);
            setAboveShelf(true);
        } else if (isAboveShelf() != wasAboveShelf) {
        } else {
            if (isAboveShelf() != wasAboveShelf) {
                mAboveShelfChangedListener.onAboveShelfStateChanged(!wasAboveShelf);
                mAboveShelfChangedListener.onAboveShelfStateChanged(!wasAboveShelf);
            }
            }
            updateInflationFlag(FLAG_REINFLATE_HEADS_UP_VIEW, false);
            mNotificationInflater.freeNotificationView(FLAG_REINFLATE_HEADS_UP_VIEW);
        }
    }
    }


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


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


    public void setGroupManager(NotificationGroupManager groupManager) {
    public void setGroupManager(NotificationGroupManager groupManager) {
@@ -2616,6 +2650,10 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
        return shouldShowPublic() ? mPublicLayout : mPrivateLayout;
        return shouldShowPublic() ? mPublicLayout : mPrivateLayout;
    }
    }


    public View getExpandedContentView() {
        return getPrivateLayout().getExpandedChild();
    }

    public void setLegacy(boolean legacy) {
    public void setLegacy(boolean legacy) {
        for (NotificationContentView l : mLayouts) {
        for (NotificationContentView l : mLayouts) {
            l.setLegacy(legacy);
            l.setLegacy(legacy);
+8 −0
Original line number Original line Diff line number Diff line
@@ -517,6 +517,14 @@ public class NotificationContentView extends FrameLayout {
            removeView(mAmbientChild);
            removeView(mAmbientChild);
        }
        }
        if (child == null) {
        if (child == null) {
            mAmbientChild = null;
            mAmbientWrapper = null;
            if (mVisibleType == VISIBLE_TYPE_AMBIENT) {
                mVisibleType = VISIBLE_TYPE_CONTRACTED;
            }
            if (mTransformationStartVisibleType == VISIBLE_TYPE_AMBIENT) {
                mTransformationStartVisibleType = UNDEFINED;
            }
            return;
            return;
        }
        }
        addView(child);
        addView(child);
Loading