ÔÚ±¾ÎÄÖУ¬ÎÒÃÇÀ´ÏêϸÁ˽âÒ»ÏÂAndroidÉϵÄNitificationʵÏÖ¡£
NotificationÊÇ×ÔAndroid·¢²¼ÒÔÀ´¾ÍÓеÄAPI£¬Ò²ÊÇÓ¦ÓóÌÐòÖÐ×î³£ÓõŦÄܵÄÖ®Ò»£¬¿ª·¢Õß¶ÔÆäÓ¦µ±ÊÇÏ൱µÄÊìϤÁË¡£
ÔÚAndroid½ü¼¸ÄêµÄ°æ±¾¸üÐÂÖУ¬¼¸ºõÿ¸ö°æ±¾¶¼»á¶Ôϵͳ֪ͨ½çÃæ£¬ÒÔ¼°Ïà¹ØAPI×öһЩµÄ¸Ä±ä¡£ÕâЩ¸Ä±äʹµÃ¿ª·¢Õß¿ÉÒÔ¸üºÃµÄ¿ØÖÆÓ¦ÓóÌÐòµÄ֪ͨÑùʽ£¬Í¬Ê±Ò²Ê¹µÃ֪ͨ¹¦ÄܸüÒ×ÓÚÓû§Ê¹Óá£
±¾ÎÄÎÒÃÇÀ´Ïêϸ¿´Ò»ÏÂNotification·½ÃæµÄ֪ʶ¡£
¿ª·¢ÕßAPI
ÕâÀï²»´òËã¶ÔNotification»ù±¾µÄʹÓ÷½Ê½×ö¹ý¶à½²½â£¬Õâ·½ÃæÄÚÈݶÔÓںܶ࿪·¢ÕßÀ´Ëµ¶¼ÒѾÊǷdz£ÊìϤµÄÁË£¬²¢ÇÒÍøÂçÉÏÒ²ºÜÈÝÒ×ËÑË÷µ½Ïà¹ØÄÚÈÝ¡£
ÏÂÃæÖ»»á˵Ã÷Notification×ÔAndroid 5.0ÒÔÀ´µÄÐÂÔö¼Ó¹¦ÄÜ¡£
Heads-up Notification
Heads-up Notification ÊÇAndroid 5.0ÉϵÄÐÂÔö¹¦ÄÜ¡£
µ±É豸´¦ÓÚʹÓÃ״̬Ï£¨ÒѾ½âËø²¢ÇÒÆÁÄ»ÁÁ×Å£©Ê±£¬ÕâÖÖ֪ͨÒÔÒ»¸öСµÄ¸¡¶¯´°¿ÚµÄÐÎʽ³ÊÏÖ³öÀ´£¬¾ÍÏñÏÂÃæÕâÑù£º

Õâ¸öÑùʽ¿´ÆðÀ´ÏñÊǶÔ֪ͨµÄÒ»ÖÖѹËõ£¬µ«ÊÇHeads-up Notification¿ÉÒÔ°üº¬Action
Button¡£Óû§¿ÉÒÔµã»÷Action Button½øÐÐÏàÓ¦µÄ²Ù×÷£¬Ò²¿ÉÒÔ½«Õâ¸ö֪ͨ½çÃæÒÆ³ýµôµ«ÊDz»À뿪µ±Ç°Ó¦Óá£
Õâ¶ÔÓÚÓû§ÌåÑéÀ´ËµÊÇÒ»Ïî·Ç³£ºÃµÄ¸Ä½ø£¬ÏµÍ³µÄÀ´µç֪ͨ¾ÍÊÇÕâÖÖÐÎʽµÄ֪ͨ¡£ÔÚÉ豸´¦ÓÚʹÓÃ״̬ÏÂʱ£¬ÕâÖÖ֪ͨ¼È²»»á¸ÉÈÅÓû§µ±Ç°µÄÐÐΪ£¨¿ÉÒÔÖ±½Ó½«Í¨Öª½çÃæÒÆ³ýµô£©£¬ÓÖ·½±ãÁËÓû§¶ÔÓÚ֪ͨµÄ´¦Àí£¨¿ÉÒÔÖ±½Óµã»÷Action
ButtonÀ´´¦Àí֪ͨ£©¡£
Ö»ÒªNotificationÂú×ãÏÂÃæµÄÁ½ÖÖÇé¿öÏÂÈκÎÒ»ÖÖ£¬¾Í»á²úÉúHeads-up Notification£º
NotificationÉèÖÃÁËfullScreenIntent
NotificationÊÇÒ»¸öHighÓÅÏȼ¶µÄ֪ͨ²¢ÇÒʹÓÃÁËÁåÉù»òÕð¶¯
ËøÆÁÉϵÄNotification
´ÓAndroid 5.0¿ªÊ¼£¬Í¨Öª¿ÉÒÔÔÚËøÆÁÉÏÏÔʾ¡£¿ª·¢Õß¿ÉÒÔÀûÓÃÕâ¸öÌØÐÔÀ´ÊµÏÖýÌå²¥·Å°´Å¥»òÕ߯äËû³£ÓõIJÙ×÷¡£µ«Í¬Ê±£¬Óû§Ò²¿ÉÒÔͨ¹ýÉèÖÃÀ´¾ö¶¨ÊÇ·ñÔÚËøÆÁ½çÃæÉÏÏÔʾij¸öÓ¦ÓõÄ֪ͨ¡£
¿ª·¢Õß¿ÉÒÔͨ¹ýNotification.Builder.setVisibility(int)·½·¨À´¿ØÖÆÍ¨ÖªÏÔʾµÄÏêϸ¼¶±ð¡£Õâ¸ö·½·¨½ÓÊÕÈý¸ö¼¶±ðµÄ¿ØÖÆ£º
VISIBILITY_PUBLIC ÏÔʾ֪ͨµÄÈ«²¿ÄÚÈÝ
VISIBILITY_PRIVATE ÏÔʾ֪ͨµÄ»ù±¾ÐÅÏ¢£¬ÀýÈç֪ͨµÄiconºÍtitle£¬µ«ÊDz»ÏÔʾÏêϸÄÚÈÝ
VISIBILITY_SECRET ²»ÏÔʾ֪ͨµÄÈκÎÄÚÈÝ
NotificationÖ±½Ó»Ø¸´
´ÓAndroid 7.0¿ªÊ¼£¬Óû§¿ÉÒÔÔÚ֪ͨ½çÃæÉϽøÐÐÖ±½Ó»Ø¸´¡£Ö±½Ó»Ø¸´°´Å¥¸½¼ÓÔÚ֪ͨµÄÏÂÃæ¡£
µ±Óû§Í¨¹ý¼üÅ̻ظ´Ê±£¬ÏµÍ³½«Óû§ÊäÈëµÄÎÄ×Ö¸½ÔÚ¿ª·¢ÕßÖ¸¶¨µÄIntentÉÏ£¬È»ºó·¢Ë͸ø¶ÔÓ¦µÄÓ¦Óá£

