Android在低电量时候充电图标不动,修改办法:

<itemandroid:maxLevel="0">
<animation-list
xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="false">
<itemandroid:drawable="@drawable/stat_sys_battery_charge_anim0"android:duration="2000"/>
<itemandroid:drawable="@drawable/stat_sys_battery_charge_anim1"android:duration="1000"/>
<itemandroid:drawable="@drawable/stat_sys_battery_charge_anim2"android:duration="1000"/>
<itemandroid:drawable="@drawable/stat_sys_battery_charge_anim3"android:duration="1000"/>
<itemandroid:drawable="@drawable/stat_sys_battery_charge_anim4"android:duration="1000"/>
<itemandroid:drawable="@drawable/stat_sys_battery_charge_anim5"android:duration="1000"/>
</animation-list>
</item>

下面分析一下:

一、StatusBarPolicy.java中:

privatefinalvoidupdateBattery(Intentintent){
finalintid=intent.getIntExtra("icon-small",0); //获取Icon的id
intlevel=intent.getIntExtra("level",0);
mService.setIcon("battery",id,level); //在这里,是决定显示充电图标的地方,mService:StatusBarManager
……
}

一、StatusBarManager.java中:

publicvoidsetIcon(Stringslot,inticonId,inticonLevel){
try{
mService.setIcon(slot,mContext.getPackageName(),iconId,iconLevel);
}catch(RemoteExceptionex){
//systemprocessisdeadanyway.
thrownewRuntimeException(ex);
}
}

mService:IStatusBarService,其实现函数在CommandQuene.java中,我们进入这个文件:

二、CommandQuene.java:

publicvoidsetIcon(intindex,StatusBarIconicon){
synchronized(mList){
intwhat=MSG_ICON|index;
mHandler.removeMessages(what);
mHandler.obtainMessage(what,OP_SET_ICON,0,icon.clone()).sendToTarget();
}
}

在这里,其实是将需要设置的Icon通过Message发送出去,在处理函数中实现设置:

