zoukankan      html  css  js  c++  java
  • android systemUI--Notification 整理

    PendingIntent

    Intent是一个意图,一个描述了想要启动一个Activity、Broadcast或是Service的意图。它主要持有的信息是它想要启动的组件(Activity、Broadcast或是Service)。

            PendingIntent可以看作是对Intent的包装。供当前App之外的其他App调用。有点“被动”或是“Callback”的意思,但不是严格意义上的“被动”或是“Callback”。总之,当前App不能用它马上启动它所包裹的Intent。而是在外部App执行这个PendingIntent时,间接地、实际地调用里面的Intent。PendingIntent主要持有的信息是它所包装的Intent和当前App的Context。正由于PendingIntent中保存有当前App的Context,使它赋予外部App一种能力,使得外部App可以如同当前App一样的执行PendingIntent里的Intent,就算在执行时当前App已经不存在了,也能通过存在PendingIntent里的Context照样执行Intent。

    参考:http://www.eoeandroid.com/thread-96512-1-1.html

    NotificationManager

    源码位置:framework/base/core/java/android/app/NotificationManager.java

    enuqunotificationwithtag

    功能:

    负责“发出”与“取消”  Notification。

    方法:

    notify();

    cancel();

    INotificationManager.Java

    frameworks/base/services/java/com/android/server/ NotificationManagerService.java

    Notification

    SystemServer.java

    StatusBarManagerService.java(初始化)

    NotificationManagerService.java(statusBarManagerService.setNotificationCallBack)

    [systemreadly]

    SystemUIService.java----onCreate(); --- for(  SystemUI.start() )

    StatusBar.java --- start() -- registerStatusBar();

    mandQueue.java 通过handler更新ui

    ./base/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java()

    nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);

            n = new Notification();

            n.flags = Notification.FLAG_ONGOING_EVENT;

            n.icon = R.drawable.notify;

            n.tickerText = "一个通知";

            n.when = System.currentTimeMillis();

    nm.notify(id,n);

     

    开机

    SystemServer

    StatusBarManagerService

    NotificationManagerService

    SystemUIService

    PhoneStatusBar

    CommandQueue

    NotificationManager

     

    发起Notification

    开机

    启动过程

    通知更新

    绑定Statusbar

    通知有Notification需要更新

    通知更新ui

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

    (frameworksasecorejavacomandroidinternalstatusbar)

    //保存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

     (frameworksasecore es esvalues)

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

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

                                            old, icon);

                        }

                   break;

             }

    }

    }

    最后就是调用PhoneStatusBar的addIcon。至此,就用StatusBar显示了icon

  • 相关阅读:
    CCCC 2020 酱油记
    CCPC 2020 威海 滚粗记
    IEEExtreme 2020 酱油记
    CCSP 2020 酱油记
    ICPC 陕西省赛 2020 游记
    CCPC 网络赛 2020 自闭记
    CSP 第20次认证 酱油记
    CSP-S 2019 酱油记
    NOI2019 退役记
    树链剖分入门
  • 原文地址:https://www.cnblogs.com/senior-engineer/p/4844552.html
Copyright © 2011-2022 走看看