`
mmdev
  • 浏览: 12937688 次
  • 性别: Icon_minigender_1
  • 来自: 大连
文章分类
社区版块
存档分类
最新评论

电池充电图标处理

 
阅读更多

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); //获取Iconid

intlevel=intent.getIntExtra("level",0);

mService.setIcon("battery",id,level); //在这里,是决定显示充电图标的地方,mServiceStatusBarManager

……

}

一、StatusBarManager.java中:

publicvoidsetIcon(Stringslot,inticonId,inticonLevel){

try{

mService.setIcon(slot,mContext.getPackageName(),iconId,iconLevel);

}catch(RemoteExceptionex){

//systemprocessisdeadanyway.

thrownewRuntimeException(ex);

}

}

mServiceIStatusBarService,其实现函数在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信息:iconPackageiconIdiconLevel等等。而StatusBarIconList则是这样的,它根据conifg.xmlStatusBarIcon添加进这个数组里去。在需要时取出。

五、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;

}

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics