Android O Notification之通知休眠流程

一句话总结

在SystemUI进程中通过INotificationManager将要休眠的通知传递给SystemServer进程,SystemServer进程中通过AlarmManager定时发送一条广播让NotificationManagerService发送通知。

1.SystemUI进程中处理点击事件

点击通知休眠按钮,由NotificationSnooze的handleCloseControls处理

NotificationSnooze.java

if (mSnoozeListener != null && mSelectedOption != null) {
 // Snooze option selected so commit it
     mSnoozing = true;
     mSnoozeListener.snooze(mSbn, mSelectedOption);
}

经过一系列的转发,最终会调用到StatusBar的setNotificationSnoozed

NotificationStackScrollLayout.java

@Override
public void snooze(StatusBarNotification sbn, SnoozeOption snoozeOption) {
   mStatusBar.setNotificationSnoozed(sbn, snoozeOption);
}

StatusBar中有一个NotificationListenserService实例mNotificationListener。负责和NotificationManagerService跨进程(SystemServer)通信。NotificationListenserService中有一个内部类NotificationListernerWrapper实现了INotificationListener接口,这个才是具体实现。

StatusBar.java
 //一般为null
 if (snoozeOption.getSnoozeCriterion() != null) {
     mNotificationListener.snoozeNotification(sbn.getKey(),
              snoozeOption.getSnoozeCriterion().getId());
  } else {
      mNotificationListener.snoozeNotification(sbn.getKey(),
              snoozeOption.getMinutesToSnoozeFor() * 60 * 1000);
  }

接下来我们看一下snoozeNotification方法的具体实现,方法的主要作用是通知NotificationManager休眠该通知。这也就实现了从systemui进程调用到了SystemServer进程

NotificationListenerService.java
/*
* @param key The key of the notification to snooze
* @param durationMs A duration to snooze the notification for, in milliseconds.
* /
public final void snoozeNotification(String key, long durationMs) {
    if (!isBound()) return;
    try {
         getNotificationInterface().snoozeNotificationUntilFromListener(
                 mWrapper, key, durationMs);
     } catch (android.os.RemoteException ex) {
         Log.v(TAG, "Unable to contact notification manager", ex);
     }
}

2.SystemServer进程处理通知休眠

getNotificationInterface()方法返回的是NotificationManagerService(以下简称NMS)的客户端,跨进程调用到NMS的snoozeNotificationUntilFromListener。然后会调用到snoozeNotificationInt。

NotificationServiceManager.java

void snoozeNotificationInt(String key, long duration, String snoozeCriterionId,
           ManagedServiceInfo listener) {
     //省略部分代码
     // Needs to post so that it can cancel notifications not yet enqueued.
     mHandler.post(new SnoozeNotificationRunnable(key, duration, snoozeCriterionId));
}

可以看到post了一个SnoozeNotificationRunnable。代码比较好理解,根据通知的Key值去找到这个通知,再调用snoozeLocked方法

NotificationManagerService$SnoozeNotificationRunnable.java

 public void run() {
     synchronized (mNotificationLock) {
           final NotificationRecord r = findNotificationByKeyLocked(mKey);
           if (r != null) {
               snoozeLocked(r);
      }
   }
 }

snoozeLocked方法也比较好理解,如果组合通知和非组合通知分开处理,但最后都是通过调用snoozeNotificationLocked。

NotificationManagerService$SnoozeNotificationRunnable.java

 @GuardedBy("mNotificationLock")
 void snoozeLocked(NotificationRecord r) {
      if (r.sbn.isGroup()) {
         //略
      } else {
          // just snooze the one notification
          snoozeNotificationLocked(r);
      }
  }

这段代码的意思很明显,1.从本地的数据即中移除该通知。2.取消这个通知,让通知从通知栏消失。3.更新通知灯。4.通过SnoozeHelper.snooze休眠通知。

@GuardedBy("mNotificationLock")
void snoozeNotificationLocked(NotificationRecord r) {
     boolean wasPosted = removeFromNotificationListsLocked(r);
     cancelNotificationLocked(r, false, REASON_SNOOZED, wasPosted, null);
     updateLightsLocked();
     if (mSnoozeCriterionId != null) {
         mAssistants.notifyAssistantSnoozedLocked(r.sbn, mSnoozeCriterionId);
         mSnoozeHelper.snooze(r);
     } else {
         mSnoozeHelper.snooze(r, mDuration);
     }
     savePolicyFile();
 }

通知休眠机制的具体实现:通过AlarmManager定时发送广播,在广播中在通过NMS发送休眠的通知

SnoozeHelper.java
/** * Snoozes a notification and schedules an alarm to repost at that time. */
 protected void snooze(com.android.server.notification.NotificationRecord record, long duration) {
     //记录数据list中
     snooze(record);
     //安排唤醒时间
     scheduleRepost(record.sbn.getPackageName(), record.getKey(), record.getUserId(), duration);
 }

private void scheduleRepost(String pkg, String key, int userId, long duration) {
     final PendingIntent pi = createPendingIntent(pkg, key, userId);
     long time = SystemClock.elapsedRealtime() + duration;
     if (DEBUG) Slog.d(TAG, "Scheduling evaluate for " + new Date(time));
     //定时发送广播
     mAm.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP, time, pi);
}

private PendingIntent createPendingIntent(String pkg, String key, int userId) {
                         //广播
    return PendingIntent.getBroadcast(mContext,
            REQUEST_CODE_REPOST,
           //略
}

 private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            if (REPOST_ACTION.equals(intent.getAction())) {
                repost(intent.getStringExtra(EXTRA_KEY), intent.getIntExtra(EXTRA_USER_ID,
                        UserHandle.USER_SYSTEM));
            }
        }
    };

protected void repost(String key, int userId) {
    if (record != null && !record.isCanceled) {
        mCallback.repost(userId, record);
    }
}
    原文作者:hjkdsa
    原文地址: https://blog.csdn.net/u013030203/article/details/79296987
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