´´½¨Ò»¸ö°üº¬Ö±½Ó»Ø¸´°´Å¥µÄ֪ͨ·ÖΪÏÂÃæ¼¸¸ö²½Ö裺
´´½¨Ò»¸öPendingIntent£¬Õâ¸öPendingIntent½«ÔÚÓû§ÊäÈëÍê³Éµã»÷·¢ËͰ´Å¥Ö®ºó´¥·¢¡£Òò´ËÎÒÃÇÐèҪΪÕâ¸öPendingIntentÉèÖÃÒ»¸ö½ÓÊÜÕߣ¬ÎÒÃÇ¿ÉÒÔʹÓÃÒ»¸öBroadcastReceiverÀ´½øÐнÓÊÕ
´´½¨Ò»¸öRemoteInput.Builder¶ÔÏóʵÀý£¬Õâ¸öÀàµÄ¹¹Ô캯Êý½ÓÊÕÒ»¸ö×Ö·û´®×÷ΪKeyÀ´ÈÃϵͳ·ÅÈëÓû§ÊäÈëµÄÎÄ×Ö¡£ÔÚ½ÓÊÕ·½Í¨¹ýÕâ¸ökeyÀ´»ñÈ¡ÊäÈë
ͨ¹ýNotification.Action.Builder.addRemoteInput()·½·¨½«µÚ1²½´´½¨µÄRemoteInput¶ÔÏóÌí¼Óµ½Notification.ActionÉÏ
´´½¨Ò»¸ö֪ͨ°üº¬Ç°Ãæ´´½¨µÄNotification.Action£¬È»ºó·¢ËÍ
Ïà¹Ø´úÂëʾÀýÈçÏ£º
intent = new Intent(context,
NotificationBroadcastReceiver.class);
intent.setAction(REPLY_ACTION);
intent.putExtra(KEY_NOTIFICATION_ID, notificationId);
intent.putExtra(KEY_MESSAGE_ID, messageId);
PendingIntent replyPendingIntent = PendingIntent.getBroadcast(
getApplicationContext(), 100, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
// Key for the string that's delivered in the
action's intent.
private static final String KEY_TEXT_REPLY =
"key_text_reply";
String replyLabel = getResources().getString(R.string.reply_label);
RemoteInput remoteInput = new RemoteInput.Builder(KEY_TEXT_REPLY)
.setLabel(replyLabel)
.build();
// Create the reply action and add the remote
input.
Notification.Action action =
new Notification.Action.Builder(R.drawable.ic_reply_icon,
getString(R.string.label), replyPendingIntent)
.addRemoteInput(remoteInput)
.build();
// Build the notification and add the action.
Notification newMessageNotification =
new Notification.Builder(mContext)
.setSmallIcon(R.drawable.ic_message)
.setContentTitle(getString(R.string.title))
.setContentText(getString(R.string.content))
.addAction(action)
.build();
// Issue the notification.
NotificationManager notificationManager =
(NotificationManager) this.getSystemService(NOTIFICATION_SERVICE);
notificationManager.notify(notificationId, newMessageNotification); |
µ±Óû§µã»÷»Ø¸´°´Å¥Ê±£¬ÏµÍ³»áÌáʾÓû§ÊäÈ룺

µ±Óû§ÊäÈëÍê³É²¢µã»÷·¢ËͰ´Å¥Ö®ºó£¬ÎÒÃÇÉèÖõÄreplyPendingIntent±»»á´¥·¢¡£Ç°ÃæÎÒÃÇÉèÖÃÁËÒ»¸öBroadcastReceiverÀ´´¦ÀíÕâ¸öIntent£¬ÓÚÊÇÔÚBroadcastReceiverÖпÉÒÔͨ¹ýÏÂÃæÕâÑùµÄ·½Ê½À´»ñÈ¡Óû§ÊäÈëµÄÎı¾£º
private CharSequence
getReplyMessage(Intent intent) {
Bundle remoteInput = RemoteInput.getResultsFromIntent(intent);
if (remoteInput != null) {
return remoteInput.getCharSequence(KEY_REPLY);
}
return null;
}
public void onReceive(Context context, Intent
intent) {
if (REPLY_ACTION.equals(intent.getAction()))
{
CharSequence message = getReplyMessage(intent);
int messageId = intent.getIntExtra(KEY_MESSAGE_ID,
0);
Toast.makeText(context, "Message ID:
" + messageId + "\nMessage: "
+ message,
Toast.LENGTH_SHORT).show();
}
} |
ÕâÀﻹÓÐÁ½µãÐèÒª¿ª·¢Õß×¢ÒâµÄ£º
Óû§µã»÷Íê·¢ËͰ´Å¥Ö®ºó£¬¸Ã°´Å¥»á±ä³ÉÒ»¸öÐýתµÄÑùʽ±íʾÕâ¸ö¶¯×÷»¹ÔÚ½øÐÐÖС£¿ª·¢ÕßÐèÒªÖØÐ·¢ËÍÒ»ÌõеÄ֪ͨÀ´¸üÐÂÕâ¸ö״̬
ͨ¹ýBroadcastReceiverÀ´´¦ÀíÕâ¸ö·¢ËÍʼþµÄͬʱ£¬Çë×¢Ò⽫BroadcastReceiverÔÚAndroidManifest.xmlÖеÄÅäÖÃÉèΪ£ºandroid:exported=¡±false¡±¡£·ñÔòÈκÎÓ¦Óö¼¿ÉÒÔ·¢ËÍÒ»ÌõIntentÀ´´¥·¢ÄãµÄBroadcastReceiver£¬Õâ¿ÉÄܶÔÄãÓ¦ÓÃÔì³ÉΣº¦¡£
Bundling Notifications
´ÓAndroid 7.0¿ªÊ¼£¬ÏµÍ³Ìṩһ¸öеķ½Ê½À´Õ¹Ê¾Á¬ÐøµÄ֪ͨ£ºBundling notifications¡£
ÕâÖÖչʾ·½Ê½ÌرðÊÊÓÃÓÚ¼´Ê±Í¨Ñ¶ÀàÓ¦Óã¬ÒòΪÕâÀàÓ¦Óûá³ÖÐø²»¶ÏµÄÊÕµ½ÐµÄÏûÏ¢²¢·¢ËÍ֪ͨ¡£ÕâÖÖչʾ·½Ê½ÊÇÒÔÒ»ÖÖ²ã´ÎÐԵĽṹÀ´×é֪֯ͨ¡£¶¥²¿ÊÇÏÔʾ×éÄÚ¸ÅÀÀÐÅÏ¢µÄÏûÏ¢£¬µ±Óû§½øÒ»²½Õ¹¿ª×éµÄʱºò£¬ÏµÍ³ÏÔʾ×éÄڵĸü¶àÐÅÏ¢¡£ÈçÏÂͼËùʾ£º

Notification.BuildÀàÖÐÌṩÁËÏàÓ¦µÄAPIÀ´½øÐÐÕâÖÖ֪ͨÑùʽµÄ¹ÜÀí£º
Notification.Builder.setGroup (String
groupKey) ͨ¹ýgroupKey½«Í¨Öª¹éΪһ¸ö×é
Notification.Builder.set GroupSummary(boolean
isGroupSummary) µ±isGroupSummary = trueʱ±íʾ½«¸ÃÌõ֪ͨÉèΪ×éÄÚµÄSummary֪ͨ
Notification.Builder.setSortKey (String
sortKey) ϵͳ½«¸ù¾ÝÕâÀïÉèÖõÄsortKey½øÐÐÅÅÐò
Notification ÏûÏ¢Ñùʽ
´ÓAndroid 7.0¿ªÊ¼£¬ÏµÍ³ÌṩÁËMessagingStyle APIÀ´×Ô¶¨Òå֪ͨµÄÑùʽ¡£¿ª·¢Õß¿ÉÒÔ×Ô¶¨Òå֪ͨµÄ¸÷ÖÖLabel£¬°üÀ¨£º¶Ô»°Title£¬¸½¼ÓÏûÏ¢ÒÔ¼°Í¨ÖªµÄContent
viewµÈ¡£ÏÂÃæÊÇÒ»¶Î´úÂëʾÀý£º
Notification notification
= new Notification.Builder()
.setSmallIcon(R.drawable.ic_menu_camera)
.setStyle(new Notification.MessagingStyle("Me")
.setConversationTitle("Team lunch")
.addMessage("Hi", timestamp1, null)
// Pass in null for user.
.addMessage("What's up?", timestamp2,
"Coworker")
.addMessage("Not much", timestamp3,
null)
.addMessage("How about lunch?", timestamp4,
"Coworker"))
.build(); |
ÕâÌõ֪ͨÏÔʾ³öÀ´ÊÇÏÂÃæÕâ¸öÑù×Ó£º

֪ͨÀ¸Óë֪ͨ´°¿Ú
Íⲿ½çÃæ
֪ͨÀ¸Î»ÓÚ״̬À¸ÖУ¬ÔÚ״̬À¸µÄ×ó²àͨ¹ýһϵÁÐÓ¦ÓõÄIconÀ´ÏÔʾ֪ͨ£º

Óû§¿ÉÒÔͨ¹ý´ÓÆÁÄ»ÉϲàÏ»¬µÄ·½·¨Õ¹¿ªÍ¨Öª´°¿Ú£¬Í¨Öª´°¿ÚµÄÉÏ·½ÊÇQuick SettingsÇøÓò£¬Ï·½ÊÇ֪ͨÁÐ±í¡£Óû§¿ÉÒÔÕ¹¿ªQuick
SettingsÇøÓò¡£

ÄÚ²¿ÊµÏÖ
ÔÚÁ˽âÁË֪ͨ½çÃæµÄÍâ¹ÛÖ®ºó£¬ÎÒÃǾÍÀ´¿´Ò»ÏÂϵͳÊÇÈçºÎʵÏÖÕâ¸ö½çÃæµÄ¡£
ÔÚSystemUIµÄʵÏÖÖУ¬Í¨¹ýXML²¼¾ÖÎļþÒÔ¼°Ò»ÏµÁÐ×Ô¶¨ÒåLayoutÀàÀ´¹ÜÀí֪ͨ½çÃæ¡£
Õû¸öStatus Barͨ¹ýsuper_status_bar.xmlÎļþÀ´½øÐв¼¾Ö£¬Õâ¸ö²¼¾ÖÎļþµÄ¸ùÔªËØÊÇÒ»¸ö×Ô¶¨ÒåµÄFrameLayout£¬ÀàÃûÊÇStatusBarWindowView¡£Õâ¸ö²¼¾ÖÎļþµÄ½á¹¹ÈçÏÂͼËùʾ£º

ÔÚÕâÀÎÒÃÇÖØµãÒª¹Ø×¢µÄ¾ÍÊÇÑ¡ÖеÄÁ½ÐУº
super_status_bar.xmlÖÐincludeÁËÒ»¸öÃû³ÆÎªstatus_barµÄ²¼¾ÖÎļþ
super_status_bar.xmlÖÐincludeÁËÒ»¸öÃû³ÆÎªstatus_bar_expandedµÄ²¼¾ÖÎļþ
ÕâÀïµÄstatus_bar±ãÊÇϵͳ״̬À¸µÄ²¼¾ÖÎļþ£¬status_bar_expanded±ãÊÇÏÂÀµÄ֪ͨ´°¿ÚµÄ²¼¾ÖÎļþ¡£
status_bar.xml²¼¾ÖÎļþ½á¹¹ÈçÏÂͼËùʾ¡£Õâ¸ö²¼¾ÖÎļþµÄ¸ùÔªËØÊÇÃû³ÆÎªPhoneStatusBarViewµÄ×Ô¶¨ÒåFrameLayoutÀà¡£
¶ÔÕÕÕâ¸ö²¼¾ÖÎļþºÍÊÖ»úÉϵÄ״̬À¸£¬ÎÒÏàÐŶÁÕßÓ¦¸ÃºÜÈÝÒ×Àí½âÁË£º
notification_icon_area ÕýÊÇϵͳÏÔʾ֪ͨiconµÄÇøÓò
system_icon_area ÊÇÏÔʾϵͳͼ±êµÄÇøÓò£¬ÀýÈ磺Wifi£¬µç»°ÐÅÏ¢ÒÔ¼°µç³ØµÈ
clock ÊÇ״̬À¸ÉÏÏÔʾʱ¼äµÄÇøÓò

ÏÂÃæÎÒÃÇÔÙÀ´¿´Ò»ÏÂstatus_bar_expanded.xmlÕâ¸ö²¼¾ÖÎļþµÄ½á¹¹£¬Õâ¸ö²¼¾ÖÎļþµÄ¸ùÔªËØÊÇÒ»¸öÃû³ÆÎªNotificationPanelViewµÄÀ࣬Õâ¸öÀàͬÑùÊÇÒ»¸ö×Ô¶¨ÒåµÄFrameLayout¡£

ÔÚÕâ¸ö²¼¾ÖÎļþÖУº
¶¥²¿ÊÇÒ»¸öÃû³ÆÎªkeyguard_status_viewµÄÔªËØ¡£Õâ¸ö±ãÊǸýçÃæÉϵÄ״̬À¸²¼¾Ö¡£Õâ¸ö״̬À¸ÏÔʾµÄÄÚÈݺÍͨ³£µÄ״̬À¸µÄÄÚÈÝÊÇÓÐËùÇø±ðµÄ£¬¶ÁÕß¿ÉÒԻص½ÉÏÃæÏàÓ¦µÄ½ØÍ¼¶Ô±Èһϲ»Í¬³¡¾°ÏÂ״̬À¸ÏÔʾµÄÄÚÈÝ
qs_auto_reinflate_container ÊÇÏÔʾQuick SettingsµÄÇøÓò¡£Õâ¸öÇøÓòÆäʵÊÇincludeÁËÒ»¸öÁíÍâ²¼¾ÖÎļþ£ºqs_panel.xml
notification_stack_scroller ±ãÊÇÕæÕýÏÔʾ֪ͨÁбíµÄµØ·½£¬ÕâÊÇÒ»¸öNotificationStackScrollLayoutÀàÐ͵ÄÔªËØ¡£´ÓÃû³ÆÉÏÎÒÃǾͿÉÒÔ¿´³ö£¬Õâ¸öÔªËØÊÇ¿ÉÒÔ¹ö¶¯µÄ£¬ÒòΪ֪ͨµÄÁбí¿ÉÄÜÊǺܳ¤µÄ¡£
ÉÏÃæÎÒÖ»´ó¸Å½²½âÁËÕâЩ½çÃæÖÐ×îÖ÷ÒªµÄÔªËØ£¬¶øÊµ¼ÊÉϲ¼¾ÖÖл¹Óзdz£¶àµÄÆäËûÔªËØ¡£ÕâÀïÎÒÃǾͲ»Ò»Ò»½²½âÁË¡£¶ÁÕß¿ÉÒÔ½èÖúAndroid
StudioÉϵÄLayout Inspector¹¤¾ßÑ¡Ôñcom.android.systemui½ø³Ì£¬È»ºóÑ¡ÔñStatusBarÀ´Ïêϸ·ÖÎö¸Ã½çÃæÉϵÄÿһ¸öÔªËØ£¬Layout
Inspector½çÃæ¿´ÆðÀ´ÏñÏÂÃæÕâÑù£º

Notification´Ó·¢Ë͵½ÏÔʾ
NotificationµÄ·¢ËÍ
ÓÐÁËÉÏÃæÍ¨Öª½çÃæ²¼¾ÖµÄ֪ʶ֮ºó£¬ÎÒÃÇÔÙ¿´Ò»Ï£¬Ó¦ÓóÌÐòÖз¢Ë͵Ä֪ͨÊÇÈçºÎ×îÖÕÏÔʾµ½ÏµÍ³µÄ֪ͨ½çÃæÉϵġ£
¿ª·¢Õßͨ¹ý´´½¨Notification¶ÔÏóÀ´·¢ËÍ֪ͨ¡£¸Ã¶ÔÏóÖмǼÁËÒ»Ìõ֪ͨµÄËùÓÐÏêϸÐÅÏ¢£¬NotificationÀàͼÈçÏÂËùʾ£º

ÕâÀïµÄºÜ¶à×Ö¶ÎÏàÐÅ¿ª·¢Õß¶¼ºÜÊìϤ£¬ÒòΪÕâЩ×ֶζ¼ÊÇÎÒÃÇ·¢ËÍ֪ͨʱҪÉèÖõġ£ÕâÀïÐèҪ˵Ã÷µÄÊÇBundle
extrasÕâ¸ö×ֶΡ£BundleÒÔ¼üÖµ¶ÔµÄÐÎʽ´æ´¢ÁË¿ÉÒÔͨ¹ýIPC´«µÝµÄһϵÁÐÊý¾Ý¡£µ±ÎÒÃÇͨ¹ýNotification.buidler¹¹½¨Notification¶ÔÏóʱ£¬ÓÐһЩ×Ô¶¨ÒåÑùʽµÄÖµ¶¼ÊÇ´æÔÚÕâ¸öextras×Ö¶ÎÖеģ¬ÀýÈçÏÂÃæÕâЩ£º
public Builder
setShowWhen(boolean show) {
mN.extras.putBoolean(EXTRA_SHOW_WHEN, show);
return this;
}
public Builder setSmallIcon(Icon icon) {
mN.setSmallIcon(icon);
if (icon != null && icon.getType() ==
Icon.TYPE_RESOURCE) {
mN.icon = icon.getResId();
}
return this;
}
public Builder setContentTitle(CharSequence
title) {
mN.extras.putCharSequence(EXTRA_TITLE, safeCharSequence(title));
return this;
}
public Builder setContentText(CharSequence text)
{
mN.extras.putCharSequence(EXTRA_TEXT, safeCharSequence(text));
return this;
}
public Builder setContentInfo(CharSequence info)
{
mN.extras.putCharSequence(EXTRA_INFO_TEXT, safeCharSequence(info));
return this;
}
public Builder setProgress(int max, int progress,
boolean indeterminate) {
mN.extras.putInt(EXTRA_PROGRESS, progress);
mN.extras.putInt(EXTRA_PROGRESS_MAX, max);
mN.extras.putBoolean(EXTRA_PROGRESS_INDETERMINATE,
indeterminate);
return this;
}
public Builder setStyle(Style style) {
if (mStyle != style) {
mStyle = style;
if (mStyle != null) {
mStyle.setBuilder(this);
mN.extras.putString(EXTRA_TEMPLATE, style.getClass().getName());
} else {
mN.extras.remove(EXTRA_TEMPLATE);
}
}
return this;
} |
NotificationÀàÊÇÒ»¸öParcelableÀ࣬ÕâÒâζ×ÅËü¿ÉÒÔͨ¹ýBinder±»¿ç½ø³Ì´«µÝ¡£
ÎÒÃÇͨ³£²»»áÊÖ¶¯´´½¨Notification£¬¶øÊÇͨ¹ýNotification.BuilderÀàÖеÄsetXXX·½·¨£¨ÉÏÃæÒѾÁгöÁËһЩ£©À´´´½¨Notification¡£ºÜÏÔÈ»£¬Õâ¸öNotification.BuilderÀàʹÓõÄÊǵäÐ͵ÄBuilderÉè¼ÆÄ£Ê½£¬Í¨¹ýÕâ¸öÀ࣬¼ò»¯ÁËÎÒÃÇ´´½¨NotificationµÄ¹ý³Ì£¬ÏÂͼÊÇNotification.BuilderÀàµÄÀàͼ£º

Õâ¸öÀàÌṩÁ˷dz£¶àµÄsetXXX·½·¨ÈÃÎÒÃÇÉèÖÃNotificationµÄÊôÐÔ£¬²¢ÇÒÕâЩ·½·¨»á·µ»ØBuilder¶ÔÏó±¾ÉíÒÔ±ãÎÒÃÇ¿ÉÒÔÁ¬Ðøµ÷Óá£×îÖÕ£¬ÎÒÃÇͨ¹ýÒ»¸öbuild·½·¨»ñÈ¡µ½¹¹ÔìºÃµÄNotification¶ÔÏó¡£
NotificationManagerService
ÔÚ¹¹ÔìºÃÁËNotification¶ÔÏóÖ®ºó£¬ÎÒÃÇͨ¹ýNotificationManagerµÄpublic
void notify (int id, Notification notification)£¨¼°ÆäÖØÔØ£©·½·¨ÕæÕý½«Í¨Öª·¢ËͳöÈ¥¡£
ÎÒÏàÐŶÁÕß×ÔÈ»ÄÜÏëµ½£¬Õâ¸öNotificationManagerÒ»¶¨Ò²ÊÇͨ¹ýBinderʵÏֵġ£
ȷʵû´í£¬ÕæÕýʵÏÖ֪ͨ·¢Ë͵ķþÎñ½Ð×öNotificationManagerService£¬Õâ¸öServiceͬÑùλÓÚsystem_server½ø³ÌÖС£
NotificationManager´ú±íÁË·þÎñµÄ¿Í»§¶Ë±»Ó¦ÓóÌÐòËùʹÓ㬶ø
NotificationManagerServiceλÓÚϵͳ½ø³ÌÖнÓÊպʹ¦ÀíÇëÇó¡£ AndroidϵͳÖдóÁ¿µÄϵͳ·þÎñ¶¼ÊÇÕâÑùµÄʵÏÖÌ×·¡£
notify½Ó¿Ú×îÖÕ»áµ÷Óõ½NotificationManagerÖеÄÁíÒ»¸ö½Ð×önotifyAsUserµÄ½Ó¿ÚÀ´·¢ËÍ֪ͨ£¬ÆäʵÏÖÈçÏ£º
public void
notifyAsUser (String tag, int id, Notification
notification, UserHandle user)
{
int[] idOut = new int[1];
INotificationManager service = getService(); ¢Ù
String pkg = mContext.getPackageName();
// Fix the notification as best we can.
Notification.addFieldsFromContext (mContext, notification);
¢Ú
if (notification.sound != null) {
notification.sound = notification.sound.getCanonicalUri();
if (StrictMode.vmFileUriExposureEnabled()) {
notification.sound.checkFileUriExposed ("Notification.sound");
}
}
fixLegacySmallIcon(notification, pkg);
if (mContext.getApplicationInfo() .targetSdkVersion
> Build.VERSION_CODES.LOLLIPOP_MR1) {
if (notification.getSmallIcon() == null) {
throw new IllegalArgumentException ("Invalid
notification (no valid small icon): "
+ notification); ¢Û
}
}
if (localLOGV) Log.v(TAG, pkg + ": notify("
+ id + ", " + notification + ")");
final Notification copy = Builder.maybeCloneStrippedForDelivery (notification);
try {
service.enqueueNotificationWithTag (pkg, mContext.getOpPackageName(),
tag, id,
copy, idOut, user.getIdentifier()); ¢Ü
if (localLOGV && id != idOut[0]) {
Log.v(TAG, "notify: id corrupted: sent "
+ id + ", got back " + idOut[0]);
}
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
} |
Õâ¶Î´úÂë˵Ã÷ÈçÏ£º
ͨ¹ýgetService·½·¨»ñÈ¡NotificationManagerServiceµÄÔ¶³Ì·þÎñ½Ó¿Ú£¬getService·½·¨µÄʵÏÖÆäʵ¾ÍÊÇͨ¹ýServiceManagerÄõ½NotificationManagerServiceµÄBinder¶ÔÏó
ͨ¹ýmContextΪNotificationÌí¼ÓһЩ¸½¼ÓÊôÐÔ£¬ÕâÀïµÄmContext´ú±íÁ˵÷Ó÷¢ËÍ֪ͨ½Ó¿ÚµÄContext£¬ÏµÍ³·þÎñÖлáͨ¹ýÕâ¸öContextÀ´È·¶¨ÊÇËÔÚʹÓ÷þÎñ
ÔÚLOLLIPOP_MR1Ö®Éϵİ汾£¨API Level 22£©ÉÏ£¬·¢ËÍ֪ͨ±ØÐëÉèÖÃSmall Icon£¬·ñÔòÖ±½ÓÅ׳öÒì³£
µ÷ÓÃNotificationManagerServiceµÄÔ¶³Ì½Ó¿ÚÀ´ÕæÕý½øÐÐ֪ͨµÄ·¢ËÍ
½ÓÏÂÀ´ÎÒÃÇÒª¹Ø×¢µÄ×ÔÈ»ÊÇNotificationManagerService. enqueueNotificationWithTag·½·¨µÄʵÏÖ¡£
NotificationManagerServiceÏà¹Ø´úÂëλÓÚÒÔÏ·¾¶£º/frameworks/ base/services/core/java/com/android/server/notification/
ÔÚNotificationManagerService. enqueueNotificationWithTag·½·¨ÖУ¬»á½«Óû§·¢Ë͹ýÀ´µÄNotification¶ÔÏó°ü×°ÔÚÒ»¸öStatusBarNotification¶ÔÏóÖУº
final StatusBarNotification
n = new StatusBarNotification(
pkg, opPkg, id, tag, callingUid, callingPid, 0,
notification,
user); |
È»ºóÓÖ½«StatusBarNotification°ü×°ÔÚNotificationRecord¶ÔÏóÖУº
final NotificationRecord
r = new NotificationRecord(getContext(), n); |
StatusBarNotification¹¹Ô캯ÊýÖÐµÄÆäËû²ÎÊý£¬ÃèÊöÁË·¢ËÍ֪ͨµÄµ÷ÓÃÕßµÄÉí·Ý£¬°üÀ¨£º°üÃû£¬µ÷ÓÃÕßµÄuid£¬pidµÈµÈ¡£Õâ¸öÉí·ÝµÄ×÷ÓÃÊÇ£ºÏµÍ³¿ÉÒÔÕë¶Ôµ÷ÓÃÕßÉí·ÝµÄ²»Í¬×ö²»Í¬µÄ´¦Àí¡£ÀýÈ磺Óû§¿ÉÄܹرÕÁËijЩӦÓõÄ֪ͨÏÔʾ£¬ÏµÍ³Í¨¹ýµ÷ÓÃÕßµÄÉí·Ý±ã¿ÉÒÔÈ·¶¨Õâ¸öÓ¦ÓõÄ֪ͨÊÇ·ñÐèÒªÏÔʾÔÚ֪ͨ½çÃæÉÏ¡£
¶ø¿´µ½NotificationRecord£¬¶ÁÕßÓ¦¸ÃºÜ×ÔÈ»ÄÜÏëµ½ActivityManagerServiceÖеÄActivityRecord£¬ProcessRecordµÈ½á¹¹¡£ÕâЩ¶¼ÊÇϵͳ·þÎñÖÐÓÃÀ´ÃèÊöÓ¦ÓóÌÐòÖжÔÏóµÄ¶ÔÓ¦½á¹¹¡£
ÏÂͼÃèÊöÁËÉÏÃæÈýÖֽṹµÄ°üº¬¹ØÏµ£º

ϵͳÔÚ´´½¨NotificationRecord¶ÔÏóÖ®ºó£¬»áPostÒ»¸öRunnableµÄTask½øÐÐ֪ͨµÄ·¢ËÍ£º
final NotificationRecord
r = new NotificationRecord(getContext(), n);
mHandler.post(new EnqueueNotificationRunnable(userId,
r)); |
ÔÚEnqueueNotificationRunnableÖУ¬ÐèÒª×öÏÂÃæ¼¸¼þÊÂÇ飺
´¦Àí֪ͨµÄ·Ö×é
¼ì²é¸Ã֪ͨÊÇ·ñÒѾ±»×èÖ¹£¨Í¨¹ýµ÷ÓÃÕßµÄÉí·Ý£º°üÃû¼°uid£©
¶Ô֪ͨ½øÐÐÅÅÐò
Åж϶ÔÒÑÓÐ֪ͨ¸üУ¬»¹ÊÇ·¢ËÍÒ»ÌõеÄ֪ͨ
µ÷ÓÃNotificationListeners.notifyPostedLocked
Èç¹ûÐèÒª£º´¦ÀíÉùÒôºÍÕð¶¯
ÕâÀïÖ»ÓÐNotificationListeners.notifyPostedLockedÐèҪ˵Ã÷һϡ£
Ò»Ìõ֪ͨ·¢Ë͵½ÏµÍ³Ö®ºó£¬ÏµÍ³ÖпÉÄÜ»áÓкܶàÄ£¿é»á¶ÔÆä¸ÐÐËȤ£¨×î»ù±¾µÄ£¬»áÓÐÄ£¿éÒª½«Õâ¸ö֪ͨÏÔʾÔÚ֪ͨ½çÃæÉÏ£©¡£·¢ËÍ֪ͨÊÇÒ»¸öʼþ£¬´¦Àí֪ͨÊÇÒ»¸öÏìÓ¦£¬µ±Ê¼þµÄÏìÓ¦Õß¿ÉÄܲ»Ö¹Ò»¸öµÄʱºò£¬ÎªÁË´ïµ½½âñîÕâÁ½ÕßÖ®¼äµÄ¹ØÏµ£¬ºÜ×ÔÈ»µÄ»áʹÓÃÎÒÃdz£¼ûµÄ¼àÌýÆ÷Ä£ÐÍ£¨»òÕß½Ð×ö£ºObserverÉè¼ÆÄ£Ê½£©¡£
ϵͳÖУ¬¶ÔÓÚ֪ͨ¸ÐÐËȤµÄ¼àÌýÆ÷ͨ¹ýNotificationListenerServiceÀàÀ´±í´ï¡£¶øÕâÀïµÄNotificationListeners.notifyPostedLocked±ãÊǶÔËùÓеÄNotificationListenerService½øÐлص÷֪ͨ¡£
ÕâÆäÖÐÓÐÒ»¸ö×îÖØÒªµÄNotificationListenerService¾ÍÊÇBaseStatusBar¡£ÒòΪËü¾ÍÊǸºÔð½«Í¨ÖªÏÔʾÔÚ֪ͨ½çÃæÉϵļàÌýÆ÷¡£
NotificationµÄÏÔʾ
BaseStatusBarÖжÔÓÚ֪ͨ·¢Ë͵Ļص÷Âß¼ÈçÏ£º
public void
onNotificationPosted(final StatusBarNotification
sbn,
final RankingMap rankingMap) {
if (DEBUG) Log.d(TAG, "onNotificationPosted:
" + sbn);
if (sbn != null) {
mHandler.post(new Runnable() {
@Override
public void run() {
processForRemoteInput(sbn.getNotification());
String key = sbn.getKey(); ¢Ù
mKeysKeptForRemoteInput.remove(key);
boolean isUpdate = mNotificationData.get(key)
!= null; ¢Ú
if (!ENABLE_CHILD_NOTIFICATIONS &&
mGroupManager.isChildInGroupWithSummary(sbn))
{
if (DEBUG) {
Log.d(TAG, "Ignoring group child due to existing
summary: " + sbn);
}
// Remove existing notification to avoid stale
data.
if (isUpdate) {
removeNotification(key, rankingMap); ¢Û
} else {
mNotificationData.updateRanking(rankingMap);
}
return;
}
if (isUpdate) {
updateNotification(sbn, rankingMap);
} else {
addNotification(sbn, rankingMap, null /* oldEntry
*/); ¢Ü
}
}
});
}
} |
Õâ¶Î´úÂëµÄ˵Ã÷ÈçÏ£º
ÿ¸öStatusBarNotification¶ÔÏó¶¼ÓÐÒ»¸öKeyÖµ£¬Õâ¸öÖµ¸ù¾Ýµ÷ÓÃÕßµÄÉí·ÝÒÔ¼°µ÷ÓÃÕßÉèÖõÄ֪ͨidÉú³É¡£µ±Ó¦ÓóÌÐòͨ¹ýͬһ¸ö֪ͨid·¢ËÍÁ˶à´Î֪ͨ£¬ÕâЩ֪ͨµÄKeyÖµÊÇÒ»ÑùµÄ£¬ÓÉ´Ë¿ÉÒÔ¶Ô֪ͨ½øÐиüÐÂ
mNotificationData£¨ÀàÐÍΪNotificationData£©ÖмǼÁËϵͳËùÓеÄ֪ͨÁбí
Èç¹ûÊÇÒ»¸öÒѾ´æÔÚµÄ֪ͨÐèÒª¸üУ¬ÔòÏȽ«´æÔÚµÄ֪ͨɾ³ý
addNotificationÊÇÒ»¸ö³éÏó·½·¨£¬ÓÉ×ÓÀàʵÏÖ
ÔÚÊÖ»úÉ豸ÉÏ£¬addNotificationÕâ¸ö·½·¨×ÔÈ»ÊÇÓÉPhoneStatusBarÀ´ÊµÏÖ¡£ÔÚaddNotification·½·¨ÖУ¬»áµ÷ÓÃupdateNotifications·½·¨À´×îÖÕ½«Í¨ÖªÏÔʾÔÚ֪ͨ½çÃæÉÏ£¬Æä´úÂëÈçÏÂËùʾ£º
protected void
updateNotifications() {
mNotificationData.filterAndSort();
updateNotificationShade();
mIconController.updateNotificationIcons(mNotificationData);
} |
ÕâÀïµÄupdateNotificationShade·½·¨±ãÊǽ«Í¨ÖªµÄÏÔʾÄÚÈÝÌí¼Óµ½Í¨ÖªÃæ°åµÄÏÔÊ¾ÇøÓò£ºNotificationStackScrollLayoutÖС£¶ømIconController.updateNotificationIcons
(mNotificationData)ÔòÊÇÔÚnotification_icon_areaÇøÓòÌí¼Ó֪ͨIcon¡£
updateNotificationShade´úÂë±È½Ï³¤£¬µ«ÊÇÂß¼ÊDZȽϺÃÀí½âµÄ¡£Ö÷ÌåÂß¼¾ÍÊǶÔÿһ¸öÐèÒªÏÔʾµÄ֪ͨ´´½¨Ò»¸öExpandableNotificationRow£¬È»ºóÉèÖöÔÓ¦µÄÄÚÈݲ¢Ìí¼Óµ½NotificationStackScrollLayout(mStackScroller¶ÔÏó)ÖС£
ä¯ÀÀÒ»ÏÂÕâ¶Î´úÂë±ã¿ÉÒÔ¿´µ½ÎÒÃÇÔÚAPI²¿·Ö½²½âµÄһЩAPIÔÚϵͳ·þÎñÖеÄʵÏÖ£ºÕâÀïÁË´¦Àí֪ͨµÄ·Ö×飬visibilityµÈÏà¹ØÐÅÏ¢¡£
private void updateNotificationShade()
{
if (mStackScroller == null) return;
// Do not modify the notifications during
collapse.
if (isCollapsing()) {
addPostCollapseAction(new Runnable() {
@Override
public void run() {
updateNotificationShade();
}
});
return;
}
ArrayList<Entry> activeNotifications
= mNotificationData.getActiveNotifications();
ArrayList<ExpandableNotificationRow> toShow
= new ArrayList<>(activeNotifications.size());
final int N = activeNotifications.size();
for (int i=0; i<N; i++) {
Entry ent = activeNotifications.get(i);
int vis = ent.notification.getNotification().visibility;
// Display public version of the notification
if we need to redact.
final boolean hideSensitive =
!userAllowsPrivateNotificationsInPublic (ent.notification.getUserId());
boolean sensitiveNote = vis == Notification.VISIBILITY_PRIVATE;
boolean sensitivePackage = packageHasVisibilityOverride (ent.notification.getKey());
boolean sensitive = (sensitiveNote &&
hideSensitive) || sensitivePackage;
boolean showingPublic = sensitive &&
isLockscreenPublicMode();
if (showingPublic) {
updatePublicContentView(ent, ent.notification);
}
ent.row.setSensitive (sensitive, hideSensitive);
if (ent.autoRedacted && ent.legacy)
{
// TODO: Also fade this? Or, maybe easier (and
better), provide a dark redacted form
// for legacy auto redacted notifications.
if (showingPublic) {
ent.row.setShowingLegacyBackground(false);
} else {
ent.row.setShowingLegacyBackground(true);
}
}
if (mGroupManager.isChildInGroupWithSummary (ent.row.getStatusBarNotification()))
{
ExpandableNotificationRow summary = mGroupManager.getGroupSummary(
ent.row.getStatusBarNotification());
List<ExpandableNotificationRow> orderedChildren
=
mTmpChildOrderMap.get(summary);
if (orderedChildren == null) {
orderedChildren = new ArrayList<>();
mTmpChildOrderMap.put (summary, orderedChildren);
}
orderedChildren.add(ent.row);
} else {
toShow.add(ent.row);
}
}
ArrayList< ExpandableNotificationRow>
toRemove = new ArrayList<>();
for (int i=0; i< mStackScroller.getChildCount();
i++) {
View child = mStackScroller.getChildAt(i);
if (!toShow.contains(child) && child
instanceof ExpandableNotificationRow) {
toRemove.add ((ExpandableNotificationRow) child);
}
}
for (ExpandableNotificationRow remove : toRemove)
{
if (mGroupManager.isChildInGroupWithSummary (remove.getStatusBarNotification()))
{
// we are only transfering this notification
to its parent, don't generate an animation
mStackScroller.setChildTransferInProgress(true);
}
if (remove.isSummaryWithChildren()) {
remove.removeAllChildren();
}
mStackScroller.removeView(remove);
mStackScroller .setChildTransferInProgress(false);
}
removeNotificationChildren();
for (int i=0; i<toShow.size(); i++) {
View v = toShow.get(i);
if (v.getParent() == null) {
mStackScroller.addView(v);
}
}
addNotificationChildrenAndSort();
// So after all this work notifications still
aren't sorted correctly.
// Let's do that now by advancing through toShow
and mStackScroller in
// lock-step, making sure mStackScroller matches
what we see in toShow.
int j = 0;
for (int i = 0; i < mStackScroller.getChildCount();
i++) {
View child = mStackScroller.getChildAt(i);
if (!(child instanceof ExpandableNotificationRow))
{
// We don't care about non-notification views.
continue;
}
ExpandableNotificationRow targetChild = toShow.get(j);
if (child != targetChild) {
// Oops, wrong notification at this position.
Put the right one
// here and advance both lists.
mStackScroller.changeViewPosition(targetChild,
i);
}
j++;
}
// clear the map again for the next usage
mTmpChildOrderMap.clear();
updateRowStates();
updateSpeedbump();
updateClearAll();
updateEmptyShadeView();
updateQsExpansionEnabled();
mShadeUpdates.check();
} |
ÖÁ´Ë£¬Ò»Ìõз¢Ë͵Ä֪ͨ¾ÍÕæÕýÏÔʾ³öÀ´ÁË¡£
ÏÂÃæÕâ·ùͼÃèÊöÁËÒ»ÌõNotification´Ó·¢Ë͵½ÏÔʾ³öÀ´µÄÁ÷³Ì£º
 |