privatefinalclassHextendsHandler{
publicvoidhandleMessage(Messagemsg){
finalintwhat=msg.what&MSG_MASK;
switch(what){
caseMSG_ICON:{
finalintindex=msg.what&INDEX_MASK;
finalintviewIndex=mList.getViewIndex(index);
switch(msg.arg1){
caseOP_SET_ICON:{
StatusBarIconicon=(StatusBarIcon)msg.obj;
StatusBarIconold=mList.getIcon(index);
if(old==null){
mList.setIcon(index,icon);
mCallbacks.addIcon(mList.getSlot(index),index,viewIndex,icon);
}else{
mList.setIcon(index,icon);
mCallbacks.updateIcon(mList.getSlot(index),index,viewIndex,
old,icon);
}
break;
}
caseOP_REMOVE_ICON:
if(mList.getIcon(index)!=null){
mList.removeIcon(index);
mCallbacks.removeIcon(mList.getSlot(index),index,viewIndex);
}
break;
}
break;
}
……
}

实际处理也就是OP_SET_ICON这个位置:若是Icon存在的,则进行更新:

四、StatusBarService.java:

publicvoidupdateIcon(Stringslot,intindex,intviewIndex,
StatusBarIconold,StatusBarIconicon){
StatusBarIconViewview=(StatusBarIconView)mStatusIcons.getChildAt(viewIndex);
view.set(icon);
}

这段代码说明,从statusIconList对象中获取这个Icon,通过StatusBarIconView进行设置:这里也充分说明了,

StatusBarIcon实际上相当于一个存储,用来存储Icon信息:iconPackage、iconId、iconLevel等等。而StatusBarIconList则是这样的,它根据conifg.xml将StatusBarIcon添加进这个数组里去。在需要时取出。

五、StatusBarIconView.java:

publicbooleanset(StatusBarIconicon){
finalbooleaniconEquals=mIcon!=null
&&streq(mIcon.iconPackage,icon.iconPackage)
&&mIcon.iconId==icon.iconId;
finalbooleanlevelEquals=iconEquals
&&mIcon.iconLevel==icon.iconLevel;
finalbooleanvisibilityEquals=mIcon!=null
&&mIcon.visible==icon.visible;
finalbooleannumberEquals=mIcon!=null
&&mIcon.number==icon.number;
mIcon=icon.clone();
//当icon不同时获取Icon并设置
if(!iconEquals){
Drawabledrawable=getIcon(icon);
if(drawable==null){
Slog.w(StatusBarService.TAG,"Noiconforslot"+mSlot);
returnfalse;
}
setImageDrawable(drawable);
}
if(!levelEquals){
setImageLevel(icon.iconLevel);
}
if(!numberEquals){
if(icon.number>0){
if(mNumberBackground==null){
mNumberBackground=getContext().getResources().getDrawable(
R.drawable.ic_notification_overlay);
}
placeNumber();
}else{
mNumberBackground=null;
mNumberText=null;
}
invalidate();
}
if(!visibilityEquals){
setVisibility(icon.visible?VISIBLE:GONE);
}
returntrue;
}

在这里特别说一下getIcon(),这更能从侧面反映出StatusBarIcon是存储作用,

r=context.getResources();
returnr.getDrawable(icon.iconId);

我们看看getDrawable:实际就是loadDrawable:这其实有解析xml文件的操作:

在publicstaticDrawablegetIcon(Contextcontext,StatusBarIconicon)函数中,

关键代码是:returnr.getDrawable(icon.iconId);

实际上,我们获得一个xml文件的id时,要先将其解析,这时就会调用Drawable.createFromXml(),在这里又会调用loadDrawable(value,id),这个函数才是对XML的解析。

if(file.endsWith(".xml"))是判断要解析的文件是否是xml文件,然后调用下面的函数:

publicstaticDrawablecreateFromXmlInner(Resourcesr,XmlPullParserparser,AttributeSetattrs)
throwsXmlPullParserException,IOException{
Drawabledrawable;
finalStringname=parser.getName();//根据名字来解析文件
if(name.equals("selector")){
drawable=newStateListDrawable();
}elseif(name.equals("level-list")){//为level-list时就创建一个LevelListDrawable实例
drawable=newLevelListDrawable();
}elseif(name.equals("layer-list")){
drawable=newLayerDrawable();
}elseif(name.equals("transition")){
drawable=newTransitionDrawable();
}elseif(name.equals("color")){
drawable=newColorDrawable();
}elseif(name.equals("shape")){
drawable=newGradientDrawable();
}elseif(name.equals("scale")){
drawable=newScaleDrawable();
}elseif(name.equals("clip")){
drawable=newClipDrawable();
}elseif(name.equals("rotate")){
drawable=newRotateDrawable();
}elseif(name.equals("animated-rotate")){
drawable=newAnimatedRotateDrawable();
}elseif(name.equals("animation-list")){
drawable=newAnimationDrawable();
}elseif(name.equals("inset")){
drawable=newInsetDrawable();
}elseif(name.equals("bitmap")){
drawable=newBitmapDrawable();
if(r!=null){
((BitmapDrawable)drawable).setTargetDensity(r.getDisplayMetrics());
}
}elseif(name.equals("nine-patch")){
drawable=newNinePatchDrawable();
if(r!=null){
((NinePatchDrawable)drawable).setTargetDensity(r.getDisplayMetrics());
}
}else{
thrownewXmlPullParserException(parser.getPositionDescription()+
":invaliddrawabletag"+name);
}
drawable.inflate(r,parser,attrs);//这一步十分关键,开始解析
returndrawable;
}
drawable.inflate(r,parser,attrs)创建一个LevelListDrawable后就开始解析xml文件:drawable.inflate(r,parser, attrs);在inflate()中,
TypedArraya=r.obtainAttributes(attrs,
com.android.internal.R.styleable.LevelListDrawableItem);
low=a.getInt(
com.android.internal.R.styleable.LevelListDrawableItem_minLevel,0);
inthigh=a.getInt(
com.android.internal.R.styleable.LevelListDrawableItem_maxLevel,0);
intdrawableRes=a.getResourceId(
com.android.internal.R.styleable.LevelListDrawableItem_drawable,0);
a.recycle();

再往下:可以看到若是LevelDrawable中还包含别的drawable,同样要进行解析。比如电池充电动画就属于这种类型,那么,就要解析AnimationDrawable.

之后,解析出来的LevelListDrawable中的Item添加到DrawableContainer中去,也就是addChild()。

六:AnimationImageView.java:

publicvoidsetImageDrawable(Drawabledrawable){
super.setImageDrawable(drawable); //调用父类方法,将drawable设置进ImageView中
updateAnim();
}
ImageView中的setImageDrawable(drawable)原型如下:
publicvoidsetImageDrawable(Drawabledrawable){
if(mDrawable!=drawable){
mResource=0;
mUri=null;
/*************************************************************************************************************/
/*到此,都只是将包含有动画的Drawable设置进去,那么经过什么样的处理之后才获得其包含的animation-list的?
因为,在updateAnim()中,需要getDrawable(),然后根据这个drawable是否是AnimationDrawable才决定动画与否*/
/*************************************************************************************************************/
updateDrawable(drawable);
requestLayout();
invalidate();
}
}

看看以下函数:

privatevoidupdateDrawable(Drawabled){
if(mDrawable!=null){ //这一段意味着若有变化,之前的Drawable的callback和
mDrawable.setCallback(null); //Message都会除去和它的关联。
unscheduleDrawable(mDrawable);
}
mDrawable=d;
if(d!=null){
d.setCallback(this); //新的drawable设置callback
if(d.isStateful()){ //新的drawable是否是isStateful
d.setState(getDrawableState());//设置state
}
d.setLevel(mLevel); //设置level
mDrawableWidth=d.getIntrinsicWidth();
mDrawableHeight=d.getIntrinsicHeight();
applyColorMod();
configureBounds();
}
}
看看setLevel()作用:
publicfinalbooleansetLevel(intlevel){
if(mLevel!=level){
mLevel=level;
returnonLevelChange(level);
}
returnfalse;
}

需要知道的是:com.android.internal.R.drawable.stat_sys_battery_charge.xml文件对应的是LevelListDrawable,因此,这时onLevelChange()必然是LevelListDrawable.java中重写Drawable的函数,这样我们就看到以下的函数实现:

protectedbooleanonLevelChange(intlevel){
intidx=mLevelListState.indexOfLevel(level);
if(selectDrawable(idx)){
returntrue;
}
returnsuper.onLevelChange(level);
}

来看看OnlevelChanged()中的语句:

intidx=mLevelListState.indexOfLevel(level);

实际上就是获得LevelListDrawable中的Item对应Id,之后才选择Drawable:

selectDrawable(idx);选中这个drawableItem并将其设置为currentdrawable

也就是正在使用的Drawable设置为由level指定的drawable:

publicbooleanselectDrawable(intidx)
{
if(idx==mCurIndex){
returnfalse;
}
if(idx>=0&&idx<mDrawableContainerState.mNumChildren){
Drawabled=mDrawableContainerState.mDrawables[idx];//刚才在解析时添加进来的
if(mCurrDrawable!=null){
mCurrDrawable.setVisible(false,false);
}
mCurrDrawable=d;
mCurIndex=idx;
if(d!=null){
d.setVisible(isVisible(),true);
d.setAlpha(mAlpha);
d.setDither(mDrawableContainerState.mDither);
d.setColorFilter(mColorFilter);
d.setState(getState());
d.setLevel(getLevel());
d.setBounds(getBounds());
}
}else{
if(mCurrDrawable!=null){
mCurrDrawable.setVisible(false,false);
}
mCurrDrawable=null;
mCurIndex=-1;
}
invalidateSelf();
returntrue;
}