灭屏状态下,接收新信息,屏幕会半亮显示通知流程:
1,应用构造notification后,传给NotificationManager,而后进入NotificationManagerService处理。
NotificationManager nm = (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);
nm.notify(NOTIFICATION_ID, notification)
frameworks\base\core\java\android\app\NotificationManager.java
public void notify(int id, Notification notification) { notify(null, id, notification); }
public void notify(String tag, int id, Notification notification) { …… Notification stripped = notification.clone(); Builder.stripForDelivery(stripped); try { service.enqueueNotificationWithTag(pkg, mContext.getOpPackageName(), tag, id, stripped, idOut, UserHandle.myUserId()); if (id != idOut[0]) { Log.w(TAG, "notify: id corrupted: sent " + id + ", got back " + idOut[0]); } } catch (RemoteException e) { } }
frameworks\base\services\core\java\com\android\server\notification\NotificationManagerService.java
public void enqueueNotificationWithTag(String pkg, String opPkg, String tag, int id, Notification notification, int[] idOut, int userId) throws RemoteException { enqueueNotificationInternal(pkg, opPkg, Binder.getCallingUid(), Binder.getCallingPid(), tag, id, notification, idOut, userId); }
同一个包名的通知超过50条不会继续处理。
if (count >= MAX_PACKAGE_NOTIFICATIONS) {
Slog.e(TAG, "Package has already posted " + count
+ " notifications. Not showing more. package=" + pkg);
return;
}
private void buzzBeepBlinkLocked(NotificationRecord record) { …… …… // light // release the light boolean wasShowLights = mLights.remove(record.getKey()); if ((notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0 && aboveThreshold) { mLights.add(record.getKey()); updateLightsLocked(); if (mUseAttentionLight) { mAttentionLight.pulse(); } blink = true; } else if (wasShowLights) { updateLightsLocked(); } if (buzz || beep || blink) { EventLogTags.writeNotificationAlert(record.getKey(), buzz ? 1 : 0, beep ? 1 : 0, blink ? 1 : 0); mHandler.post(mBuzzBeepBlinked); } }
屏幕半亮闪烁需要判断 (notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0
所以在应用构建notification时可以通过给flag赋值来控制是否要屏幕半亮闪烁。
先读取设置数据库中的NOTIFICATION_LIGHT_PULSE来判断是否闪烁,如果mNotificationPulseEnabled为true,则先闪烁一次(Light.LIGHT_FLASH_TIMED =1)。
Settings.System.getInt(resolver, Settings.System.NOTIFICATION_LIGHT_PULSE, 0)
if (mNotificationPulseEnabled) {
// pulse repeatedly
mNotificationLight.setFlashing(ledARGB, Light.LIGHT_FLASH_TIMED, //Light.LIGHT_FLASH_TIMED =1
ledOnMS, ledOffMS);
}
// let SystemUI make an independent decision //进入SystemUI处理
mStatusBar.notificationLightPulse(ledARGB, ledOnMS, ledOffMS);
2,然后进入SystemUi继续处理。
SystemUI中最终处理在DozeService中,也有一个开关判断,是否要闪烁。
if (!mDozeParameters.getPulseOnNotifications()) return;//getPulseOnNotifications默认为true
DozeService.java中调用private void requestPulse(final int reason)执行点亮屏幕。
private void requestPulse(final int reason, boolean performedProxCheck) { if (mHost != null && mDreaming && !mPulsing) { // Let the host know we want to pulse. Wait for it to be ready, then // turn the screen on. When finished, turn the screen off again. // Here we need a wakelock to stay awake until the pulse is finished. mWakeLock.acquire(); mPulsing = true; if (!mDozeParameters.getProxCheckBeforePulse()) {//这里先判断是否要先执行ProxCheck, proxCheck会检查手机sensor是否正常,如果不正常就退出,不执行点亮屏幕 // skip proximity check continuePulsing(reason); return; } final long start = SystemClock.uptimeMillis(); if (performedProxCheck) { // the caller already performed a successful proximity check; we'll only do one to // capture statistics, continue pulsing immediately. continuePulsing(reason); } // perform a proximity check new ProximityCheck() { @Override public void onProximityResult(int result) { …… …… } }.check(); } } private abstract class ProximityCheck implements SensorEventListener, Runnable { …… …… public void check() { if (mFinished || mRegistered) return; final Sensor sensor = mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY); if (sensor == null) {//手机sensor无效,直接退出程序。 if (DEBUG) Log.d(mTag, "No sensor found"); finishWithResult(RESULT_UNKNOWN); return; } // the pickup sensor interferes with the prox event, disable it until we have a result mPickupSensor.setDisabled(true); mMaxRange = sensor.getMaximumRange(); mSensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_NORMAL, 0, mHandler); mHandler.postDelayed(this, TIMEOUT_DELAY_MS); mRegistered = true; } …… …… }
----------------------------------------------------------------------------------------------------
3,SystemUI下拉展开布局中显示通知处理流程:
BaseStatusBar中通过mNotificationListener监听通知更新,获取通知
private final NotificationListenerService mNotificationListener = new NotificationListenerService() { public void onListenerConnected() { if (DEBUG) Log.d(TAG, "onListenerConnected"); final StatusBarNotification[] notifications = getActiveNotifications();//获取当前所有通知集合 final RankingMap currentRanking = getCurrentRanking(); mHandler.post(new Runnable() { @Override public void run() { for (StatusBarNotification sbn : notifications) { addNotification(sbn, currentRanking, null /* oldEntry */); } } }); } …… }
NotificationListenerService获取通知
public StatusBarNotification[] getActiveNotifications() { return getActiveNotifications(null, TRIM_FULL); } public StatusBarNotification[] getActiveNotifications(String[] keys, int trim) { if (!isBound()) return null; try { //这里通过Binder调用NotificationManagerService调用getActiveNotificationsFromListener获取通知 ParceledListSlice<StatusBarNotification> parceledList = getNotificationInterface().getActiveNotificationsFromListener(mWrapper, keys, trim); List<StatusBarNotification> list = parceledList.getList(); ………… return list.toArray(new StatusBarNotification[list.size()]); } catch (android.os.RemoteException ex) { Log.v(TAG, "Unable to contact notification manager", ex); } return null; } //获取INotificationManager的实例,也就是NotificationManagerService中的mService private final INotificationManager getNotificationInterface() { if (mNoMan == null) { mNoMan = INotificationManager.Stub.asInterface( ServiceManager.getService(Context.NOTIFICATION_SERVICE)); } return mNoMan; }
NotificationManagerService中对Context.NOTIFICATION_SERVICE的映射
public class NotificationManagerService extends SystemService public void onStart() { …… publishBinderService(Context.NOTIFICATION_SERVICE, mService);//SystemService中定义的方法 publishBinderService(..) …… }
通过上述流程已经获取通知数据,将数据显示在SystemUI中在PhoneStatusBar中处理
//重载父类BaseStatusBar中的方法,mNotificationListener中会直接调用这里添加通知 public void addNotification(StatusBarNotification notification, RankingMap ranking, Entry oldEntry) { if (DEBUG) Log.d(TAG, "addNotification key=" + notification.getKey()); Entry shadeEntry = createNotificationViews(notification); if (shadeEntry == null) { return; } …… addNotificationViews(shadeEntry, ranking);// // Recalculate the position of the sliding windows and the titles. setAreThereNotifications(); }
protected void addNotificationViews(Entry entry, RankingMap ranking) { if (entry == null) { return; } // Add the expanded view and icon. mNotificationData.add(entry, ranking);// updateNotifications(); //此方法会将新通知添加到SystemUI布局中显示 }