• 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.row;
18 
19 import static com.android.systemui.Dependency.ALLOW_NOTIFICATION_LONG_PRESS_NAME;
20 import static com.android.systemui.statusbar.NotificationRemoteInputManager.ENABLE_REMOTE_INPUT;
21 import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
22 import static com.android.systemui.statusbar.notification.NotificationUtils.logKey;
23 
24 import android.util.Log;
25 import android.view.View;
26 import android.view.ViewGroup;
27 
28 import androidx.annotation.NonNull;
29 import androidx.annotation.Nullable;
30 
31 import com.android.internal.logging.MetricsLogger;
32 import com.android.internal.statusbar.IStatusBarService;
33 import com.android.systemui.classifier.FalsingCollector;
34 import com.android.systemui.flags.FeatureFlags;
35 import com.android.systemui.flags.Flags;
36 import com.android.systemui.plugins.FalsingManager;
37 import com.android.systemui.plugins.PluginManager;
38 import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
39 import com.android.systemui.plugins.statusbar.StatusBarStateController;
40 import com.android.systemui.statusbar.NotificationMediaManager;
41 import com.android.systemui.statusbar.SmartReplyController;
42 import com.android.systemui.statusbar.notification.FeedbackIcon;
43 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
44 import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager;
45 import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager;
46 import com.android.systemui.statusbar.notification.collection.render.NodeController;
47 import com.android.systemui.statusbar.notification.collection.render.NotifViewController;
48 import com.android.systemui.statusbar.notification.logging.NotificationLogger;
49 import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
50 import com.android.systemui.statusbar.notification.row.dagger.AppName;
51 import com.android.systemui.statusbar.notification.row.dagger.NotificationKey;
52 import com.android.systemui.statusbar.notification.row.dagger.NotificationRowScope;
53 import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
54 import com.android.systemui.statusbar.phone.KeyguardBypassController;
55 import com.android.systemui.statusbar.policy.HeadsUpManager;
56 import com.android.systemui.statusbar.policy.SmartReplyConstants;
57 import com.android.systemui.statusbar.policy.dagger.RemoteInputViewSubcomponent;
58 import com.android.systemui.util.time.SystemClock;
59 import com.android.systemui.wmshell.BubblesManager;
60 
61 import java.util.List;
62 import java.util.Optional;
63 
64 import javax.inject.Inject;
65 import javax.inject.Named;
66 
67 /**
68  * Controller for {@link ExpandableNotificationRow}.
69  */
70 @NotificationRowScope
71 public class ExpandableNotificationRowController implements NotifViewController {
72     private static final String TAG = "NotifRowController";
73     private final ExpandableNotificationRow mView;
74     private final NotificationListContainer mListContainer;
75     private final RemoteInputViewSubcomponent.Factory mRemoteInputViewSubcomponentFactory;
76     private final ActivatableNotificationViewController mActivatableNotificationViewController;
77     private final NotificationMediaManager mMediaManager;
78     private final PluginManager mPluginManager;
79     private final SystemClock mClock;
80     private final String mAppName;
81     private final String mNotificationKey;
82     private final KeyguardBypassController mKeyguardBypassController;
83     private final GroupMembershipManager mGroupMembershipManager;
84     private final GroupExpansionManager mGroupExpansionManager;
85     private final RowContentBindStage mRowContentBindStage;
86     private final NotificationLogger mNotificationLogger;
87     private final NotificationRowLogger mLogBufferLogger;
88     private final HeadsUpManager mHeadsUpManager;
89     private final ExpandableNotificationRow.OnExpandClickListener mOnExpandClickListener;
90     private final StatusBarStateController mStatusBarStateController;
91     private final MetricsLogger mMetricsLogger;
92     private final ExpandableNotificationRow.CoordinateOnClickListener mOnFeedbackClickListener;
93     private final NotificationGutsManager mNotificationGutsManager;
94     private final OnUserInteractionCallback mOnUserInteractionCallback;
95     private final FalsingManager mFalsingManager;
96     private final FalsingCollector mFalsingCollector;
97     private final FeatureFlags mFeatureFlags;
98     private final boolean mAllowLongPress;
99     private final PeopleNotificationIdentifier mPeopleNotificationIdentifier;
100     private final Optional<BubblesManager> mBubblesManagerOptional;
101     private final SmartReplyConstants mSmartReplyConstants;
102     private final SmartReplyController mSmartReplyController;
103     private final ExpandableNotificationRowDragController mDragController;
104     private final IStatusBarService mStatusBarService;
105     private final ExpandableNotificationRow.ExpandableNotificationRowLogger mLoggerCallback =
106             new ExpandableNotificationRow.ExpandableNotificationRowLogger() {
107                 @Override
108                 public void logNotificationExpansion(String key, boolean userAction,
109                         boolean expanded) {
110                     mNotificationLogger.onExpansionChanged(key, userAction, expanded);
111                 }
112 
113                 @Override
114                 public void logKeepInParentChildDetached(
115                         NotificationEntry child,
116                         NotificationEntry oldParent
117                 ) {
118                     mLogBufferLogger.logKeepInParentChildDetached(child, oldParent);
119                 }
120 
121                 @Override
122                 public void logSkipAttachingKeepInParentChild(
123                         NotificationEntry child,
124                         NotificationEntry newParent
125                 ) {
126                     mLogBufferLogger.logSkipAttachingKeepInParentChild(child, newParent);
127                 }
128             };
129 
130 
131     @Inject
ExpandableNotificationRowController( ExpandableNotificationRow view, ActivatableNotificationViewController activatableNotificationViewController, RemoteInputViewSubcomponent.Factory rivSubcomponentFactory, MetricsLogger metricsLogger, NotificationRowLogger logBufferLogger, NotificationListContainer listContainer, NotificationMediaManager mediaManager, SmartReplyConstants smartReplyConstants, SmartReplyController smartReplyController, PluginManager pluginManager, SystemClock clock, @AppName String appName, @NotificationKey String notificationKey, KeyguardBypassController keyguardBypassController, GroupMembershipManager groupMembershipManager, GroupExpansionManager groupExpansionManager, RowContentBindStage rowContentBindStage, NotificationLogger notificationLogger, HeadsUpManager headsUpManager, ExpandableNotificationRow.OnExpandClickListener onExpandClickListener, StatusBarStateController statusBarStateController, NotificationGutsManager notificationGutsManager, @Named(ALLOW_NOTIFICATION_LONG_PRESS_NAME) boolean allowLongPress, OnUserInteractionCallback onUserInteractionCallback, FalsingManager falsingManager, FalsingCollector falsingCollector, FeatureFlags featureFlags, PeopleNotificationIdentifier peopleNotificationIdentifier, Optional<BubblesManager> bubblesManagerOptional, ExpandableNotificationRowDragController dragController, IStatusBarService statusBarService)132     public ExpandableNotificationRowController(
133             ExpandableNotificationRow view,
134             ActivatableNotificationViewController activatableNotificationViewController,
135             RemoteInputViewSubcomponent.Factory rivSubcomponentFactory,
136             MetricsLogger metricsLogger,
137             NotificationRowLogger logBufferLogger,
138             NotificationListContainer listContainer,
139             NotificationMediaManager mediaManager,
140             SmartReplyConstants smartReplyConstants,
141             SmartReplyController smartReplyController,
142             PluginManager pluginManager,
143             SystemClock clock,
144             @AppName String appName,
145             @NotificationKey String notificationKey,
146             KeyguardBypassController keyguardBypassController,
147             GroupMembershipManager groupMembershipManager,
148             GroupExpansionManager groupExpansionManager,
149             RowContentBindStage rowContentBindStage,
150             NotificationLogger notificationLogger,
151             HeadsUpManager headsUpManager,
152             ExpandableNotificationRow.OnExpandClickListener onExpandClickListener,
153             StatusBarStateController statusBarStateController,
154             NotificationGutsManager notificationGutsManager,
155             @Named(ALLOW_NOTIFICATION_LONG_PRESS_NAME) boolean allowLongPress,
156             OnUserInteractionCallback onUserInteractionCallback,
157             FalsingManager falsingManager,
158             FalsingCollector falsingCollector,
159             FeatureFlags featureFlags,
160             PeopleNotificationIdentifier peopleNotificationIdentifier,
161             Optional<BubblesManager> bubblesManagerOptional,
162             ExpandableNotificationRowDragController dragController,
163             IStatusBarService statusBarService) {
164         mView = view;
165         mListContainer = listContainer;
166         mRemoteInputViewSubcomponentFactory = rivSubcomponentFactory;
167         mActivatableNotificationViewController = activatableNotificationViewController;
168         mMediaManager = mediaManager;
169         mPluginManager = pluginManager;
170         mClock = clock;
171         mAppName = appName;
172         mNotificationKey = notificationKey;
173         mKeyguardBypassController = keyguardBypassController;
174         mGroupMembershipManager = groupMembershipManager;
175         mGroupExpansionManager = groupExpansionManager;
176         mRowContentBindStage = rowContentBindStage;
177         mNotificationLogger = notificationLogger;
178         mHeadsUpManager = headsUpManager;
179         mOnExpandClickListener = onExpandClickListener;
180         mStatusBarStateController = statusBarStateController;
181         mNotificationGutsManager = notificationGutsManager;
182         mOnUserInteractionCallback = onUserInteractionCallback;
183         mFalsingManager = falsingManager;
184         mOnFeedbackClickListener = mNotificationGutsManager::openGuts;
185         mAllowLongPress = allowLongPress;
186         mFalsingCollector = falsingCollector;
187         mFeatureFlags = featureFlags;
188         mPeopleNotificationIdentifier = peopleNotificationIdentifier;
189         mBubblesManagerOptional = bubblesManagerOptional;
190         mDragController = dragController;
191         mMetricsLogger = metricsLogger;
192         mLogBufferLogger = logBufferLogger;
193         mSmartReplyConstants = smartReplyConstants;
194         mSmartReplyController = smartReplyController;
195         mStatusBarService = statusBarService;
196     }
197 
198     /**
199      * Initialize the controller.
200      */
init(NotificationEntry entry)201     public void init(NotificationEntry entry) {
202         mActivatableNotificationViewController.init();
203         mView.initialize(
204                 entry,
205                 mRemoteInputViewSubcomponentFactory,
206                 mAppName,
207                 mNotificationKey,
208                 mLoggerCallback,
209                 mKeyguardBypassController,
210                 mGroupMembershipManager,
211                 mGroupExpansionManager,
212                 mHeadsUpManager,
213                 mRowContentBindStage,
214                 mOnExpandClickListener,
215                 mMediaManager,
216                 mOnFeedbackClickListener,
217                 mFalsingManager,
218                 mFalsingCollector,
219                 mStatusBarStateController,
220                 mPeopleNotificationIdentifier,
221                 mOnUserInteractionCallback,
222                 mBubblesManagerOptional,
223                 mNotificationGutsManager,
224                 mMetricsLogger,
225                 mSmartReplyConstants,
226                 mSmartReplyController,
227                 mFeatureFlags,
228                 mStatusBarService
229         );
230         mView.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
231         if (mAllowLongPress) {
232             if (mFeatureFlags.isEnabled(Flags.NOTIFICATION_DRAG_TO_CONTENTS)) {
233                 mView.setDragController(mDragController);
234             }
235 
236             mView.setLongPressListener((v, x, y, item) -> {
237                 if (mView.isSummaryWithChildren()) {
238                     mView.expandNotification();
239                     return true;
240                 }
241                 return mNotificationGutsManager.openGuts(v, x, y, item);
242             });
243         }
244         if (ENABLE_REMOTE_INPUT) {
245             mView.setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS);
246         }
247 
248         mView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
249             @Override
250             public void onViewAttachedToWindow(View v) {
251                 mView.getEntry().setInitializationTime(mClock.elapsedRealtime());
252                 mPluginManager.addPluginListener(mView,
253                         NotificationMenuRowPlugin.class, false /* Allow multiple */);
254                 mView.setOnKeyguard(mStatusBarStateController.getState() == KEYGUARD);
255                 mStatusBarStateController.addCallback(mStatusBarStateListener);
256             }
257 
258             @Override
259             public void onViewDetachedFromWindow(View v) {
260                 mPluginManager.removePluginListener(mView);
261                 mStatusBarStateController.removeCallback(mStatusBarStateListener);
262             }
263         });
264         mView.useRoundnessSourceTypes(
265                 mFeatureFlags.isEnabled(Flags.USE_ROUNDNESS_SOURCETYPES));
266     }
267 
268     private final StatusBarStateController.StateListener mStatusBarStateListener =
269             new StatusBarStateController.StateListener() {
270                 @Override
271                 public void onStateChanged(int newState) {
272                     mView.setOnKeyguard(newState == KEYGUARD);
273                 }
274             };
275 
276     @Override
277     @NonNull
getNodeLabel()278     public String getNodeLabel() {
279         return logKey(mView.getEntry());
280     }
281 
282     @Override
283     @NonNull
getView()284     public View getView() {
285         return mView;
286     }
287 
288     @Override
getChildAt(int index)289     public View getChildAt(int index) {
290         return mView.getChildNotificationAt(index);
291     }
292 
293     @Override
addChildAt(NodeController child, int index)294     public void addChildAt(NodeController child, int index) {
295         ExpandableNotificationRow childView = (ExpandableNotificationRow) child.getView();
296 
297         mView.addChildNotification((ExpandableNotificationRow) child.getView(), index);
298         mListContainer.notifyGroupChildAdded(childView);
299         childView.setChangingPosition(false);
300     }
301 
302     @Override
moveChildTo(NodeController child, int index)303     public void moveChildTo(NodeController child, int index) {
304         ExpandableNotificationRow childView = (ExpandableNotificationRow) child.getView();
305         childView.setChangingPosition(true);
306         mView.removeChildNotification(childView);
307         mView.addChildNotification(childView, index);
308         childView.setChangingPosition(false);
309     }
310 
311     @Override
removeChild(NodeController child, boolean isTransfer)312     public void removeChild(NodeController child, boolean isTransfer) {
313         ExpandableNotificationRow childView = (ExpandableNotificationRow) child.getView();
314 
315         if (isTransfer) {
316             childView.setChangingPosition(true);
317         }
318         mView.removeChildNotification(childView);
319         if (!isTransfer) {
320             mListContainer.notifyGroupChildRemoved(childView, mView.getChildrenContainer());
321         }
322     }
323 
324     @Override
onViewAdded()325     public void onViewAdded() {
326     }
327 
328     @Override
onViewMoved()329     public void onViewMoved() {
330     }
331 
332     @Override
onViewRemoved()333     public void onViewRemoved() {
334     }
335 
336     @Override
getChildCount()337     public int getChildCount() {
338         final List<ExpandableNotificationRow> mChildren = mView.getAttachedChildren();
339         return mChildren != null ? mChildren.size() : 0;
340     }
341 
342     @Override
setUntruncatedChildCount(int childCount)343     public void setUntruncatedChildCount(int childCount) {
344         if (mView.isSummaryWithChildren()) {
345             mView.setUntruncatedChildCount(childCount);
346         } else {
347             Log.w(TAG, "Called setUntruncatedChildCount(" + childCount + ") on a leaf row");
348         }
349     }
350 
351     @Override
setSystemExpanded(boolean systemExpanded)352     public void setSystemExpanded(boolean systemExpanded) {
353         mView.setSystemExpanded(systemExpanded);
354     }
355 
356     @Override
setLastAudiblyAlertedMs(long lastAudiblyAlertedMs)357     public void setLastAudiblyAlertedMs(long lastAudiblyAlertedMs) {
358         mView.setLastAudiblyAlertedMs(lastAudiblyAlertedMs);
359     }
360 
361     @Override
setFeedbackIcon(@ullable FeedbackIcon icon)362     public void setFeedbackIcon(@Nullable FeedbackIcon icon) {
363         mView.setFeedbackIcon(icon);
364     }
365 
366     @Override
offerToKeepInParentForAnimation()367     public boolean offerToKeepInParentForAnimation() {
368         //If the User dismissed the notification's parent, we want to keep it attached until the
369         //dismiss animation is ongoing. Therefore we don't want to remove it in the ShadeViewDiffer.
370         if (mFeatureFlags.isEnabled(Flags.NOTIFICATION_GROUP_DISMISSAL_ANIMATION)
371                 && mView.isParentDismissed()) {
372             mView.setKeepInParentForDismissAnimation(true);
373             return true;
374         }
375 
376         //Otherwise the view system doesn't do the removal, so we rely on the ShadeViewDiffer
377         return false;
378     }
379 
380     @Override
removeFromParentIfKeptForAnimation()381     public boolean removeFromParentIfKeptForAnimation() {
382         ExpandableNotificationRow parent = mView.getNotificationParent();
383         if (mView.keepInParentForDismissAnimation() && parent != null) {
384             parent.removeChildNotification(mView);
385             return true;
386         }
387 
388         return false;
389     }
390 
391     @Override
resetKeepInParentForAnimation()392     public void resetKeepInParentForAnimation() {
393         mView.setKeepInParentForDismissAnimation(false);
394     }
395 }
396