android4.0 statusbar加載icon

StatusBar分為兩個部分:一是通常在手機界面最上端的未下拉的statusbar;二是下拉狀態欄,也就是擴展狀態欄。

通過在實際應用中,我們可以發現,statusbar就是一個activity,那麼,它的使用自然少不瞭和service之間的交互。

PhoneStatusBar 通過IStatusBarService來訪問StatusBarManagerService,而

StatusBarManagerService通過CommandQueue來和PhoneStatusBar進行交互。

一、StatusBar.java

通過class StatusBar的聲明,我們可以看出,它或者其子類實現和StatusBarManagerService進行交互的CommandQueue的回調方法。

public abstract class StatusBar extends SystemUI implements CommandQueue.Callbacks {

public void start() {

View sb = makeStatusBarView();

//創建包括在config.xml中定義要在statusbar上顯示的所有icons,那麼它包含icons個數在何處初始化?

        StatusBarIconList iconList = new StatusBarIconList();

//保存Notification是以Binder為key的

        ArrayList<IBinder> notificationKeys = new ArrayList<IBinder>();

//保存在statusbar上顯示的StatusBarNotification

        ArrayList<StatusBarNotification> notifications = new ArrayList<StatusBarNotification>();

        //和IStatusBarService進行交互的IBinder

mCommandQueue = new CommandQueue(this, iconList);

//獲取StatusBarManagerService的本地實現

        mBarService = IStatusBarService.Stub.asInterface(

                ServiceManager.getService(Context.STATUS_BAR_SERVICE));

        int[] switches = new int[7];

        ArrayList<IBinder> binders = new ArrayList<IBinder>();

        try {

//這一步實際上就是將PhoneStatusBar的實現的CommandQueue其中包含

//callbacks傳遞給StatusbarManagerService使用

            mBarService.registerStatusBar(mCommandQueue,

iconList, notificationKeys, notifications,

                    switches, binders);

        } catch (RemoteException ex) {

            // If the system process isn't there we're doomed anyway.

        }

for (int i=0; i<N; i++) {

   //這裡第一次使用時icon僅僅是開辟一個存儲空間,i代表的是數組的index,而viewIndex和i對應

       StatusBarIcon icon = iconList.getIcon(i);

       if (icon != null) {

           addIcon①(iconList.getSlot(i), i, viewIndex, icon);

           viewIndex++;

       }

}

N = notificationKeys.size();

if (N == notifications.size()) {

    for (int i=0; i<N; i++) {

          addNotification②(notificationKeys.get(i), notifications.get(i));

    }

} else {

           

}

//xml文件中定義的statusbar的height

final int height = getStatusBarHeight();

}

//這裡將所有的狀態欄上的view先初始化

WindowManagerImpl.getDefault().addView(sb, lp);

}

二、PhoneStatusBar.java

public class PhoneStatusBar extends StatusBar {

}

PhoneStatusBar 是StatusBar(extends SystemUI)的子類,真正和StatusBarManagerService交互的實際上就是它。

對於SystemUI,首先啟動的是Start();

public void start() {

……

//調用StatusBar 的start方法,建立和StatusbarManagerService之間的聯系

super.start();//在StatusBar的start中實現makeStatusBarView然後初始化statusbar icon狀態

//啟動更新Icon的方法

mIconPolicy = new PhoneStatusBarPolicy(mContext);

}

super.start()中我們看到,StatusBar是一個abstract類,真正要建立View是不能夠的,必須在子類中創建。

實際上,StatusBar中也這樣定義protected abstract View makeStatusBarView()

PhoneStatusBar 中:

protected View makeStatusBarView() {

final Context context = mContext;

Resources res = context.getResources();

//定義Icon的大小,縮放率和彼此間距

loadDimens();

mIconSize =                                                                 

res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_icon_size);

//狀態欄下拉時的view

ExpandedView expanded = (ExpandedView)View.inflate(context,

                R.layout.status_bar_expanded, null);

//真正顯示的statusbar是根據是否是雙卡來選擇xml文件

PhoneStatusBarView sb;

