android6.0锁屏界面接收新通知处理流程
灭屏状态下,接收新信息,屏幕会半亮显示通知流程:
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布局中显示
}
android6.0锁屏界面接收新通知处理流程的更多相关文章
- 解决:Android4.3锁屏界面Emergency calls only - China Unicom与EMERGENCY CALL语义重复
从图片中我们可以看到,这里在语义上有一定的重复,当然这是谷歌的原始设计.这个问题在博客上进行共享从表面上来看着实没有什么太大的意义,不过由于Android4.3在锁屏功能上比起老版本做了很大的改动,而 ...
- android------锁屏(手机启动出现锁屏界面)
以前用过一个红包锁屏的软件,第一次打开手机出现锁屏,滑动领取收益,当时觉得这功能不错,就查阅资料,写了一个案例, apk运行流程: 进入软件--->启动服务--->关闭手机(可先退出应用) ...
- Android 7.1.1 锁屏界面启动流程
前几天遇到一个低概率复现锁屏界面不显示,仅仅显示状态栏的问题,跟了下锁屏界面启动显示的流程,在这分享下,也方便以后自己查看.前面简介了下Zygote启动流程, Zygote进程启动后会首先创建一个Sy ...
- Android4.0+锁屏程序开发——设置锁屏页面篇
[如何开发一个锁屏应用] 想要开发一个锁屏应用,似乎很难,其实并没有想象中那么难. 从本质上来说,锁屏界面也只是一个Activity而已,只是这个界面比较特殊,在我们点亮屏幕的时候,这个界面就会出现. ...
- Android4.0+锁屏程序开发——按键屏蔽篇
开发锁屏程序的时候我们要面临的重要问题无疑是如何屏蔽三个按键,Back,Home,Menu 看似简单的功能,实现起来却并不是那么容易. [屏蔽Back按键] 相对来说,屏蔽Back键是比较简单的,只 ...
- 解决:Android4.3锁屏界面Emergency calls only - China Unicom与EMERGENCY CALL语义反复
从图片中我们能够看到,这里在语义上有一定的反复,当然这是谷歌的原始设计.这个问题在博客上进行共享从表面上来看着实没有什么太大的意义,只是因为Android4.3在锁屏功能上比起老版本号做了非常大的修改 ...
- Qt - 锁屏界面加虚拟小键盘
一.实现效果 鼠标点击"密码输入栏",弹出虚拟键盘,输入锁屏密码后,点击虚拟键盘外部区域,则会隐藏虚拟键盘,再点击登录,成功进入主界面. 二.虚拟键盘-程序设计 2.1 frmNu ...
- iOS开发--QQ音乐练习,后台播放和锁屏界面
一.设置后台播放 首先允许程序后台播放 代码实现 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOpti ...
- win10锁屏界面无法更新
win10的锁屏界面都是巨硬公司推送过来的,质量还不错,最近锁屏界面无法更新,解决方案如下: 以管理员身份运行cmd,分别运行如下两个命令 del /f /s /q /a "%userpro ...
随机推荐
- * {margin:0px; padding:0px;}什么意思?
* {margin:0px; padding:0px;} * 表示所有的元素的对齐方式以及和父类之间的间距都为0 body{margin:0px;padding:0px;} body里面的则表示的是 ...
- linux 命令总结
①用find命令查找并删除文件 用脚本创建测试数据: [root@greymouster ceshidata]# for n in `seq 10`> do > date -s " ...
- VMware 虚拟机桥接网络设置
一.桥接的基本原理 配置成桥接网络连接模式的虚拟机就当作主机所在以太网的一部分,虚拟系统和宿主机器的关系,就像连接在同一个Hub上的两台电脑,可以像主机一样可以访问以太网中的所有共享资源和网络连 ...
- Jenkins自动部署Tomcat项目
Jenkins自动部署Tomcat项目 1.安装jenkins 插件 启动Jenkins,进入系统管理-插件管理: 选择Deploy to container Plugin 插件安装:
- Windows 10设置桌面图标间距、窗口的背景颜色、选中文字的背景颜色
Windows 10取消了“高级外观设置”(或者叫“窗口颜色和外观”设置),想调整一些参数只能进注册表了. 修改后可能需要注销或重启才能生效. 按Win+R,然后输入regedit进入注册表编辑器. ...
- 基本TCP套接字编程
1.listen函数 将主动套接字转换成一个被动套接字 backlog指定相应套接字连接队列的大小. 监听套接字有2个队列: (1)未完成连接队列,接收客户SYN,发出SYN.ACK,等待完成三次握手 ...
- 协同开发中SVN的使用建议
协同开发中SVN的使用建议 1. 注意个人账户密码安全 各员工需牢记各自的账户和密码,不得向他人透漏,严禁使用他人账户进行SVN各项操作(主要考虑每个SVN账号的使用者的权限范围问题).如有忘记,请 ...
- 关于UI系统的问题
function OnGUI(){ GUI.skin = myskin; if(GUILayout.Button("add_component",GUILayout.Height( ...
- c# NPOI 导出EXCEL
需要引入dll文件 也可以在NuGet里面管理(推荐) 比较方便 . using System; using System.Collections.Generic; using System.Linq ...
- nginx + lua +redis环境搭建
环境搭建,其实主要是lua的环境,这个环境够麻烦的,在网上找了很多前辈的文章,终于完成了 ,安装redis wget http://download.redis.io/releases/redis-3 ...