1 /*
2  * Copyright (C) 2018 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.phone;
18 
19 import static android.app.ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED;
20 import static android.service.notification.NotificationListenerService.REASON_CLICK;
21 
22 import static com.android.systemui.statusbar.phone.CentralSurfaces.getActivityOptions;
23 
24 import android.app.ActivityManager;
25 import android.app.ActivityOptions;
26 import android.app.KeyguardManager;
27 import android.app.Notification;
28 import android.app.PendingIntent;
29 import android.app.TaskStackBuilder;
30 import android.content.Context;
31 import android.content.Intent;
32 import android.content.pm.ResolveInfo;
33 import android.os.AsyncTask;
34 import android.os.Bundle;
35 import android.os.Handler;
36 import android.os.Looper;
37 import android.os.RemoteException;
38 import android.os.UserHandle;
39 import android.provider.Settings;
40 import android.service.dreams.IDreamManager;
41 import android.service.notification.StatusBarNotification;
42 import android.text.TextUtils;
43 import android.util.EventLog;
44 import android.view.View;
45 
46 import androidx.annotation.VisibleForTesting;
47 
48 import com.android.internal.jank.InteractionJankMonitor;
49 import com.android.internal.logging.MetricsLogger;
50 import com.android.internal.statusbar.NotificationVisibility;
51 import com.android.internal.util.FrameworkStatsLog;
52 import com.android.internal.widget.LockPatternUtils;
53 import com.android.systemui.ActivityIntentHelper;
54 import com.android.systemui.EventLogTags;
55 import com.android.systemui.animation.ActivityLaunchAnimator;
56 import com.android.systemui.assist.AssistManager;
57 import com.android.systemui.dagger.qualifiers.DisplayId;
58 import com.android.systemui.flags.FeatureFlags;
59 import com.android.systemui.plugins.ActivityStarter;
60 import com.android.systemui.power.domain.interactor.PowerInteractor;
61 import com.android.systemui.settings.UserTracker;
62 import com.android.systemui.shade.ShadeController;
63 import com.android.systemui.shade.ShadeViewController;
64 import com.android.systemui.statusbar.NotificationClickNotifier;
65 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
66 import com.android.systemui.statusbar.NotificationPresenter;
67 import com.android.systemui.statusbar.NotificationRemoteInputManager;
68 import com.android.systemui.statusbar.NotificationShadeWindowController;
69 import com.android.systemui.statusbar.notification.NotificationActivityStarter;
70 import com.android.systemui.statusbar.notification.NotificationLaunchAnimatorControllerProvider;
71 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
72 import com.android.systemui.statusbar.notification.collection.provider.LaunchFullScreenIntentProvider;
73 import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider;
74 import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
75 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
76 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRowDragController;
77 import com.android.systemui.statusbar.notification.row.OnUserInteractionCallback;
78 import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent;
79 import com.android.systemui.statusbar.policy.HeadsUpUtil;
80 import com.android.systemui.statusbar.policy.KeyguardStateController;
81 import com.android.systemui.wmshell.BubblesManager;
82 
83 import dagger.Lazy;
84 
85 import java.util.List;
86 import java.util.Optional;
87 import java.util.concurrent.Executor;
88 
89 import javax.inject.Inject;
90 
91 
92 /**
93  * Status bar implementation of {@link NotificationActivityStarter}.
94  */
95 @CentralSurfacesComponent.CentralSurfacesScope
96 class StatusBarNotificationActivityStarter implements NotificationActivityStarter {
97 
98     private final Context mContext;
99     private final int mDisplayId;
100 
101     private final Handler mMainThreadHandler;
102     private final Executor mUiBgExecutor;
103 
104     private final NotificationVisibilityProvider mVisibilityProvider;
105     private final HeadsUpManagerPhone mHeadsUpManager;
106     private final ActivityStarter mActivityStarter;
107     private final NotificationClickNotifier mClickNotifier;
108     private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
109     private final KeyguardManager mKeyguardManager;
110     private final IDreamManager mDreamManager;
111     private final Optional<BubblesManager> mBubblesManagerOptional;
112     private final Lazy<AssistManager> mAssistManagerLazy;
113     private final NotificationRemoteInputManager mRemoteInputManager;
114     private final NotificationLockscreenUserManager mLockscreenUserManager;
115     private final com.android.systemui.shade.ShadeController mShadeController;
116     private final KeyguardStateController mKeyguardStateController;
117     private final NotificationInterruptStateProvider mNotificationInterruptStateProvider;
118     private final LockPatternUtils mLockPatternUtils;
119     private final StatusBarRemoteInputCallback mStatusBarRemoteInputCallback;
120     private final ActivityIntentHelper mActivityIntentHelper;
121     private final FeatureFlags mFeatureFlags;
122 
123     private final MetricsLogger mMetricsLogger;
124     private final StatusBarNotificationActivityStarterLogger mLogger;
125 
126     private final NotificationPresenter mPresenter;
127     private final ShadeViewController mShadeViewController;
128     private final NotificationShadeWindowController mNotificationShadeWindowController;
129     private final ActivityLaunchAnimator mActivityLaunchAnimator;
130     private final NotificationLaunchAnimatorControllerProvider mNotificationAnimationProvider;
131     private final PowerInteractor mPowerInteractor;
132     private final UserTracker mUserTracker;
133     private final OnUserInteractionCallback mOnUserInteractionCallback;
134 
135     private boolean mIsCollapsingToShowActivityOverLockscreen;
136 
137     @Inject
StatusBarNotificationActivityStarter( Context context, @DisplayId int displayId, Handler mainThreadHandler, Executor uiBgExecutor, NotificationVisibilityProvider visibilityProvider, HeadsUpManagerPhone headsUpManager, ActivityStarter activityStarter, NotificationClickNotifier clickNotifier, StatusBarKeyguardViewManager statusBarKeyguardViewManager, KeyguardManager keyguardManager, IDreamManager dreamManager, Optional<BubblesManager> bubblesManagerOptional, Lazy<AssistManager> assistManagerLazy, NotificationRemoteInputManager remoteInputManager, NotificationLockscreenUserManager lockscreenUserManager, ShadeController shadeController, KeyguardStateController keyguardStateController, NotificationInterruptStateProvider notificationInterruptStateProvider, LockPatternUtils lockPatternUtils, StatusBarRemoteInputCallback remoteInputCallback, ActivityIntentHelper activityIntentHelper, MetricsLogger metricsLogger, StatusBarNotificationActivityStarterLogger logger, OnUserInteractionCallback onUserInteractionCallback, NotificationPresenter presenter, ShadeViewController shadeViewController, NotificationShadeWindowController notificationShadeWindowController, ActivityLaunchAnimator activityLaunchAnimator, NotificationLaunchAnimatorControllerProvider notificationAnimationProvider, LaunchFullScreenIntentProvider launchFullScreenIntentProvider, PowerInteractor powerInteractor, FeatureFlags featureFlags, UserTracker userTracker)138     StatusBarNotificationActivityStarter(
139             Context context,
140             @DisplayId int displayId,
141             Handler mainThreadHandler,
142             Executor uiBgExecutor,
143             NotificationVisibilityProvider visibilityProvider,
144             HeadsUpManagerPhone headsUpManager,
145             ActivityStarter activityStarter,
146             NotificationClickNotifier clickNotifier,
147             StatusBarKeyguardViewManager statusBarKeyguardViewManager,
148             KeyguardManager keyguardManager,
149             IDreamManager dreamManager,
150             Optional<BubblesManager> bubblesManagerOptional,
151             Lazy<AssistManager> assistManagerLazy,
152             NotificationRemoteInputManager remoteInputManager,
153             NotificationLockscreenUserManager lockscreenUserManager,
154             ShadeController shadeController,
155             KeyguardStateController keyguardStateController,
156             NotificationInterruptStateProvider notificationInterruptStateProvider,
157             LockPatternUtils lockPatternUtils,
158             StatusBarRemoteInputCallback remoteInputCallback,
159             ActivityIntentHelper activityIntentHelper,
160             MetricsLogger metricsLogger,
161             StatusBarNotificationActivityStarterLogger logger,
162             OnUserInteractionCallback onUserInteractionCallback,
163             NotificationPresenter presenter,
164             ShadeViewController shadeViewController,
165             NotificationShadeWindowController notificationShadeWindowController,
166             ActivityLaunchAnimator activityLaunchAnimator,
167             NotificationLaunchAnimatorControllerProvider notificationAnimationProvider,
168             LaunchFullScreenIntentProvider launchFullScreenIntentProvider,
169             PowerInteractor powerInteractor,
170             FeatureFlags featureFlags,
171             UserTracker userTracker) {
172         mContext = context;
173         mDisplayId = displayId;
174         mMainThreadHandler = mainThreadHandler;
175         mUiBgExecutor = uiBgExecutor;
176         mVisibilityProvider = visibilityProvider;
177         mHeadsUpManager = headsUpManager;
178         mActivityStarter = activityStarter;
179         mClickNotifier = clickNotifier;
180         mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
181         mKeyguardManager = keyguardManager;
182         mDreamManager = dreamManager;
183         mBubblesManagerOptional = bubblesManagerOptional;
184         mAssistManagerLazy = assistManagerLazy;
185         mRemoteInputManager = remoteInputManager;
186         mLockscreenUserManager = lockscreenUserManager;
187         mShadeController = shadeController;
188         mKeyguardStateController = keyguardStateController;
189         mNotificationInterruptStateProvider = notificationInterruptStateProvider;
190         mLockPatternUtils = lockPatternUtils;
191         mStatusBarRemoteInputCallback = remoteInputCallback;
192         mActivityIntentHelper = activityIntentHelper;
193         mNotificationShadeWindowController = notificationShadeWindowController;
194         mFeatureFlags = featureFlags;
195         mMetricsLogger = metricsLogger;
196         mLogger = logger;
197         mOnUserInteractionCallback = onUserInteractionCallback;
198         mPresenter = presenter;
199         mShadeViewController = shadeViewController;
200         mActivityLaunchAnimator = activityLaunchAnimator;
201         mNotificationAnimationProvider = notificationAnimationProvider;
202         mPowerInteractor = powerInteractor;
203         mUserTracker = userTracker;
204 
205         launchFullScreenIntentProvider.registerListener(entry -> launchFullScreenIntent(entry));
206     }
207 
208     /**
209      * Called when a notification is clicked.
210      *
211      * @param entry notification that was clicked
212      * @param row row for that notification
213      */
214     @Override
onNotificationClicked(NotificationEntry entry, ExpandableNotificationRow row)215     public void onNotificationClicked(NotificationEntry entry, ExpandableNotificationRow row) {
216         mLogger.logStartingActivityFromClick(entry);
217 
218         if (mRemoteInputManager.isRemoteInputActive(entry)) {
219             // We have an active remote input typed and the user clicked on the notification.
220             // this was probably unintentional, so we're closing the edit text instead.
221             mRemoteInputManager.closeRemoteInputs();
222             return;
223         }
224         Notification notification = entry.getSbn().getNotification();
225         final PendingIntent intent = notification.contentIntent != null
226                 ? notification.contentIntent
227                 : notification.fullScreenIntent;
228         final boolean isBubble = entry.isBubble();
229 
230         // This code path is now executed for notification without a contentIntent.
231         // The only valid case is Bubble notifications. Guard against other cases
232         // entering here.
233         if (intent == null && !isBubble) {
234             mLogger.logNonClickableNotification(entry);
235             return;
236         }
237 
238         boolean isActivityIntent = intent != null && intent.isActivity() && !isBubble;
239         final boolean willLaunchResolverActivity = isActivityIntent
240                 && mActivityIntentHelper.wouldPendingLaunchResolverActivity(intent,
241                 mLockscreenUserManager.getCurrentUserId());
242         final boolean animate = !willLaunchResolverActivity
243                 && mActivityStarter.shouldAnimateLaunch(isActivityIntent);
244         boolean showOverLockscreen = mKeyguardStateController.isShowing() && intent != null
245                 && mActivityIntentHelper.wouldPendingShowOverLockscreen(intent,
246                 mLockscreenUserManager.getCurrentUserId());
247         ActivityStarter.OnDismissAction postKeyguardAction = new ActivityStarter.OnDismissAction() {
248             @Override
249             public boolean onDismiss() {
250                 return handleNotificationClickAfterKeyguardDismissed(
251                         entry, row, intent, isActivityIntent, animate, showOverLockscreen);
252             }
253 
254             @Override
255             public boolean willRunAnimationOnKeyguard() {
256                 return animate;
257             }
258         };
259         if (showOverLockscreen) {
260             mIsCollapsingToShowActivityOverLockscreen = true;
261             postKeyguardAction.onDismiss();
262         } else {
263             mActivityStarter.dismissKeyguardThenExecute(
264                     postKeyguardAction,
265                     null,
266                     willLaunchResolverActivity);
267         }
268     }
269 
handleNotificationClickAfterKeyguardDismissed( NotificationEntry entry, ExpandableNotificationRow row, PendingIntent intent, boolean isActivityIntent, boolean animate, boolean showOverLockscreen)270     private boolean handleNotificationClickAfterKeyguardDismissed(
271             NotificationEntry entry,
272             ExpandableNotificationRow row,
273             PendingIntent intent,
274             boolean isActivityIntent,
275             boolean animate,
276             boolean showOverLockscreen) {
277         mLogger.logHandleClickAfterKeyguardDismissed(entry);
278 
279         final Runnable runnable = () -> handleNotificationClickAfterPanelCollapsed(
280                 entry, row, intent, isActivityIntent, animate);
281 
282         if (showOverLockscreen) {
283             mShadeController.addPostCollapseAction(runnable);
284             mShadeController.collapseShade(true /* animate */);
285         } else if (mKeyguardStateController.isShowing()
286                 && mKeyguardStateController.isOccluded()) {
287             mStatusBarKeyguardViewManager.addAfterKeyguardGoneRunnable(runnable);
288             mShadeController.collapseShade();
289         } else {
290             runnable.run();
291         }
292 
293         // Always defer the keyguard dismiss when animating.
294         return animate || !mShadeViewController.isFullyCollapsed();
295     }
296 
handleNotificationClickAfterPanelCollapsed( NotificationEntry entry, ExpandableNotificationRow row, PendingIntent intent, boolean isActivityIntent, boolean animate)297     private void handleNotificationClickAfterPanelCollapsed(
298             NotificationEntry entry,
299             ExpandableNotificationRow row,
300             PendingIntent intent,
301             boolean isActivityIntent,
302             boolean animate) {
303         String notificationKey = entry.getKey();
304         mLogger.logHandleClickAfterPanelCollapsed(entry);
305 
306         try {
307             // The intent we are sending is for the application, which
308             // won't have permission to immediately start an activity after
309             // the user switches to home.  We know it is safe to do at this
310             // point, so make sure new activity switches are now allowed.
311             ActivityManager.getService().resumeAppSwitches();
312         } catch (RemoteException e) {
313         }
314         // If the notification should be cancelled on click and we are launching a work activity in
315         // a locked profile with separate challenge, we defer the activity action and cancelling of
316         // the notification until work challenge is unlocked. If the notification shouldn't be
317         // cancelled, the work challenge will be shown by ActivityManager if necessary anyway.
318         if (isActivityIntent && shouldAutoCancel(entry.getSbn())) {
319             final int userId = intent.getCreatorUserHandle().getIdentifier();
320             if (mLockPatternUtils.isSeparateProfileChallengeEnabled(userId)
321                     && mKeyguardManager.isDeviceLocked(userId)) {
322                 // TODO(b/28935539): should allow certain activities to
323                 // bypass work challenge
324                 if (mStatusBarRemoteInputCallback.startWorkChallengeIfNecessary(userId,
325                         intent.getIntentSender(), notificationKey)) {
326                     removeHunAfterClick(row);
327                     // Show work challenge, do not run PendingIntent and
328                     // remove notification
329                     mShadeController.collapseOnMainThread();
330                     return;
331                 }
332             }
333         }
334         Intent fillInIntent = null;
335         CharSequence remoteInputText = null;
336         if (!TextUtils.isEmpty(entry.remoteInputText)) {
337             remoteInputText = entry.remoteInputText;
338         }
339         if (!TextUtils.isEmpty(remoteInputText)
340                 && !mRemoteInputManager.isSpinning(notificationKey)) {
341             fillInIntent = new Intent().putExtra(Notification.EXTRA_REMOTE_INPUT_DRAFT,
342                     remoteInputText.toString());
343         }
344         final boolean canBubble = entry.canBubble();
345         if (canBubble) {
346             mLogger.logExpandingBubble(entry);
347             removeHunAfterClick(row);
348             expandBubbleStackOnMainThread(entry);
349         } else {
350             startNotificationIntent(intent, fillInIntent, entry, row, animate, isActivityIntent);
351         }
352         if (isActivityIntent || canBubble) {
353             mAssistManagerLazy.get().hideAssist();
354         }
355 
356         final NotificationVisibility nv = mVisibilityProvider.obtain(entry, true);
357 
358         if (!canBubble && (shouldAutoCancel(entry.getSbn())
359                 || mRemoteInputManager.isNotificationKeptForRemoteInputHistory(notificationKey))) {
360             final Runnable removeNotification =
361                     mOnUserInteractionCallback.registerFutureDismissal(entry, REASON_CLICK);
362             // Immediately remove notification from visually showing.
363             // We have to post the removal to the UI thread for synchronization.
364             mMainThreadHandler.post(() -> {
365                 if (mPresenter.isCollapsing()) {
366                     // To avoid lags we're only performing the remove after the shade is collapsed
367                     mShadeController.addPostCollapseAction(removeNotification);
368                 } else {
369                     removeNotification.run();
370                 }
371             });
372         }
373 
374         // inform NMS that the notification was clicked
375         mClickNotifier.onNotificationClick(notificationKey, nv);
376 
377         mIsCollapsingToShowActivityOverLockscreen = false;
378     }
379 
380     /**
381      * Called when a notification is dropped on proper target window.
382      * Intent that is included in this entry notification,
383      * will be sent by {@link ExpandableNotificationRowDragController}
384      *
385      * @param entry notification entry that is dropped.
386      */
387     @Override
onDragSuccess(NotificationEntry entry)388     public void onDragSuccess(NotificationEntry entry) {
389         // this method is not responsible for intent sending.
390         // will focus follow operation only after drag-and-drop that notification.
391         final NotificationVisibility nv = mVisibilityProvider.obtain(entry, true);
392 
393         String notificationKey = entry.getKey();
394         if (shouldAutoCancel(entry.getSbn())
395                 || mRemoteInputManager.isNotificationKeptForRemoteInputHistory(notificationKey)) {
396             final Runnable removeNotification =
397                     mOnUserInteractionCallback.registerFutureDismissal(entry, REASON_CLICK);
398             // Immediately remove notification from visually showing.
399             // We have to post the removal to the UI thread for synchronization.
400             mMainThreadHandler.post(() -> {
401                 if (mPresenter.isCollapsing()) {
402                     // To avoid lags we're only performing the remove
403                     // after the shade is collapsed
404                     mShadeController.addPostCollapseAction(removeNotification);
405                 } else {
406                     removeNotification.run();
407                 }
408             });
409         }
410 
411         // inform NMS that the notification was clicked
412         mClickNotifier.onNotificationClick(notificationKey, nv);
413 
414         mIsCollapsingToShowActivityOverLockscreen = false;
415     }
416 
expandBubbleStackOnMainThread(NotificationEntry entry)417     private void expandBubbleStackOnMainThread(NotificationEntry entry) {
418         if (!mBubblesManagerOptional.isPresent()) {
419             return;
420         }
421 
422         if (Looper.getMainLooper().isCurrentThread()) {
423             expandBubbleStack(entry);
424         } else {
425             mMainThreadHandler.post(() -> expandBubbleStack(entry));
426         }
427     }
428 
expandBubbleStack(NotificationEntry entry)429     private void expandBubbleStack(NotificationEntry entry) {
430         mBubblesManagerOptional.get().expandStackAndSelectBubble(entry);
431         mShadeController.collapseShade();
432     }
433 
startNotificationIntent( PendingIntent intent, Intent fillInIntent, NotificationEntry entry, ExpandableNotificationRow row, boolean animate, boolean isActivityIntent)434     private void startNotificationIntent(
435             PendingIntent intent,
436             Intent fillInIntent,
437             NotificationEntry entry,
438             ExpandableNotificationRow row,
439             boolean animate,
440             boolean isActivityIntent) {
441         mLogger.logStartNotificationIntent(entry);
442         try {
443             ActivityLaunchAnimator.Controller animationController =
444                     new StatusBarLaunchAnimatorController(
445                             mNotificationAnimationProvider.getAnimatorController(row, null),
446                             mShadeViewController,
447                             mShadeController,
448                             mNotificationShadeWindowController,
449                             isActivityIntent);
450             mActivityLaunchAnimator.startPendingIntentWithAnimation(
451                     animationController,
452                     animate,
453                     intent.getCreatorPackage(),
454                     (adapter) -> {
455                         long eventTime = row.getAndResetLastActionUpTime();
456                         Bundle options = eventTime > 0
457                                 ? getActivityOptions(
458                                 mDisplayId,
459                                 adapter,
460                                 mKeyguardStateController.isShowing(),
461                                 eventTime)
462                                 : getActivityOptions(mDisplayId, adapter);
463                         int result = intent.sendAndReturnResult(mContext, 0, fillInIntent, null,
464                                 null, null, options);
465                         mLogger.logSendPendingIntent(entry, intent, result);
466                         return result;
467                     });
468         } catch (PendingIntent.CanceledException e) {
469             // the stack trace isn't very helpful here.
470             // Just log the exception message.
471             mLogger.logSendingIntentFailed(e);
472             // TODO: Dismiss Keyguard.
473         }
474     }
475 
476     @Override
startNotificationGutsIntent(final Intent intent, final int appUid, ExpandableNotificationRow row)477     public void startNotificationGutsIntent(final Intent intent, final int appUid,
478             ExpandableNotificationRow row) {
479         boolean animate = mActivityStarter.shouldAnimateLaunch(true /* isActivityIntent */);
480         ActivityStarter.OnDismissAction onDismissAction = new ActivityStarter.OnDismissAction() {
481             @Override
482             public boolean onDismiss() {
483                 AsyncTask.execute(() -> {
484                     ActivityLaunchAnimator.Controller animationController =
485                             new StatusBarLaunchAnimatorController(
486                                     mNotificationAnimationProvider.getAnimatorController(row),
487                                     mShadeViewController,
488                                     mShadeController,
489                                     mNotificationShadeWindowController,
490                                     true /* isActivityIntent */);
491 
492                     mActivityLaunchAnimator.startIntentWithAnimation(
493                             animationController, animate, intent.getPackage(),
494                             (adapter) -> TaskStackBuilder.create(mContext)
495                                     .addNextIntentWithParentStack(intent)
496                                     .startActivities(getActivityOptions(
497                                             mDisplayId,
498                                             adapter),
499                                             new UserHandle(UserHandle.getUserId(appUid))));
500                 });
501                 return true;
502             }
503 
504             @Override
505             public boolean willRunAnimationOnKeyguard() {
506                 return animate;
507             }
508         };
509         mActivityStarter.dismissKeyguardThenExecute(onDismissAction, null,
510                 false /* afterKeyguardGone */);
511     }
512 
513     @Override
startHistoryIntent(View view, boolean showHistory)514     public void startHistoryIntent(View view, boolean showHistory) {
515         boolean animate = mActivityStarter.shouldAnimateLaunch(true /* isActivityIntent */);
516         ActivityStarter.OnDismissAction onDismissAction = new ActivityStarter.OnDismissAction() {
517             @Override
518             public boolean onDismiss() {
519                 AsyncTask.execute(() -> {
520                     Intent intent = showHistory ? new Intent(
521                             Settings.ACTION_NOTIFICATION_HISTORY) : new Intent(
522                             Settings.ACTION_NOTIFICATION_SETTINGS);
523                     TaskStackBuilder tsb = TaskStackBuilder.create(mContext)
524                             .addNextIntent(new Intent(Settings.ACTION_NOTIFICATION_SETTINGS));
525                     if (showHistory) {
526                         tsb.addNextIntent(intent);
527                     }
528 
529                     ActivityLaunchAnimator.Controller viewController =
530                             ActivityLaunchAnimator.Controller.fromView(view,
531                                     InteractionJankMonitor.CUJ_SHADE_APP_LAUNCH_FROM_HISTORY_BUTTON
532                             );
533                     ActivityLaunchAnimator.Controller animationController =
534                             viewController == null ? null
535                                 : new StatusBarLaunchAnimatorController(
536                                         viewController,
537                                         mShadeViewController,
538                                         mShadeController,
539                                         mNotificationShadeWindowController,
540                                         true /* isActivityIntent */);
541 
542                     mActivityLaunchAnimator.startIntentWithAnimation(animationController, animate,
543                             intent.getPackage(),
544                             (adapter) -> tsb.startActivities(
545                                     getActivityOptions(mDisplayId, adapter),
546                                     mUserTracker.getUserHandle()));
547                 });
548                 return true;
549             }
550 
551             @Override
552             public boolean willRunAnimationOnKeyguard() {
553                 return animate;
554             }
555         };
556         mActivityStarter.dismissKeyguardThenExecute(onDismissAction, null,
557                 false /* afterKeyguardGone */);
558     }
559 
removeHunAfterClick(ExpandableNotificationRow row)560     private void removeHunAfterClick(ExpandableNotificationRow row) {
561         String key = row.getEntry().getSbn().getKey();
562         if (mHeadsUpManager != null && mHeadsUpManager.isAlerting(key)) {
563             // Release the HUN notification to the shade.
564             if (mPresenter.isPresenterFullyCollapsed()) {
565                 HeadsUpUtil.setNeedsHeadsUpDisappearAnimationAfterClick(row, true);
566             }
567 
568             // In most cases, when FLAG_AUTO_CANCEL is set, the notification will
569             // become canceled shortly by NoMan, but we can't assume that.
570             mHeadsUpManager.removeNotification(key, true /* releaseImmediately */);
571         }
572     }
573 
574     @VisibleForTesting
launchFullScreenIntent(NotificationEntry entry)575     void launchFullScreenIntent(NotificationEntry entry) {
576         // Skip if device is in VR mode.
577         if (mPresenter.isDeviceInVrMode()) {
578             mLogger.logFullScreenIntentSuppressedByVR(entry);
579             return;
580         }
581         // Stop screensaver if the notification has a fullscreen intent.
582         // (like an incoming phone call)
583         mUiBgExecutor.execute(() -> {
584             try {
585                 mDreamManager.awaken();
586             } catch (RemoteException e) {
587                 e.printStackTrace();
588             }
589         });
590 
591         // not immersive & a fullscreen alert should be shown
592         final PendingIntent fullScreenIntent =
593                 entry.getSbn().getNotification().fullScreenIntent;
594         mLogger.logSendingFullScreenIntent(entry, fullScreenIntent);
595         try {
596             EventLog.writeEvent(EventLogTags.SYSUI_FULLSCREEN_NOTIFICATION,
597                     entry.getKey());
598             mPowerInteractor.wakeUpForFullScreenIntent();
599 
600             ActivityOptions options = ActivityOptions.makeBasic();
601             options.setPendingIntentBackgroundActivityStartMode(
602                     MODE_BACKGROUND_ACTIVITY_START_ALLOWED);
603             fullScreenIntent.sendAndReturnResult(null, 0, null, null, null, null,
604                     options.toBundle());
605             entry.notifyFullScreenIntentLaunched();
606 
607             mMetricsLogger.count("note_fullscreen", 1);
608 
609             String activityName;
610             List<ResolveInfo> resolveInfos = fullScreenIntent.queryIntentComponents(0);
611             if (resolveInfos.size() > 0 && resolveInfos.get(0) != null
612                     && resolveInfos.get(0).activityInfo != null
613                     && resolveInfos.get(0).activityInfo.name != null) {
614                 activityName = resolveInfos.get(0).activityInfo.name;
615             } else {
616                 activityName = "";
617             }
618             FrameworkStatsLog.write(FrameworkStatsLog.FULL_SCREEN_INTENT_LAUNCHED,
619                     fullScreenIntent.getCreatorUid(),
620                     activityName);
621         } catch (PendingIntent.CanceledException e) {
622             // ignore
623         }
624     }
625 
626     @Override
isCollapsingToShowActivityOverLockscreen()627     public boolean isCollapsingToShowActivityOverLockscreen() {
628         return mIsCollapsingToShowActivityOverLockscreen;
629     }
630 
shouldAutoCancel(StatusBarNotification sbn)631     private static boolean shouldAutoCancel(StatusBarNotification sbn) {
632         int flags = sbn.getNotification().flags;
633         if ((flags & Notification.FLAG_AUTO_CANCEL) != Notification.FLAG_AUTO_CANCEL) {
634             return false;
635         }
636         return true;
637     }
638 
639 }
640