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

Commit 1a48babb authored by Selim Cinek's avatar Selim Cinek
Browse files

Move the inflation away from the statusbar

Since the notifications need to inflate more dynamically
based on their own state, the inflation is moved away
from the statusbar.
This also improves the apply inplace logic, that was
reinflating all views even if only a single notification
layout was changed.

Test: runtest systemui
Bug: 35125708
Change-Id: I42a33065ab60b7c45ca979ae2d7baa1518bf92b7
parent 3aa3a007
Loading
Loading
Loading
Loading
+0 −6
Original line number Diff line number Diff line
@@ -923,12 +923,6 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
        mOnActivatedListener = onActivatedListener;
    }

    public void reset() {
        setTintColor(0);
        resetBackgroundAlpha();
        setBelowSpeedBump(false);
    }

    public boolean hasSameBgColor(ActivatableNotificationView otherView) {
        return calculateBgColor() == otherView.calculateBgColor();
    }
+19 −22
Original line number Diff line number Diff line
@@ -42,6 +42,7 @@ import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.Chronometer;
import android.widget.ImageView;
import android.widget.RemoteViews;

import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
@@ -52,6 +53,8 @@ import com.android.systemui.R;
import com.android.systemui.classifier.FalsingManager;
import com.android.systemui.plugins.statusbar.NotificationMenuRowProvider.MenuItem;
import com.android.systemui.statusbar.notification.HybridNotificationView;
import com.android.systemui.statusbar.notification.InflationException;
import com.android.systemui.statusbar.notification.NotificationInflater;
import com.android.systemui.statusbar.notification.NotificationUtils;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
@@ -70,6 +73,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {

    private static final int DEFAULT_DIVIDER_ALPHA = 0x29;
    private static final int COLORED_DIVIDER_ALPHA = 0x7B;
    private final NotificationInflater mNotificationInflater;
    private int mIconTransformContentShift;
    private int mIconTransformContentShiftNoIcon;
    private int mNotificationMinHeightLegacy;
@@ -298,9 +302,10 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
        }
    }

    public void onNotificationUpdated(NotificationData.Entry entry) {
    public void updateNotification(NotificationData.Entry entry) throws InflationException {
        mEntry = entry;
        mStatusBarNotification = entry.notification;
        mNotificationInflater.inflateNotificationViews();
        for (NotificationContentView l : mLayouts) {
            l.onNotificationUpdated(entry);
        }
@@ -711,7 +716,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
        }
    }

    public void reInflateViews() {
    public void onDensityOrFontScaleChanged() {
        initDimens();
        if (mIsSummaryWithChildren) {
            if (mChildrenContainer != null) {
@@ -742,6 +747,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
        for (NotificationContentView l : mLayouts) {
            l.reInflateViews();
        }
        mNotificationInflater.onDensityOrFontScaleChanged();
        onNotificationUpdated();
    }

    public void setContentBackground(int customBackgroundColor, boolean animate,
@@ -1008,6 +1015,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
    public void setIsLowPriority(boolean isLowPriority) {
        mIsLowPriority = isLowPriority;
        mPrivateLayout.setIsLowPriority(isLowPriority);
        mNotificationInflater.setIsLowPriority(mIsLowPriority);
        if (mChildrenContainer != null) {
            mChildrenContainer.setIsLowPriority(isLowPriority);
        }
@@ -1015,10 +1023,16 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {

    public void setUseIncreasedCollapsedHeight(boolean use) {
        mUseIncreasedCollapsedHeight = use;
        mNotificationInflater.setUsesIncreasedHeight(use);
    }

    public void setUseIncreasedHeadsUpHeight(boolean use) {
        mUseIncreasedHeadsUpHeight = use;
        mNotificationInflater.setUsesIncreasedHeadsUpHeight(use);
    }

    public void setRemoteViewClickHandler(RemoteViews.OnClickHandler remoteViewClickHandler) {
        mNotificationInflater.setRemoteViewClickHandler(remoteViewClickHandler);
    }

    public interface ExpansionLogger {
@@ -1028,6 +1042,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
    public ExpandableNotificationRow(Context context, AttributeSet attrs) {
        super(context, attrs);
        mFalsingManager = FalsingManager.getInstance(context);
        mNotificationInflater = new NotificationInflater(this);
        initDimens();
    }

@@ -1063,26 +1078,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
    /**
     * Resets this view so it can be re-used for an updated notification.
     */
    @Override
    public void reset() {
        super.reset();
        final boolean wasExpanded = isExpanded();
        mExpandable = false;
        mHasUserChangedExpansion = false;
        mUserLocked = false;
        mShowingPublic = false;
        mSensitive = false;
        mShowingPublicInitialized = false;
        mIsSystemExpanded = false;
        mOnKeyguard = false;
        mPublicLayout.reset();
        mPrivateLayout.reset();
        resetHeight();
        resetTranslation();
        logExpansionEvent(false, wasExpanded);
    }

    public void resetHeight() {
        onHeightReset();
        requestLayout();
    }
@@ -1828,9 +1825,9 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
        return mShowingPublic ? mPublicLayout : mPrivateLayout;
    }

    public void setShowingLegacyBackground(boolean showing) {
    public void setLegacy(boolean legacy) {
        for (NotificationContentView l : mLayouts) {
            l.setShowingLegacyBackground(showing);
            l.setLegacy(legacy);
        }
    }

+53 −45
Original line number Diff line number Diff line
@@ -80,7 +80,7 @@ public class NotificationContentView extends FrameLayout {
    private boolean mDark;
    private boolean mAnimate;
    private boolean mIsHeadsUp;
    private boolean mShowingLegacyBackground;
    private boolean mLegacy;
    private boolean mIsChildInGroup;
    private int mSmallHeight;
    private int mHeadsUpHeight;
@@ -140,7 +140,6 @@ public class NotificationContentView extends FrameLayout {
                R.dimen.min_notification_layout_height);
        mNotificationContentMarginEnd = getResources().getDimensionPixelSize(
                com.android.internal.R.dimen.notification_content_margin_end);
        reset();
    }

    public void setHeights(int smallHeight, int headsUpMaxHeight, int maxHeight,
@@ -329,41 +328,6 @@ public class NotificationContentView extends FrameLayout {
        updateVisibility();
    }

    public void reset() {
        mPreviousExpandedRemoteInputIntent = null;
        if (mExpandedRemoteInput != null) {
            mExpandedRemoteInput.onNotificationUpdateOrReset();
            if (mExpandedRemoteInput.isActive()) {
                mPreviousExpandedRemoteInputIntent = mExpandedRemoteInput.getPendingIntent();
                mCachedExpandedRemoteInput = mExpandedRemoteInput;
                mExpandedRemoteInput.dispatchStartTemporaryDetach();
                ((ViewGroup)mExpandedRemoteInput.getParent()).removeView(mExpandedRemoteInput);
            }
        }
        if (mExpandedChild != null) {
            mExpandedChild.animate().cancel();
            removeView(mExpandedChild);
            mExpandedRemoteInput = null;
        }
        mPreviousHeadsUpRemoteInputIntent = null;
        if (mHeadsUpRemoteInput != null) {
            mHeadsUpRemoteInput.onNotificationUpdateOrReset();
            if (mHeadsUpRemoteInput.isActive()) {
                mPreviousHeadsUpRemoteInputIntent = mHeadsUpRemoteInput.getPendingIntent();
                mCachedHeadsUpRemoteInput = mHeadsUpRemoteInput;
                mHeadsUpRemoteInput.dispatchStartTemporaryDetach();
                ((ViewGroup)mHeadsUpRemoteInput.getParent()).removeView(mHeadsUpRemoteInput);
            }
        }
        if (mHeadsUpChild != null) {
            mHeadsUpChild.animate().cancel();
            removeView(mHeadsUpChild);
            mHeadsUpRemoteInput = null;
        }
        mExpandedChild = null;
        mHeadsUpChild = null;
    }

    public View getContractedChild() {
        return mContractedChild;
    }
@@ -394,8 +358,30 @@ public class NotificationContentView extends FrameLayout {

    public void setExpandedChild(View child) {
        if (mExpandedChild != null) {
            mPreviousExpandedRemoteInputIntent = null;
            if (mExpandedRemoteInput != null) {
                mExpandedRemoteInput.onNotificationUpdateOrReset();
                if (mExpandedRemoteInput.isActive()) {
                    mPreviousExpandedRemoteInputIntent = mExpandedRemoteInput.getPendingIntent();
                    mCachedExpandedRemoteInput = mExpandedRemoteInput;
                    mExpandedRemoteInput.dispatchStartTemporaryDetach();
                    ((ViewGroup)mExpandedRemoteInput.getParent()).removeView(mExpandedRemoteInput);
                }
            }
            mExpandedChild.animate().cancel();
            removeView(mExpandedChild);
            mExpandedRemoteInput = null;
        }
        if (child == null) {
            mExpandedChild = null;
            mExpandedWrapper = null;
            if (mVisibleType == VISIBLE_TYPE_EXPANDED) {
                mVisibleType = VISIBLE_TYPE_CONTRACTED;
            }
            if (mTransformationStartVisibleType == VISIBLE_TYPE_EXPANDED) {
                mTransformationStartVisibleType = UNDEFINED;
            }
            return;
        }
        addView(child);
        mExpandedChild = child;
@@ -405,8 +391,30 @@ public class NotificationContentView extends FrameLayout {

    public void setHeadsUpChild(View child) {
        if (mHeadsUpChild != null) {
            mPreviousHeadsUpRemoteInputIntent = null;
            if (mHeadsUpRemoteInput != null) {
                mHeadsUpRemoteInput.onNotificationUpdateOrReset();
                if (mHeadsUpRemoteInput.isActive()) {
                    mPreviousHeadsUpRemoteInputIntent = mHeadsUpRemoteInput.getPendingIntent();
                    mCachedHeadsUpRemoteInput = mHeadsUpRemoteInput;
                    mHeadsUpRemoteInput.dispatchStartTemporaryDetach();
                    ((ViewGroup)mHeadsUpRemoteInput.getParent()).removeView(mHeadsUpRemoteInput);
                }
            }
            mHeadsUpChild.animate().cancel();
            removeView(mHeadsUpChild);
            mHeadsUpRemoteInput = null;
        }
        if (child == null) {
            mHeadsUpChild = null;
            mHeadsUpWrapper = null;
            if (mVisibleType == VISIBLE_TYPE_HEADSUP) {
                mVisibleType = VISIBLE_TYPE_CONTRACTED;
            }
            if (mTransformationStartVisibleType == VISIBLE_TYPE_HEADSUP) {
                mTransformationStartVisibleType = UNDEFINED;
            }
            return;
        }
        addView(child);
        mHeadsUpChild = child;
@@ -978,20 +986,20 @@ public class NotificationContentView extends FrameLayout {
        return false;
    }

    public void setShowingLegacyBackground(boolean showing) {
        mShowingLegacyBackground = showing;
        updateShowingLegacyBackground();
    public void setLegacy(boolean legacy) {
        mLegacy = legacy;
        updateLegacy();
    }

    private void updateShowingLegacyBackground() {
    private void updateLegacy() {
        if (mContractedChild != null) {
            mContractedWrapper.setShowingLegacyBackground(mShowingLegacyBackground);
            mContractedWrapper.setLegacy(mLegacy);
        }
        if (mExpandedChild != null) {
            mExpandedWrapper.setShowingLegacyBackground(mShowingLegacyBackground);
            mExpandedWrapper.setLegacy(mLegacy);
        }
        if (mHeadsUpChild != null) {
            mHeadsUpWrapper.setShowingLegacyBackground(mShowingLegacyBackground);
            mHeadsUpWrapper.setLegacy(mLegacy);
        }
    }

@@ -1017,7 +1025,7 @@ public class NotificationContentView extends FrameLayout {
            mAmbientWrapper.notifyContentUpdated(entry.notification, mIsLowPriority);
        }
        applyRemoteInput(entry);
        updateShowingLegacyBackground();
        updateLegacy();
        mForceSelectNextLayout = true;
        setDark(mDark, false /* animate */, 0 /* delay */);
        mPreviousExpandedRemoteInputIntent = null;
+9 −112
Original line number Diff line number Diff line
@@ -34,6 +34,7 @@ import android.widget.RemoteViews;

import com.android.internal.statusbar.StatusBarIcon;
import com.android.internal.util.NotificationColorUtil;
import com.android.systemui.statusbar.notification.InflationException;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.policy.HeadsUpManager;
@@ -65,7 +66,6 @@ public class NotificationData {
        public ExpandableNotificationRow row; // the outer expanded view
        private boolean interruption;
        public boolean autoRedacted; // whether the redacted notification was generated by us
        public boolean legacy; // whether the notification has a legacy, dark background
        public int targetSdk;
        private long lastFullScreenIntentLaunchTime = NOT_LAUNCHED_YET;
        public RemoteViews cachedContentView;
@@ -95,118 +95,20 @@ public class NotificationData {
         * Resets the notification entry to be re-used.
         */
        public void reset() {
            // NOTE: Icon needs to be preserved for now.
            // We should fix this at some point.
            autoRedacted = false;
            legacy = false;
            lastFullScreenIntentLaunchTime = NOT_LAUNCHED_YET;
            if (row != null) {
                row.reset();
            }
        }

        public View getContentView() {
            return row.getPrivateLayout().getContractedChild();
        }

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

        public View getHeadsUpContentView() {
            return row.getPrivateLayout().getHeadsUpChild();
        }

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

        public View getAmbientContentView() {
            return row.getPrivateLayout().getAmbientChild();
        }

        public boolean cacheContentViews(Context ctx, Notification updatedNotification,
                boolean isLowPriority, boolean useIncreasedCollapsedView,
                boolean useIncreasedHeadsUp) {
            boolean applyInPlace = false;
            if (updatedNotification != null) {
                final Notification.Builder updatedNotificationBuilder
                        = Notification.Builder.recoverBuilder(ctx, updatedNotification);
                final RemoteViews newContentView = createContentView(updatedNotificationBuilder,
                        isLowPriority, useIncreasedCollapsedView);
                final RemoteViews newBigContentView = createBigContentView(
                        updatedNotificationBuilder, isLowPriority);
                final RemoteViews newHeadsUpContentView =
                        updatedNotificationBuilder.createHeadsUpContentView(useIncreasedHeadsUp);
                final RemoteViews newPublicNotification
                        = updatedNotificationBuilder.makePublicContentView();
                final RemoteViews newAmbientNotification
                        = updatedNotificationBuilder.makeAmbientNotification();

                boolean sameCustomView = Objects.equals(
                        notification.getNotification().extras.getBoolean(
                                Notification.EXTRA_CONTAINS_CUSTOM_VIEW),
                        updatedNotification.extras.getBoolean(
                                Notification.EXTRA_CONTAINS_CUSTOM_VIEW));
                applyInPlace = compareRemoteViews(cachedContentView, newContentView)
                        && compareRemoteViews(cachedBigContentView, newBigContentView)
                        && compareRemoteViews(cachedHeadsUpContentView, newHeadsUpContentView)
                        && compareRemoteViews(cachedPublicContentView, newPublicNotification)
                        && compareRemoteViews(cachedAmbientContentView, newAmbientNotification)
                        && sameCustomView;
                cachedPublicContentView = newPublicNotification;
                cachedHeadsUpContentView = newHeadsUpContentView;
                cachedBigContentView = newBigContentView;
                cachedContentView = newContentView;
                cachedAmbientContentView = newAmbientNotification;
            } else {
                final Notification.Builder builder
                        = Notification.Builder.recoverBuilder(ctx, notification.getNotification());

                cachedContentView = createContentView(builder, isLowPriority,
                        useIncreasedCollapsedView);
                cachedBigContentView = createBigContentView(builder, isLowPriority);
                cachedHeadsUpContentView = builder.createHeadsUpContentView(useIncreasedHeadsUp);
                cachedPublicContentView = builder.makePublicContentView();
                cachedAmbientContentView = builder.makeAmbientNotification();

                applyInPlace = false;
            }
            return applyInPlace;
        }

        private RemoteViews createBigContentView(Notification.Builder builder,
                boolean isLowPriority) {
            RemoteViews bigContentView = builder.createBigContentView();
            if (bigContentView != null) {
                return bigContentView;
            }
            if (isLowPriority) {
                RemoteViews contentView = builder.createContentView();
                Notification.Builder.makeHeaderExpanded(contentView);
                return contentView;
            }
            return null;
        }

        private RemoteViews createContentView(Notification.Builder builder,
                boolean isLowPriority, boolean useLarge) {
            if (isLowPriority) {
                return builder.makeLowPriorityContentView(false /* useRegularSubtext */);
            }
            return builder.createContentView(useLarge);
        }

        // Returns true if the RemoteViews are the same.
        private boolean compareRemoteViews(final RemoteViews a, final RemoteViews b) {
            return (a == null && b == null) ||
                    (a != null && b != null
                    && b.getPackage() != null
                    && a.getPackage() != null
                    && a.getPackage().equals(b.getPackage())
                    && a.getLayoutId() == b.getLayoutId());
        }

        public void notifyFullScreenIntentLaunched() {
            lastFullScreenIntentLaunchTime = SystemClock.elapsedRealtime();
        }
@@ -219,13 +121,14 @@ public class NotificationData {
         * Create the icons for a notification
         * @param context the context to create the icons with
         * @param sbn the notification
         * @throws IconException
         * @throws InflationException
         */
        public void createIcons(Context context, StatusBarNotification sbn) throws IconException {
        public void createIcons(Context context, StatusBarNotification sbn)
                throws InflationException {
            Notification n = sbn.getNotification();
            final Icon smallIcon = n.getSmallIcon();
            if (smallIcon == null) {
                throw new IconException("No small icon in notification from "
                throw new InflationException("No small icon in notification from "
                        + sbn.getPackageName());
            }

@@ -248,7 +151,7 @@ public class NotificationData {
            if (!icon.set(ic) || !expandedIcon.set(ic)) {
                icon = null;
                expandedIcon = null;
                throw new IconException("Couldn't create icon: " + ic);
                throw new InflationException("Couldn't create icon: " + ic);
            }
            expandedIcon.setVisibility(View.INVISIBLE);
            expandedIcon.setOnVisibilityChangedListener(
@@ -270,9 +173,9 @@ public class NotificationData {
         * Update the notification icons.
         * @param context the context to create the icons with.
         * @param n the notification to read the icon from.
         * @throws IconException
         * @throws InflationException
         */
        public void updateIcons(Context context, Notification n) throws IconException {
        public void updateIcons(Context context, Notification n) throws InflationException {
            if (icon != null) {
                // Update the icon
                final StatusBarIcon ic = new StatusBarIcon(
@@ -285,7 +188,7 @@ public class NotificationData {
                icon.setNotification(n);
                expandedIcon.setNotification(n);
                if (!icon.set(ic) || !expandedIcon.set(ic)) {
                    throw new IconException("Couldn't update icon: " + ic);
                    throw new InflationException("Couldn't update icon: " + ic);
                }
            }
        }
@@ -612,10 +515,4 @@ public class NotificationData {
        public String getCurrentMediaNotificationKey();
        public NotificationGroupManager getGroupManager();
    }

    public static class IconException extends Exception {
        IconException(String error) {
            super(error);
        }
    }
}
+26 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2017 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License
 */

package com.android.systemui.statusbar.notification;

/**
 * An exception that something went wrong during the inflation
 */
public class InflationException extends Exception {
    public InflationException(String error) {
        super(error);
    }
}
Loading