if (TelephonyManager.getDefault().isMultiSimEnabled()) {

    sb = (PhoneStatusBarView)View.inflate(context,

                    R.layout.msim_status_bar, null);

} else {

    sb = (PhoneStatusBarView)View.inflate(context,

                    R.layout.status_bar, null);

}

//獲取statusbar的實例

sb.mService = this;

mStatusBarView = sb;

//顯示statusbar icon的view

mStatusIcons = (LinearLayout)sb.findViewById(R.id.statusIcons);

//顯示notification的view

mNotificationIcons = (IconMerger)sb.findViewById(R.id.notificationIcons);

mMoreIcon = sb.findViewById(R.id.moreIcon);

//定義下拉狀態欄,顯示Notifications

mExpandedDialog = new ExpandedDialog(context);

/*這個expanded就是指layout下的status_bar_expanded.xml解析所得下拉狀態欄*/

        mExpandedView = expanded;

//顯示Notification的控件,NotificationRowLayout是處理函數,

        mPile = (NotificationRowLayout)expanded.findViewById(R.id.latestItems);

        mExpandedContents = mPile; // was: expanded.findViewById(R.id.notificationLinearLayout);

        //android2.3中顯示onGoing等信息的textview,android4.0已經不用瞭

mNoNotificationsTitle = (TextView)expanded.findViewById(R.id.noNotificationsTitle);

        mNoNotificationsTitle.setVisibility(View.GONE);

……

}

在步驟一的函數start()中的標識①處調用的是PhoneStatusBar的函數,在那裡初始化status bar icon,

前面說瞭,在registerStatusBar時獲得的iconList是沒有icon的

  public void addIcon(String slot, int index, int viewIndex, StatusBarIcon icon) {

//依據config.xml中的config_statusBarIcons定義的字符串創建StatusBarIconView,註意

//mContext是PhoneStatusBar的mContext

        StatusBarIconView view = new StatusBarIconView(mContext, slot, null);

//設置顯示的icon

        view.set(icon);

//添加到msim_status_bar.xml的保存icon的view中去

        if (FeatureQuery.FEATURE_ANNUCIATOR_NEW_STATUSBAR_STYLE) {

            mStatusIcons.addView(view, viewIndex,

new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, mIconSize));

        } else {

            mStatusIcons.addView(view, viewIndex,

new LinearLayout.LayoutParams(mIconSize, mIconSize));

        }

}

在PhoneStatusBar.java中用到下面這兩個類

StatusBarIconsView.java

public class StatusBarIconView extends AnimatedImageView

public StatusBarIconView(Context context, String slot, Notification notification) {

final Resources res = context.getResources();

mSlot = slot;

mNumberPain = new Paint();

         mNumberPain.setTextAlign(Paint.Align.CENTER);

         mNumberPain.setColor(res.getColor(R.drawable.notification_number_text_color));

         mNumberPain.setAntiAlias(true);

         mNotification = notification;

……

setScaleType(ImageView.ScaleType.CENTER);

}

}

由class的聲明可以看出,StatusBarIconView 是一個AnimatedImageView,因此,可以顯示icon

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;

//將icon信息拷貝給mIcon

        mIcon = icon.clone();

if (!iconEquals) {

       Drawable drawable = getIcon(icon);

       if (drawable == null) {

                return false;

        }

//下面兩步就是獲取drawable,然後設置到view中去

        setImageDrawable(drawable);

 }

}

private Drawable getIcon(StatusBarIcon icon) {

//我們在PhoneStatusBar中創建StatusBarIconView時傳瞭mContext,因此這裡getContext()

//也是PhoneStatusBar的

        return getIcon(getContext(), icon);

}

public static Drawable getIcon(Context context, StatusBarIcon icon) {

……

try {

 //獲取icon

     return r.getDrawable(icon.iconId);

} catch (RuntimeException e) {

           

}

return null;

}

隻有在下面這個類中才正式顯示icon在statusbar上

PhoneStatusBarPolicy.java

Context是PhoneStatusBar的mContext

public PhoneStatusBarPolicy(Context context) {

//StatusBarManagerService

mService = (StatusBarManager)context.getSystemService(Context.STATUS_BAR_SERVICE);

mStorageManager = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE);

mStorageManager.registerListener(

       new com.android.systemui.usb.StorageNotification(context));

