Android中Notification的framework层讲解【安卓源码解析四】

来源:互联网 发布:网络数字矩阵 编辑:程序博客网 时间:2024/05/21 23:30

           android的notificaiton的声音sound也是申请的AudioManager机制来播放声音的。最近让我找恢复出厂设置后,手机刚启动,接受短信没有声音,如果恢复出厂设置后,等一会儿,过个2分钟再接受短信,就有铃声了。下面我把我分析代码的方法写下来,给自己和读者一些启发:

      日历也是用的是Notification,但是恢复出厂设置后,立马设置日历后,日历可以出声音,我看日历的代码,结果发现日历只是用了Notification的闪屏,真正声音是日历自己实现了Mediaplayer来出声音的。所以我又不得不老老实实地研究Notification.sound到底把声音传递到什么地方去了?

       转载请标明出处:http://blog.csdn.net/wdaming1986/article/details/7081787

       首先我在短信的com.android.mms.transaction包中的MessagingNotification的573行的java代码:notification.sound = TextUtils.isEmpty(ringtoneStr) ? null : Uri.parse(ringtoneStr);打log查看,发现这个uri确实是存在的,我推测:就是说这个uri传给了framework一层,但是framework一层有没有执行完的动作,所以不响。为了验证是不是短信的错误,我自己单独写了个notification的例子,一个按钮,点击就发出声音。这个例子在正常情况下能正常发声。我就恢复出厂设置后,运行这个例子,结果发现没有声音,这就充分验证了我的猜测。我就去framework去着notificaion.sound = 的声音传递给framework做什么事情了??

       接着,在Source Insight软件中导入framework整个工程,然后搜索,notificaiton.sounds,结果搜到了,在framework/base/core/java/android/app/Notification.java类。

 

