Don't let everyone reach into NotificationData.Entry for its row

Test: atest SystemUITests
Change-Id: I0b4b66769afcf39c35800d293c22263e31790788
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index e868f96..c6dcfc7 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -268,7 +268,7 @@
         for (BubbleView bv : mBubbles.values()) {
             NotificationData.Entry entry = bv.getEntry();
             if (entry != null) {
-                if (entry.row.isRemoved() || entry.isBubbleDismissed() || entry.row.isDismissed()) {
+                if (entry.isRowRemoved() || entry.isBubbleDismissed() || entry.isRowDismissed()) {
                     viewsToRemove.add(bv);
                 }
             }
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleView.java
index a79e047..6c47aac 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleView.java
@@ -120,7 +120,7 @@
      * @return the view to display when the bubble is expanded.
      */
     public ExpandableNotificationRow getRowView() {
-        return mEntry.row;
+        return mEntry.getRow();
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java
index 3da6d2e..bc38169 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java
@@ -112,8 +112,7 @@
             return;
         }
 
-        alertEntry.mEntry.row.sendAccessibilityEvent(
-                AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
+        alertEntry.mEntry.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
         if (alert) {
             alertEntry.updateEntry(true /* updatePostTime */);
         }
@@ -186,7 +185,7 @@
         alertEntry.setEntry(entry);
         mAlertEntries.put(entry.key, alertEntry);
         onAlertEntryAdded(alertEntry);
-        entry.row.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
+        entry.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
     }
 
     /**
@@ -207,7 +206,7 @@
         Entry entry = alertEntry.mEntry;
         mAlertEntries.remove(key);
         onAlertEntryRemoved(alertEntry);
-        entry.row.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
+        entry.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
         alertEntry.reset();
         if (mExtendedLifetimeAlertEntries.contains(entry)) {
             if (mNotificationLifetimeFinishedCallback != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/AmbientPulseManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/AmbientPulseManager.java
index f1c0304..a5e7f04 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/AmbientPulseManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/AmbientPulseManager.java
@@ -79,7 +79,7 @@
     @Override
     protected void onAlertEntryAdded(AlertEntry alertEntry) {
         NotificationData.Entry entry = alertEntry.mEntry;
-        entry.row.setAmbientPulsing(true);
+        entry.setAmbientPulsing(true);
         for (OnAmbientChangedListener listener : mListeners) {
             listener.onAmbientStateChanged(entry, true);
         }
@@ -88,11 +88,11 @@
     @Override
     protected void onAlertEntryRemoved(AlertEntry alertEntry) {
         NotificationData.Entry entry = alertEntry.mEntry;
-        entry.row.setAmbientPulsing(false);
+        entry.setAmbientPulsing(false);
         for (OnAmbientChangedListener listener : mListeners) {
             listener.onAmbientStateChanged(entry, false);
         }
-        entry.row.freeContentViewWhenSafe(FLAG_CONTENT_VIEW_AMBIENT);
+        entry.freeContentViewWhenSafe(FLAG_CONTENT_VIEW_AMBIENT);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
index fc1e94a..f045548 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
@@ -199,7 +199,7 @@
             for (int i = 0; i < N; i++) {
                 final NotificationData.Entry entry = activeNotifications.get(i);
 
-                if (isMediaNotification(entry)) {
+                if (entry.isMediaNotification()) {
                     final MediaSession.Token token =
                             entry.notification.getNotification().extras.getParcelable(
                                     Notification.EXTRA_MEDIA_SESSION);
@@ -336,13 +336,6 @@
         return PlaybackState.STATE_NONE;
     }
 
-    private boolean isMediaNotification(NotificationData.Entry entry) {
-        // TODO: confirm that there's a valid media key
-        return entry.row.getExpandedContentView() != null
-                && entry.row.getExpandedContentView().findViewById(
-                        com.android.internal.R.id.media_actions) != null;
-    }
-
     private void clearCurrentMediaNotificationSession() {
         mMediaMetadata = null;
         if (mMediaController != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
index 8c53cc2..2ee5443 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
@@ -393,7 +393,7 @@
     }
 
     public boolean shouldKeepForRemoteInputHistory(NotificationData.Entry entry) {
-        if (entry.row == null || entry.row.isDismissed()) {
+        if (entry.isDismissed()) {
             return false;
         }
         if (!FORCE_REMOTE_INPUT_HISTORY) {
@@ -403,7 +403,7 @@
     }
 
     public boolean shouldKeepForSmartReplyHistory(NotificationData.Entry entry) {
-        if (entry.row == null || entry.row.isDismissed()) {
+        if (entry.isDismissed()) {
             return false;
         }
         if (!FORCE_REMOTE_INPUT_HISTORY) {
@@ -532,7 +532,7 @@
 
                 // Ensure the entry hasn't already been removed. This can happen if there is an
                 // inflation exception while updating the remote history
-                if (entry.row == null || entry.row.isRemoved()) {
+                if (entry.isRemoved()) {
                     return;
                 }
 
@@ -570,7 +570,7 @@
 
                 mEntryManager.updateNotification(newSbn, null);
 
-                if (entry.row == null || entry.row.isRemoved()) {
+                if (entry.isRemoved()) {
                     return;
                 }
 
@@ -593,7 +593,7 @@
     protected class RemoteInputActiveExtender extends RemoteInputExtender {
         @Override
         public boolean shouldExtendLifetime(@NonNull NotificationData.Entry entry) {
-            if (entry.row == null || entry.row.isDismissed()) {
+            if (entry.isDismissed()) {
                 return false;
             }
             return mRemoteInputController.isRemoteInputActive(entry);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
index ea67736..daa2fd4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
@@ -51,6 +51,7 @@
 public class NotificationViewHierarchyManager {
     private static final String TAG = "NotificationViewHierarchyManager";
 
+    //TODO: change this top <Entry, List<Entry>>?
     private final HashMap<ExpandableNotificationRow, List<ExpandableNotificationRow>>
             mTmpChildOrderMap = new HashMap<>();
 
@@ -140,6 +141,7 @@
     /**
      * Updates the visual representation of the notifications.
      */
+    //TODO: Rewrite this to focus on Entries, or some other data object instead of views
     public void updateNotificationViews() {
         ArrayList<NotificationData.Entry> activeNotifications = mEntryManager.getNotificationData()
                 .getActiveNotifications();
@@ -148,12 +150,12 @@
         final int N = activeNotifications.size();
         for (int i = 0; i < N; i++) {
             NotificationData.Entry ent = activeNotifications.get(i);
-            if (ent.row.isDismissed() || ent.row.isRemoved()) {
+            if (ent.isRowDismissed() || ent.isRowRemoved()) {
                 // we don't want to update removed notifications because they could
                 // temporarily become children if they were isolated before.
                 continue;
             }
-            ent.row.setStatusBarState(mStatusBarStateListener.getCurrentState());
+            ent.getRow().setStatusBarState(mStatusBarStateListener.getCurrentState());
             boolean showAsBubble = ent.isBubble() && !ent.isBubbleDismissed()
                     && mStatusBarStateListener.getCurrentState() == SHADE;
             if (showAsBubble) {
@@ -175,20 +177,19 @@
             boolean deviceSensitive = devicePublic
                     && !mLockscreenUserManager.userAllowsPrivateNotificationsInPublic(
                     mLockscreenUserManager.getCurrentUserId());
-            ent.row.setSensitive(sensitive, deviceSensitive);
-            ent.row.setNeedsRedaction(needsRedaction);
-            if (mGroupManager.isChildInGroupWithSummary(ent.row.getStatusBarNotification())) {
-                ExpandableNotificationRow summary = mGroupManager.getGroupSummary(
-                        ent.row.getStatusBarNotification());
+            ent.getRow().setSensitive(sensitive, deviceSensitive);
+            ent.getRow().setNeedsRedaction(needsRedaction);
+            if (mGroupManager.isChildInGroupWithSummary(ent.notification)) {
+                NotificationData.Entry summary = mGroupManager.getGroupSummary(ent.notification);
                 List<ExpandableNotificationRow> orderedChildren =
-                        mTmpChildOrderMap.get(summary);
+                        mTmpChildOrderMap.get(summary.getRow());
                 if (orderedChildren == null) {
                     orderedChildren = new ArrayList<>();
-                    mTmpChildOrderMap.put(summary, orderedChildren);
+                    mTmpChildOrderMap.put(summary.getRow(), orderedChildren);
                 }
-                orderedChildren.add(ent.row);
+                orderedChildren.add(ent.getRow());
             } else {
-                toShow.add(ent.row);
+                toShow.add(ent.getRow());
             }
 
         }
@@ -391,19 +392,19 @@
                         && !row.isLowPriority()));
             }
 
-            entry.row.setOnAmbient(getShadeController().isDozing());
+            entry.getRow().setOnAmbient(getShadeController().isDozing());
             int userId = entry.notification.getUserId();
             boolean suppressedSummary = mGroupManager.isSummaryOfSuppressedGroup(
-                    entry.notification) && !entry.row.isRemoved();
+                    entry.notification) && !entry.isRowRemoved();
             boolean showOnKeyguard = mLockscreenUserManager.shouldShowOnKeyguard(entry
                     .notification);
             if (!showOnKeyguard) {
                 // min priority notifications should show if their summary is showing
                 if (mGroupManager.isChildInGroupWithSummary(entry.notification)) {
-                    ExpandableNotificationRow summary = mGroupManager.getLogicalGroupSummary(
+                    NotificationData.Entry summary = mGroupManager.getLogicalGroupSummary(
                             entry.notification);
                     if (summary != null && mLockscreenUserManager.shouldShowOnKeyguard(
-                            summary.getStatusBarNotification()))         {
+                            summary.notification))         {
                         showOnKeyguard = true;
                     }
                 }
@@ -411,16 +412,16 @@
             if (suppressedSummary
                     || mLockscreenUserManager.shouldHideNotifications(userId)
                     || (onKeyguard && !showOnKeyguard)) {
-                entry.row.setVisibility(View.GONE);
+                entry.getRow().setVisibility(View.GONE);
             } else {
-                boolean wasGone = entry.row.getVisibility() == View.GONE;
+                boolean wasGone = entry.getRow().getVisibility() == View.GONE;
                 if (wasGone) {
-                    entry.row.setVisibility(View.VISIBLE);
+                    entry.getRow().setVisibility(View.VISIBLE);
                 }
-                if (!isChildNotification && !entry.row.isRemoved()) {
+                if (!isChildNotification && !entry.getRow().isRemoved()) {
                     if (wasGone) {
                         // notify the scroller of a child addition
-                        mListContainer.generateAddAnimation(entry.row,
+                        mListContainer.generateAddAnimation(entry.getRow(),
                                 !showOnKeyguard /* fromMoreCard */);
                     }
                     visibleNotifications++;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java b/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java
index 929f43e..e8abcc2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java
@@ -250,16 +250,16 @@
         // Make a copy because closing the remote inputs will modify mOpen.
         ArrayList<NotificationData.Entry> list = new ArrayList<>(mOpen.size());
         for (int i = mOpen.size() - 1; i >= 0; i--) {
-            NotificationData.Entry item = mOpen.get(i).first.get();
-            if (item != null && item.row != null) {
-                list.add(item);
+            NotificationData.Entry entry = mOpen.get(i).first.get();
+            if (entry != null && entry.rowExists()) {
+                list.add(entry);
             }
         }
 
         for (int i = list.size() - 1; i >= 0; i--) {
-            NotificationData.Entry item = list.get(i);
-            if (item.row != null) {
-                item.row.closeRemoteInput();
+            NotificationData.Entry entry = list.get(i);
+            if (entry.rowExists()) {
+                entry.closeRemoteInput();
             }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationData.java
index da6d977..d7680b3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationData.java
@@ -64,6 +64,9 @@
 import com.android.systemui.statusbar.NotificationMediaManager;
 import com.android.systemui.statusbar.StatusBarIconView;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
+import com.android.systemui.statusbar.notification.row.NotificationGuts;
+import com.android.systemui.statusbar.notification.row.NotificationInflater.InflationFlag;
+import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
 import com.android.systemui.statusbar.phone.NotificationGroupManager;
 import com.android.systemui.statusbar.phone.ShadeController;
 import com.android.systemui.statusbar.phone.StatusBar;
@@ -106,7 +109,6 @@
         public int importance;
         public StatusBarIconView icon;
         public StatusBarIconView expandedIcon;
-        public ExpandableNotificationRow row; // the outer expanded view
         private boolean interruption;
         public boolean autoRedacted; // whether the redacted notification was generated by us
         public int targetSdk;
@@ -119,6 +121,10 @@
         public List<Notification.Action> systemGeneratedSmartActions = Collections.emptyList();
         public CharSequence[] smartReplies = new CharSequence[0];
 
+        private Entry parent; // our parent (if we're in a group)
+        private ArrayList<Entry> children = new ArrayList<Entry>();
+        private ExpandableNotificationRow row; // the outer expanded view
+
         private int mCachedContrastColor = COLOR_INVALID;
         private int mCachedContrastColorIsFor = COLOR_INVALID;
         private InflationTask mRunningTask = null;
@@ -212,6 +218,24 @@
             }
         }
 
+        public ExpandableNotificationRow getRow() {
+            return row;
+        }
+
+        //TODO: This will go away when we have a way to bind an entry to a row
+        public void setRow(ExpandableNotificationRow row) {
+            this.row = row;
+        }
+
+        @Nullable
+        public List<Entry> getChildren() {
+            if (children.size() <= 0) {
+                return null;
+            }
+
+            return children;
+        }
+
         public void notifyFullScreenIntentLaunched() {
             setInterruption();
             lastFullScreenIntentLaunchTime = SystemClock.elapsedRealtime();
@@ -409,6 +433,198 @@
                 initializationTime = time;
             }
         }
+
+        public void sendAccessibilityEvent(int eventType) {
+            if (row != null) {
+                row.sendAccessibilityEvent(eventType);
+            }
+        }
+
+        /**
+         * Used by NotificationMediaManager to determine... things
+         * @return {@code true} if we are a media notification
+         */
+        public boolean isMediaNotification() {
+            if (row == null) return false;
+
+            return row.isMediaRow();
+        }
+
+        /**
+         * We are a top level child if our parent is the list of notifications duh
+         * @return {@code true} if we're a top level notification
+         */
+        public boolean isTopLevelChild() {
+            return row != null && row.isTopLevelChild();
+        }
+
+        public void resetUserExpansion() {
+            if (row != null) row.resetUserExpansion();
+        }
+
+        public void freeContentViewWhenSafe(@InflationFlag int inflationFlag) {
+            if (row != null) row.freeContentViewWhenSafe(inflationFlag);
+        }
+
+        public void setAmbientPulsing(boolean pulsing) {
+            if (row != null) row.setAmbientPulsing(pulsing);
+        }
+
+        public boolean rowExists() {
+            return row != null;
+        }
+
+        public boolean isRowDismissed() {
+            return row != null && row.isDismissed();
+        }
+
+        public boolean isRowRemoved() {
+            return row != null && row.isRemoved();
+        }
+
+        /**
+         * @return {@code true} if the row is null or removed
+         */
+        public boolean isRemoved() {
+            //TODO: recycling invalidates this
+            return row == null || row.isRemoved();
+        }
+
+        /**
+         * @return {@code true} if the row is null or dismissed
+         */
+        public boolean isDismissed() {
+            //TODO: recycling
+            return row == null || row.isDismissed();
+        }
+
+        public boolean isRowPinned() {
+            return row != null && row.isPinned();
+        }
+
+        public void setRowPinned(boolean pinned) {
+            if (row != null) row.setPinned(pinned);
+        }
+
+        public boolean isRowAnimatingAway() {
+            return row != null && row.isHeadsUpAnimatingAway();
+        }
+
+        public boolean isRowHeadsUp() {
+            return row != null && row.isHeadsUp();
+        }
+
+        public void setHeadsUp(boolean shouldHeadsUp) {
+            if (row != null) row.setHeadsUp(shouldHeadsUp);
+        }
+
+        public boolean mustStayOnScreen() {
+            return row != null && row.mustStayOnScreen();
+        }
+
+        public void setHeadsUpIsVisible() {
+            if (row != null) row.setHeadsUpIsVisible();
+        }
+
+        //TODO: i'm imagining a world where this isn't just the row, but I could be rwong
+        public ExpandableNotificationRow getHeadsUpAnimationView() {
+            return row;
+        }
+
+        public void setUserLocked(boolean userLocked) {
+            if (row != null) row.setUserLocked(userLocked);
+        }
+
+        public void setUserExpanded(boolean userExpanded, boolean allowChildExpansion) {
+            if (row != null) row.setUserExpanded(userExpanded, allowChildExpansion);
+        }
+
+        public void setGroupExpansionChanging(boolean changing) {
+            if (row != null) row.setGroupExpansionChanging(changing);
+        }
+
+        public void notifyHeightChanged(boolean needsAnimation) {
+            if (row != null) row.notifyHeightChanged(needsAnimation);
+        }
+
+        public void closeRemoteInput() {
+            if (row != null) row.closeRemoteInput();
+        }
+
+        public boolean areChildrenExpanded() {
+            return row != null && row.areChildrenExpanded();
+        }
+
+        public boolean keepInParent() {
+            return row != null && row.keepInParent();
+        }
+
+        //TODO: probably less confusing to say "is group fully visible"
+        public boolean isGroupNotFullyVisible() {
+            return row == null || row.isGroupNotFullyVisible();
+        }
+
+        public NotificationGuts getGuts() {
+            if (row != null) return row.getGuts();
+            return null;
+        }
+
+        public boolean hasLowPriorityStateUpdated() {
+            return row != null && row.hasLowPriorityStateUpdated();
+        }
+
+        public void removeRow() {
+            if (row != null) row.setRemoved();
+        }
+
+        public boolean isSummaryWithChildren() {
+            return row != null && row.isSummaryWithChildren();
+        }
+
+        public void setKeepInParent(boolean keep) {
+            if (row != null) row.setKeepInParent(keep);
+        }
+
+        public void onDensityOrFontScaleChanged() {
+            if (row != null) row.onDensityOrFontScaleChanged();
+        }
+
+        public boolean areGutsExposed() {
+            return row != null && row.getGuts().isExposed();
+        }
+
+        public boolean isChildInGroup() {
+            return parent == null;
+        }
+
+        public void setLowPriorityStateUpdated(boolean updated) {
+            if (row != null) row.setLowPriorityStateUpdated(updated);
+        }
+
+        /**
+         * @return Can the underlying notification be cleared? This can be different from whether the
+         *         notification can be dismissed in case notifications are sensitive on the lockscreen.
+         * @see #canViewBeDismissed()
+         */
+        public boolean isClearable() {
+            if (notification == null || !notification.isClearable()) {
+                return false;
+            }
+            if (children.size() > 0) {
+                for (int i = 0; i < children.size(); i++) {
+                    Entry child =  children.get(i);
+                    if (!child.isClearable()) {
+                        return false;
+                    }
+                }
+            }
+            return true;
+        }
+
+        public boolean canViewBeDismissed() {
+            if (row == null) return true;
+            return row.canViewBeDismissed();
+        }
     }
 
     private final ArrayMap<String, Entry> mEntries = new ArrayMap<>();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
index 0818513..a7415c8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
@@ -384,9 +384,9 @@
                 entry.notification.getUser().getIdentifier());
 
         final StatusBarNotification sbn = entry.notification;
-        if (entry.row != null) {
+        if (entry.rowExists()) {
             entry.reset();
-            updateNotification(entry, pmUser, sbn, entry.row);
+            updateNotification(entry, pmUser, sbn, entry.getRow());
         } else {
             new RowInflaterTask().inflate(mContext, parent, entry,
                     row -> {
@@ -540,14 +540,14 @@
                 // Mark as seen immediately
                 setNotificationShown(entry.notification);
             } else {
-                entry.row.freeContentViewWhenSafe(FLAG_CONTENT_VIEW_HEADS_UP);
+                entry.freeContentViewWhenSafe(FLAG_CONTENT_VIEW_HEADS_UP);
             }
         }
         if ((inflatedFlags & FLAG_CONTENT_VIEW_AMBIENT) != 0) {
             if (shouldPulse(entry)) {
                 mAmbientPulseManager.showNotification(entry);
             } else {
-                entry.row.freeContentViewWhenSafe(FLAG_CONTENT_VIEW_AMBIENT);
+                entry.freeContentViewWhenSafe(FLAG_CONTENT_VIEW_AMBIENT);
             }
         }
     }
@@ -558,20 +558,20 @@
         mPendingNotifications.remove(entry.key);
         // 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.
-        if (!entry.row.isRemoved()) {
+        if (!entry.isRowRemoved()) {
             boolean isNew = mNotificationData.get(entry.key) == null;
             if (isNew) {
                 showAlertingView(entry, inflatedFlags);
                 addEntry(entry);
             } else {
-                if (entry.row.hasLowPriorityStateUpdated()) {
+                if (entry.getRow().hasLowPriorityStateUpdated()) {
                     mVisualStabilityManager.onLowPriorityUpdated(entry);
                     mPresenter.updateNotificationViews();
                 }
                 mGroupAlertTransferHelper.onInflationFinished(entry);
             }
         }
-        entry.row.setLowPriorityStateUpdated(false);
+        entry.setLowPriorityStateUpdated(false);
     }
 
     @Override
@@ -630,9 +630,9 @@
         getMediaManager().onNotificationRemoved(key);
         mForegroundServiceController.removeNotification(entry.notification);
 
-        if (entry.row != null) {
-            entry.row.setRemoved();
-            mListContainer.cleanUpViewState(entry.row);
+        if (entry.rowExists()) {
+            entry.removeRow();
+            mListContainer.cleanUpViewStateForEntry(entry);
         }
 
         // Let's remove the children if this was a summary
@@ -667,19 +667,19 @@
      */
     private void handleGroupSummaryRemoved(String key) {
         NotificationData.Entry entry = mNotificationData.get(key);
-        if (entry != null && entry.row != null
-                && entry.row.isSummaryWithChildren()) {
-            if (entry.notification.getOverrideGroupKey() != null && !entry.row.isDismissed()) {
+        if (entry != null && entry.rowExists() && entry.isSummaryWithChildren()) {
+            if (entry.notification.getOverrideGroupKey() != null && !entry.isRowDismissed()) {
                 // We don't want to remove children for autobundled notifications as they are not
                 // always cancelled. We only remove them if they were dismissed by the user.
                 return;
             }
-            List<ExpandableNotificationRow> notificationChildren =
-                    entry.row.getNotificationChildren();
-            for (int i = 0; i < notificationChildren.size(); i++) {
-                ExpandableNotificationRow row = notificationChildren.get(i);
-                NotificationData.Entry childEntry = row.getEntry();
-                boolean isForeground = (row.getStatusBarNotification().getNotification().flags
+            List<NotificationData.Entry> childEntries = entry.getChildren();
+            if (childEntries == null) {
+                return;
+            }
+            for (int i = 0; i < childEntries.size(); i++) {
+                NotificationData.Entry childEntry = childEntries.get(i);
+                boolean isForeground = (entry.notification.getNotification().flags
                         & Notification.FLAG_FOREGROUND_SERVICE) != 0;
                 boolean keepForReply =
                         getRemoteInputManager().shouldKeepForRemoteInputHistory(childEntry)
@@ -689,10 +689,10 @@
                     // a child we're keeping around for reply!
                     continue;
                 }
-                row.setKeepInParent(true);
+                entry.setKeepInParent(true);
                 // we need to set this state earlier as otherwise we might generate some weird
                 // animations
-                row.setRemoved();
+                entry.removeRow();
             }
         }
     }
@@ -702,15 +702,15 @@
                 mNotificationData.getNotificationsForCurrentUser();
         for (int i = 0; i < userNotifications.size(); i++) {
             NotificationData.Entry entry = userNotifications.get(i);
-            boolean exposedGuts = mGutsManager.getExposedGuts() != null
-                    && entry.row.getGuts() == mGutsManager.getExposedGuts();
-            entry.row.onDensityOrFontScaleChanged();
+            entry.onDensityOrFontScaleChanged();
+            boolean exposedGuts = entry.areGutsExposed();
             if (exposedGuts) {
-                mGutsManager.onDensityOrFontScaleChanged(entry.row);
+                mGutsManager.onDensityOrFontScaleChanged(entry);
             }
         }
     }
 
+    //TODO: This method associates a row with an entry, but eventually needs to not do that
     protected void updateNotification(NotificationData.Entry entry, PackageManager pmUser,
             StatusBarNotification sbn, ExpandableNotificationRow row) {
         boolean isLowPriority = mNotificationData.isAmbient(sbn.getKey());
@@ -733,8 +733,8 @@
         entry.setIconTag(R.id.icon_is_pre_L, entry.targetSdk < Build.VERSION_CODES.LOLLIPOP);
         entry.autoRedacted = entry.notification.getNotification().publicVersion == null;
 
-        entry.row = row;
-        entry.row.setOnActivatedListener(mPresenter);
+        entry.setRow(row);
+        row.setOnActivatedListener(mPresenter);
 
         boolean useIncreasedCollapsedHeight = mMessagingUtil.isImportantMessaging(sbn,
                 mNotificationData.getImportance(sbn.getKey()));
@@ -917,7 +917,7 @@
         if (!notification.isClearable()) {
             // The user may have performed a dismiss action on the notification, since it's
             // not clearable we should snap it back.
-            mListContainer.snapViewIfNeeded(entry.row);
+            mListContainer.snapViewIfNeeded(entry);
         }
 
         if (DEBUG) {
@@ -970,11 +970,11 @@
 
             if (NotificationUiAdjustment.needReinflate(
                     oldAdjustments.get(entry.key), newAdjustment)) {
-                if (entry.row != null) {
+                if (entry.rowExists()) {
                     entry.reset();
                     PackageManager pmUser = StatusBar.getPackageManagerForUser(mContext,
                             entry.notification.getUser().getIdentifier());
-                    updateNotification(entry, pmUser, entry.notification, entry.row);
+                    updateNotification(entry, pmUser, entry.notification, entry.getRow());
                 } else {
                     // Once the RowInflaterTask is done, it will pick up the updated entry, so
                     // no-op here.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisibilityLocationProvider.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisibilityLocationProvider.java
index 53ebe74..247c1ab 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisibilityLocationProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisibilityLocationProvider.java
@@ -26,8 +26,8 @@
     /**
      * Returns whether an ExpandableNotificationRow is in a visible location or not.
      *
-     * @param row
+     * @param entry
      * @return true if row is in a visible location
      */
-    boolean isInVisibleLocation(ExpandableNotificationRow row);
+    boolean isInVisibleLocation(NotificationData.Entry entry);
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisualStabilityManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisualStabilityManager.java
index 75613a4..fce7980 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisualStabilityManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisualStabilityManager.java
@@ -120,7 +120,7 @@
             return true;
         }
         if (mAllowedReorderViews.contains(row)
-                && !mVisibilityLocationProvider.isInVisibleLocation(row)) {
+                && !mVisibilityLocationProvider.isInVisibleLocation(row.getEntry())) {
             return true;
         }
         return false;
@@ -142,12 +142,12 @@
         if (isHeadsUp) {
             // Heads up notifications should in general be allowed to reorder if they are out of
             // view and stay at the current location if they aren't.
-            mAllowedReorderViews.add(entry.row);
+            mAllowedReorderViews.add(entry.getRow());
         }
     }
 
     public void onLowPriorityUpdated(NotificationData.Entry entry) {
-        mLowPriorityReorderingViews.add(entry.row);
+        mLowPriorityReorderingViews.add(entry.getRow());
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java
index 5dfd5d0..87313b8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java
@@ -115,7 +115,7 @@
             for (int i = 0; i < N; i++) {
                 NotificationData.Entry entry = activeNotifications.get(i);
                 String key = entry.notification.getKey();
-                boolean isVisible = mListContainer.isInVisibleLocation(entry.row);
+                boolean isVisible = mListContainer.isInVisibleLocation(entry);
                 NotificationVisibility visObj = NotificationVisibility.obtain(key, i, N, isVisible);
                 boolean previouslyVisible = mCurrentlyVisibleNotifications.contains(visObj);
                 if (isVisible) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index b6d99b2..ffd58ab 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -104,6 +104,7 @@
 import com.android.systemui.statusbar.notification.stack.AnimationProperties;
 import com.android.systemui.statusbar.notification.stack.ExpandableViewState;
 import com.android.systemui.statusbar.notification.stack.NotificationChildrenContainer;
+import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
 import com.android.systemui.statusbar.notification.stack.StackScrollState;
 import com.android.systemui.statusbar.phone.NotificationGroupManager;
 import com.android.systemui.statusbar.phone.StatusBar;
@@ -1411,16 +1412,16 @@
 
     public void performDismiss(boolean fromAccessibility) {
         if (isOnlyChildInGroup()) {
-            ExpandableNotificationRow groupSummary =
+            NotificationData.Entry groupSummary =
                     mGroupManager.getLogicalGroupSummary(getStatusBarNotification());
             if (groupSummary.isClearable()) {
                 // If this is the only child in the group, dismiss the group, but don't try to show
                 // the blocking helper affordance!
-                groupSummary.performDismiss(fromAccessibility);
+                groupSummary.getRow().performDismiss(fromAccessibility);
             }
         }
         setDismissed(fromAccessibility);
-        if (isClearable()) {
+        if (mEntry.isClearable()) {
             // TODO: track dismiss sentiment
             if (mOnDismissRunnable != null) {
                 mOnDismissRunnable.run();
@@ -2244,28 +2245,6 @@
         setRippleAllowed(allowed);
     }
 
-    /**
-     * @return Can the underlying notification be cleared? This can be different from whether the
-     *         notification can be dismissed in case notifications are sensitive on the lockscreen.
-     * @see #canViewBeDismissed()
-     */
-    public boolean isClearable() {
-        if (mStatusBarNotification == null || !mStatusBarNotification.isClearable()) {
-            return false;
-        }
-        if (mIsSummaryWithChildren) {
-            List<ExpandableNotificationRow> notificationChildren =
-                    mChildrenContainer.getNotificationChildren();
-            for (int i = 0; i < notificationChildren.size(); i++) {
-                ExpandableNotificationRow child = notificationChildren.get(i);
-                if (!child.isClearable()) {
-                    return false;
-                }
-            }
-        }
-        return true;
-    }
-
     @Override
     public int getIntrinsicHeight() {
         if (isShownAsBubble()) {
@@ -2533,10 +2512,10 @@
     /**
      * @return Whether this view is allowed to be dismissed. Only valid for visible notifications as
      *         otherwise some state might not be updated. To request about the general clearability
-     *         see {@link #isClearable()}.
+     *         see {@link NotificationData.Entry#isClearable()}.
      */
     public boolean canViewBeDismissed() {
-        return isClearable() && (!shouldShowPublic() || !mSensitiveHiddenInGeneral);
+        return mEntry.isClearable() && (!shouldShowPublic() || !mSensitiveHiddenInGeneral);
     }
 
     private boolean shouldShowPublic() {
@@ -3038,6 +3017,21 @@
         return mOnAmbient;
     }
 
+    //TODO: this logic can't depend on layout if we are recycling!
+    public boolean isMediaRow() {
+        return getExpandedContentView() != null
+                && getExpandedContentView().findViewById(
+                com.android.internal.R.id.media_actions) != null;
+    }
+
+    public boolean isTopLevelChild() {
+        return getParent() instanceof NotificationStackScrollLayout;
+    }
+
+    public boolean isGroupNotFullyVisible() {
+        return getClipTopAmount() > 0 || getTranslationY() < 0;
+    }
+
     public void setAboveShelf(boolean aboveShelf) {
         boolean wasAboveShelf = isAboveShelf();
         mAboveShelf = aboveShelf;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
index bb9a341..783ca7b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
@@ -1227,17 +1227,18 @@
         mOnContentViewInactiveListeners.clear();
         mBeforeN = entry.targetSdk < Build.VERSION_CODES.N;
         updateAllSingleLineViews();
+        ExpandableNotificationRow row = entry.getRow();
         if (mContractedChild != null) {
-            mContractedWrapper.onContentUpdated(entry.row);
+            mContractedWrapper.onContentUpdated(row);
         }
         if (mExpandedChild != null) {
-            mExpandedWrapper.onContentUpdated(entry.row);
+            mExpandedWrapper.onContentUpdated(row);
         }
         if (mHeadsUpChild != null) {
-            mHeadsUpWrapper.onContentUpdated(entry.row);
+            mHeadsUpWrapper.onContentUpdated(row);
         }
         if (mAmbientChild != null) {
-            mAmbientWrapper.onContentUpdated(entry.row);
+            mAmbientWrapper.onContentUpdated(row);
         }
         applyRemoteInputAndSmartReply(entry);
         updateLegacy();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
index 37bf06e..7895a8e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
@@ -86,7 +86,6 @@
     private final ActivityStarter mActivityStarter = Dependency.get(ActivityStarter.class);
 
     // which notification is currently being longpress-examined by the user
-    private final IStatusBarService mBarService;
     private NotificationGuts mNotificationGutsExposed;
     private NotificationMenuRowPlugin.MenuItem mGutsMenuItem;
     private NotificationSafeToRemoveCallback mNotificationLifetimeFinishedCallback;
@@ -103,8 +102,6 @@
 
         mAccessibilityManager = (AccessibilityManager)
                 mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
-        mBarService = IStatusBarService.Stub.asInterface(
-                ServiceManager.getService(Context.STATUS_BAR_SERVICE));
     }
 
     public void setUpWithPresenter(NotificationPresenter presenter,
@@ -116,9 +113,9 @@
         mOnSettingsClickListener = onSettingsClick;
     }
 
-    public void onDensityOrFontScaleChanged(ExpandableNotificationRow row) {
-        setExposedGuts(row.getGuts());
-        bindGuts(row);
+    public void onDensityOrFontScaleChanged(NotificationData.Entry entry) {
+        setExposedGuts(entry.getGuts());
+        bindGuts(entry.getRow());
     }
 
     /**
@@ -441,8 +438,8 @@
     public boolean shouldExtendLifetime(NotificationData.Entry entry) {
         return entry != null
                 &&(mNotificationGutsExposed != null
-                    && entry.row.getGuts() != null
-                    && mNotificationGutsExposed == entry.row.getGuts()
+                    && entry.getGuts() != null
+                    && mNotificationGutsExposed == entry.getGuts()
                     && !mNotificationGutsExposed.isLeavebehind());
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListContainer.java
index 4d100a4..6de4fc8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListContainer.java
@@ -118,9 +118,9 @@
     /**
      * Handle snapping a non-dismissable row back if the user tried to dismiss it.
      *
-     * @param row row to snap back
+     * @param entry the entry whose row needs to snap back
      */
-    void snapViewIfNeeded(ExpandableNotificationRow row);
+    void snapViewIfNeeded(NotificationData.Entry entry);
 
     /**
      * Get the view parent for a notification entry. For example, NotificationStackScrollLayout.
@@ -149,9 +149,9 @@
      * Called when a notification is removed from the shade. This cleans up the state for a
      * given view.
      *
-     * @param view view to clean up view state for
+     * @param entry the entry whose view's view state needs to be cleaned up (say that 5 times fast)
      */
-    void cleanUpViewState(View view);
+    void cleanUpViewStateForEntry(NotificationData.Entry entry);
 
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManager.java
index c867a41..27838a2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManager.java
@@ -21,6 +21,7 @@
 
 import android.view.View;
 
+import com.android.systemui.statusbar.notification.NotificationData;
 import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
@@ -50,13 +51,13 @@
     }
 
     @Override
-    public void onHeadsUpPinned(ExpandableNotificationRow headsUp) {
-        updateView(headsUp, false /* animate */);
+    public void onHeadsUpPinned(NotificationData.Entry headsUp) {
+        updateView(headsUp.getRow(), false /* animate */);
     }
 
     @Override
-    public void onHeadsUpUnPinned(ExpandableNotificationRow headsUp) {
-        updateView(headsUp, true /* animate */);
+    public void onHeadsUpUnPinned(NotificationData.Entry headsUp) {
+        updateView(headsUp.getRow(), true /* animate */);
     }
 
     public void onHeadsupAnimatingAwayChanged(ExpandableNotificationRow row,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index ecd0d98..faccff3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -600,12 +600,12 @@
             public void setRemoteInputActive(NotificationData.Entry entry,
                     boolean remoteInputActive) {
                 mHeadsUpManager.setRemoteInputActive(entry, remoteInputActive);
-                entry.row.notifyHeightChanged(true /* needsAnimation */);
+                entry.notifyHeightChanged(true /* needsAnimation */);
                 updateFooter();
             }
 
             public void lockScrollTo(NotificationData.Entry entry) {
-                NotificationStackScrollLayout.this.lockScrollTo(entry.row);
+                NotificationStackScrollLayout.this.lockScrollTo(entry.getRow());
             }
 
             public void requestDisallowLongPressAndDismiss() {
@@ -897,7 +897,8 @@
 
     @Override
     @ShadeViewRefactor(RefactorComponent.LAYOUT_ALGORITHM)
-    public boolean isInVisibleLocation(ExpandableNotificationRow row) {
+    public boolean isInVisibleLocation(NotificationData.Entry entry) {
+        ExpandableNotificationRow row = entry.getRow();
         ExpandableViewState childViewState = mCurrentStackScrollState.getViewStateForView(row);
         if (childViewState == null) {
             return false;
@@ -1213,12 +1214,12 @@
         if (topEntry == null) {
             return 0;
         }
-        ExpandableNotificationRow row = topEntry.row;
+        ExpandableNotificationRow row = topEntry.getRow();
         if (row.isChildInGroup()) {
-            final ExpandableNotificationRow groupSummary
+            final NotificationData.Entry groupSummary
                     = mGroupManager.getGroupSummary(row.getStatusBarNotification());
             if (groupSummary != null) {
-                row = groupSummary;
+                row = groupSummary.getRow();
             }
         }
         return row.getPinnedHeadsUpHeight();
@@ -1390,11 +1391,12 @@
                     && touchY >= top && touchY <= bottom && touchX >= left && touchX <= right) {
                 if (slidingChild instanceof ExpandableNotificationRow) {
                     ExpandableNotificationRow row = (ExpandableNotificationRow) slidingChild;
+                    NotificationData.Entry entry = row.getEntry();
                     if (!mIsExpanded && row.isHeadsUp() && row.isPinned()
-                            && mHeadsUpManager.getTopEntry().row != row
+                            && mHeadsUpManager.getTopEntry().getRow() != row
                             && mGroupManager.getGroupSummary(
-                            mHeadsUpManager.getTopEntry().row.getStatusBarNotification())
-                            != row) {
+                                mHeadsUpManager.getTopEntry().notification)
+                            != entry) {
                         continue;
                     }
                     return row.getViewAtPosition(touchY - childTop);
@@ -1524,7 +1526,8 @@
 
     @Override
     @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
-    public void snapViewIfNeeded(ExpandableNotificationRow child) {
+    public void snapViewIfNeeded(NotificationData.Entry entry) {
+        ExpandableNotificationRow child = entry.getRow();
         boolean animate = mIsExpanded || isPinnedHeadsUp(child);
         // If the child is showing the notification menu snap to that
         float targetLeft = child.getProvider().isMenuVisible() ? child.getTranslation() : 0;
@@ -2514,7 +2517,8 @@
 
     @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
     @Override
-    public void cleanUpViewState(View child) {
+    public void cleanUpViewStateForEntry(NotificationData.Entry entry) {
+        View child = entry.getRow();
         if (child == mSwipeHelper.getTranslatingParentView()) {
             mSwipeHelper.clearTranslatingParentView();
         }
@@ -2644,9 +2648,9 @@
     private boolean isChildInInvisibleGroup(View child) {
         if (child instanceof ExpandableNotificationRow) {
             ExpandableNotificationRow row = (ExpandableNotificationRow) child;
-            ExpandableNotificationRow groupSummary =
+            NotificationData.Entry groupSummary =
                     mGroupManager.getGroupSummary(row.getStatusBarNotification());
-            if (groupSummary != null && groupSummary != row) {
+            if (groupSummary != null && groupSummary.getRow() != row) {
                 return row.getVisibility() == View.INVISIBLE;
             }
         }
@@ -4662,6 +4666,11 @@
         mHeadsUpManager.setAnimationStateHandler(this::setHeadsUpGoingAwayAnimationsAllowed);
     }
 
+    public void generateHeadsUpAnimation(NotificationData.Entry entry, boolean isHeadsUp) {
+        ExpandableNotificationRow row = entry.getHeadsUpAnimationView();
+        generateHeadsUpAnimation(row, isHeadsUp);
+    }
+
     @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
     public void generateHeadsUpAnimation(ExpandableNotificationRow row, boolean isHeadsUp) {
         if (mAnimationsEnabled && (isHeadsUp || mHeadsUpGoingAwayAnimationsAllowed)) {
@@ -5692,7 +5701,7 @@
                         && (parent.areGutsExposed()
                         || mSwipeHelper.getExposedMenuView() == parent
                         || (parent.getNotificationChildren().size() == 1
-                        && parent.isClearable()))) {
+                        && parent.getEntry().isClearable()))) {
                     // In this case the group is expanded and showing the menu for the
                     // group, further interaction should apply to the group, not any
                     // child notifications so we use the parent of the child. We also do the same
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
index 40f9f45..3c8cad7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
@@ -143,9 +143,9 @@
     }
 
     @Override
-    public void onHeadsUpPinned(ExpandableNotificationRow headsUp) {
+    public void onHeadsUpPinned(NotificationData.Entry entry) {
         updateTopEntry();
-        updateHeader(headsUp.getEntry());
+        updateHeader(entry);
     }
 
     /** To count the distance from the window right boundary to scroller right boundary. The
@@ -298,9 +298,9 @@
     }
 
     @Override
-    public void onHeadsUpUnPinned(ExpandableNotificationRow headsUp) {
+    public void onHeadsUpUnPinned(NotificationData.Entry entry) {
         updateTopEntry();
-        updateHeader(headsUp.getEntry());
+        updateHeader(entry);
     }
 
     public void setExpandedHeight(float expandedHeight, float appearFraction) {
@@ -339,7 +339,7 @@
     }
 
     public void updateHeader(NotificationData.Entry entry) {
-        ExpandableNotificationRow row = entry.row;
+        ExpandableNotificationRow row = entry.getRow();
         float headerVisibleAmount = 1.0f;
         if (row.isPinned() || row.isHeadsUpAnimatingAway() || row == mTrackedChild) {
             headerVisibleAmount = mExpandFraction;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
index 00d6b14..9faada0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
@@ -304,18 +304,19 @@
             return;
         }
         if (hasPinnedHeadsUp()) {
-            ExpandableNotificationRow topEntry = getTopEntry().row;
+            NotificationData.Entry topEntry = getTopEntry();
             if (topEntry.isChildInGroup()) {
-                final ExpandableNotificationRow groupSummary
-                        = mGroupManager.getGroupSummary(topEntry.getStatusBarNotification());
+                final NotificationData.Entry groupSummary
+                        = mGroupManager.getGroupSummary(topEntry.notification);
                 if (groupSummary != null) {
                     topEntry = groupSummary;
                 }
             }
-            topEntry.getLocationOnScreen(mTmpTwoArray);
+            ExpandableNotificationRow topRow = topEntry.getRow();
+            topRow.getLocationOnScreen(mTmpTwoArray);
             int minX = mTmpTwoArray[0];
-            int maxX = mTmpTwoArray[0] + topEntry.getWidth();
-            int height = topEntry.getIntrinsicHeight();
+            int maxX = mTmpTwoArray[0] + topRow.getWidth();
+            int height = topRow.getIntrinsicHeight();
 
             info.setTouchableInsets(ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION);
             info.touchableRegion.set(minX, 0, maxX, mHeadsUpInset + height);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java
index be4df45..9c1c71a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java
@@ -84,8 +84,8 @@
                     // We might touch above the visible heads up child, but then we still would
                     // like to capture it.
                     NotificationData.Entry topEntry = mHeadsUpManager.getTopEntry();
-                    if (topEntry != null && topEntry.row.isPinned()) {
-                        mPickedChild = topEntry.row;
+                    if (topEntry != null && topEntry.isRowPinned()) {
+                        mPickedChild = topEntry.getRow();
                         mTouchingHeadsUpView = true;
                     }
                 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java
index c74514e..3e31fa0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java
@@ -198,7 +198,7 @@
                 alertNotificationWhenPossible(entry, getActiveAlertManager());
             } else {
                 // The transfer is no longer valid. Free the content.
-                entry.row.freeContentViewWhenSafe(alertInfo.mAlertManager.getContentFlag());
+                entry.getRow().freeContentViewWhenSafe(alertInfo.mAlertManager.getContentFlag());
             }
         }
     }
@@ -299,9 +299,9 @@
 
         Entry child = mGroupManager.getLogicalChildren(summary.notification).iterator().next();
         if (child != null) {
-            if (child.row.keepInParent()
-                    || child.row.isRemoved()
-                    || child.row.isDismissed()) {
+            if (child.getRow().keepInParent()
+                    || child.isRowRemoved()
+                    || child.isRowDismissed()) {
                 // The notification is actually already removed. No need to alert it.
                 return;
             }
@@ -390,10 +390,10 @@
     private void alertNotificationWhenPossible(@NonNull Entry entry,
             @NonNull AlertingNotificationManager alertManager) {
         @InflationFlag int contentFlag = alertManager.getContentFlag();
-        if (!entry.row.isInflationFlagSet(contentFlag)) {
+        if (!entry.getRow().isInflationFlagSet(contentFlag)) {
             mPendingAlerts.put(entry.key, new PendingAlertInfo(entry, alertManager));
-            entry.row.updateInflationFlag(contentFlag, true /* shouldInflate */);
-            entry.row.inflateViews();
+            entry.getRow().updateInflationFlag(contentFlag, true /* shouldInflate */);
+            entry.getRow().inflateViews();
             return;
         }
         if (alertManager.isAlerting(entry.key)) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java
index 8ceabf8..448b5c3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java
@@ -87,8 +87,7 @@
         group.expanded = expanded;
         if (group.summary != null) {
             for (OnGroupChangeListener listener : mListeners) {
-                listener.onGroupExpansionChanged(group.summary.row,
-                        expanded);
+                listener.onGroupExpansionChanged(group.summary.getRow(), expanded);
             }
         }
     }
@@ -133,7 +132,7 @@
     }
 
     public void onEntryAdded(final NotificationData.Entry added) {
-        if (added.row.isRemoved()) {
+        if (added.isRowRemoved()) {
             added.setDebugThrowable(new Throwable());
         }
         final StatusBarNotification sbn = added.notification;
@@ -152,17 +151,17 @@
             if (existing != null && existing != added) {
                 Throwable existingThrowable = existing.getDebugThrowable();
                 Log.wtf(TAG, "Inconsistent entries found with the same key " + added.key
-                        + "existing removed: " + existing.row.isRemoved()
+                        + "existing removed: " + existing.isRowRemoved()
                         + (existingThrowable != null
                                 ? Log.getStackTraceString(existingThrowable) + "\n": "")
-                        + " added removed" + added.row.isRemoved()
+                        + " added removed" + added.isRowRemoved()
                         , new Throwable());
             }
             group.children.put(added.key, added);
             updateSuppression(group);
         } else {
             group.summary = added;
-            group.expanded = added.row.areChildrenExpanded();
+            group.expanded = added.areChildrenExpanded();
             updateSuppression(group);
             if (!group.children.isEmpty()) {
                 ArrayList<NotificationData.Entry> childrenCopy
@@ -263,9 +262,9 @@
         if (!isOnlyChild(sbn)) {
             return false;
         }
-        ExpandableNotificationRow logicalGroupSummary = getLogicalGroupSummary(sbn);
+        NotificationData.Entry logicalGroupSummary = getLogicalGroupSummary(sbn);
         return logicalGroupSummary != null
-                && !logicalGroupSummary.getStatusBarNotification().equals(sbn);
+                && !logicalGroupSummary.notification.equals(sbn);
     }
 
     private int getTotalNumberOfChildren(StatusBarNotification sbn) {
@@ -339,7 +338,7 @@
      * Get the summary of a specified status bar notification. For isolated notification this return
      * itself.
      */
-    public ExpandableNotificationRow getGroupSummary(StatusBarNotification sbn) {
+    public NotificationData.Entry getGroupSummary(StatusBarNotification sbn) {
         return getGroupSummary(getGroupKey(sbn));
     }
 
@@ -348,16 +347,17 @@
      * but the logical summary, i.e when a child is isolated, it still returns the summary as if
      * it wasn't isolated.
      */
-    public ExpandableNotificationRow getLogicalGroupSummary(StatusBarNotification sbn) {
+    public NotificationData.Entry getLogicalGroupSummary(StatusBarNotification sbn) {
         return getGroupSummary(sbn.getGroupKey());
     }
 
     @Nullable
-    private ExpandableNotificationRow getGroupSummary(String groupKey) {
+    private NotificationData.Entry getGroupSummary(String groupKey) {
         NotificationGroup group = mGroupMap.get(groupKey);
+        //TODO: see if this can become an Entry
         return group == null ? null
                 : group.summary == null ? null
-                        : group.summary.row;
+                        : group.summary;
     }
 
     /**
@@ -438,11 +438,11 @@
     }
 
     @Override
-    public void onHeadsUpPinned(ExpandableNotificationRow headsUp) {
+    public void onHeadsUpPinned(NotificationData.Entry entry) {
     }
 
     @Override
-    public void onHeadsUpUnPinned(ExpandableNotificationRow headsUp) {
+    public void onHeadsUpUnPinned(NotificationData.Entry entry) {
     }
 
     @Override
@@ -533,8 +533,7 @@
 
     private boolean isGroupNotFullyVisible(NotificationGroup notificationGroup) {
         return notificationGroup.summary == null
-                || notificationGroup.summary.row.getClipTopAmount() > 0
-                || notificationGroup.summary.row.getTranslationY() < 0;
+                || notificationGroup.summary.isGroupNotFullyVisible();
     }
 
     public void setHeadsUpManager(HeadsUpManager headsUpManager) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
index 184766c..2d5d562 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
@@ -192,13 +192,13 @@
                 && !mEntryManager.getNotificationData().isHighPriority(entry.notification)) {
             return false;
         }
-        if (!StatusBar.isTopLevelChild(entry)) {
+        if (!entry.isTopLevelChild()) {
             return false;
         }
-        if (entry.row.getVisibility() == View.GONE) {
+        if (entry.getRow().getVisibility() == View.GONE) {
             return false;
         }
-        if (entry.row.isDismissed() && hideDismissed) {
+        if (entry.isRowDismissed() && hideDismissed) {
             return false;
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 851e6d0..33d176a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -2500,25 +2500,26 @@
     }
 
     @Override
-    public void onHeadsUpPinned(ExpandableNotificationRow headsUp) {
-        mNotificationStackScroller.generateHeadsUpAnimation(headsUp, true);
+    public void onHeadsUpPinned(NotificationData.Entry entry) {
+        mNotificationStackScroller.generateHeadsUpAnimation(entry.getHeadsUpAnimationView(), true);
     }
 
     @Override
-    public void onHeadsUpUnPinned(ExpandableNotificationRow headsUp) {
+    public void onHeadsUpUnPinned(NotificationData.Entry entry) {
 
         // When we're unpinning the notification via active edge they remain heads-upped,
         // we need to make sure that an animation happens in this case, otherwise the notification
         // will stick to the top without any interaction.
-        if (isFullyCollapsed() && headsUp.isHeadsUp()) {
-            mNotificationStackScroller.generateHeadsUpAnimation(headsUp, false);
-            headsUp.setHeadsUpIsVisible();
+        if (isFullyCollapsed() && entry.isRowHeadsUp()) {
+            mNotificationStackScroller.generateHeadsUpAnimation(
+                    entry.getHeadsUpAnimationView(), false);
+            entry.setHeadsUpIsVisible();
         }
     }
 
     @Override
     public void onHeadsUpStateChanged(NotificationData.Entry entry, boolean isHeadsUp) {
-        mNotificationStackScroller.generateHeadsUpAnimation(entry.row, isHeadsUp);
+        mNotificationStackScroller.generateHeadsUpAnimation(entry, isHeadsUp);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index bdddf5b..05f8f18 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -484,7 +484,7 @@
 
     private Runnable mLaunchTransitionEndRunnable;
     protected boolean mLaunchTransitionFadingAway;
-    private ExpandableNotificationRow mDraggedDownRow;
+    private NotificationData.Entry mDraggedDownEntry;
     private boolean mLaunchCameraOnScreenTurningOn;
     private boolean mLaunchCameraOnFinishedGoingToSleep;
     private int mLastCameraLaunchSource;
@@ -1265,10 +1265,6 @@
         mQSPanel.clickTile(tile);
     }
 
-    public static boolean isTopLevelChild(Entry entry) {
-        return entry.row.getParent() instanceof NotificationStackScrollLayout;
-    }
-
     public boolean areNotificationsHidden() {
         return mZenController.areNotificationsHiddenInShade();
     }
@@ -1491,12 +1487,12 @@
     }
 
     @Override
-    public void onHeadsUpPinned(ExpandableNotificationRow headsUp) {
+    public void onHeadsUpPinned(NotificationData.Entry entry) {
         dismissVolumeDialog();
     }
 
     @Override
-    public void onHeadsUpUnPinned(ExpandableNotificationRow headsUp) {
+    public void onHeadsUpUnPinned(NotificationData.Entry entry) {
     }
 
     @Override
@@ -2605,9 +2601,7 @@
         final int notificationCount = activeNotifications.size();
         for (int i = 0; i < notificationCount; i++) {
             NotificationData.Entry entry = activeNotifications.get(i);
-            if (entry.row != null) {
-                entry.row.resetUserExpansion();
-            }
+            entry.resetUserExpansion();
         }
     }
 
@@ -3038,10 +3032,10 @@
             mStatusBarStateController.setState(StatusBarState.KEYGUARD);
         }
         updatePanelExpansionForKeyguard();
-        if (mDraggedDownRow != null) {
-            mDraggedDownRow.setUserLocked(false);
-            mDraggedDownRow.notifyHeightChanged(false  /* needsAnimation */);
-            mDraggedDownRow = null;
+        if (mDraggedDownEntry != null) {
+            mDraggedDownEntry.setUserLocked(false);
+            mDraggedDownEntry.notifyHeightChanged(false /* needsAnimation */);
+            mDraggedDownEntry = null;
         }
     }
 
@@ -3181,9 +3175,9 @@
             }
             long delay = mKeyguardMonitor.calculateGoingToFullShadeDelay();
             mNotificationPanel.animateToFullShade(delay);
-            if (mDraggedDownRow != null) {
-                mDraggedDownRow.setUserLocked(false);
-                mDraggedDownRow = null;
+            if (mDraggedDownEntry != null) {
+                mDraggedDownEntry.setUserLocked(false);
+                mDraggedDownEntry = null;
             }
 
             // TODO(115978725): Support animations on external nav bars.
@@ -3575,14 +3569,15 @@
 
         int userId = mLockscreenUserManager.getCurrentUserId();
         ExpandableNotificationRow row = null;
+        NotificationData.Entry entry = null;
         if (expandView instanceof ExpandableNotificationRow) {
-            row = (ExpandableNotificationRow) expandView;
-            row.setUserExpanded(true /* userExpanded */, true /* allowChildExpansion */);
+            entry = ((ExpandableNotificationRow) expandView).getEntry();
+            entry.setUserExpanded(true /* userExpanded */, true /* allowChildExpansion */);
             // Indicate that the group expansion is changing at this time -- this way the group
             // and children backgrounds / divider animations will look correct.
-            row.setGroupExpansionChanging(true);
-            if (row.getStatusBarNotification() != null) {
-                userId = row.getStatusBarNotification().getUserId();
+            entry.setGroupExpansionChanging(true);
+            if (entry.notification != null) {
+                userId = entry.notification.getUserId();
             }
         }
         boolean fullShadeNeedsBouncer = !mLockscreenUserManager.
@@ -3592,7 +3587,7 @@
         if (mLockscreenUserManager.isLockscreenPublicMode(userId) && fullShadeNeedsBouncer) {
             mStatusBarStateController.setLeaveOpenOnKeyguardHide(true);
             showBouncerIfKeyguard();
-            mDraggedDownRow = row;
+            mDraggedDownEntry = entry;
             mPendingRemoteInputView = null;
         } else {
             mNotificationPanel.animateToFullShade(0 /* delay */);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
index edfc049..588c3a8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
@@ -418,7 +418,7 @@
             StatusBarNotification parentToCancel = null;
             if (shouldAutoCancel(sbn) && mGroupManager.isOnlyChildInGroup(sbn)) {
                 StatusBarNotification summarySbn =
-                        mGroupManager.getLogicalGroupSummary(sbn).getStatusBarNotification();
+                        mGroupManager.getLogicalGroupSummary(sbn).notification;
                 if (shouldAutoCancel(summarySbn)) {
                     parentToCancel = summarySbn;
                 }
@@ -591,7 +591,7 @@
     public void onExpandClicked(Entry clickedEntry, boolean nowExpanded) {
         mHeadsUpManager.setExpanded(clickedEntry, nowExpanded);
         if (mStatusBarStateController.getState() == StatusBarState.KEYGUARD && nowExpanded) {
-            mShadeController.goToLockedShade(clickedEntry.row);
+            mShadeController.goToLockedShade(clickedEntry.getRow());
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
index fdab616..e7280643 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
@@ -123,15 +123,15 @@
         if (Log.isLoggable(TAG, Log.VERBOSE)) {
             Log.v(TAG, "setEntryPinned: " + isPinned);
         }
-        ExpandableNotificationRow row = headsUpEntry.mEntry.row;
-        if (row.isPinned() != isPinned) {
-            row.setPinned(isPinned);
+        NotificationData.Entry entry = headsUpEntry.mEntry;
+        if (entry.isRowPinned() != isPinned) {
+            entry.setRowPinned(isPinned);
             updatePinnedMode();
             for (OnHeadsUpChangedListener listener : mListeners) {
                 if (isPinned) {
-                    listener.onHeadsUpPinned(row);
+                    listener.onHeadsUpPinned(entry);
                 } else {
-                    listener.onHeadsUpUnPinned(row);
+                    listener.onHeadsUpUnPinned(entry);
                 }
             }
         }
@@ -144,7 +144,7 @@
     @Override
     protected void onAlertEntryAdded(AlertEntry alertEntry) {
         NotificationData.Entry entry = alertEntry.mEntry;
-        entry.row.setHeadsUp(true);
+        entry.setHeadsUp(true);
         setEntryPinned((HeadsUpEntry) alertEntry, shouldHeadsUpBecomePinned(entry));
         for (OnHeadsUpChangedListener listener : mListeners) {
             listener.onHeadsUpStateChanged(entry, true);
@@ -154,12 +154,12 @@
     @Override
     protected void onAlertEntryRemoved(AlertEntry alertEntry) {
         NotificationData.Entry entry = alertEntry.mEntry;
-        entry.row.setHeadsUp(false);
+        entry.setHeadsUp(false);
         setEntryPinned((HeadsUpEntry) alertEntry, false /* isPinned */);
         for (OnHeadsUpChangedListener listener : mListeners) {
             listener.onHeadsUpStateChanged(entry, false);
         }
-        entry.row.freeContentViewWhenSafe(FLAG_CONTENT_VIEW_HEADS_UP);
+        entry.freeContentViewWhenSafe(FLAG_CONTENT_VIEW_HEADS_UP);
     }
 
     protected void updatePinnedMode() {
@@ -282,7 +282,7 @@
     private boolean hasPinnedNotificationInternal() {
         for (String key : mAlertEntries.keySet()) {
             AlertEntry entry = getHeadsUpEntry(key);
-            if (entry.mEntry.row.isPinned()) {
+            if (entry.mEntry.isRowPinned()) {
                 return true;
             }
         }
@@ -302,10 +302,9 @@
 
             // when the user unpinned all of HUNs by moving one HUN, all of HUNs should not stay
             // on the screen.
-            if (userUnPinned && entry.mEntry != null && entry.mEntry.row != null) {
-                ExpandableNotificationRow row = entry.mEntry.row;
-                if (row.mustStayOnScreen()) {
-                    row.setHeadsUpIsVisible();
+            if (userUnPinned && entry.mEntry != null) {
+                if (entry.mEntry.mustStayOnScreen()) {
+                    entry.mEntry.setHeadsUpIsVisible();
                 }
             }
         }
@@ -341,7 +340,7 @@
      */
     public void setExpanded(@NonNull NotificationData.Entry entry, boolean expanded) {
         HeadsUpEntry headsUpEntry = getHeadsUpEntry(entry.key);
-        if (headsUpEntry != null && entry.row.isPinned()) {
+        if (headsUpEntry != null && entry.isRowPinned()) {
             headsUpEntry.setExpanded(expanded);
         }
     }
@@ -365,15 +364,15 @@
 
         @Override
         protected boolean isSticky() {
-            return (mEntry.row.isPinned() && expanded)
+            return (mEntry.isRowPinned() && expanded)
                     || remoteInputActive || hasFullScreenIntent(mEntry);
         }
 
         @Override
         public int compareTo(@NonNull AlertEntry alertEntry) {
             HeadsUpEntry headsUpEntry = (HeadsUpEntry) alertEntry;
-            boolean isPinned = mEntry.row.isPinned();
-            boolean otherPinned = headsUpEntry.mEntry.row.isPinned();
+            boolean isPinned = mEntry.isRowPinned();
+            boolean otherPinned = headsUpEntry.mEntry.isRowPinned();
             if (isPinned && !otherPinned) {
                 return -1;
             } else if (!isPinned && otherPinned) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/OnHeadsUpChangedListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/OnHeadsUpChangedListener.java
index d434768..7ad547a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/OnHeadsUpChangedListener.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/OnHeadsUpChangedListener.java
@@ -33,12 +33,12 @@
     /**
      * A notification was just pinned to the top.
      */
-    default void onHeadsUpPinned(ExpandableNotificationRow headsUp) {}
+    default void onHeadsUpPinned(NotificationData.Entry entry) {}
 
     /**
      * A notification was just unpinned from the top.
      */
-    default void onHeadsUpUnPinned(ExpandableNotificationRow headsUp) {}
+    default void onHeadsUpUnPinned(NotificationData.Entry entry) {}
 
     /**
      * A notification just became a heads up or turned back to its normal state.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
index a485fa8..866015e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
@@ -245,7 +245,7 @@
     @Override
     protected void onAttachedToWindow() {
         super.onAttachedToWindow();
-        if (mEntry.row.isChangingPosition()) {
+        if (mEntry.getRow().isChangingPosition()) {
             if (getVisibility() == VISIBLE && mEditText.isFocusable()) {
                 mEditText.requestFocus();
             }
@@ -255,7 +255,7 @@
     @Override
     protected void onDetachedFromWindow() {
         super.onDetachedFromWindow();
-        if (mEntry.row.isChangingPosition() || isTemporarilyDetached()) {
+        if (mEntry.getRow().isChangingPosition() || isTemporarilyDetached()) {
             return;
         }
         mController.removeRemoteInput(mEntry, mToken);
@@ -495,7 +495,7 @@
         }
 
         private void defocusIfNeeded(boolean animate) {
-            if (mRemoteInputView != null && mRemoteInputView.mEntry.row.isChangingPosition()
+            if (mRemoteInputView != null && mRemoteInputView.mEntry.getRow().isChangingPosition()
                     || isTemporarilyDetached()) {
                 if (isTemporarilyDetached()) {
                     // We might get reattached but then the other one of HUN / expanded might steal