// TTY status

mService.setIcon("tty",  R.drawable.stat_sys_tty_mode, 0, null);

// Alarm clock

        mService.setIcon("alarm_clock", R.drawable.stat_sys_alarm, 0, null);

        mService.setIconVisibility("alarm_clock", false);

// volume

        mService.setIcon("volume", R.drawable.stat_sys_ringer_silent, 0, null);

        mService.setIconVisibility("volume", false);

        updateVolume();

//headset

mService.setIcon("headset", com.android.internal.R.drawable.stat_sys_headset, 0, null);

        mService.setIconVisibility("headset", false);

}

上面的mService是StatusBarManager,那麼setIcon是操作如下:

StatusBarManager.java

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

        try {

//StatusBarManagerService的本地代理service

            final IStatusBarService svc = getService();

            if (svc != null) {

                svc.setIcon(slot, mContext.getPackageName(), iconId, iconLevel,

                    contentDescription);

            }

        } catch (RemoteException ex) {

            // system process is dead anyway.

            throw new RuntimeException(ex);

        }

}

三、StatusBarManagerService.java

前面,我們啟動PhoneStatusBar時會調用StatusBar的start函數,在這裡和StatusbarManagerService

建立聯系。

StatusBar.java中

mBarService.registerStatusBar(mCommandQueue, iconList, notificationKeys, notifications,

                    switches, binders);

public class StatusBarManagerService extends IStatusBarService.Stub

    implements WindowManagerService.OnHardKeyboardStatusChangeListener

{

public StatusBarManagerService(Context context, WindowManagerService windowManager) {

         mContext = context;

         mWindowManager = windowManager;

         mWindowManager.setOnHardKeyboardStatusChangeListener(this);

         final Resources res = context.getResources();

//這裡,獲取config_statusBarIcons.xm中定義的顯示icon的數組

    mIcons.defineSlots(res.

getStringArray(com.android.internal.R.array.config_statusBarIcons));

       }

}

public void registerStatusBar(IStatusBar bar, StatusBarIconList iconList,

            List<IBinder> notificationKeys, List<StatusBarNotification> notifications,

            int switches[], List<IBinder> binders) {

//這個bar就是CommandQueue在PhoneStatusbar中的實現callbacks

mBar = bar;

synchronized (mIcons) {

//將初始化這個service時獲取的config_statusBarIcons數組中字符串保存到iconList,

//也就是傳遞給PhoneStatusBar使用瞭

    iconList.copyFrom(mIcons);

}

synchronized (mNotifications) {

    for (Map.Entry<IBinder,StatusBarNotification> e: mNotifications.entrySet()) {

         notificationKeys.add(e.getKey());

         notifications.add(e.getValue());

    }

 }

……

}

public void setIcon(String slot, String iconPackage, int iconId, int iconLevel,

            String contentDescription) {

        enforceStatusBar();

        synchronized (mIcons) {

//也就是當前這個slot在數組中的index

            int index = mIcons.getSlotIndex(slot);

//如果沒有定義的slot,就報異常

            if (index < 0) {

                throw new SecurityException("invalid status bar icon slot: " + slot);

            }

//這才正式創建StatusBarIcon,iconPackage是PhoneStatusBar的,iconId就是我們設置的

            StatusBarIcon icon = new StatusBarIcon(iconPackage, iconId, iconLevel, 0,

                    contentDescription);

//數組中對應的index設置瞭icon

            mIcons.setIcon(index, icon);

            if (mBar != null) {

                try {

                    mBar.setIcon(index, icon);

                } catch (RemoteException ex) {

                }

            }

        }

}

CommandQueue.java

 public void setIcon(int index, StatusBarIcon icon) {

        synchronized (mList) {

//mList用的也是StatusBarManagerService中初始化的iconList

            int what = MSG_ICON | index;

            mHandler.removeMessages(what);

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

        }

 }

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;

//mList

                    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);  www.aiwalls.com

                        mCallbacks.updateIcon(mList.getSlot(index), index, viewIndex,

                                        old, icon);

                    }

               break;
作者:kakaBack

         }

}

}

最後就是調用PhoneStatusBar的addIcon。至此,就用StatusBar顯示瞭icon

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *