• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.flags.Flags.NOTIFICATION_INLINE_REPLY_ANIMATION;
20 import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_CONTRACTED;
21 import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_EXPANDED;
22 import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_PUBLIC;
23 
24 import static java.util.Objects.requireNonNull;
25 
26 import android.annotation.NonNull;
27 import android.annotation.Nullable;
28 import android.content.Context;
29 import android.os.Build;
30 import android.view.ViewGroup;
31 
32 import com.android.internal.util.NotificationMessagingUtil;
33 import com.android.systemui.dagger.SysUISingleton;
34 import com.android.systemui.flags.FeatureFlags;
35 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
36 import com.android.systemui.statusbar.NotificationPresenter;
37 import com.android.systemui.statusbar.NotificationRemoteInputManager;
38 import com.android.systemui.statusbar.notification.InflationException;
39 import com.android.systemui.statusbar.notification.NotificationClicker;
40 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
41 import com.android.systemui.statusbar.notification.icon.IconManager;
42 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
43 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRowController;
44 import com.android.systemui.statusbar.notification.row.NotifBindPipeline;
45 import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder;
46 import com.android.systemui.statusbar.notification.row.RowContentBindParams;
47 import com.android.systemui.statusbar.notification.row.RowContentBindStage;
48 import com.android.systemui.statusbar.notification.row.RowInflaterTask;
49 import com.android.systemui.statusbar.notification.row.dagger.ExpandableNotificationRowComponent;
50 import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
51 
52 import javax.inject.Inject;
53 import javax.inject.Provider;
54 
55 /** Handles inflating and updating views for notifications. */
56 @SysUISingleton
57 public class NotificationRowBinderImpl implements NotificationRowBinder {
58 
59     private static final String TAG = "NotificationViewManager";
60 
61     private final Context mContext;
62     private final NotificationMessagingUtil mMessagingUtil;
63     private final NotificationRemoteInputManager mNotificationRemoteInputManager;
64     private final NotificationLockscreenUserManager mNotificationLockscreenUserManager;
65     private final NotifBindPipeline mNotifBindPipeline;
66     private final RowContentBindStage mRowContentBindStage;
67     private final Provider<RowInflaterTask> mRowInflaterTaskProvider;
68     private final ExpandableNotificationRowComponent.Builder
69             mExpandableNotificationRowComponentBuilder;
70     private final IconManager mIconManager;
71 
72     private NotificationPresenter mPresenter;
73     private NotificationListContainer mListContainer;
74     private BindRowCallback mBindRowCallback;
75     private NotificationClicker mNotificationClicker;
76     private FeatureFlags mFeatureFlags;
77 
78     @Inject
NotificationRowBinderImpl( Context context, NotificationMessagingUtil notificationMessagingUtil, NotificationRemoteInputManager notificationRemoteInputManager, NotificationLockscreenUserManager notificationLockscreenUserManager, NotifBindPipeline notifBindPipeline, RowContentBindStage rowContentBindStage, Provider<RowInflaterTask> rowInflaterTaskProvider, ExpandableNotificationRowComponent.Builder expandableNotificationRowComponentBuilder, IconManager iconManager, FeatureFlags featureFlags)79     public NotificationRowBinderImpl(
80             Context context,
81             NotificationMessagingUtil notificationMessagingUtil,
82             NotificationRemoteInputManager notificationRemoteInputManager,
83             NotificationLockscreenUserManager notificationLockscreenUserManager,
84             NotifBindPipeline notifBindPipeline,
85             RowContentBindStage rowContentBindStage,
86             Provider<RowInflaterTask> rowInflaterTaskProvider,
87             ExpandableNotificationRowComponent.Builder expandableNotificationRowComponentBuilder,
88             IconManager iconManager,
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         mFeatureFlags = featureFlags;
100     }
101 
102     /**
103      * Sets up late-bound dependencies for this component.
104      */
setUpWithPresenter(NotificationPresenter presenter, NotificationListContainer listContainer, BindRowCallback bindRowCallback)105     public void setUpWithPresenter(NotificationPresenter presenter,
106             NotificationListContainer listContainer,
107             BindRowCallback bindRowCallback) {
108         mPresenter = presenter;
109         mListContainer = listContainer;
110         mBindRowCallback = bindRowCallback;
111 
112         mIconManager.attach();
113     }
114 
setNotificationClicker(NotificationClicker clicker)115     public void setNotificationClicker(NotificationClicker clicker) {
116         mNotificationClicker = clicker;
117     }
118 
119     /**
120      * Inflates the views for the given entry (possibly asynchronously).
121      */
122     @Override
inflateViews( NotificationEntry entry, @NonNull NotifInflater.Params params, NotificationRowContentBinder.InflationCallback callback)123     public void inflateViews(
124             NotificationEntry entry,
125             @NonNull NotifInflater.Params params,
126             NotificationRowContentBinder.InflationCallback callback)
127             throws InflationException {
128         ViewGroup parent = mListContainer.getViewParentForNotification(entry);
129 
130         if (entry.rowExists()) {
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             mIconManager.createIcons(entry);
138             mRowInflaterTaskProvider.get().inflate(mContext, parent, entry,
139                     row -> {
140                         // Setup the controller for the view.
141                         ExpandableNotificationRowComponent component =
142                                 mExpandableNotificationRowComponentBuilder
143                                         .expandableNotificationRow(row)
144                                         .notificationEntry(entry)
145                                         .onExpandClickListener(mPresenter)
146                                         .listContainer(mListContainer)
147                                         .build();
148                         ExpandableNotificationRowController rowController =
149                                 component.getExpandableNotificationRowController();
150                         rowController.init(entry);
151                         entry.setRowController(rowController);
152                         bindRow(entry, row);
153                         updateRow(entry, row);
154                         inflateContentViews(entry, params, row, callback);
155                     });
156         }
157     }
158 
159     @Override
releaseViews(NotificationEntry entry)160     public void releaseViews(NotificationEntry entry) {
161         if (!entry.rowExists()) {
162             return;
163         }
164         final RowContentBindParams params = mRowContentBindStage.getStageParams(entry);
165         params.markContentViewsFreeable(FLAG_CONTENT_VIEW_CONTRACTED);
166         params.markContentViewsFreeable(FLAG_CONTENT_VIEW_EXPANDED);
167         params.markContentViewsFreeable(FLAG_CONTENT_VIEW_PUBLIC);
168         mRowContentBindStage.requestRebind(entry, null);
169     }
170 
171     /**
172      * Bind row to various controllers and managers. This is only called when the row is first
173      * created.
174      *
175      * TODO: This method associates a row with an entry, but eventually needs to not do that
176      */
bindRow(NotificationEntry entry, ExpandableNotificationRow row)177     private void bindRow(NotificationEntry entry, ExpandableNotificationRow row) {
178         mListContainer.bindRow(row);
179         mNotificationRemoteInputManager.bindRow(row);
180         row.setOnActivatedListener(mPresenter);
181         entry.setRow(row);
182         mNotifBindPipeline.manageRow(entry, row);
183         mBindRowCallback.onBindRow(row);
184         row.setInlineReplyAnimationFlagEnabled(
185                 mFeatureFlags.isEnabled(NOTIFICATION_INLINE_REPLY_ANIMATION));
186     }
187 
188     /**
189      * Update row after the notification has updated.
190      *
191      * @param entry notification that has updated
192      */
updateRow( NotificationEntry entry, ExpandableNotificationRow row)193     private void updateRow(
194             NotificationEntry entry,
195             ExpandableNotificationRow row) {
196         row.setLegacy(entry.targetSdk >= Build.VERSION_CODES.GINGERBREAD
197                 && entry.targetSdk < Build.VERSION_CODES.LOLLIPOP);
198 
199         // bind the click event to the content area
200         requireNonNull(mNotificationClicker).register(row, entry.getSbn());
201     }
202 
203     /**
204      * Inflate the row's basic content views.
205      */
inflateContentViews( NotificationEntry entry, @NonNull NotifInflater.Params inflaterParams, ExpandableNotificationRow row, @Nullable NotificationRowContentBinder.InflationCallback inflationCallback)206     private void inflateContentViews(
207             NotificationEntry entry,
208             @NonNull NotifInflater.Params inflaterParams,
209             ExpandableNotificationRow row,
210             @Nullable NotificationRowContentBinder.InflationCallback inflationCallback) {
211         final boolean useIncreasedCollapsedHeight =
212                 mMessagingUtil.isImportantMessaging(entry.getSbn(), entry.getImportance());
213         final boolean isLowPriority = inflaterParams.isLowPriority();
214 
215         RowContentBindParams params = mRowContentBindStage.getStageParams(entry);
216         params.requireContentViews(FLAG_CONTENT_VIEW_CONTRACTED);
217         params.requireContentViews(FLAG_CONTENT_VIEW_EXPANDED);
218         params.setUseIncreasedCollapsedHeight(useIncreasedCollapsedHeight);
219         params.setUseLowPriority(isLowPriority);
220 
221         if (mNotificationLockscreenUserManager.needsRedaction(entry)) {
222             params.requireContentViews(FLAG_CONTENT_VIEW_PUBLIC);
223         } else {
224             params.markContentViewsFreeable(FLAG_CONTENT_VIEW_PUBLIC);
225         }
226 
227         params.rebindAllContentViews();
228         mRowContentBindStage.requestRebind(entry, en -> {
229             row.setUsesIncreasedCollapsedHeight(useIncreasedCollapsedHeight);
230             row.setIsLowPriority(isLowPriority);
231             if (inflationCallback != null) {
232                 inflationCallback.onAsyncInflationFinished(en);
233             }
234         });
235     }
236 
237     /** Callback for when a row is bound to an entry. */
238     public interface BindRowCallback {
239         /**
240          * Called when a new row is created and bound to a notification.
241          */
onBindRow(ExpandableNotificationRow row)242         void onBindRow(ExpandableNotificationRow row);
243     }
244 }
245