Android P Notification(3) 之 Fullscreen intent被拦截

源码网站:http://androidxref.com/9.0.0_r3

可以参照: Android O 8.0 Notification 源码分析(一)

                Android O 8.0 Notification 源码分析(二)

link:

Android P Notification(1) 之 removeNotification

Android P Notification(2) 之 发送通知慢

Android P Notification(3) 之 Fullscreen intent被拦截

 

NotificationManagerService原理分析

 

1.来电话时发现全屏通知被拦截

拦截原因

1): No Fullscreen intent: suppressed by DND(do not disturb) 被勿扰模式拦截

2).No Fullscreen intent: not important enough 通知优先级不够

 

2.Fullscreen intent app处理

incallUI发送通知的代码如下

@/packages/apps/Dialer/java/com/android/incallui/StatusBarNotifier.java
private void buildAndSendNotification(
  LogUtil.i("StatusBarNotifier.buildAndSendNotification", "notificationType=" + notificationType);  //2 log会打印2,表示incallUI发送通知开始
  switch (notificationType) {
    case NOTIFICATION_INCOMING_CALL: //2
      if (BuildCompat.isAtLeastO()) {
        builder.setChannelId(NotificationChannelId.INCOMING_CALL);  //channel id : INCOMING_CALL
      }
      // Set the intent as a full screen intent as well if a call is incoming
      configureFullScreenIntent(builder, createLaunchPendingIntent(true /* isFullScreen */));  //发送全屏通知
      // Set the notification category and bump the priority for incoming calls
      builder.setCategory(Notification.CATEGORY_CALL);
      // This will be ignored on O+ and handled by the channel
      builder.setPriority(Notification.PRIORITY_MAX);  //优先级 PRIORITY_MAX
      if (currentNotification != NOTIFICATION_INCOMING_CALL) {
        LogUtil.i(
            "StatusBarNotifier.buildAndSendNotification",
            "Canceling old notification so this one can be noisy");
        // Moving from a non-interuptive notification (or none) to a noisy one. Cancel the old
        // notification (if there is one) so the fullScreenIntent or HUN will show
        TelecomAdapter.getInstance().stopForegroundNotification();
      }
      break;
   
  LogUtil.i(
      "StatusBarNotifier.buildAndSendNotification",
      "displaying notification for " + notificationType);

  // If a notification exists, this will only update it.
  TelecomAdapter.getInstance().startForegroundNotification(NOTIFICATION_ID, notification);  //notify通知
}

需要设置setFullScreenIntent为true

http://androidxref.com/9.0.0_r3
packages/apps/Dialer/java/com/android/incallui/StatusBarNotifier.java
983  private void configureFullScreenIntent(Notification.Builder builder, PendingIntent intent) {
984    // Ok, we actually want to launch the incoming call
985    // UI at this point (in addition to simply posting a notification
986    // to the status bar).  Setting fullScreenIntent will cause
987    // the InCallScreen to be launched immediately *unless* the
988    // current foreground activity is marked as "immersive".
989    LogUtil.d("StatusBarNotifier.configureFullScreenIntent", "setting fullScreenIntent: " + intent);
990    builder.setFullScreenIntent(intent, true);
991  }

3.Framework层收到通知拦截fullScreen Intent

在addNotificationInternal回去拦截,看了几个Android 版本位置都有点差异,不过代码逻辑都是一样的

@/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/NotificationEntryManager.java
743    protected NotificationData.Entry createNotificationViews(StatusBarNotification sbn)
744            throws InflationException {
745        if (DEBUG) {
746            Log.d(TAG, "createNotificationViews(notification=" + sbn);
747        }
748        NotificationData.Entry entry = new NotificationData.Entry(sbn);
749        Dependency.get(LeakDetector.class).trackInstance(entry);
750        entry.createIcons(mContext, sbn);
751        // Construct the expanded view.
752        inflateViews(entry, mListContainer.getViewParentForNotification(entry));
753        return entry;
754    }
755
756    private void addNotificationInternal(StatusBarNotification notification,
757            NotificationListenerService.RankingMap ranking) throws InflationException {
758        String key = notification.getKey();
759        if (DEBUG) Log.d(TAG, "addNotification key=" + key);
760
761        mNotificationData.updateRanking(ranking);
762        NotificationData.Entry shadeEntry = createNotificationViews(notification);
763        boolean isHeadsUped = shouldPeek(shadeEntry);
764        if (!isHeadsUped && notification.getNotification().fullScreenIntent != null) {
765            if (shouldSuppressFullScreenIntent(shadeEntry)) {
766                if (DEBUG) {
767                    Log.d(TAG, "No Fullscreen intent: suppressed by DND: " + key);
768                }
769            } else if (mNotificationData.getImportance(key)
770                    < NotificationManager.IMPORTANCE_HIGH) {
771                if (DEBUG) {
772                    Log.d(TAG, "No Fullscreen intent: not important enough: "
773                            + key);
774                }
775            } else {
776                // Stop screensaver if the notification has a fullscreen intent.
777                // (like an incoming phone call)
778                SystemServicesProxy.getInstance(mContext).awakenDreamsAsync();
779
780                // not immersive & a fullscreen alert should be shown
781                if (DEBUG)
782                    Log.d(TAG, "Notification has fullScreenIntent; sending fullScreenIntent");
783                try {
784                    EventLog.writeEvent(EventLogTags.SYSUI_FULLSCREEN_NOTIFICATION,
785                            key);
786                    notification.getNotification().fullScreenIntent.send();
787                    shadeEntry.notifyFullScreenIntentLaunched();
788                    mMetricsLogger.count("note_fullscreen", 1);
789                } catch (PendingIntent.CanceledException e) {
790                }
791            }
792        }
793        abortExistingInflation(key);
794
795        mForegroundServiceController.addNotification(notification,
796                mNotificationData.getImportance(key));
797
798        mPendingNotifications.put(key, shadeEntry);
799        mGroupManager.onPendingEntryAdded(shadeEntry);
800    }

4.NotificationRecord 设置importance等级

      由于app没有setimportance()方法,因此Importance是在这里赋值。

如果出现优先级低导致fullscreen initent被拦截,可以添加下详细LOG来DEBUG。

@frameworks/base/services/core/java/com/android/server/notification/NotificationRecord.java
@VisibleForTesting
public NotificationRecord(Context context, StatusBarNotification sbn,
        NotificationChannel channel)
{
    this.sbn = sbn;
    mOriginalFlags = sbn.getNotification().flags;
    mRankingTimeMs = calculateRankingTimeMs(0L);
    mCreationTimeMs = sbn.getPostTime();
    mUpdateTimeMs = mCreationTimeMs;
    mContext = context;
    stats = new NotificationUsageStats.SingleNotificationStats();
    mChannel = channel;
    mPreChannelsNotification = isPreChannelsNotification();
    mSound = calculateSound();
    mVibration = calculateVibration();
    mAttributes = calculateAttributes();
    mImportance = calculateImportance();  //app没有setimprotance方法,是在这里赋值
    mLight = calculateLights();
}


private int calculateImportance() {
    final Notification n = sbn.getNotification();
    int importance = getChannel().getImportance();
    int requestedImportance = IMPORTANCE_DEFAULT;

    // Migrate notification flags to scores
    if (0 != (n.flags & Notification.FLAG_HIGH_PRIORITY)) {
        n.priority = Notification.PRIORITY_MAX;
    }

    n.priority = NotificationManagerService.clamp(n.priority, Notification.PRIORITY_MIN,
            Notification.PRIORITY_MAX);
    switch (n.priority) {
        case Notification.PRIORITY_MIN:
            requestedImportance = IMPORTANCE_MIN;
            break;
        case Notification.PRIORITY_LOW:
            requestedImportance = IMPORTANCE_LOW;
            break;
        case Notification.PRIORITY_DEFAULT:
            requestedImportance = IMPORTANCE_DEFAULT;
            break;
        case Notification.PRIORITY_HIGH:
        case Notification.PRIORITY_MAX:
            requestedImportance = IMPORTANCE_HIGH;
            break;
    }
    stats.requestedImportance = requestedImportance;
    stats.isNoisy = mSound != null || mVibration != null;   //isNoisy可能优先级会和这个有关

    if (mPreChannelsNotification
            && (importance == IMPORTANCE_UNSPECIFIED
            || (getChannel().getUserLockedFields()
            & NotificationChannel.USER_LOCKED_IMPORTANCE) == 0)) {
        if (!stats.isNoisy && requestedImportance > IMPORTANCE_LOW) {
            requestedImportance = IMPORTANCE_LOW;
        }

        if (stats.isNoisy) {
            if (requestedImportance < IMPORTANCE_DEFAULT) {
                requestedImportance = IMPORTANCE_DEFAULT;
            }
        }

        if (n.fullScreenIntent != null) {
            requestedImportance = IMPORTANCE_HIGH;
        }
        importance = requestedImportance;
    }

    stats.naturalImportance = importance;
    return importance;
}

 

 

 

 

你可能感兴趣的:(Notification)