1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
5  * except in compliance with the License. You may obtain a copy of the License at
6  *
7  *      http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software distributed under the
10  * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
11  * KIND, either express or implied. See the License for the specific language governing
12  * permissions and limitations under the License.
13  */
14 
15 package com.android.systemui.statusbar.phone;
16 
17 import static com.android.systemui.statusbar.phone.StatusBar.CLOSE_PANEL_WHEN_EMPTIED;
18 import static com.android.systemui.statusbar.phone.StatusBar.DEBUG;
19 import static com.android.systemui.statusbar.phone.StatusBar.MULTIUSER_DEBUG;
20 import static com.android.systemui.statusbar.phone.StatusBar.SPEW;
21 
22 import android.annotation.Nullable;
23 import android.app.KeyguardManager;
24 import android.content.Context;
25 import android.os.RemoteException;
26 import android.os.ServiceManager;
27 import android.service.notification.StatusBarNotification;
28 import android.service.vr.IVrManager;
29 import android.service.vr.IVrStateCallbacks;
30 import android.util.Log;
31 import android.util.Slog;
32 import android.view.View;
33 import android.view.ViewGroup;
34 import android.view.accessibility.AccessibilityManager;
35 import android.widget.TextView;
36 
37 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
38 import com.android.internal.statusbar.IStatusBarService;
39 import com.android.internal.statusbar.NotificationVisibility;
40 import com.android.internal.widget.MessagingGroup;
41 import com.android.internal.widget.MessagingMessage;
42 import com.android.keyguard.KeyguardUpdateMonitor;
43 import com.android.systemui.Dependency;
44 import com.android.systemui.ForegroundServiceNotificationListener;
45 import com.android.systemui.InitController;
46 import com.android.systemui.R;
47 import com.android.systemui.plugins.ActivityStarter;
48 import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
49 import com.android.systemui.plugins.statusbar.StatusBarStateController;
50 import com.android.systemui.statusbar.CommandQueue;
51 import com.android.systemui.statusbar.KeyguardIndicationController;
52 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
53 import com.android.systemui.statusbar.NotificationMediaManager;
54 import com.android.systemui.statusbar.NotificationPresenter;
55 import com.android.systemui.statusbar.NotificationRemoteInputManager;
56 import com.android.systemui.statusbar.NotificationViewHierarchyManager;
57 import com.android.systemui.statusbar.StatusBarState;
58 import com.android.systemui.statusbar.SysuiStatusBarStateController;
59 import com.android.systemui.statusbar.notification.AboveShelfObserver;
60 import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
61 import com.android.systemui.statusbar.notification.DynamicPrivacyController;
62 import com.android.systemui.statusbar.notification.NotificationEntryListener;
63 import com.android.systemui.statusbar.notification.NotificationEntryManager;
64 import com.android.systemui.statusbar.notification.VisualStabilityManager;
65 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
66 import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl;
67 import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
68 import com.android.systemui.statusbar.notification.interruption.NotificationInterruptSuppressor;
69 import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
70 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
71 import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
72 import com.android.systemui.statusbar.notification.row.NotificationGutsManager.OnSettingsClickListener;
73 import com.android.systemui.statusbar.notification.row.NotificationInfo.CheckSaveListener;
74 import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
75 import com.android.systemui.statusbar.phone.LockscreenGestureLogger.LockscreenUiEvent;
76 import com.android.systemui.statusbar.policy.ConfigurationController;
77 import com.android.systemui.statusbar.policy.KeyguardStateController;
78 
79 import java.util.List;
80 
81 public class StatusBarNotificationPresenter implements NotificationPresenter,
82         ConfigurationController.ConfigurationListener,
83         NotificationRowBinderImpl.BindRowCallback,
84         CommandQueue.Callbacks {
85 
86     private final LockscreenGestureLogger mLockscreenGestureLogger =
87             Dependency.get(LockscreenGestureLogger.class);
88 
89     private static final String TAG = "StatusBarNotificationPresenter";
90 
91     private final ActivityStarter mActivityStarter = Dependency.get(ActivityStarter.class);
92     private final KeyguardStateController mKeyguardStateController;
93     private final NotificationViewHierarchyManager mViewHierarchyManager =
94             Dependency.get(NotificationViewHierarchyManager.class);
95     private final NotificationLockscreenUserManager mLockscreenUserManager =
96             Dependency.get(NotificationLockscreenUserManager.class);
97     private final SysuiStatusBarStateController mStatusBarStateController =
98             (SysuiStatusBarStateController) Dependency.get(StatusBarStateController.class);
99     private final NotificationEntryManager mEntryManager =
100             Dependency.get(NotificationEntryManager.class);
101     private final NotificationMediaManager mMediaManager =
102             Dependency.get(NotificationMediaManager.class);
103     private final VisualStabilityManager mVisualStabilityManager =
104             Dependency.get(VisualStabilityManager.class);
105     private final NotificationGutsManager mGutsManager =
106             Dependency.get(NotificationGutsManager.class);
107 
108     private final NotificationPanelViewController mNotificationPanel;
109     private final HeadsUpManagerPhone mHeadsUpManager;
110     private final AboveShelfObserver mAboveShelfObserver;
111     private final DozeScrimController mDozeScrimController;
112     private final ScrimController mScrimController;
113     private final Context mContext;
114     private final KeyguardIndicationController mKeyguardIndicationController;
115     private final StatusBar mStatusBar;
116     private final ShadeController mShadeController;
117     private final CommandQueue mCommandQueue;
118 
119     private final AccessibilityManager mAccessibilityManager;
120     private final KeyguardManager mKeyguardManager;
121     private final ActivityLaunchAnimator mActivityLaunchAnimator;
122     private final int mMaxAllowedKeyguardNotifications;
123     private final IStatusBarService mBarService;
124     private final DynamicPrivacyController mDynamicPrivacyController;
125     private boolean mReinflateNotificationsOnUserSwitched;
126     private boolean mDispatchUiModeChangeOnUserSwitched;
127     private TextView mNotificationPanelDebugText;
128 
129     protected boolean mVrMode;
130     private int mMaxKeyguardNotifications;
131 
StatusBarNotificationPresenter(Context context, NotificationPanelViewController panel, HeadsUpManagerPhone headsUp, NotificationShadeWindowView statusBarWindow, ViewGroup stackScroller, DozeScrimController dozeScrimController, ScrimController scrimController, ActivityLaunchAnimator activityLaunchAnimator, DynamicPrivacyController dynamicPrivacyController, KeyguardStateController keyguardStateController, KeyguardIndicationController keyguardIndicationController, StatusBar statusBar, ShadeController shadeController, CommandQueue commandQueue, InitController initController, NotificationInterruptStateProvider notificationInterruptStateProvider)132     public StatusBarNotificationPresenter(Context context,
133             NotificationPanelViewController panel,
134             HeadsUpManagerPhone headsUp,
135             NotificationShadeWindowView statusBarWindow,
136             ViewGroup stackScroller,
137             DozeScrimController dozeScrimController,
138             ScrimController scrimController,
139             ActivityLaunchAnimator activityLaunchAnimator,
140             DynamicPrivacyController dynamicPrivacyController,
141             KeyguardStateController keyguardStateController,
142             KeyguardIndicationController keyguardIndicationController,
143             StatusBar statusBar,
144             ShadeController shadeController,
145             CommandQueue commandQueue,
146             InitController initController,
147             NotificationInterruptStateProvider notificationInterruptStateProvider) {
148         mContext = context;
149         mKeyguardStateController = keyguardStateController;
150         mNotificationPanel = panel;
151         mHeadsUpManager = headsUp;
152         mDynamicPrivacyController = dynamicPrivacyController;
153         mKeyguardIndicationController = keyguardIndicationController;
154         // TODO: use KeyguardStateController#isOccluded to remove this dependency
155         mStatusBar = statusBar;
156         mShadeController = shadeController;
157         mCommandQueue = commandQueue;
158         mAboveShelfObserver = new AboveShelfObserver(stackScroller);
159         mActivityLaunchAnimator = activityLaunchAnimator;
160         mAboveShelfObserver.setListener(statusBarWindow.findViewById(
161                 R.id.notification_container_parent));
162         mAccessibilityManager = context.getSystemService(AccessibilityManager.class);
163         mDozeScrimController = dozeScrimController;
164         mScrimController = scrimController;
165         mKeyguardManager = context.getSystemService(KeyguardManager.class);
166         mMaxAllowedKeyguardNotifications = context.getResources().getInteger(
167                 R.integer.keyguard_max_notification_count);
168         mBarService = IStatusBarService.Stub.asInterface(
169                 ServiceManager.getService(Context.STATUS_BAR_SERVICE));
170 
171         if (MULTIUSER_DEBUG) {
172             mNotificationPanelDebugText = mNotificationPanel.getHeaderDebugInfo();
173             mNotificationPanelDebugText.setVisibility(View.VISIBLE);
174         }
175 
176         IVrManager vrManager = IVrManager.Stub.asInterface(ServiceManager.getService(
177                 Context.VR_SERVICE));
178         if (vrManager != null) {
179             try {
180                 vrManager.registerListener(mVrStateCallbacks);
181             } catch (RemoteException e) {
182                 Slog.e(TAG, "Failed to register VR mode state listener: " + e);
183             }
184         }
185         NotificationRemoteInputManager remoteInputManager =
186                 Dependency.get(NotificationRemoteInputManager.class);
187         remoteInputManager.setUpWithCallback(
188                 Dependency.get(NotificationRemoteInputManager.Callback.class),
189                 mNotificationPanel.createRemoteInputDelegate());
190         remoteInputManager.getController().addCallback(
191                 Dependency.get(NotificationShadeWindowController.class));
192 
193         NotificationListContainer notifListContainer = (NotificationListContainer) stackScroller;
194         initController.addPostInitTask(() -> {
195             NotificationEntryListener notificationEntryListener = new NotificationEntryListener() {
196                 @Override
197                 public void onEntryRemoved(
198                         @Nullable NotificationEntry entry,
199                         NotificationVisibility visibility,
200                         boolean removedByUser,
201                         int reason) {
202                     StatusBarNotificationPresenter.this.onNotificationRemoved(
203                             entry.getKey(), entry.getSbn());
204                     if (removedByUser) {
205                         maybeEndAmbientPulse();
206                     }
207                 }
208             };
209 
210             mViewHierarchyManager.setUpWithPresenter(this, notifListContainer);
211             mEntryManager.setUpWithPresenter(this);
212             mEntryManager.addNotificationEntryListener(notificationEntryListener);
213             mEntryManager.addNotificationLifetimeExtender(mHeadsUpManager);
214             mEntryManager.addNotificationLifetimeExtender(mGutsManager);
215             mEntryManager.addNotificationLifetimeExtenders(
216                     remoteInputManager.getLifetimeExtenders());
217             notificationInterruptStateProvider.addSuppressor(mInterruptSuppressor);
218             mLockscreenUserManager.setUpWithPresenter(this);
219             mMediaManager.setUpWithPresenter(this);
220             mVisualStabilityManager.setUpWithPresenter(this);
221             mGutsManager.setUpWithPresenter(this,
222                     notifListContainer, mCheckSaveListener, mOnSettingsClickListener);
223             // ForegroundServiceNotificationListener adds its listener in its constructor
224             // but we need to request it here in order for it to be instantiated.
225             // TODO: figure out how to do this correctly once Dependency.get() is gone.
226             Dependency.get(ForegroundServiceNotificationListener.class);
227 
228             onUserSwitched(mLockscreenUserManager.getCurrentUserId());
229         });
230         Dependency.get(ConfigurationController.class).addCallback(this);
231     }
232 
233     @Override
onDensityOrFontScaleChanged()234     public void onDensityOrFontScaleChanged() {
235         MessagingMessage.dropCache();
236         MessagingGroup.dropCache();
237         if (!Dependency.get(KeyguardUpdateMonitor.class).isSwitchingUser()) {
238             updateNotificationsOnDensityOrFontScaleChanged();
239         } else {
240             mReinflateNotificationsOnUserSwitched = true;
241         }
242     }
243 
244     @Override
onUiModeChanged()245     public void onUiModeChanged() {
246         if (!Dependency.get(KeyguardUpdateMonitor.class).isSwitchingUser()) {
247             updateNotificationOnUiModeChanged();
248         } else {
249             mDispatchUiModeChangeOnUserSwitched = true;
250         }
251     }
252 
253     @Override
onOverlayChanged()254     public void onOverlayChanged() {
255         onDensityOrFontScaleChanged();
256     }
257 
updateNotificationOnUiModeChanged()258     private void updateNotificationOnUiModeChanged() {
259         List<NotificationEntry> userNotifications =
260                 mEntryManager.getActiveNotificationsForCurrentUser();
261         for (int i = 0; i < userNotifications.size(); i++) {
262             NotificationEntry entry = userNotifications.get(i);
263             ExpandableNotificationRow row = entry.getRow();
264             if (row != null) {
265                 row.onUiModeChanged();
266             }
267         }
268     }
269 
updateNotificationsOnDensityOrFontScaleChanged()270     private void updateNotificationsOnDensityOrFontScaleChanged() {
271         List<NotificationEntry> userNotifications =
272                 mEntryManager.getActiveNotificationsForCurrentUser();
273         for (int i = 0; i < userNotifications.size(); i++) {
274             NotificationEntry entry = userNotifications.get(i);
275             entry.onDensityOrFontScaleChanged();
276             boolean exposedGuts = entry.areGutsExposed();
277             if (exposedGuts) {
278                 mGutsManager.onDensityOrFontScaleChanged(entry);
279             }
280         }
281     }
282 
283     @Override
isCollapsing()284     public boolean isCollapsing() {
285         return mNotificationPanel.isCollapsing()
286                 || mActivityLaunchAnimator.isAnimationPending()
287                 || mActivityLaunchAnimator.isAnimationRunning();
288     }
289 
maybeEndAmbientPulse()290     private void maybeEndAmbientPulse() {
291         if (mNotificationPanel.hasPulsingNotifications() &&
292                 !mHeadsUpManager.hasNotifications()) {
293             // We were showing a pulse for a notification, but no notifications are pulsing anymore.
294             // Finish the pulse.
295             mDozeScrimController.pulseOutNow();
296         }
297     }
298 
299     @Override
updateNotificationViews(final String reason)300     public void updateNotificationViews(final String reason) {
301         // The function updateRowStates depends on both of these being non-null, so check them here.
302         // We may be called before they are set from DeviceProvisionedController's callback.
303         if (mScrimController == null) return;
304 
305         // Do not modify the notifications during collapse.
306         if (isCollapsing()) {
307             mShadeController.addPostCollapseAction(() -> updateNotificationViews(reason));
308             return;
309         }
310 
311         mViewHierarchyManager.updateNotificationViews();
312 
313         mNotificationPanel.updateNotificationViews(reason);
314     }
315 
onNotificationRemoved(String key, StatusBarNotification old)316     public void onNotificationRemoved(String key, StatusBarNotification old) {
317         if (SPEW) Log.d(TAG, "removeNotification key=" + key + " old=" + old);
318 
319         if (old != null) {
320             if (CLOSE_PANEL_WHEN_EMPTIED && !hasActiveNotifications()
321                     && !mNotificationPanel.isTracking() && !mNotificationPanel.isQsExpanded()) {
322                 if (mStatusBarStateController.getState() == StatusBarState.SHADE) {
323                     mCommandQueue.animateCollapsePanels();
324                 } else if (mStatusBarStateController.getState() == StatusBarState.SHADE_LOCKED
325                         && !isCollapsing()) {
326                     mStatusBarStateController.setState(StatusBarState.KEYGUARD);
327                 }
328             }
329         }
330     }
331 
hasActiveNotifications()332     public boolean hasActiveNotifications() {
333         return mEntryManager.hasActiveNotifications();
334     }
335 
336     @Override
onUserSwitched(int newUserId)337     public void onUserSwitched(int newUserId) {
338         // Begin old BaseStatusBar.userSwitched
339         mHeadsUpManager.setUser(newUserId);
340         // End old BaseStatusBar.userSwitched
341         if (MULTIUSER_DEBUG) mNotificationPanelDebugText.setText("USER " + newUserId);
342         mCommandQueue.animateCollapsePanels();
343         if (mReinflateNotificationsOnUserSwitched) {
344             updateNotificationsOnDensityOrFontScaleChanged();
345             mReinflateNotificationsOnUserSwitched = false;
346         }
347         if (mDispatchUiModeChangeOnUserSwitched) {
348             updateNotificationOnUiModeChanged();
349             mDispatchUiModeChangeOnUserSwitched = false;
350         }
351         updateNotificationViews("user switched");
352         mMediaManager.clearCurrentMediaNotification();
353         mStatusBar.setLockscreenUser(newUserId);
354         updateMediaMetaData(true, false);
355     }
356 
357     @Override
onBindRow(ExpandableNotificationRow row)358     public void onBindRow(ExpandableNotificationRow row) {
359         row.setAboveShelfChangedListener(mAboveShelfObserver);
360         row.setSecureStateProvider(mKeyguardStateController::canDismissLockScreen);
361     }
362 
363     @Override
isPresenterFullyCollapsed()364     public boolean isPresenterFullyCollapsed() {
365         return mNotificationPanel.isFullyCollapsed();
366     }
367 
368     @Override
onActivated(ActivatableNotificationView view)369     public void onActivated(ActivatableNotificationView view) {
370         onActivated();
371         if (view != null) mNotificationPanel.setActivatedChild(view);
372     }
373 
onActivated()374     public void onActivated() {
375         mLockscreenGestureLogger.write(
376                 MetricsEvent.ACTION_LS_NOTE,
377                 0 /* lengthDp - N/A */, 0 /* velocityDp - N/A */);
378         mLockscreenGestureLogger.log(LockscreenUiEvent.LOCKSCREEN_NOTIFICATION_FALSE_TOUCH);
379         mNotificationPanel.showTransientIndication(R.string.notification_tap_again);
380         ActivatableNotificationView previousView = mNotificationPanel.getActivatedChild();
381         if (previousView != null) {
382             previousView.makeInactive(true /* animate */);
383         }
384     }
385 
386     @Override
onActivationReset(ActivatableNotificationView view)387     public void onActivationReset(ActivatableNotificationView view) {
388         if (view == mNotificationPanel.getActivatedChild()) {
389             mNotificationPanel.setActivatedChild(null);
390             mKeyguardIndicationController.hideTransientIndication();
391         }
392     }
393 
394     @Override
updateMediaMetaData(boolean metaDataChanged, boolean allowEnterAnimation)395     public void updateMediaMetaData(boolean metaDataChanged, boolean allowEnterAnimation) {
396         mMediaManager.updateMediaMetaData(metaDataChanged, allowEnterAnimation);
397     }
398 
399     @Override
getMaxNotificationsWhileLocked(boolean recompute)400     public int getMaxNotificationsWhileLocked(boolean recompute) {
401         if (recompute) {
402             mMaxKeyguardNotifications = Math.max(1,
403                     mNotificationPanel.computeMaxKeyguardNotifications(
404                             mMaxAllowedKeyguardNotifications));
405             return mMaxKeyguardNotifications;
406         }
407         return mMaxKeyguardNotifications;
408     }
409 
410     @Override
onUpdateRowStates()411     public void onUpdateRowStates() {
412         mNotificationPanel.onUpdateRowStates();
413     }
414 
415     @Override
onExpandClicked(NotificationEntry clickedEntry, boolean nowExpanded)416     public void onExpandClicked(NotificationEntry clickedEntry, boolean nowExpanded) {
417         mHeadsUpManager.setExpanded(clickedEntry, nowExpanded);
418         if (nowExpanded) {
419             if (mStatusBarStateController.getState() == StatusBarState.KEYGUARD) {
420                 mShadeController.goToLockedShade(clickedEntry.getRow());
421             } else if (clickedEntry.isSensitive()
422                     && mDynamicPrivacyController.isInLockedDownShade()) {
423                 mStatusBarStateController.setLeaveOpenOnKeyguardHide(true);
424                 mActivityStarter.dismissKeyguardThenExecute(() -> false /* dismissAction */
425                         , null /* cancelRunnable */, false /* afterKeyguardGone */);
426             }
427         }
428     }
429 
430     @Override
isDeviceInVrMode()431     public boolean isDeviceInVrMode() {
432         return mVrMode;
433     }
434 
onLockedNotificationImportanceChange(OnDismissAction dismissAction)435     private void onLockedNotificationImportanceChange(OnDismissAction dismissAction) {
436         mStatusBarStateController.setLeaveOpenOnKeyguardHide(true);
437         mActivityStarter.dismissKeyguardThenExecute(dismissAction, null,
438                 true /* afterKeyguardGone */);
439     }
440 
441     private final IVrStateCallbacks mVrStateCallbacks = new IVrStateCallbacks.Stub() {
442         @Override
443         public void onVrStateChanged(boolean enabled) {
444             mVrMode = enabled;
445         }
446     };
447 
448     private final CheckSaveListener mCheckSaveListener = new CheckSaveListener() {
449         @Override
450         public void checkSave(Runnable saveImportance, StatusBarNotification sbn) {
451             // If the user has security enabled, show challenge if the setting is changed.
452             if (mLockscreenUserManager.isLockscreenPublicMode(sbn.getUser().getIdentifier())
453                     && mKeyguardManager.isKeyguardLocked()) {
454                 onLockedNotificationImportanceChange(() -> {
455                     saveImportance.run();
456                     return true;
457                 });
458             } else {
459                 saveImportance.run();
460             }
461         }
462     };
463 
464     private final OnSettingsClickListener mOnSettingsClickListener = new OnSettingsClickListener() {
465         @Override
466         public void onSettingsClick(String key) {
467             try {
468                 mBarService.onNotificationSettingsViewed(key);
469             } catch (RemoteException e) {
470                 // if we're here we're dead
471             }
472         }
473     };
474 
475     private final NotificationInterruptSuppressor mInterruptSuppressor =
476             new NotificationInterruptSuppressor() {
477         @Override
478         public String getName() {
479             return TAG;
480         }
481 
482         @Override
483         public boolean suppressAwakeHeadsUp(NotificationEntry entry) {
484             final StatusBarNotification sbn = entry.getSbn();
485             if (mStatusBar.isOccluded()) {
486                 boolean devicePublic = mLockscreenUserManager
487                         .isLockscreenPublicMode(mLockscreenUserManager.getCurrentUserId());
488                 boolean userPublic = devicePublic
489                         || mLockscreenUserManager.isLockscreenPublicMode(sbn.getUserId());
490                 boolean needsRedaction = mLockscreenUserManager.needsRedaction(entry);
491                 if (userPublic && needsRedaction) {
492                     // TODO(b/135046837): we can probably relax this with dynamic privacy
493                     return true;
494                 }
495             }
496 
497             if (!mCommandQueue.panelsEnabled()) {
498                 if (DEBUG) {
499                     Log.d(TAG, "No heads up: disabled panel : " + sbn.getKey());
500                 }
501                 return true;
502             }
503 
504             if (sbn.getNotification().fullScreenIntent != null) {
505                 // we don't allow head-up on the lockscreen (unless there's a
506                 // "showWhenLocked" activity currently showing)  if
507                 // the potential HUN has a fullscreen intent
508                 if (mKeyguardStateController.isShowing() && !mStatusBar.isOccluded()) {
509                     if (DEBUG) {
510                         Log.d(TAG, "No heads up: entry has fullscreen intent on lockscreen "
511                                 + sbn.getKey());
512                     }
513                     return true;
514                 }
515 
516                 if (mAccessibilityManager.isTouchExplorationEnabled()) {
517                     if (DEBUG) {
518                         Log.d(TAG, "No heads up: accessible fullscreen: " + sbn.getKey());
519                     }
520                     return true;
521                 }
522             }
523             return false;
524         }
525 
526         @Override
527         public boolean suppressAwakeInterruptions(NotificationEntry entry) {
528             return isDeviceInVrMode();
529         }
530 
531         @Override
532         public boolean suppressInterruptions(NotificationEntry entry) {
533             return mStatusBar.areNotificationAlertsDisabled();
534         }
535     };
536 }
537