电池充电图标处理

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

<item android:maxLevel="0">

        <animation-list

                xmlns:android="http://schemas.android.com/apk/res/android"

                android:oneshot="false">

            <item android:drawable="@drawable/stat_sys_battery_charge_anim0" android:duration="2000" />

            <item android:drawable="@drawable/stat_sys_battery_charge_anim1" android:duration="1000" />

            <item android:drawable="@drawable/stat_sys_battery_charge_anim2" android:duration="1000" />

            <item android:drawable="@drawable/stat_sys_battery_charge_anim3" android:duration="1000" />

            <item android:drawable="@drawable/stat_sys_battery_charge_anim4" android:duration="1000" />

            <item android:drawable="@drawable/stat_sys_battery_charge_anim5" android:duration="1000" />

      </animation-list>

</item>

下面分析一下:

一、StatusBarPolicy.java中:

private final void updateBattery(Intent intent) {

        final int id = intent.getIntExtra("icon-small", 0); //获取Iconid

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

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

……

}

一、StatusBarManager.java中:

public void setIcon(String slot, int iconId, int iconLevel) {

        try {

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

        } catch (RemoteException ex) {

            // system process is dead anyway.

            throw new RuntimeException(ex);

        }

}

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

二、CommandQuene.java

public void setIcon(int index, StatusBarIcon icon) {

        synchronized (mList) {

            int what = MSG_ICON | index;

            mHandler.removeMessages(what);

            mHandler.obtainMessage(what, OP_SET_ICON, 0, icon.clone()).sendToTarget();

        }

}

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

private final class H extends Handler {

        public void handleMessage(Message msg) {

            final int what = msg.what & MSG_MASK;

            switch (what) {

                case MSG_ICON: {

                    final int index = msg.what & INDEX_MASK;

                    final int viewIndex = mList.getViewIndex(index);

                    switch (msg.arg1) {

                        case OP_SET_ICON: {

                            StatusBarIcon icon = (StatusBarIcon)msg.obj;

                            StatusBarIcon old = 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;

                        }

                        case OP_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:

public void updateIcon(String slot, int index, int viewIndex,

            StatusBarIcon old, StatusBarIcon icon) {

        StatusBarIconView view = (StatusBarIconView)mStatusIcons.getChildAt(viewIndex);

        view.set(icon);

}

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

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

五、StatusBarIconView.java:

public boolean set(StatusBarIcon icon) {

        final boolean iconEquals = mIcon != null

                && streq(mIcon.iconPackage, icon.iconPackage)

                && mIcon.iconId == icon.iconId;

        final boolean levelEquals = iconEquals

                && mIcon.iconLevel == icon.iconLevel;

        final boolean visibilityEquals = mIcon != null

                && mIcon.visible == icon.visible;

        final boolean numberEquals = mIcon != null

                && mIcon.number == icon.number;

        mIcon = icon.clone();

            //当icon不同时获取Icon并设置

        if (!iconEquals) {

            Drawable drawable = getIcon(icon);

            if (drawable == null) {

                Slog.w(StatusBarService.TAG, "No icon for slot " + mSlot);

                return false;

            }

            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);

        }

        return true;

    }

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

 r = context.getResources();

      return r.getDrawable(icon.iconId);

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

在public static Drawable getIcon(Context context, StatusBarIcon icon)函数中,

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

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

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

public static Drawable createFromXmlInner(Resources r, XmlPullParser parser, AttributeSet attrs)

    throws XmlPullParserException, IOException {

        Drawable drawable;

        final String name = parser.getName();//根据名字来解析文件

        if (name.equals("selector")) {

            drawable = new StateListDrawable();

        } else if (name.equals("level-list")) {  //为level-list时就创建一个LevelListDrawable实例

            drawable = new LevelListDrawable();

        } else if (name.equals("layer-list")) {

            drawable = new LayerDrawable();

        } else if (name.equals("transition")) {

            drawable = new TransitionDrawable();

        } else if (name.equals("color")) {

            drawable = new ColorDrawable();

        } else if (name.equals("shape")) {

            drawable = new GradientDrawable();

        } else if (name.equals("scale")) {

            drawable = new ScaleDrawable();

        } else if (name.equals("clip")) {

            drawable = new ClipDrawable();

        } else if (name.equals("rotate")) {

            drawable = new RotateDrawable();

        } else if (name.equals("animated-rotate")) {

            drawable = new AnimatedRotateDrawable();            

        } else if (name.equals("animation-list")) {

            drawable = new AnimationDrawable();

        } else if (name.equals("inset")) {

            drawable = new InsetDrawable();

        } else if (name.equals("bitmap")) {

            drawable = new BitmapDrawable();

            if (r != null) {

               ((BitmapDrawable) drawable).setTargetDensity(r.getDisplayMetrics());

            }

        } else if (name.equals("nine-patch")) {

            drawable = new NinePatchDrawable();

            if (r != null) {

                ((NinePatchDrawable) drawable).setTargetDensity(r.getDisplayMetrics());

             }

        } else {

            throw new XmlPullParserException(parser.getPositionDescription() +

                    ": invalid drawable tag " + name);

        }

        drawable.inflate(r, parser, attrs);//这一步十分关键,开始解析

        return drawable;

    }

drawable.inflate(r, parser, attrs)创建一个LevelListDrawable后就开始解析xml文件:drawable.inflate(r, parser,  attrs);在inflate()中,

 TypedArray a = r.obtainAttributes(attrs,

                    com.android.internal.R.styleable.LevelListDrawableItem);

            low = a.getInt(

                    com.android.internal.R.styleable.LevelListDrawableItem_minLevel, 0);

            int high = a.getInt(

                    com.android.internal.R.styleable.LevelListDrawableItem_maxLevel, 0);

            int drawableRes = a.getResourceId(

                    com.android.internal.R.styleable.LevelListDrawableItem_drawable, 0);

            a.recycle();

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

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

六:AnimationImageView.java:

 public void setImageDrawable(Drawable drawable) {

        super.setImageDrawable(drawable); //调用父类方法,将drawable设置进ImageView中

        updateAnim();

 }

ImageView中的setImageDrawable(drawable)原型如下:

  public void setImageDrawable(Drawable drawable) {

        if (mDrawable != drawable) {

            mResource = 0;

            mUri = null;

/*************************************************************************************************************/

/*到此,都只是将包含有动画的Drawable设置进去,那么经过什么样的处理之后才获得其包含的animation-list的?

  因为,在 updateAnim()中,需要 getDrawable(),然后根据这个drawable是否是AnimationDrawable才决定动画与否 */

/*************************************************************************************************************/

            updateDrawable(drawable);

            requestLayout();

            invalidate();

        }

    }

看看以下函数:

private void updateDrawable(Drawable d) {

        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()作用:

  public final boolean setLevel(int level) {

        if (mLevel != level) {

            mLevel = level;

            return onLevelChange(level);

        }

        return false;

    }

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

 protected boolean onLevelChange(int level) {

        int idx = mLevelListState.indexOfLevel(level);

        if (selectDrawable(idx)) {

            return true;

        }

        return super.onLevelChange(level);

    }

来看看OnlevelChanged()中的语句:

int idx = mLevelListState.indexOfLevel(level);

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

selectDrawable(idx);选中这个drawable Item并将其设置为current drawable

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

public boolean selectDrawable(int idx)

    {

        if (idx == mCurIndex) {

            return false;

        }

        if (idx >= 0 && idx < mDrawableContainerState.mNumChildren) {

            Drawable d = 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();

        return true;

    }

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值