[java] view plaincopyprint?
  1. /* 
  2.  * Copyright (C) 2007 The Android Open Source Project 
  3.  * 
  4.  * Licensed under the Apache License, Version 2.0 (the "License"); 
  5.  * you may not use this file except in compliance with the License. 
  6.  * You may obtain a copy of the License at 
  7.  * 
  8.  *      http://www.apache.org/licenses/LICENSE-2.0 
  9.  * 
  10.  * Unless required by applicable law or agreed to in writing, software 
  11.  * distributed under the License is distributed on an "AS IS" BASIS, 
  12.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
  13.  * See the License for the specific language governing permissions and 
  14.  * limitations under the License. 
  15.  */  
  16.   
  17. package android.app;  
  18.   
  19. import java.util.Date;  
  20.   
  21. import android.app.PendingIntent;  
  22. import android.content.Context;  
  23. import android.content.Intent;  
  24. import android.media.AudioManager;  
  25. import android.net.Uri;  
  26. import android.os.Parcel;  
  27. import android.os.Parcelable;  
  28. import android.text.TextUtils;  
  29. import android.text.format.DateFormat;  
  30. import android.text.format.DateUtils;  
  31. import android.widget.RemoteViews;  
  32.   
  33. /** 
  34.  * A class that represents how a persistent notification is to be presented to 
  35.  * the user using the {@link android.app.NotificationManager}. 
  36.  * 
  37.  * <p>For a guide to creating notifications, see the 
  38.  * <a href="{@docRoot}guide/topics/ui/notifiers/notifications.html">Creating Status  
  39.  * Bar Notifications</a> document in the Dev Guide.</p> 
  40.  */  
  41. public class Notification implements Parcelable  
  42. {  
  43.     /** 
  44.      * Use all default values (where applicable). 
  45.      */  
  46.     public static final int DEFAULT_ALL = ~0;  
  47.       
  48.     /** 
  49.      * Use the default notification sound. This will ignore any given 
  50.      * {@link #sound}. 
  51.      *  
  52.      * @see #defaults 
  53.      */   
  54.     public static final int DEFAULT_SOUND = 1;  
  55.   
  56.     /** 
  57.      * Use the default notification vibrate. This will ignore any given 
  58.      * {@link #vibrate}. Using phone vibration requires the  
  59.      * {@link android.Manifest.permission#VIBRATE VIBRATE} permission. 
  60.      *  
  61.      * @see #defaults 
  62.      */   
  63.     public static final int DEFAULT_VIBRATE = 2;  
  64.       
  65.     /** 
  66.      * Use the default notification lights. This will ignore the 
  67.      * {@link #FLAG_SHOW_LIGHTS} bit, and {@link #ledARGB}, {@link #ledOffMS}, or 
  68.      * {@link #ledOnMS}. 
  69.      *  
  70.      * @see #defaults 
  71.      */   
  72.     public static final int DEFAULT_LIGHTS = 4;  
  73.       
  74.     /** 
  75.      * The timestamp for the notification.  The icons and expanded views 
  76.      * are sorted by this key. 
  77.      */  
  78.     public long when;  
  79.   
  80.     /** 
  81.      * The resource id of a drawable to use as the icon in the status bar. 
  82.      */  
  83.     public int icon;  
  84.   
  85.     /** 
  86.      * The number of events that this notification represents.  For example, in a new mail 
  87.      * notification, this could be the number of unread messages.  This number is superimposed over 
  88.      * the icon in the status bar.  If the number is 0 or negative, it is not shown in the status 
  89.      * bar. 
  90.      */  
  91.     public int number;  
  92.   
  93.     /** 
  94.      * The intent to execute when the expanded status entry is clicked.  If 
  95.      * this is an activity, it must include the 
  96.      * {@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK} flag, which requires 
  97.      * that you take care of task management as described in the <em>Activities and Tasks</em> 
  98.      * section of the <a href="{@docRoot}guide/topics/fundamentals.html#acttask">Application  
  99.      * Fundamentals</a> document. 
  100.      */  
  101.     public PendingIntent contentIntent;  
  102.   
  103.     /** 
  104.      * The intent to execute when the status entry is deleted by the user 
  105.      * with the "Clear All Notifications" button. This probably shouldn't 
  106.      * be launching an activity since several of those will be sent at the 
  107.      * same time. 
  108.      */  
  109.     public PendingIntent deleteIntent;  
  110.   
  111.     /** 
  112.      * An intent to launch instead of posting the notification to the status bar. 
  113.      * Only for use with extremely high-priority notifications demanding the user's 
  114.      * <strong>immediate</strong> attention, such as an incoming phone call or 
  115.      * alarm clock that the user has explicitly set to a particular time. 
  116.      * If this facility is used for something else, please give the user an option 
  117.      * to turn it off and use a normal notification, as this can be extremely 
  118.      * disruptive. 
  119.      */  
  120.     public PendingIntent fullScreenIntent;  
  121.   
  122.     /** 
  123.      * Text to scroll across the screen when this item is added to 
  124.      * the status bar. 
  125.      */  
  126.     public CharSequence tickerText;  
  127.   
  128.     /** 
  129.      * The view that will represent this notification in the expanded status bar. 
  130.      */  
  131.     public RemoteViews contentView;  
  132.   
  133.     /** 
  134.      * If the icon in the status bar is to have more than one level, you can set this.  Otherwise, 
  135.      * leave it at its default value of 0. 
  136.      * 
  137.      * @see android.widget.ImageView#setImageLevel 
  138.      * @see android.graphics.drawable#setLevel 
  139.      */  
  140.     public int iconLevel;  
  141.   
  142.     /** 
  143.      * The sound to play. 
  144.      *  
  145.      * <p> 
  146.      * To play the default notification sound, see {@link #defaults}.  
  147.      * </p> 
  148.      */  
  149.     public Uri sound;  
  150.   
  151.     /** 
  152.      * Use this constant as the value for audioStreamType to request that 
  153.      * the default stream type for notifications be used.  Currently the 
  154.      * default stream type is STREAM_RING. 
  155.      */  
  156.     public static final int STREAM_DEFAULT = -1;  
  157.   
  158.     /** 
  159.      * The audio stream type to use when playing the sound. 
  160.      * Should be one of the STREAM_ constants from 
  161.      * {@link android.media.AudioManager}. 
  162.      */  
  163.     public int audioStreamType = STREAM_DEFAULT;  
  164.   
  165.       
  166.     /** 
  167.      * The pattern with which to vibrate.  
  168.      *  
  169.      * <p> 
  170.      * To vibrate the default pattern, see {@link #defaults}. 
  171.      * </p> 
  172.      *  
  173.      * @see android.os.Vibrator#vibrate(long[],int) 
  174.      */  
  175.     public long[] vibrate;  
  176.   
  177.     /** 
  178.      * The color of the led.  The hardware will do its best approximation. 
  179.      * 
  180.      * @see #FLAG_SHOW_LIGHTS 
  181.      * @see #flags 
  182.      */  
  183.     public int ledARGB;  
  184.   
  185.     /** 
  186.      * The number of milliseconds for the LED to be on while it's flashing. 
  187.      * The hardware will do its best approximation. 
  188.      * 
  189.      * @see #FLAG_SHOW_LIGHTS 
  190.      * @see #flags 
  191.      */  
  192.     public int ledOnMS;  
  193.   
  194.     /** 
  195.      * The number of milliseconds for the LED to be off while it's flashing. 
  196.      * The hardware will do its best approximation. 
  197.      * 
  198.      * @see #FLAG_SHOW_LIGHTS 
  199.      * @see #flags 
  200.      */  
  201.     public int ledOffMS;  
  202.   
  203.     /** 
  204.      * Specifies which values should be taken from the defaults. 
  205.      * <p> 
  206.      * To set, OR the desired from {@link #DEFAULT_SOUND}, 
  207.      * {@link #DEFAULT_VIBRATE}, {@link #DEFAULT_LIGHTS}. For all default 
  208.      * values, use {@link #DEFAULT_ALL}. 
  209.      * </p> 
  210.      */  
  211.     public int defaults;  
  212.   
  213.   
  214.     /** 
  215.      * Bit to be bitwise-ored into the {@link #flags} field that should be 
  216.      * set if you want the LED on for this notification. 
  217.      * <ul> 
  218.      * <li>To turn the LED off, pass 0 in the alpha channel for colorARGB 
  219.      *      or 0 for both ledOnMS and ledOffMS.</li> 
  220.      * <li>To turn the LED on, pass 1 for ledOnMS and 0 for ledOffMS.</li> 
  221.      * <li>To flash the LED, pass the number of milliseconds that it should 
  222.      *      be on and off to ledOnMS and ledOffMS.</li> 
  223.      * </ul> 
  224.      * <p> 
  225.      * Since hardware varies, you are not guaranteed that any of the values 
  226.      * you pass are honored exactly.  Use the system defaults (TODO) if possible 
  227.      * because they will be set to values that work on any given hardware. 
  228.      * <p> 
  229.      * The alpha channel must be set for forward compatibility. 
  230.      *  
  231.      */  
  232.     public static final int FLAG_SHOW_LIGHTS        = 0x00000001;  
  233.   
  234.     /** 
  235.      * Bit to be bitwise-ored into the {@link #flags} field that should be 
  236.      * set if this notification is in reference to something that is ongoing, 
  237.      * like a phone call.  It should not be set if this notification is in 
  238.      * reference to something that happened at a particular point in time, 
  239.      * like a missed phone call. 
  240.      */  
  241.     public static final int FLAG_ONGOING_EVENT      = 0x00000002;  
  242.   
  243.     /** 
  244.      * Bit to be bitwise-ored into the {@link #flags} field that if set, 
  245.      * the audio will be repeated until the notification is 
  246.      * cancelled or the notification window is opened. 
  247.      */  
  248.     public static final int FLAG_INSISTENT          = 0x00000004;  
  249.   
  250.     /** 
  251.      * Bit to be bitwise-ored into the {@link #flags} field that should be 
  252.      * set if you want the sound and/or vibration play each time the 
  253.      * notification is sent, even if it has not been canceled before that. 
  254.      */  
  255.     public static final int FLAG_ONLY_ALERT_ONCE    = 0x00000008;  
  256.   
  257.     /** 
  258.      * Bit to be bitwise-ored into the {@link #flags} field that should be 
  259.      * set if the notification should be canceled when it is clicked by the 
  260.      * user.  
  261.      */  
  262.     public static final int FLAG_AUTO_CANCEL        = 0x00000010;  
  263.   
  264.     /** 
  265.      * Bit to be bitwise-ored into the {@link #flags} field that should be 
  266.      * set if the notification should not be canceled when the user clicks 
  267.      * the Clear all button. 
  268.      */  
  269.     public static final int FLAG_NO_CLEAR           = 0x00000020;  
  270.   
  271.     /** 
  272.      * Bit to be bitwise-ored into the {@link #flags} field that should be 
  273.      * set if this notification represents a currently running service.  This 
  274.      * will normally be set for you by {@link Service#startForeground}. 
  275.      */  
  276.     public static final int FLAG_FOREGROUND_SERVICE = 0x00000040;  
  277.   
  278.     public int flags;  
  279.   
  280.     /** 
  281.      * Constructs a Notification object with everything set to 0. 
  282.      */  
  283.     public Notification()  
  284.     {  
  285.         this.when = System.currentTimeMillis();  
  286.     }  
  287.   
  288.     /** 
  289.      * @deprecated use {@link #Notification(int,CharSequence,long)} and {@link #setLatestEventInfo}. 
  290.      * @hide 
  291.      */  
  292.     public Notification(Context context, int icon, CharSequence tickerText, long when,  
  293.             CharSequence contentTitle, CharSequence contentText, Intent contentIntent)  
  294.     {  
  295.         this.when = when;  
  296.         this.icon = icon;  
  297.         this.tickerText = tickerText;  
  298.         setLatestEventInfo(context, contentTitle, contentText,  
  299.                 PendingIntent.getActivity(context, 0, contentIntent, 0));  
  300.     }  
  301.   
  302.     /** 
  303.      * Constructs a Notification object with the information needed to 
  304.      * have a status bar icon without the standard expanded view. 
  305.      * 
  306.      * @param icon          The resource id of the icon to put in the status bar. 
  307.      * @param tickerText    The text that flows by in the status bar when the notification first 
  308.      *                      activates. 
  309.      * @param when          The time to show in the time field.  In the System.currentTimeMillis 
  310.      *                      timebase. 
  311.      */  
  312.     public Notification(int icon, CharSequence tickerText, long when)  
  313.     {  
  314.         this.icon = icon;  
  315.         this.tickerText = tickerText;  
  316.         this.when = when;  
  317.     }  
  318.   
  319.     /** 
  320.      * Unflatten the notification from a parcel. 
  321.      */  
  322.     public Notification(Parcel parcel)  
  323.     {  
  324.         int version = parcel.readInt();  
  325.   
  326.         when = parcel.readLong();  
  327.         icon = parcel.readInt();  
  328.         number = parcel.readInt();  
  329.         if (parcel.readInt() != 0) {  
  330.             contentIntent = PendingIntent.CREATOR.createFromParcel(parcel);  
  331.         }  
  332.         if (parcel.readInt() != 0) {  
  333.             deleteIntent = PendingIntent.CREATOR.createFromParcel(parcel);  
  334.         }  
  335.         if (parcel.readInt() != 0) {  
  336.             tickerText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel);  
  337.         }  
  338.         if (parcel.readInt() != 0) {  
  339.             contentView = RemoteViews.CREATOR.createFromParcel(parcel);  
  340.         }  
  341.         defaults = parcel.readInt();  
  342.         flags = parcel.readInt();  
  343.         if (parcel.readInt() != 0) {  
  344.             sound = Uri.CREATOR.createFromParcel(parcel);  
  345.         }  
  346.   
  347.         audioStreamType = parcel.readInt();  
  348.         vibrate = parcel.createLongArray();  
  349.         ledARGB = parcel.readInt();  
  350.         ledOnMS = parcel.readInt();  
  351.         ledOffMS = parcel.readInt();  
  352.         iconLevel = parcel.readInt();  
  353.   
  354.         if (parcel.readInt() != 0) {  
  355.             fullScreenIntent = PendingIntent.CREATOR.createFromParcel(parcel);  
  356.         }  
  357.     }  
  358.   
  359.     public Notification clone() {  
  360.         Notification that = new Notification();  
  361.   
  362.         that.when = this.when;  
  363.         that.icon = this.icon;  
  364.         that.number = this.number;  
  365.   
  366.         // PendingIntents are global, so there's no reason (or way) to clone them.  
  367.         that.contentIntent = this.contentIntent;  
  368.         that.deleteIntent = this.deleteIntent;  
  369.         that.fullScreenIntent = this.fullScreenIntent;  
  370.   
  371.         if (this.tickerText != null) {  
  372.             that.tickerText = this.tickerText.toString();  
  373.         }  
  374.         if (this.contentView != null) {  
  375.             that.contentView = this.contentView.clone();  
  376.         }  
  377.         that.iconLevel = that.iconLevel;  
  378.         that.sound = this.sound; // android.net.Uri is immutable  
  379.         that.audioStreamType = this.audioStreamType;  
  380.   
  381.         final long[] vibrate = this.vibrate;  
  382.         if (vibrate != null) {  
  383.             final int N = vibrate.length;  
  384.             final long[] vib = that.vibrate = new long[N];  
  385.             System.arraycopy(vibrate, 0, vib, 0, N);  
  386.         }  
  387.   
  388.         that.ledARGB = this.ledARGB;  
  389.         that.ledOnMS = this.ledOnMS;  
  390.         that.ledOffMS = this.ledOffMS;  
  391.         that.defaults = this.defaults;  
  392.           
  393.         that.flags = this.flags;  
  394.   
  395.         return that;  
  396.     }  
  397.   
  398.     public int describeContents() {  
  399.         return 0;  
  400.     }  
  401.   
  402.     /** 
  403.      * Flatten this notification from a parcel. 
  404.      */  
  405.     public void writeToParcel(Parcel parcel, int flags)  
  406.     {  
  407.         parcel.writeInt(1);  
  408.   
  409.         parcel.writeLong(when);  
  410.         parcel.writeInt(icon);  
  411.         parcel.writeInt(number);  
  412.         if (contentIntent != null) {  
  413.             parcel.writeInt(1);  
  414.             contentIntent.writeToParcel(parcel, 0);  
  415.         } else {  
  416.             parcel.writeInt(0);  
  417.         }  
  418.         if (deleteIntent != null) {  
  419.             parcel.writeInt(1);  
  420.             deleteIntent.writeToParcel(parcel, 0);  
  421.         } else {  
  422.             parcel.writeInt(0);  
  423.         }  
  424.         if (tickerText != null) {  
  425.             parcel.writeInt(1);  
  426.             TextUtils.writeToParcel(tickerText, parcel, flags);  
  427.         } else {  
  428.             parcel.writeInt(0);  
  429.         }  
  430.         if (contentView != null) {  
  431.             parcel.writeInt(1);  
  432.             contentView.writeToParcel(parcel, 0);  
  433.         } else {  
  434.             parcel.writeInt(0);  
  435.         }  
  436.   
  437.         parcel.writeInt(defaults);  
  438.         parcel.writeInt(this.flags);  
  439.   
  440.         if (sound != null) {  
  441.             parcel.writeInt(1);  
  442.             sound.writeToParcel(parcel, 0);  
  443.         } else {  
  444.             parcel.writeInt(0);  
  445.         }  
  446.         parcel.writeInt(audioStreamType);  
  447.         parcel.writeLongArray(vibrate);  
  448.         parcel.writeInt(ledARGB);  
  449.         parcel.writeInt(ledOnMS);  
  450.         parcel.writeInt(ledOffMS);  
  451.         parcel.writeInt(iconLevel);  
  452.   
  453.         if (fullScreenIntent != null) {  
  454.             parcel.writeInt(1);  
  455.             fullScreenIntent.writeToParcel(parcel, 0);  
  456.         } else {  
  457.             parcel.writeInt(0);  
  458.         }  
  459.     }  
  460.   
  461.     /** 
  462.      * Parcelable.Creator that instantiates Notification objects 
  463.      */  
  464.     public static final Parcelable.Creator<Notification> CREATOR  
  465.             = new Parcelable.Creator<Notification>()  
  466.     {  
  467.         public Notification createFromParcel(Parcel parcel)  
  468.         {  
  469.             return new Notification(parcel);  
  470.         }  
  471.   
  472.         public Notification[] newArray(int size)  
  473.         {  
  474.             return new Notification[size];  
  475.         }  
  476.     };  
  477.   
  478.     /** 
  479.      * Sets the {@link #contentView} field to be a view with the standard "Latest Event" 
  480.      * layout. 
  481.      * 
  482.      * <p>Uses the {@link #icon} and {@link #when} fields to set the icon and time fields 
  483.      * in the view.</p> 
  484.      * @param context       The context for your application / activity. 
  485.      * @param contentTitle The title that goes in the expanded entry. 
  486.      * @param contentText  The text that goes in the expanded entry. 
  487.      * @param contentIntent The intent to launch when the user clicks the expanded notification. 
  488.      * If this is an activity, it must include the 
  489.      * {@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK} flag, which requires 
  490.      * that you take care of task management as described in  
  491.      * <a href="{@docRoot}guide/topics/fundamentals.html#lcycles">Application Fundamentals: Activities and Tasks</a>. 
  492.      */  
  493.     public void setLatestEventInfo(Context context,  
  494.             CharSequence contentTitle, CharSequence contentText, PendingIntent contentIntent) {  
  495.         RemoteViews contentView = new RemoteViews(context.getPackageName(),  
  496.                 com.android.internal.R.layout.status_bar_latest_event_content);  
  497.         if (this.icon != 0) {  
  498.             contentView.setImageViewResource(com.android.internal.R.id.icon, this.icon);  
  499.         }  
  500.         if (contentTitle != null) {  
  501.             contentView.setTextViewText(com.android.internal.R.id.title, contentTitle);  
  502.         }  
  503.         if (contentText != null) {  
  504.             contentView.setTextViewText(com.android.internal.R.id.text, contentText);  
  505.         }  
  506.         if (this.when != 0) {  
  507.             contentView.setLong(com.android.internal.R.id.time, "setTime", when);  
  508.         }  
  509.   
  510.         this.contentView = contentView;  
  511.         this.contentIntent = contentIntent;  
  512.     }  
  513.   
  514.     @Override  
  515.     public String toString() {  
  516.         StringBuilder sb = new StringBuilder();  
  517.         sb.append("Notification(vibrate=");  
  518.         if (this.vibrate != null) {  
  519.             int N = this.vibrate.length-1;  
  520.             sb.append("[");  
  521.             for (int i=0; i<N; i++) {  
  522.                 sb.append(this.vibrate[i]);  
  523.                 sb.append(',');  
  524.             }  
  525.             if (N != -1) {  
  526.                 sb.append(this.vibrate[N]);  
  527.             }  
  528.             sb.append("]");  
  529.         } else if ((this.defaults & DEFAULT_VIBRATE) != 0) {  
  530.             sb.append("default");  
  531.         } else {  
  532.             sb.append("null");  
  533.         }  
  534.         sb.append(",sound=");  
  535.         if (this.sound != null) {  
  536.             sb.append(this.sound.toString());  
  537.         } else if ((this.defaults & DEFAULT_SOUND) != 0) {  
  538.             sb.append("default");  
  539.         } else {  
  540.             sb.append("null");  
  541.         }  
  542.         sb.append(",defaults=0x");  
  543.         sb.append(Integer.toHexString(this.defaults));  
  544.         sb.append(",flags=0x");  
  545.         sb.append(Integer.toHexString(this.flags));  
  546.         sb.append(")");  
  547.         return sb.toString();  
  548.     }  
  549. }  


在344行, sound = Uri.CREATOR.createFromParcel(parcel);回来经过打log发现,问题的关键不再这个类中。

          再次,改变方向,换条思路走,找notification的服务类,看有什么新的发现,在framework/base/services/java/com/android/server/NotificationManagerService.java类中,真的找到了我需要的,

[java] view plaincopyprint?
  1. /* 
  2.  * Copyright (C) 2007 The Android Open Source Project 
  3.  * 
  4.  * Licensed under the Apache License, Version 2.0 (the "License"); 
  5.  * you may not use this file except in compliance with the License. 
  6.  * You may obtain a copy of the License at 
  7.  * 
  8.  *      http://www.apache.org/licenses/LICENSE-2.0 
  9.  * 
  10.  * Unless required by applicable law or agreed to in writing, software 
  11.  * distributed under the License is distributed on an "AS IS" BASIS, 
  12.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
  13.  * See the License for the specific language governing permissions and 
  14.  * limitations under the License. 
  15.  */  
  16.   
  17. package com.android.server;  
  18.   
  19. import com.android.internal.statusbar.StatusBarNotification;  
  20. import com.android.server.StatusBarManagerService;  
  21.   
  22. import android.app.ActivityManagerNative;  
  23. import android.app.IActivityManager;  
  24. import android.app.INotificationManager;  
  25. import android.app.ITransientNotification;  
  26. import android.app.Notification;  
  27. import android.app.NotificationManager;  
  28. import android.app.PendingIntent;  
  29. import android.app.StatusBarManager;  
  30. import android.content.BroadcastReceiver;  
  31. import android.content.ComponentName;  
  32. import android.content.ContentResolver;  
  33. import android.content.Context;  
  34. import android.content.Intent;  
  35. import android.content.IntentFilter;  
  36. import android.content.pm.ApplicationInfo;  
  37. import android.content.pm.PackageManager;  
  38. import android.content.pm.PackageManager.NameNotFoundException;  
  39. import android.content.res.Resources;  
  40. import android.database.ContentObserver;  
  41. import android.hardware.usb.UsbManager;  
  42. import android.media.AudioManager;  
  43. import android.net.Uri;  
  44. import android.os.BatteryManager;  
  45. import android.os.Bundle;  
  46. import android.os.Binder;  
  47. import android.os.Handler;  
  48. import android.os.IBinder;  
  49. import android.os.Message;  
  50. import android.os.Power;  
  51. import android.os.Process;  
  52. import android.os.RemoteException;  
  53. import android.os.SystemProperties;  
  54. import android.os.Vibrator;  
  55. import android.os.SystemClock;  
  56. import android.provider.Settings;  
  57. import android.telephony.TelephonyManager;  
  58. import android.text.TextUtils;  
  59. import android.util.EventLog;  
  60. import android.util.Slog;  
  61. import android.util.Log;  
  62. import android.view.accessibility.AccessibilityEvent;  
  63. import android.view.accessibility.AccessibilityManager;  
  64. import android.widget.Toast;  
  65.   
  66. import java.io.FileDescriptor;  
  67. import java.io.PrintWriter;  
  68. import java.util.ArrayList;  
  69. import java.util.Arrays;  
  70. import java.util.HashMap;  
  71.   
  72. /** {@hide} */  
  73. public class NotificationManagerService extends INotificationManager.Stub  
  74. {  
  75.     private static final String TAG = "NotificationService";  
  76.     private static final boolean DBG = false;  
  77.   
  78.     private static final int MAX_PACKAGE_NOTIFICATIONS = 50;  
  79.     private static final int NOTIFICATION_REQUEST_INTERVAL = 30000// 30 seconds  
  80.     private static final int MAX_PACKAGE_NOTIFICATION_REQUESTS = 500;  
  81.   
  82.     // message codes  
  83.     private static final int MESSAGE_TIMEOUT = 2;  
  84.   
  85.     private static final int LONG_DELAY = 3500// 3.5 seconds  
  86.     private static final int SHORT_DELAY = 2000// 2 seconds  
  87.   
  88.     private static final long[] DEFAULT_VIBRATE_PATTERN = {0250250250};  
  89.   
  90.     private static final int DEFAULT_STREAM_TYPE = AudioManager.STREAM_NOTIFICATION;  
  91.   
  92.     final Context mContext;  
  93.     final IActivityManager mAm;  
  94.     final IBinder mForegroundToken = new Binder();  
  95.   
  96.     private WorkerHandler mHandler;  
  97.     private StatusBarManagerService mStatusBar;  
  98.     private LightsService mLightsService;  
  99.     private LightsService.Light mBatteryLight;  
  100.     private LightsService.Light mNotificationLight;  
  101.     private LightsService.Light mAttentionLight;  
  102.   
  103.     private int mDefaultNotificationColor;  
  104.     private int mDefaultNotificationLedOn;  
  105.     private int mDefaultNotificationLedOff;  
  106.   
  107.     private NotificationRecord mSoundNotification;  
  108.     private NotificationPlayer mSound;  
  109.     private boolean mSystemReady;  
  110.     private int mDisabledNotifications;  
  111.   
  112.     private NotificationRecord mVibrateNotification;  
  113.     private Vibrator mVibrator = new Vibrator();  
  114.   
  115.     // for enabling and disabling notification pulse behavior  
  116.     private boolean mScreenOn = true;  
  117.     private boolean mInCall = false;  
  118.     private boolean mNotificationPulseEnabled;  
  119.     // This is true if we have received a new notification while the screen is off  
  120.     // (that is, if mLedNotification was set while the screen was off)  
  121.     // This is reset to false when the screen is turned on.  
  122.     private boolean mPendingPulseNotification;  
  123.   
  124.     // for adb connected notifications  
  125.     private boolean mAdbNotificationShown = false;  
  126.     private Notification mAdbNotification;  
  127.   
  128.     private final ArrayList<NotificationRecord> mNotificationList =  
  129.             new ArrayList<NotificationRecord>();  
  130.   
  131.     private class PackageRequestInfo {  
  132.         int requestCount;  
  133.         long lastPostTime;  
  134.     }  
  135.   
  136.     private final HashMap<String, PackageRequestInfo> mPackageInfo =  
  137.             new HashMap<String, PackageRequestInfo>();  
  138.   
  139.     private ArrayList<ToastRecord> mToastQueue;  
  140.   
  141.     private ArrayList<NotificationRecord> mLights = new ArrayList<NotificationRecord>();  
  142.   
  143.     private boolean mBatteryCharging;  
  144.     private boolean mBatteryLow;  
  145.     private boolean mBatteryFull;  
  146.     private NotificationRecord mLedNotification;  
  147.   
  148.     private static final int BATTERY_LOW_ARGB = 0xFFFF0000// Charging Low - red solid on  
  149.     private static final int BATTERY_MEDIUM_ARGB = 0xFFFFFF00;    // Charging - orange solid on  
  150.     private static final int BATTERY_FULL_ARGB = 0xFF00FF00// Charging Full - green solid on  
  151.     private static final int BATTERY_BLINK_ON = 125;  
  152.     private static final int BATTERY_BLINK_OFF = 2875;  
  153.   
  154.     private static String idDebugString(Context baseContext, String packageName, int id) {  
  155.         Context c = null;  
  156.   
  157.         if (packageName != null) {  
  158.             try {  
  159.                 c = baseContext.createPackageContext(packageName, 0);  
  160.             } catch (NameNotFoundException e) {  
  161.                 c = baseContext;  
  162.             }  
  163.         } else {  
  164.             c = baseContext;  
  165.         }  
  166.   
  167.         String pkg;  
  168.         String type;  
  169.         String name;  
  170.   
  171.         Resources r = c.getResources();  
  172.         try {  
  173.             return r.getResourceName(id);  
  174.         } catch (Resources.NotFoundException e) {  
  175.             return "<name unknown>";  
  176.         }  
  177.     }  
  178.   
  179.     private static final class NotificationRecord  
  180.     {  
  181.         final String pkg;  
  182.         final String tag;  
  183.         final int id;  
  184.         final int uid;  
  185.         final int initialPid;  
  186.         ITransientNotification callback;  
  187.         int duration;  
  188.         final Notification notification;  
  189.         IBinder statusBarKey;  
  190.   
  191.         NotificationRecord(String pkg, String tag, int id, int uid, int initialPid,  
  192.                 Notification notification)  
  193.         {  
  194.             this.pkg = pkg;  
  195.             this.tag = tag;  
  196.             this.id = id;  
  197.             this.uid = uid;  
  198.             this.initialPid = initialPid;  
  199.             this.notification = notification;  
  200.         }  
  201.   
  202.         void dump(PrintWriter pw, String prefix, Context baseContext) {  
  203.             pw.println(prefix + this);  
  204.             pw.println(prefix + "  icon=0x" + Integer.toHexString(notification.icon)  
  205.                     + " / " + idDebugString(baseContext, this.pkg, notification.icon));  
  206.             pw.println(prefix + "  contentIntent=" + notification.contentIntent);  
  207.             pw.println(prefix + "  deleteIntent=" + notification.deleteIntent);  
  208.             pw.println(prefix + "  tickerText=" + notification.tickerText);  
  209.             pw.println(prefix + "  contentView=" + notification.contentView);  
  210.             pw.println(prefix + "  defaults=0x" + Integer.toHexString(notification.defaults));  
  211.             pw.println(prefix + "  flags=0x" + Integer.toHexString(notification.flags));  
  212.             pw.println(prefix + "  sound=" + notification.sound);  
  213.             pw.println(prefix + "  vibrate=" + Arrays.toString(notification.vibrate));  
  214.             pw.println(prefix + "  ledARGB=0x" + Integer.toHexString(notification.ledARGB)  
  215.                     + " ledOnMS=" + notification.ledOnMS  
  216.                     + " ledOffMS=" + notification.ledOffMS);  
  217.         }  
  218.   
  219.         @Override  
  220.         public final String toString()  
  221.         {  
  222.             return "NotificationRecord{"  
  223.                 + Integer.toHexString(System.identityHashCode(this))  
  224.                 + " pkg=" + pkg  
  225.                 + " id=" + Integer.toHexString(id)  
  226.                 + " tag=" + tag + "}";  
  227.         }  
  228.     }  
  229.   
  230.     private static final class ToastRecord  
  231.     {  
  232.         final int pid;  
  233.         final String pkg;  
  234.         final ITransientNotification callback;  
  235.         int duration;  
  236.   
  237.         ToastRecord(int pid, String pkg, ITransientNotification callback, int duration)  
  238.         {  
  239.             this.pid = pid;  
  240.             this.pkg = pkg;  
  241.             this.callback = callback;  
  242.             this.duration = duration;  
  243.         }  
  244.   
  245.         void update(int duration) {  
  246.             this.duration = duration;  
  247.         }  
  248.   
  249.         void dump(PrintWriter pw, String prefix) {  
  250.             pw.println(prefix + this);  
  251.         }  
  252.   
  253.         @Override  
  254.         public final String toString()  
  255.         {  
  256.             return "ToastRecord{"  
  257.                 + Integer.toHexString(System.identityHashCode(this))  
  258.                 + " pkg=" + pkg  
  259.                 + " callback=" + callback  
  260.                 + " duration=" + duration;  
  261.         }  
  262.     }  
  263.   
  264.     private StatusBarManagerService.NotificationCallbacks mNotificationCallbacks  
  265.             = new StatusBarManagerService.NotificationCallbacks() {  
  266.   
  267.         public void onSetDisabled(int status) {  
  268.             synchronized (mNotificationList) {  
  269.                 mDisabledNotifications = status;  
  270.                 if ((mDisabledNotifications & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0) {  
  271.                     // cancel whatever's going on  
  272.                     long identity = Binder.clearCallingIdentity();  
  273.                     try {  
  274.                         mSound.stop();  
  275.                     }  
  276.                     finally {  
  277.                         Binder.restoreCallingIdentity(identity);  
  278.                     }  
  279.   
  280.                     identity = Binder.clearCallingIdentity();  
  281.                     try {  
  282.                         mVibrator.cancel();  
  283.                     }  
  284.                     finally {  
  285.                         Binder.restoreCallingIdentity(identity);  
  286.                     }  
  287.                 }  
  288.             }  
  289.         }  
  290.   
  291.         public void onClearAll() {  
  292.             cancelAll();  
  293.         }  
  294.   
  295.         public void onNotificationClick(String pkg, String tag, int id) {  
  296.             cancelNotification(pkg, tag, id, Notification.FLAG_AUTO_CANCEL,  
  297.                     Notification.FLAG_FOREGROUND_SERVICE);  
  298.         }  
  299.   
  300.         public void onPanelRevealed() {  
  301.             synchronized (mNotificationList) {  
  302.                 // sound  
  303.                 mSoundNotification = null;  
  304.                 long identity = Binder.clearCallingIdentity();  
  305.                 try {  
  306.                     mSound.stop();  
  307.                 }  
  308.                 finally {  
  309.                     Binder.restoreCallingIdentity(identity);  
  310.                 }  
  311.   
  312.                 // vibrate  
  313.                 mVibrateNotification = null;  
  314.                 identity = Binder.clearCallingIdentity();  
  315.                 try {  
  316.                     mVibrator.cancel();  
  317.                 }  
  318.                 finally {  
  319.                     Binder.restoreCallingIdentity(identity);  
  320.                 }  
  321.   
  322.                 // light  
  323.                 mLights.clear();  
  324.                 mLedNotification = null;  
  325.                 updateLightsLocked();  
  326.             }  
  327.         }  
  328.   
  329.         public void onNotificationError(String pkg, String tag, int id,  
  330.                 int uid, int initialPid, String message) {  
  331.             Slog.d(TAG, "onNotification error pkg=" + pkg + " tag=" + tag + " id=" + id  
  332.                     + "; will crashApplication(uid=" + uid + ", pid=" + initialPid + ")");  
  333.             cancelNotification(pkg, tag, id, 00);  
  334.             long ident = Binder.clearCallingIdentity();  
  335.             try {  
  336.                 ActivityManagerNative.getDefault().crashApplication(uid, initialPid, pkg,  
  337.                         "Bad notification posted from package " + pkg  
  338.                         + ": " + message);  
  339.             } catch (RemoteException e) {  
  340.             }  
  341.             Binder.restoreCallingIdentity(ident);  
  342.         }  
  343.     };  
  344.   
  345.     private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {  
  346.         @Override  
  347.         public void onReceive(Context context, Intent intent) {  
  348.             String action = intent.getAction();  
  349.   
  350.             boolean queryRestart = false;  
  351.               
  352.             if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {  
  353.                 boolean batteryCharging = (intent.getIntExtra("plugged"0) != 0);  
  354.                 int level = intent.getIntExtra("level", -1);  
  355.                 boolean batteryLow = (level >= 0 && level <= Power.LOW_BATTERY_THRESHOLD);  
  356.                 int status = intent.getIntExtra("status", BatteryManager.BATTERY_STATUS_UNKNOWN);  
  357.                 boolean batteryFull = (status == BatteryManager.BATTERY_STATUS_FULL || level >= 90);  
  358.   
  359.                 if (batteryCharging != mBatteryCharging ||  
  360.                         batteryLow != mBatteryLow ||  
  361.                         batteryFull != mBatteryFull) {  
  362.                     mBatteryCharging = batteryCharging;  
  363.                     mBatteryLow = batteryLow;  
  364.                     mBatteryFull = batteryFull;  
  365.                     updateLights();  
  366.                 }  
  367.             } else if (action.equals(UsbManager.ACTION_USB_STATE)) {  
  368.                 Bundle extras = intent.getExtras();  
  369.                 boolean usbConnected = extras.getBoolean(UsbManager.USB_CONNECTED);  
  370.                 boolean adbEnabled = (UsbManager.USB_FUNCTION_ENABLED.equals(  
  371.                                     extras.getString(UsbManager.USB_FUNCTION_ADB)));  
  372.                 updateAdbNotification(usbConnected && adbEnabled);  
  373.             } else if (action.equals(Intent.ACTION_PACKAGE_REMOVED)  
  374.                     || action.equals(Intent.ACTION_PACKAGE_RESTARTED)  
  375.                     || (queryRestart=action.equals(Intent.ACTION_QUERY_PACKAGE_RESTART))  
  376.                     || action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {  
  377.                 String pkgList[] = null;  
  378.                 if (action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {  
  379.                     pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);  
  380.                 } else if (queryRestart) {  
  381.                     pkgList = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES);  
  382.                 } else {  
  383.                     Uri uri = intent.getData();  
  384.                     if (uri == null) {  
  385.                         return;  
  386.                     }  
  387.                     String pkgName = uri.getSchemeSpecificPart();  
  388.                     if (pkgName == null) {  
  389.                         return;  
  390.                     }  
  391.                     pkgList = new String[]{pkgName};  
  392.                 }  
  393.                 if (pkgList != null && (pkgList.length > 0)) {  
  394.                     for (String pkgName : pkgList) {  
  395.                         cancelAllNotificationsInt(pkgName, 00, !queryRestart);  
  396.                     }  
  397.                 }  
  398.             } else if (action.equals(Intent.ACTION_SCREEN_ON)) {  
  399.                 mScreenOn = true;  
  400.                 updateNotificationPulse();  
  401.             } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {  
  402.                 mScreenOn = false;  
  403.                 updateNotificationPulse();  
  404.             } else if (action.equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)) {  
  405.                 mInCall = (intent.getStringExtra(TelephonyManager.EXTRA_STATE).equals(TelephonyManager.EXTRA_STATE_OFFHOOK));  
  406.                 updateNotificationPulse();  
  407.             }  
  408.         }  
  409.     };  
  410.   
  411.     class SettingsObserver extends ContentObserver {  
  412.         SettingsObserver(Handler handler) {  
  413.             super(handler);  
  414.         }  
  415.   
  416.         void observe() {  
  417.             ContentResolver resolver = mContext.getContentResolver();  
  418.             resolver.registerContentObserver(Settings.System.getUriFor(  
  419.                     Settings.System.NOTIFICATION_LIGHT_PULSE), falsethis);  
  420.             update();  
  421.         }  
  422.   
  423.         @Override public void onChange(boolean selfChange) {  
  424.             update();  
  425.         }  
  426.   
  427.         public void update() {  
  428.             ContentResolver resolver = mContext.getContentResolver();  
  429.             boolean pulseEnabled = Settings.System.getInt(resolver,  
  430.                         Settings.System.NOTIFICATION_LIGHT_PULSE, 0) != 0;  
  431.             if (mNotificationPulseEnabled != pulseEnabled) {  
  432.                 mNotificationPulseEnabled = pulseEnabled;  
  433.                 updateNotificationPulse();  
  434.             }  
  435.         }  
  436.     }  
  437.   
  438.     NotificationManagerService(Context context, StatusBarManagerService statusBar,  
  439.             LightsService lights)  
  440.     {  
  441.         super();  
  442.         mContext = context;  
  443.         mLightsService = lights;  
  444.         mAm = ActivityManagerNative.getDefault();  
  445.         mSound = new NotificationPlayer(TAG);  
  446.         mSound.setUsesWakeLock(context);  
  447.         mToastQueue = new ArrayList<ToastRecord>();  
  448.         mHandler = new WorkerHandler();  
  449.   
  450.         mStatusBar = statusBar;  
  451.         statusBar.setNotificationCallbacks(mNotificationCallbacks);  
  452.   
  453.         mBatteryLight = lights.getLight(LightsService.LIGHT_ID_BATTERY);  
  454.         mNotificationLight = lights.getLight(LightsService.LIGHT_ID_NOTIFICATIONS);  
  455.         mAttentionLight = lights.getLight(LightsService.LIGHT_ID_ATTENTION);  
  456.   
  457.         Resources resources = mContext.getResources();  
  458.         mDefaultNotificationColor = resources.getColor(  
  459.                 com.android.internal.R.color.config_defaultNotificationColor);  
  460.         mDefaultNotificationLedOn = resources.getInteger(  
  461.                 com.android.internal.R.integer.config_defaultNotificationLedOn);  
  462.         mDefaultNotificationLedOff = resources.getInteger(  
  463.                 com.android.internal.R.integer.config_defaultNotificationLedOff);  
  464.   
  465.         // Don't start allowing notifications until the setup wizard has run once.  
  466.         // After that, including subsequent boots, init with notifications turned on.  
  467.         // This works on the first boot because the setup wizard will toggle this  
  468.         // flag at least once and we'll go back to 0 after that.  
  469.         if (0 == Settings.Secure.getInt(mContext.getContentResolver(),  
  470.                     Settings.Secure.DEVICE_PROVISIONED, 0)) {  
  471.             mDisabledNotifications = StatusBarManager.DISABLE_NOTIFICATION_ALERTS;  
  472.         }  
  473.   
  474.         // register for battery changed notifications  
  475.         IntentFilter filter = new IntentFilter();  
  476.         filter.addAction(Intent.ACTION_BATTERY_CHANGED);  
  477.         filter.addAction(UsbManager.ACTION_USB_STATE);  
  478.         filter.addAction(Intent.ACTION_SCREEN_ON);  
  479.         filter.addAction(Intent.ACTION_SCREEN_OFF);  
  480.         filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);  
  481.         mContext.registerReceiver(mIntentReceiver, filter);  
  482.         IntentFilter pkgFilter = new IntentFilter();  
  483.         pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);  
  484.         pkgFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);  
  485.         pkgFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);  
  486.         pkgFilter.addDataScheme("package");  
  487.         mContext.registerReceiver(mIntentReceiver, pkgFilter);  
  488.         IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);  
  489.         mContext.registerReceiver(mIntentReceiver, sdFilter);  
  490.   
  491.         SettingsObserver observer = new SettingsObserver(mHandler);  
  492.         observer.observe();  
  493.     }  
  494.   
  495.     void systemReady() {  
  496.         // no beeping until we're basically done booting  
  497.         mSystemReady = true;  
  498.     }  
  499.   
  500.     // Toasts  
  501.     // ============================================================================  
  502.     public void enqueueToast(String pkg, ITransientNotification callback, int duration)  
  503.     {  
  504.         if (DBG) Slog.i(TAG, "enqueueToast pkg=" + pkg + " callback=" + callback + " duration=" + duration);  
  505.   
  506.         if (pkg == null || callback == null) {  
  507.             Slog.e(TAG, "Not doing toast. pkg=" + pkg + " callback=" + callback);  
  508.             return ;  
  509.         }  
  510.   
  511.         synchronized (mToastQueue) {  
  512.             int callingPid = Binder.getCallingPid();  
  513.             long callingId = Binder.clearCallingIdentity();  
  514.             try {  
  515.                 ToastRecord record;  
  516.                 int index = indexOfToastLocked(pkg, callback);  
  517.                 // If it's already in the queue, we update it in place, we don't  
  518.                 // move it to the end of the queue.  
  519.                 if (index >= 0) {  
  520.                     record = mToastQueue.get(index);  
  521.                     record.update(duration);  
  522.                 } else {  
  523.                     // Limit the number of toasts that any given package except the android  
  524.                     // package can enqueue.  Prevents DOS attacks and deals with leaks.  
  525.                     if (!"android".equals(pkg)) {  
  526.                         int count = 0;  
  527.                         final int N = mToastQueue.size();  
  528.                         for (int i=0; i<N; i++) {  
  529.                              final ToastRecord r = mToastQueue.get(i);  
  530.                              if (r.pkg.equals(pkg)) {  
  531.                                  count++;  
  532.                                  if (count >= MAX_PACKAGE_NOTIFICATIONS) {  
  533.                                      Slog.e(TAG, "Package has already posted " + count  
  534.                                             + " toasts. Not showing more. Package=" + pkg);  
  535.                                      return;  
  536.                                  }  
  537.                              }  
  538.                         }  
  539.                     }  
  540.   
  541.                     record = new ToastRecord(callingPid, pkg, callback, duration);  
  542.                     mToastQueue.add(record);  
  543.                     index = mToastQueue.size() - 1;  
  544.                     keepProcessAliveLocked(callingPid);  
  545.                 }  
  546.                 // If it's at index 0, it's the current toast.  It doesn't matter if it's  
  547.                 // new or just been updated.  Call back and tell it to show itself.  
  548.                 // If the callback fails, this will remove it from the list, so don't  
  549.                 // assume that it's valid after this.  
  550.                 if (index == 0) {  
  551.                     showNextToastLocked();  
  552.                 }  
  553.             } finally {  
  554.                 Binder.restoreCallingIdentity(callingId);  
  555.             }  
  556.         }  
  557.     }  
  558.   
  559.     public void cancelToast(String pkg, ITransientNotification callback) {  
  560.         Slog.i(TAG, "cancelToast pkg=" + pkg + " callback=" + callback);  
  561.   
  562.         if (pkg == null || callback == null) {  
  563.             Slog.e(TAG, "Not cancelling notification. pkg=" + pkg + " callback=" + callback);  
  564.             return ;  
  565.         }  
  566.   
  567.         synchronized (mToastQueue) {  
  568.             long callingId = Binder.clearCallingIdentity();  
  569.             try {  
  570.                 int index = indexOfToastLocked(pkg, callback);  
  571.                 if (index >= 0) {  
  572.                     cancelToastLocked(index);  
  573.                 } else {  
  574.                     Slog.w(TAG, "Toast already cancelled. pkg=" + pkg + " callback=" + callback);  
  575.                 }  
  576.             } finally {  
  577.                 Binder.restoreCallingIdentity(callingId);  
  578.             }  
  579.         }  
  580.     }  
  581.   
  582.     private void showNextToastLocked() {  
  583.         ToastRecord record = mToastQueue.get(0);  
  584.         while (record != null) {  
  585.             if (DBG) Slog.d(TAG, "Show pkg=" + record.pkg + " callback=" + record.callback);  
  586.             try {  
  587.                 record.callback.show();  
  588.                 scheduleTimeoutLocked(record, false);  
  589.                 return;  
  590.             } catch (RemoteException e) {  
  591.                 Slog.w(TAG, "Object died trying to show notification " + record.callback  
  592.                         + " in package " + record.pkg);  
  593.                 // remove it from the list and let the process die  
  594.                 int index = mToastQueue.indexOf(record);  
  595.                 if (index >= 0) {  
  596.                     mToastQueue.remove(index);  
  597.                 }  
  598.                 keepProcessAliveLocked(record.pid);  
  599.                 if (mToastQueue.size() > 0) {  
  600.                     record = mToastQueue.get(0);  
  601.                 } else {  
  602.                     record = null;  
  603.                 }  
  604.             }  
  605.         }  
  606.     }  
  607.   
  608.     private void cancelToastLocked(int index) {  
  609.         ToastRecord record = mToastQueue.get(index);  
  610.         try {  
  611.             record.callback.hide();  
  612.         } catch (RemoteException e) {  
  613.             Slog.w(TAG, "Object died trying to hide notification " + record.callback  
  614.                     + " in package " + record.pkg);  
  615.             // don't worry about this, we're about to remove it from  
  616.             // the list anyway  
  617.         }  
  618.         mToastQueue.remove(index);  
  619.         keepProcessAliveLocked(record.pid);  
  620.         if (mToastQueue.size() > 0) {  
  621.             // Show the next one. If the callback fails, this will remove  
  622.             // it from the list, so don't assume that the list hasn't changed  
  623.             // after this point.  
  624.             showNextToastLocked();  
  625.         }  
  626.     }  
  627.   
  628.     private void scheduleTimeoutLocked(ToastRecord r, boolean immediate)  
  629.     {  
  630.         Message m = Message.obtain(mHandler, MESSAGE_TIMEOUT, r);  
  631.         long delay = immediate ? 0 : (r.duration == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY);  
  632.         mHandler.removeCallbacksAndMessages(r);  
  633.         mHandler.sendMessageDelayed(m, delay);  
  634.     }  
  635.   
  636.     private void handleTimeout(ToastRecord record)  
  637.     {  
  638.         if (DBG) Slog.d(TAG, "Timeout pkg=" + record.pkg + " callback=" + record.callback);  
  639.         synchronized (mToastQueue) {  
  640.             int index = indexOfToastLocked(record.pkg, record.callback);  
  641.             if (index >= 0) {  
  642.                 cancelToastLocked(index);  
  643.             }  
  644.         }  
  645.     }  
  646.   
  647.     // lock on mToastQueue  
  648.     private int indexOfToastLocked(String pkg, ITransientNotification callback)  
  649.     {  
  650.         IBinder cbak = callback.asBinder();  
  651.         ArrayList<ToastRecord> list = mToastQueue;  
  652.         int len = list.size();  
  653.         for (int i=0; i<len; i++) {  
  654.             ToastRecord r = list.get(i);  
  655.             if (r.pkg.equals(pkg) && r.callback.asBinder() == cbak) {  
  656.                 return i;  
  657.             }  
  658.         }  
  659.         return -1;  
  660.     }  
  661.   
  662.     // lock on mToastQueue  
  663.     private void keepProcessAliveLocked(int pid)  
  664.     {  
  665.         int toastCount = 0// toasts from this pid  
  666.         ArrayList<ToastRecord> list = mToastQueue;  
  667.         int N = list.size();  
  668.         for (int i=0; i<N; i++) {  
  669.             ToastRecord r = list.get(i);  
  670.             if (r.pid == pid) {  
  671.                 toastCount++;  
  672.             }  
  673.         }  
  674.         try {  
  675.             mAm.setProcessForeground(mForegroundToken, pid, toastCount > 0);  
  676.         } catch (RemoteException e) {  
  677.             // Shouldn't happen.  
  678.         }  
  679.     }  
  680.   
  681.     private final class WorkerHandler extends Handler  
  682.     {  
  683.         @Override  
  684.         public void handleMessage(Message msg)  
  685.         {  
  686.             switch (msg.what)  
  687.             {  
  688.                 case MESSAGE_TIMEOUT:  
  689.                     handleTimeout((ToastRecord)msg.obj);  
  690.                     break;  
  691.             }  
  692.         }  
  693.     }  
  694.   
  695.   
  696.     // Notifications  
  697.     // ============================================================================  
  698.     public void enqueueNotification(String pkg, int id, Notification notification, int[] idOut)  
  699.     {  
  700.         enqueueNotificationWithTag(pkg, null /* tag */, id, notification, idOut);  
  701.     }  
  702.   
  703.     public void enqueueNotificationWithTag(String pkg, String tag, int id, Notification notification,  
  704.             int[] idOut)  
  705.     {  
  706.         enqueueNotificationInternal(pkg, Binder.getCallingUid(), Binder.getCallingPid(),  
  707.                 tag, id, notification, idOut);  
  708.     }  
  709.   
  710.     // Not exposed via Binder; for system use only (otherwise malicious apps could spoof the  
  711.     // uid/pid of another application)  
  712.     public void enqueueNotificationInternal(String pkg, int callingUid, int callingPid,  
  713.             String tag, int id, Notification notification, int[] idOut)  
  714.     {  
  715.         checkIncomingCall(pkg);  
  716.   
  717.         // Limit the number of notifications that any given package except the android  
  718.         // package can enqueue.  Prevents DOS attacks and deals with leaks.  
  719.         if (!"android".equals(pkg)) {  
  720.             synchronized (mNotificationList) {  
  721.                 int count = 0;  
  722.                 final int N = mNotificationList.size();  
  723.                 for (int i=0; i<N; i++) {  
  724.                     final NotificationRecord r = mNotificationList.get(i);  
  725.                     if (r.pkg.equals(pkg)) {  
  726.                         count++;  
  727.                         if (count >= MAX_PACKAGE_NOTIFICATIONS) {  
  728.                             Slog.e(TAG, "Package has already posted " + count  
  729.                                     + " notifications.  Not showing more.  package=" + pkg);  
  730.                             return;  
  731.                         }  
  732.                     }  
  733.                 }  
  734.             }  
  735.         }  
  736.   
  737.         // Limit the number of notification requests, notify and cancel that  
  738.         // a package can post. The MAX_PACKAGE_NOTIFICATIONS doesn't work for  
  739.         // packages which notify and quickly cancel it and do this in an  
  740.         // iteration  
  741.         if (!"android".equals(pkg)) {  
  742.             synchronized (mPackageInfo) {  
  743.                 if (!mPackageInfo.containsKey(pkg)) {  
  744.                     final PackageRequestInfo pInfo = new PackageRequestInfo();  
  745.                     pInfo.requestCount = 1;  
  746.                     pInfo.lastPostTime = SystemClock.elapsedRealtime();  
  747.                     mPackageInfo.put(pkg,pInfo);  
  748.                 }  
  749.                 else {  
  750.                     final PackageRequestInfo pInfo = mPackageInfo.get(pkg);  
  751.                     final long currentTime = SystemClock.elapsedRealtime();  
  752.                     if ((currentTime - pInfo.lastPostTime) <= NOTIFICATION_REQUEST_INTERVAL) {  
  753.                          // Keep track of requests posted within last 30 seconds  
  754.                          pInfo.requestCount++;  
  755.                     }  
  756.                     else {  
  757.                          pInfo.requestCount = 1;  
  758.                          pInfo.lastPostTime = SystemClock.elapsedRealtime();  
  759.                     }  
  760.   
  761.                     if (pInfo.requestCount >= MAX_PACKAGE_NOTIFICATION_REQUESTS) {  
  762.                         // 500 requests within a span of 30 seconds is high  
  763.                         if (pInfo.requestCount%MAX_PACKAGE_NOTIFICATION_REQUESTS == 0) {  
  764.                             Slog.e(TAG, "Package has already posted too many notifications. "  
  765.                                     + "Not showing more.  package=" + pkg);  
  766.                         }  
  767.                         return;  
  768.                     }  
  769.                 }  
  770.             }  
  771.         }  
  772.   
  773.         // This conditional is a dirty hack to limit the logging done on  
  774.         //     behalf of the download manager without affecting other apps.  
  775.         if (!pkg.equals("com.android.providers.downloads")  
  776.                 || Log.isLoggable("DownloadManager", Log.VERBOSE)) {  
  777.             EventLog.writeEvent(EventLogTags.NOTIFICATION_ENQUEUE, pkg, id, notification.toString());  
  778.         }  
  779.   
  780.         if (pkg == null || notification == null) {  
  781.             throw new IllegalArgumentException("null not allowed: pkg=" + pkg  
  782.                     + " id=" + id + " notification=" + notification);  
  783.         }  
  784.         if (notification.icon != 0) {  
  785.             if (notification.contentView == null) {  
  786.                 throw new IllegalArgumentException("contentView required: pkg=" + pkg  
  787.                         + " id=" + id + " notification=" + notification);  
  788.             }  
  789.             if (notification.contentIntent == null) {  
  790.                 throw new IllegalArgumentException("contentIntent required: pkg=" + pkg  
  791.                         + " id=" + id + " notification=" + notification);  
  792.             }  
  793.         }  
  794.   
  795.         synchronized (mNotificationList) {  
  796.             NotificationRecord r = new NotificationRecord(pkg, tag, id,  
  797.                     callingUid, callingPid, notification);  
  798.             NotificationRecord old = null;  
  799.   
  800.             int index = indexOfNotificationLocked(pkg, tag, id);  
  801.             if (index < 0) {  
  802.                 mNotificationList.add(r);  
  803.             } else {  
  804.                 old = mNotificationList.remove(index);  
  805.                 mNotificationList.add(index, r);  
  806.                 // Make sure we don't lose the foreground service state.  
  807.                 if (old != null) {  
  808.                     notification.flags |=  
  809.                         old.notification.flags&Notification.FLAG_FOREGROUND_SERVICE;  
  810.                 }  
  811.             }  
  812.   
  813.             // Ensure if this is a foreground service that the proper additional  
  814.             // flags are set.  
  815.             if ((notification.flags&Notification.FLAG_FOREGROUND_SERVICE) != 0) {  
  816.                 notification.flags |= Notification.FLAG_ONGOING_EVENT  
  817.                         | Notification.FLAG_NO_CLEAR;  
  818.             }  
  819.   
  820.             if (notification.icon != 0) {  
  821.                 StatusBarNotification n = new StatusBarNotification(pkg, id, tag,  
  822.                         r.uid, r.initialPid, notification);  
  823.                 if (old != null && old.statusBarKey != null) {  
  824.                     r.statusBarKey = old.statusBarKey;  
  825.                     long identity = Binder.clearCallingIdentity();  
  826.                     try {  
  827.                         mStatusBar.updateNotification(r.statusBarKey, n);  
  828.                     }  
  829.                     finally {  
  830.                         Binder.restoreCallingIdentity(identity);  
  831.                     }  
  832.                 } else {  
  833.                     long identity = Binder.clearCallingIdentity();  
  834.                     try {  
  835.                         r.statusBarKey = mStatusBar.addNotification(n);  
  836.                         mAttentionLight.pulse();  
  837.                     }  
  838.                     finally {  
  839.                         Binder.restoreCallingIdentity(identity);  
  840.                     }  
  841.                 }  
  842.                 sendAccessibilityEvent(notification, pkg);  
  843.             } else {  
  844.                 if (old != null && old.statusBarKey != null) {  
  845.                     long identity = Binder.clearCallingIdentity();  
  846.                     try {  
  847.                         mStatusBar.removeNotification(old.statusBarKey);  
  848.                     }  
  849.                     finally {  
  850.                         Binder.restoreCallingIdentity(identity);  
  851.                     }  
  852.                 }  
  853.             }  
  854.   
  855.             // If we're not supposed to beep, vibrate, etc. then don't.  
  856.             if (((mDisabledNotifications & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) == 0)  
  857.                     && (!(old != null  
  858.                         && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0 ))  
  859.                     && mSystemReady) {  
  860.   
  861.                 final AudioManager audioManager = (AudioManager) mContext  
  862.                 .getSystemService(Context.AUDIO_SERVICE);  
  863.                 // sound  
  864.                 final boolean useDefaultSound =  
  865.                     (notification.defaults & Notification.DEFAULT_SOUND) != 0;  
  866.                 if (useDefaultSound || notification.sound != null) {  
  867.                     Uri uri;  
  868.                     if (useDefaultSound) {  
  869.                         uri = Settings.System.DEFAULT_NOTIFICATION_URI;  
  870.                     } else {  
  871.                         uri = notification.sound;  
  872.                     }  
  873.                     boolean looping = (notification.flags & Notification.FLAG_INSISTENT) != 0;  
  874.                     int audioStreamType;  
  875.                     if (notification.audioStreamType >= 0) {  
  876.                         audioStreamType = notification.audioStreamType;  
  877.                     } else {  
  878.                         audioStreamType = DEFAULT_STREAM_TYPE;  
  879.                     }  
  880.                     mSoundNotification = r;  
  881.                     // do not play notifications if stream volume is 0  
  882.                     // (typically because ringer mode is silent).  
  883.                     if (audioManager.getStreamVolume(audioStreamType) != 0) {  
  884.                         long identity = Binder.clearCallingIdentity();  
  885.                         try {  
  886.                             mSound.play(mContext, uri, looping, audioStreamType);  
  887.                         }  
  888.                         finally {  
  889.                             Binder.restoreCallingIdentity(identity);  
  890.                         }  
  891.                     }  
  892.                 }  
  893.   
  894.                 // vibrate  
  895.                 final boolean useDefaultVibrate =  
  896.                     (notification.defaults & Notification.DEFAULT_VIBRATE) != 0;  
  897.                 if ((useDefaultVibrate || notification.vibrate != null)  
  898.                         && audioManager.shouldVibrate(AudioManager.VIBRATE_TYPE_NOTIFICATION)) {  
  899.                     mVibrateNotification = r;  
  900.   
  901.                     mVibrator.vibrate(useDefaultVibrate ? DEFAULT_VIBRATE_PATTERN  
  902.                                                         : notification.vibrate,  
  903.                               ((notification.flags & Notification.FLAG_INSISTENT) != 0) ? 0: -1);  
  904.                 }  
  905.             }  
  906.   
  907.             // this option doesn't shut off the lights  
  908.   
  909.             // light  
  910.             // the most recent thing gets the light  
  911.             mLights.remove(old);  
  912.             if (mLedNotification == old) {  
  913.                 mLedNotification = null;  
  914.             }  
  915.             //Slog.i(TAG, "notification.lights="  
  916.             //        + ((old.notification.lights.flags & Notification.FLAG_SHOW_LIGHTS) != 0));  
  917.             if ((notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0) {  
  918.                 mLights.add(r);  
  919.                 updateLightsLocked();  
  920.             } else {  
  921.                 if (old != null  
  922.                         && ((old.notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0)) {  
  923.                     updateLightsLocked();  
  924.                 }  
  925.             }  
  926.         }  
  927.   
  928.         idOut[0] = id;  
  929.     }  
  930.   
  931.     private void sendAccessibilityEvent(Notification notification, CharSequence packageName) {  
  932.         AccessibilityManager manager = AccessibilityManager.getInstance(mContext);  
  933.         if (!manager.isEnabled()) {  
  934.             return;  
  935.         }  
  936.   
  937.         AccessibilityEvent event =  
  938.             AccessibilityEvent.obtain(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED);  
  939.         event.setPackageName(packageName);  
  940.         event.setClassName(Notification.class.getName());  
  941.         event.setParcelableData(notification);  
  942.         CharSequence tickerText = notification.tickerText;  
  943.         if (!TextUtils.isEmpty(tickerText)) {  
  944.             event.getText().add(tickerText);  
  945.         }  
  946.   
  947.         manager.sendAccessibilityEvent(event);  
  948.     }  
  949.   
  950.     private void cancelNotificationLocked(NotificationRecord r) {  
  951.         // status bar  
  952.         if (r.notification.icon != 0) {  
  953.             long identity = Binder.clearCallingIdentity();  
  954.             try {  
  955.                 mStatusBar.removeNotification(r.statusBarKey);  
  956.             }  
  957.             finally {  
  958.                 Binder.restoreCallingIdentity(identity);  
  959.             }  
  960.             r.statusBarKey = null;  
  961.         }  
  962.   
  963.         // sound  
  964.         if (mSoundNotification == r) {  
  965.             mSoundNotification = null;  
  966.             long identity = Binder.clearCallingIdentity();  
  967.             try {  
  968.                 mSound.stop();  
  969.             }  
  970.             finally {  
  971.                 Binder.restoreCallingIdentity(identity);  
  972.             }  
  973.         }  
  974.   
  975.         // vibrate  
  976.         if (mVibrateNotification == r) {  
  977.             mVibrateNotification = null;  
  978.             long identity = Binder.clearCallingIdentity();  
  979.             try {  
  980.                 mVibrator.cancel();  
  981.             }  
  982.             finally {  
  983.                 Binder.restoreCallingIdentity(identity);  
  984.             }  
  985.         }  
  986.   
  987.         // light  
  988.         mLights.remove(r);  
  989.         if (mLedNotification == r) {  
  990.             mLedNotification = null;  
  991.         }  
  992.     }  
  993.   
  994.     /** 
  995.      * Cancels a notification ONLY if it has all of the {@code mustHaveFlags} 
  996.      * and none of the {@code mustNotHaveFlags}. 
  997.      */  
  998.     private void cancelNotification(String pkg, String tag, int id, int mustHaveFlags,  
  999.             int mustNotHaveFlags) {  
  1000.         EventLog.writeEvent(EventLogTags.NOTIFICATION_CANCEL, pkg, id, mustHaveFlags);  
  1001.   
  1002.         synchronized (mNotificationList) {  
  1003.             int index = indexOfNotificationLocked(pkg, tag, id);  
  1004.             if (index >= 0) {  
  1005.                 NotificationRecord r = mNotificationList.get(index);  
  1006.   
  1007.                 if ((r.notification.flags & mustHaveFlags) != mustHaveFlags) {  
  1008.                     return;  
  1009.                 }  
  1010.                 if ((r.notification.flags & mustNotHaveFlags) != 0) {  
  1011.                     return;  
  1012.                 }  
  1013.   
  1014.                 mNotificationList.remove(index);  
  1015.   
  1016.                 cancelNotificationLocked(r);  
  1017.                 updateLightsLocked();  
  1018.             }  
  1019.         }  
  1020.     }  
  1021.   
  1022.     /** 
  1023.      * Cancels all notifications from a given package that have all of the 
  1024.      * {@code mustHaveFlags}. 
  1025.      */  
  1026.     boolean cancelAllNotificationsInt(String pkg, int mustHaveFlags,  
  1027.             int mustNotHaveFlags, boolean doit) {  
  1028.         EventLog.writeEvent(EventLogTags.NOTIFICATION_CANCEL_ALL, pkg, mustHaveFlags);  
  1029.   
  1030.         synchronized (mNotificationList) {  
  1031.             final int N = mNotificationList.size();  
  1032.             boolean canceledSomething = false;  
  1033.             for (int i = N-1; i >= 0; --i) {  
  1034.                 NotificationRecord r = mNotificationList.get(i);  
  1035.                 if ((r.notification.flags & mustHaveFlags) != mustHaveFlags) {  
  1036.                     continue;  
  1037.                 }  
  1038.                 if ((r.notification.flags & mustNotHaveFlags) != 0) {  
  1039.                     continue;  
  1040.                 }  
  1041.                 if (!r.pkg.equals(pkg)) {  
  1042.                     continue;  
  1043.                 }  
  1044.                 canceledSomething = true;  
  1045.                 if (!doit) {  
  1046.                     return true;  
  1047.                 }  
  1048.                 mNotificationList.remove(i);  
  1049.                 cancelNotificationLocked(r);  
  1050.             }  
  1051.             if (canceledSomething) {  
  1052.                 updateLightsLocked();  
  1053.             }  
  1054.             return canceledSomething;  
  1055.         }  
  1056.     }  
  1057.   
  1058.   
  1059.     public void cancelNotification(String pkg, int id) {  
  1060.         cancelNotificationWithTag(pkg, null /* tag */, id);  
  1061.     }  
  1062.   
  1063.     public void cancelNotificationWithTag(String pkg, String tag, int id) {  
  1064.         checkIncomingCall(pkg);  
  1065.   
  1066.         // Limit the number of notification requests, notify and cancel that  
  1067.         // a package can post. The MAX_PACKAGE_NOTIFICATIONS doesn't work for  
  1068.         // packages which notify and quickly cancel it and do this in an  
  1069.         // iteration  
  1070.         synchronized (mPackageInfo) {  
  1071.             if (!"android".equals(pkg) && mPackageInfo.containsKey(pkg)) {  
  1072.                 final PackageRequestInfo pInfo = mPackageInfo.get(pkg);  
  1073.                 final long currentTime = SystemClock.elapsedRealtime();  
  1074.                 if ((currentTime - pInfo.lastPostTime) <= NOTIFICATION_REQUEST_INTERVAL) {  
  1075.                     // Keep track of requests posted within last 30 seconds  
  1076.                     pInfo.requestCount++;  
  1077.                 }  
  1078.                 else {  
  1079.                     pInfo.requestCount = 1;  
  1080.                     pInfo.lastPostTime = SystemClock.elapsedRealtime();  
  1081.                 }  
  1082.             }  
  1083.         }  
  1084.   
  1085.         // Don't allow client applications to cancel foreground service notis.  
  1086.         cancelNotification(pkg, tag, id, 0,  
  1087.                 Binder.getCallingUid() == Process.SYSTEM_UID  
  1088.                 ? 0 : Notification.FLAG_FOREGROUND_SERVICE);  
  1089.     }  
  1090.   
  1091.     public void cancelAllNotifications(String pkg) {  
  1092.         checkIncomingCall(pkg);  
  1093.   
  1094.         // Calling from user space, don't allow the canceling of actively  
  1095.         // running foreground services.  
  1096.         cancelAllNotificationsInt(pkg, 0, Notification.FLAG_FOREGROUND_SERVICE, true);  
  1097.     }  
  1098.   
  1099.     void checkIncomingCall(String pkg) {  
  1100.         int uid = Binder.getCallingUid();  
  1101.         if (uid == Process.SYSTEM_UID || uid == 0) {  
  1102.             return;  
  1103.         }  
  1104.         try {  
  1105.             ApplicationInfo ai = mContext.getPackageManager().getApplicationInfo(  
  1106.                     pkg, 0);  
  1107.             if (ai.uid != uid) {  
  1108.                 throw new SecurityException("Calling uid " + uid + " gave package"  
  1109.                         + pkg + " which is owned by uid " + ai.uid);  
  1110.             }  
  1111.         } catch (PackageManager.NameNotFoundException e) {  
  1112.             throw new SecurityException("Unknown package " + pkg);  
  1113.         }  
  1114.     }  
  1115.   
  1116.     void cancelAll() {  
  1117.         synchronized (mNotificationList) {  
  1118.             final int N = mNotificationList.size();  
  1119.             for (int i=N-1; i>=0; i--) {  
  1120.                 NotificationRecord r = mNotificationList.get(i);  
  1121.   
  1122.                 if ((r.notification.flags & (Notification.FLAG_ONGOING_EVENT  
  1123.                                 | Notification.FLAG_NO_CLEAR)) == 0) {  
  1124.                     if (r.notification.deleteIntent != null) {  
  1125.                         try {  
  1126.                             r.notification.deleteIntent.send();  
  1127.                         } catch (PendingIntent.CanceledException ex) {  
  1128.                             // do nothing - there's no relevant way to recover, and  
  1129.                             //     no reason to let this propagate  
  1130.                             Slog.w(TAG, "canceled PendingIntent for " + r.pkg, ex);  
  1131.                         }  
  1132.                     }  
  1133.                     mNotificationList.remove(i);  
  1134.                     cancelNotificationLocked(r);  
  1135.                 }  
  1136.             }  
  1137.   
  1138.             updateLightsLocked();  
  1139.         }  
  1140.     }  
  1141.   
  1142.     private void updateLights() {  
  1143.         synchronized (mNotificationList) {  
  1144.             updateLightsLocked();  
  1145.         }  
  1146.     }  
  1147.   
  1148.     // lock on mNotificationList  
  1149.     private void updateLightsLocked()  
  1150.     {  
  1151.         // Battery low always shows, other states only show if charging.  
  1152.         if (mBatteryLow) {  
  1153.             if (mBatteryCharging) {  
  1154.                 mBatteryLight.setColor(BATTERY_LOW_ARGB);  
  1155.             } else {  
  1156.                 // Flash when battery is low and not charging  
  1157.                 mBatteryLight.setFlashing(BATTERY_LOW_ARGB, LightsService.LIGHT_FLASH_TIMED,  
  1158.                         BATTERY_BLINK_ON, BATTERY_BLINK_OFF);  
  1159.             }  
  1160.         } else if (mBatteryCharging) {  
  1161.             if (mBatteryFull) {  
  1162.                 mBatteryLight.setColor(BATTERY_FULL_ARGB);  
  1163.             } else {  
  1164.                 mBatteryLight.setColor(BATTERY_MEDIUM_ARGB);  
  1165.             }  
  1166.         } else {  
  1167.             mBatteryLight.turnOff();  
  1168.         }  
  1169.   
  1170.         // clear pending pulse notification if screen is on  
  1171.         if (mScreenOn || mLedNotification == null) {  
  1172.             mPendingPulseNotification = false;  
  1173.         }  
  1174.   
  1175.         // handle notification lights  
  1176.         if (mLedNotification == null) {  
  1177.             // get next notification, if any  
  1178.             int n = mLights.size();  
  1179.             if (n > 0) {  
  1180.                 mLedNotification = mLights.get(n-1);  
  1181.             }  
  1182.             if (mLedNotification != null && !mScreenOn) {  
  1183.                 mPendingPulseNotification = true;  
  1184.             }  
  1185.         }  
  1186.   
  1187.         // we only flash if screen is off and persistent pulsing is enabled  
  1188.         // and we are not currently in a call  
  1189.         if (!mPendingPulseNotification || mScreenOn || mInCall) {  
  1190.             mNotificationLight.turnOff();  
  1191.         } else {  
  1192.             int ledARGB = mLedNotification.notification.ledARGB;  
  1193.             int ledOnMS = mLedNotification.notification.ledOnMS;  
  1194.             int ledOffMS = mLedNotification.notification.ledOffMS;  
  1195.             if ((mLedNotification.notification.defaults & Notification.DEFAULT_LIGHTS) != 0) {  
  1196.                 ledARGB = mDefaultNotificationColor;  
  1197.                 ledOnMS = mDefaultNotificationLedOn;  
  1198.                 ledOffMS = mDefaultNotificationLedOff;  
  1199.             }  
  1200.             if (mNotificationPulseEnabled) {  
  1201.                 // pulse repeatedly  
  1202.                 mNotificationLight.setFlashing(ledARGB, LightsService.LIGHT_FLASH_TIMED,  
  1203.                         ledOnMS, ledOffMS);  
  1204.             } else {  
  1205.                 // pulse only once  
  1206.                 mNotificationLight.pulse(ledARGB, ledOnMS);  
  1207.             }  
  1208.         }  
  1209.     }  
  1210.   
  1211.     // lock on mNotificationList  
  1212.     private int indexOfNotificationLocked(String pkg, String tag, int id)  
  1213.     {  
  1214.         ArrayList<NotificationRecord> list = mNotificationList;  
  1215.         final int len = list.size();  
  1216.         for (int i=0; i<len; i++) {  
  1217.             NotificationRecord r = list.get(i);  
  1218.             if (tag == null) {  
  1219.                 if (r.tag != null) {  
  1220.                     continue;  
  1221.                 }  
  1222.             } else {  
  1223.                 if (!tag.equals(r.tag)) {  
  1224.                     continue;  
  1225.                 }  
  1226.             }  
  1227.             if (r.id == id && r.pkg.equals(pkg)) {  
  1228.                 return i;  
  1229.             }  
  1230.         }  
  1231.         return -1;  
  1232.     }  
  1233.   
  1234.     // This is here instead of StatusBarPolicy because it is an important  
  1235.     // security feature that we don't want people customizing the platform  
  1236.     // to accidentally lose.  
  1237.     private void updateAdbNotification(boolean adbEnabled) {  
  1238.         if (adbEnabled) {  
  1239.             if ("0".equals(SystemProperties.get("persist.adb.notify"))) {  
  1240.                 return;  
  1241.             }  
  1242.             if (!mAdbNotificationShown) {  
  1243.                 NotificationManager notificationManager = (NotificationManager) mContext  
  1244.                         .getSystemService(Context.NOTIFICATION_SERVICE);  
  1245.                 if (notificationManager != null) {  
  1246.                     Resources r = mContext.getResources();  
  1247.                     CharSequence title = r.getText(  
  1248.                             com.android.internal.R.string.adb_active_notification_title);  
  1249.                     CharSequence message = r.getText(  
  1250.                             com.android.internal.R.string.adb_active_notification_message);  
  1251.   
  1252.                     if (mAdbNotification == null) {  
  1253.                         mAdbNotification = new Notification();  
  1254.                         mAdbNotification.icon = com.android.internal.R.drawable.stat_sys_adb;  
  1255.                         mAdbNotification.when = 0;  
  1256.                         mAdbNotification.flags = Notification.FLAG_ONGOING_EVENT;  
  1257.                         mAdbNotification.tickerText = title;  
  1258.                         mAdbNotification.defaults = 0// please be quiet  
  1259.                         mAdbNotification.sound = null;  
  1260.                         mAdbNotification.vibrate = null;  
  1261.                     }  
  1262.   
  1263.                     Intent intent = new Intent(  
  1264.                             Settings.ACTION_APPLICATION_DEVELOPMENT_SETTINGS);  
  1265.                     intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |  
  1266.                             Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);  
  1267.                     // Note: we are hard-coding the component because this is  
  1268.                     // an important security UI that we don't want anyone  
  1269.                     // intercepting.  
  1270.                     intent.setComponent(new ComponentName("com.android.settings",  
  1271.                             "com.android.settings.DevelopmentSettings"));  
  1272.                     PendingIntent pi = PendingIntent.getActivity(mContext, 0,  
  1273.                             intent, 0);  
  1274.   
  1275.                     mAdbNotification.setLatestEventInfo(mContext, title, message, pi);  
  1276.   
  1277.                     mAdbNotificationShown = true;  
  1278.                     notificationManager.notify(  
  1279.                             com.android.internal.R.string.adb_active_notification_title,  
  1280.                             mAdbNotification);  
  1281.                 }  
  1282.             }  
  1283.   
  1284.         } else if (mAdbNotificationShown) {  
  1285.             NotificationManager notificationManager = (NotificationManager) mContext  
  1286.                     .getSystemService(Context.NOTIFICATION_SERVICE);  
  1287.             if (notificationManager != null) {  
  1288.                 mAdbNotificationShown = false;  
  1289.                 notificationManager.cancel(  
  1290.                         com.android.internal.R.string.adb_active_notification_title);  
  1291.             }  
  1292.         }  
  1293.     }  
  1294.   
  1295.     private void updateNotificationPulse() {  
  1296.         synchronized (mNotificationList) {  
  1297.             updateLightsLocked();  
  1298.         }  
  1299.     }  
  1300.   
  1301.     // ======================================================================  
  1302.     @Override  
  1303.     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {  
  1304.         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)  
  1305.                 != PackageManager.PERMISSION_GRANTED) {  
  1306.             pw.println("Permission Denial: can't dump NotificationManager from from pid="  
  1307.                     + Binder.getCallingPid()  
  1308.                     + ", uid=" + Binder.getCallingUid());  
  1309.             return;  
  1310.         }  
  1311.   
  1312.         pw.println("Current Notification Manager state:");  
  1313.   
  1314.         int N;  
  1315.   
  1316.         synchronized (mToastQueue) {  
  1317.             N = mToastQueue.size();  
  1318.             if (N > 0) {  
  1319.                 pw.println("  Toast Queue:");  
  1320.                 for (int i=0; i<N; i++) {  
  1321.                     mToastQueue.get(i).dump(pw, "    ");  
  1322.                 }  
  1323.                 pw.println("  ");  
  1324.             }  
  1325.   
  1326.         }  
  1327.   
  1328.         synchronized (mNotificationList) {  
  1329.             N = mNotificationList.size();  
  1330.             if (N > 0) {  
  1331.                 pw.println("  Notification List:");  
  1332.                 for (int i=0; i<N; i++) {  
  1333.                     mNotificationList.get(i).dump(pw, "    ", mContext);  
  1334.                 }  
  1335.                 pw.println("  ");  
  1336.             }  
  1337.   
  1338.             N = mLights.size();  
  1339.             if (N > 0) {  
  1340.                 pw.println("  Lights List:");  
  1341.                 for (int i=0; i<N; i++) {  
  1342.                     mLights.get(i).dump(pw, "    ", mContext);  
  1343.                 }  
  1344.                 pw.println("  ");  
  1345.             }  
  1346.   
  1347.             pw.println("  mSoundNotification=" + mSoundNotification);  
  1348.             pw.println("  mSound=" + mSound);  
  1349.             pw.println("  mVibrateNotification=" + mVibrateNotification);  
  1350.             pw.println("  mDisabledNotifications=0x" + Integer.toHexString(mDisabledNotifications));  
  1351.             pw.println("  mSystemReady=" + mSystemReady);  
  1352.         }  
  1353.     }  
  1354. }  


在871行有这句代码:uri = notification.sound;在886行有这句代码:mSound.play(mContext, uri, looping, audioStreamType);当时我就有点兴奋了,感觉这就是问题的关键,然后打log,发现这就是问题的关键,当notification正常发声音的时候,这个886行的代码走进来了,不发声音的时候这个代码没有走进来,所以我离问题的根源又进了一步。最后发现是包着这段代码的if语句中的判断引起的,所以我把if语句中的代码都打印出来,发现是mDisabledNotifications这个变量引起的,我就追踪这个mDisabledNotifications变量值的变化的地方。发现在467行有这段代码:

[java] view plaincopyprint?
  1. // Don't start allowing notifications until the setup wizard has run once.  
  2.      // After that, including subsequent boots, init with notifications turned on.  
  3.      // This works on the first boot because the setup wizard will toggle this  
  4.      // flag at least once and we'll go back to 0 after that.  
  5.      if (0 == Settings.Secure.getInt(mContext.getContentResolver(),  
  6.                  Settings.Secure.DEVICE_PROVISIONED, 0)) {  
  7.          mDisabledNotifications = StatusBarManager.DISABLE_NOTIFICATION_ALERTS;  
  8.      }  

研究以上的注释,发现原来google故意这么设置的,至于google为什么要这么设置,我没有深究,暂时没有想明白,但是这个这个初始化的时候必须要tsetup wizard (设置向导)运行一次,所以导致了值不对,所以这个notification就不响了。


在264行有这段代码对mDisabledNotification进行改变的:

[java] view plaincopyprint?
  1. private StatusBarManagerService.NotificationCallbacks mNotificationCallbacks  
  2.         = new StatusBarManagerService.NotificationCallbacks() {  
  3.   
  4.     public void onSetDisabled(int status) {  
  5.         synchronized (mNotificationList) {  
  6.             mDisabledNotifications = status;  
  7.             if ((mDisabledNotifications & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0) {  
  8.                 // cancel whatever's going on  
  9.                 long identity = Binder.clearCallingIdentity();  
  10.                 try {  
  11.                     mSound.stop();  
  12.                 }  
  13.                 finally {  
  14.                     Binder.restoreCallingIdentity(identity);  
  15.                 }  
  16.   
  17.                 identity = Binder.clearCallingIdentity();  
  18.                 try {  
  19.                     mVibrator.cancel();  
  20.                 }  
  21.                 finally {  
  22.                     Binder.restoreCallingIdentity(identity);  
  23.                 }  
  24.             }  
  25.         }  
  26.     }  

找到问题的根源了,太兴奋了,这个问题断断续续困扰了我3周,终于经过我3天地认真分析,把问题的根源找到了,要想解决就很简单了,可以在初始化的时候直接赋值为0就ok了!

       最后、886行mSound.play(mContext, uri, looping, audioStreamType);是NotificationPlayer类中的一个方法,在play()方法中有一个线程,  mThread = new CmdThread();   mThread.start();线程中的run方法中有:case   PLAY:startSound(cmd);在startSound()方法中又有一个线程:  mCompletionThread = new CreationAndCompletionThread(cmd);

[java] view plaincopyprint?
  1. mCompletionThread = new CreationAndCompletionThread(cmd);  
  2.                 synchronized(mCompletionThread) {  
  3.                     mCompletionThread.start();  
  4.                     mCompletionThread.wait();  
  5.                 }  

在这个线程类中的run方法中:在这个线程中进行播放音乐的 ,真正的发声音也是通过Mediapaly来实现的:

[java] view plaincopyprint?
  1. <span style="font-size:13px;"public void run() {  
  2.             Looper.prepare();  
  3.             mLooper = Looper.myLooper();  
  4.             synchronized(this) {  
  5.                 AudioManager audioManager =  
  6.                     (AudioManager) mCmd.context.getSystemService(Context.AUDIO_SERVICE);  
  7.                 try {  
  8.                     MediaPlayer player = new MediaPlayer();  
  9.                     player.setAudioStreamType(mCmd.stream);  
  10.                     player.setDataSource(mCmd.context, mCmd.uri);  
  11.                     player.setLooping(mCmd.looping);  
  12.                     player.prepare();  
  13.                     if ((mCmd.uri != null) && (mCmd.uri.getEncodedPath() != null)  
  14.                             && (mCmd.uri.getEncodedPath().length() > 0)) {  
  15.                         if (mCmd.looping) {  
  16.                             audioManager.requestAudioFocus(null, mCmd.stream,  
  17.                                     AudioManager.AUDIOFOCUS_GAIN);  
  18.                         } else {  
  19.                             audioManager.requestAudioFocus(null, mCmd.stream,  
  20.                                     AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK);  
  21.                         }  
  22.                     }  
  23.                     player.setOnCompletionListener(NotificationPlayer.this);  
  24.                     player.start();  
  25.                     if (mPlayer != null) {  
  26.                         mPlayer.release();  
  27.                     }  
  28.                     mPlayer = player;  
  29.                 }  
  30.                 catch (Exception e) {  
  31.                     Log.w(mTag, "error loading sound for " + mCmd.uri, e);  
  32.                 }  
  33.                 mAudioManager = audioManager;  
  34.                 this.notify();  
  35.             }  
  36.             Looper.loop();  
  37.         }</span>  
原创粉丝点击