1 /* 2 * Copyright (C) 2020 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.systemui.statusbar.notification.collection.inflation; 18 19 import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_CONTRACTED; 20 import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_EXPANDED; 21 import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_PUBLIC; 22 23 import static java.util.Objects.requireNonNull; 24 25 import android.annotation.NonNull; 26 import android.annotation.Nullable; 27 import android.content.Context; 28 import android.os.Build; 29 import android.view.ViewGroup; 30 31 import com.android.internal.util.NotificationMessagingUtil; 32 import com.android.systemui.dagger.SysUISingleton; 33 import com.android.systemui.flags.FeatureFlags; 34 import com.android.systemui.statusbar.NotificationLockscreenUserManager; 35 import com.android.systemui.statusbar.NotificationPresenter; 36 import com.android.systemui.statusbar.NotificationRemoteInputManager; 37 import com.android.systemui.statusbar.notification.InflationException; 38 import com.android.systemui.statusbar.notification.NotificationClicker; 39 import com.android.systemui.statusbar.notification.collection.NotificationEntry; 40 import com.android.systemui.statusbar.notification.icon.IconManager; 41 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; 42 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRowController; 43 import com.android.systemui.statusbar.notification.row.NotifBindPipeline; 44 import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder; 45 import com.android.systemui.statusbar.notification.row.RowContentBindParams; 46 import com.android.systemui.statusbar.notification.row.RowContentBindStage; 47 import com.android.systemui.statusbar.notification.row.RowInflaterTask; 48 import com.android.systemui.statusbar.notification.row.dagger.ExpandableNotificationRowComponent; 49 import com.android.systemui.statusbar.notification.stack.NotificationListContainer; 50 51 import javax.inject.Inject; 52 import javax.inject.Provider; 53 54 /** Handles inflating and updating views for notifications. */ 55 @SysUISingleton 56 public class NotificationRowBinderImpl implements NotificationRowBinder { 57 58 private static final String TAG = "NotificationViewManager"; 59 60 private final Context mContext; 61 private final NotificationMessagingUtil mMessagingUtil; 62 private final NotificationRemoteInputManager mNotificationRemoteInputManager; 63 private final NotificationLockscreenUserManager mNotificationLockscreenUserManager; 64 private final NotifBindPipeline mNotifBindPipeline; 65 private final RowContentBindStage mRowContentBindStage; 66 private final Provider<RowInflaterTask> mRowInflaterTaskProvider; 67 private final ExpandableNotificationRowComponent.Builder 68 mExpandableNotificationRowComponentBuilder; 69 private final IconManager mIconManager; 70 private final NotificationRowBinderLogger mLogger; 71 72 private NotificationPresenter mPresenter; 73 private NotificationListContainer mListContainer; 74 private NotificationClicker mNotificationClicker; 75 private FeatureFlags mFeatureFlags; 76 77 @Inject NotificationRowBinderImpl( Context context, NotificationMessagingUtil notificationMessagingUtil, NotificationRemoteInputManager notificationRemoteInputManager, NotificationLockscreenUserManager notificationLockscreenUserManager, NotifBindPipeline notifBindPipeline, RowContentBindStage rowContentBindStage, Provider<RowInflaterTask> rowInflaterTaskProvider, ExpandableNotificationRowComponent.Builder expandableNotificationRowComponentBuilder, IconManager iconManager, NotificationRowBinderLogger logger, FeatureFlags featureFlags)78 public NotificationRowBinderImpl( 79 Context context, 80 NotificationMessagingUtil notificationMessagingUtil, 81 NotificationRemoteInputManager notificationRemoteInputManager, 82 NotificationLockscreenUserManager notificationLockscreenUserManager, 83 NotifBindPipeline notifBindPipeline, 84 RowContentBindStage rowContentBindStage, 85 Provider<RowInflaterTask> rowInflaterTaskProvider, 86 ExpandableNotificationRowComponent.Builder expandableNotificationRowComponentBuilder, 87 IconManager iconManager, 88 NotificationRowBinderLogger logger, 89 FeatureFlags featureFlags) { 90 mContext = context; 91 mNotifBindPipeline = notifBindPipeline; 92 mRowContentBindStage = rowContentBindStage; 93 mMessagingUtil = notificationMessagingUtil; 94 mNotificationRemoteInputManager = notificationRemoteInputManager; 95 mNotificationLockscreenUserManager = notificationLockscreenUserManager; 96 mRowInflaterTaskProvider = rowInflaterTaskProvider; 97 mExpandableNotificationRowComponentBuilder = expandableNotificationRowComponentBuilder; 98 mIconManager = iconManager; 99 mLogger = logger; 100 mFeatureFlags = featureFlags; 101 } 102 103 /** 104 * Sets up late-bound dependencies for this component. 105 */ setUpWithPresenter(NotificationPresenter presenter, NotificationListContainer listContainer)106 public void setUpWithPresenter(NotificationPresenter presenter, 107 NotificationListContainer listContainer) { 108 mPresenter = presenter; 109 mListContainer = listContainer; 110 111 mIconManager.attach(); 112 } 113 setNotificationClicker(NotificationClicker clicker)114 public void setNotificationClicker(NotificationClicker clicker) { 115 mNotificationClicker = clicker; 116 } 117 118 /** 119 * Inflates the views for the given entry (possibly asynchronously). 120 */ 121 @Override inflateViews( NotificationEntry entry, @NonNull NotifInflater.Params params, NotificationRowContentBinder.InflationCallback callback)122 public void inflateViews( 123 NotificationEntry entry, 124 @NonNull NotifInflater.Params params, 125 NotificationRowContentBinder.InflationCallback callback) 126 throws InflationException { 127 ViewGroup parent = mListContainer.getViewParentForNotification(entry); 128 129 if (entry.rowExists()) { 130 mLogger.logUpdatingRow(entry, params); 131 mIconManager.updateIcons(entry); 132 ExpandableNotificationRow row = entry.getRow(); 133 row.reset(); 134 updateRow(entry, row); 135 inflateContentViews(entry, params, row, callback); 136 } else { 137 mLogger.logCreatingRow(entry, params); 138 mIconManager.createIcons(entry); 139 mLogger.logInflatingRow(entry); 140 mRowInflaterTaskProvider.get().inflate(mContext, parent, entry, 141 row -> { 142 mLogger.logInflatedRow(entry); 143 // Setup the controller for the view. 144 ExpandableNotificationRowComponent component = 145 mExpandableNotificationRowComponentBuilder 146 .expandableNotificationRow(row) 147 .notificationEntry(entry) 148 .onExpandClickListener(mPresenter) 149 .build(); 150 ExpandableNotificationRowController rowController = 151 component.getExpandableNotificationRowController(); 152 rowController.init(entry); 153 entry.setRowController(rowController); 154 bindRow(entry, row); 155 updateRow(entry, row); 156 inflateContentViews(entry, params, row, callback); 157 }); 158 } 159 } 160 161 @Override releaseViews(NotificationEntry entry)162 public void releaseViews(NotificationEntry entry) { 163 if (!entry.rowExists()) { 164 mLogger.logNotReleasingViewsRowDoesntExist(entry); 165 return; 166 } 167 mLogger.logReleasingViews(entry); 168 final RowContentBindParams params = mRowContentBindStage.getStageParams(entry); 169 params.markContentViewsFreeable(FLAG_CONTENT_VIEW_CONTRACTED); 170 params.markContentViewsFreeable(FLAG_CONTENT_VIEW_EXPANDED); 171 params.markContentViewsFreeable(FLAG_CONTENT_VIEW_PUBLIC); 172 mRowContentBindStage.requestRebind(entry, null); 173 } 174 175 /** 176 * Bind row to various controllers and managers. This is only called when the row is first 177 * created. 178 * 179 * TODO: This method associates a row with an entry, but eventually needs to not do that 180 */ bindRow(NotificationEntry entry, ExpandableNotificationRow row)181 private void bindRow(NotificationEntry entry, ExpandableNotificationRow row) { 182 mListContainer.bindRow(row); 183 mNotificationRemoteInputManager.bindRow(row); 184 entry.setRow(row); 185 mNotifBindPipeline.manageRow(entry, row); 186 mPresenter.onBindRow(row); 187 } 188 189 /** 190 * Update row after the notification has updated. 191 * 192 * @param entry notification that has updated 193 */ updateRow( NotificationEntry entry, ExpandableNotificationRow row)194 private void updateRow( 195 NotificationEntry entry, 196 ExpandableNotificationRow row) { 197 row.setLegacy(entry.targetSdk >= Build.VERSION_CODES.GINGERBREAD 198 && entry.targetSdk < Build.VERSION_CODES.LOLLIPOP); 199 200 // bind the click event to the content area 201 requireNonNull(mNotificationClicker).register(row, entry.getSbn()); 202 } 203 204 /** 205 * Inflate the row's basic content views. 206 */ inflateContentViews( NotificationEntry entry, @NonNull NotifInflater.Params inflaterParams, ExpandableNotificationRow row, @Nullable NotificationRowContentBinder.InflationCallback inflationCallback)207 private void inflateContentViews( 208 NotificationEntry entry, 209 @NonNull NotifInflater.Params inflaterParams, 210 ExpandableNotificationRow row, 211 @Nullable NotificationRowContentBinder.InflationCallback inflationCallback) { 212 final boolean useIncreasedCollapsedHeight = 213 mMessagingUtil.isImportantMessaging(entry.getSbn(), entry.getImportance()); 214 final boolean isLowPriority = inflaterParams.isLowPriority(); 215 216 // Set show snooze action 217 row.setShowSnooze(inflaterParams.getShowSnooze()); 218 219 RowContentBindParams params = mRowContentBindStage.getStageParams(entry); 220 params.requireContentViews(FLAG_CONTENT_VIEW_CONTRACTED); 221 params.requireContentViews(FLAG_CONTENT_VIEW_EXPANDED); 222 params.setUseIncreasedCollapsedHeight(useIncreasedCollapsedHeight); 223 params.setUseLowPriority(isLowPriority); 224 225 if (mNotificationLockscreenUserManager.needsRedaction(entry)) { 226 params.requireContentViews(FLAG_CONTENT_VIEW_PUBLIC); 227 } else { 228 params.markContentViewsFreeable(FLAG_CONTENT_VIEW_PUBLIC); 229 } 230 231 params.rebindAllContentViews(); 232 mLogger.logRequestingRebind(entry, inflaterParams); 233 mRowContentBindStage.requestRebind(entry, en -> { 234 mLogger.logRebindComplete(entry); 235 row.setUsesIncreasedCollapsedHeight(useIncreasedCollapsedHeight); 236 row.setIsLowPriority(isLowPriority); 237 if (inflationCallback != null) { 238 inflationCallback.onAsyncInflationFinished(en); 239 } 240 }); 241 } 242 } 243