自作者是什么从家徒四壁到负债累累的

 
故事要怎么说呢?就从一伍年十月始于说吧。今年本人刚刚正式结业,然后就去了母校领毕业证,传说正是在此刻起始的。 
                 
领达成束学业证的笔者对将要做的事未有丝毫安插,对前途一片迷茫,笔者要怎么?小编会干什么?小编不通晓!自己学的正经是机电1体化,工作是好找,但关于那么些行业本身心坎是打心里里争持的,为何呢?在实习时期作者同多少个大学校友去了一家机械厂,里面什么情况就不多描述了,因为是实习期薪水不高,我们也不是很注意,能解决温饱就行,当时就是那般想的,后来厂里相比较缺人,于是我们就代表各个地点,早上换班休息1人要干多人的活,说实话真的好累呦。后来在那里呆了半年就呆不住了,立刻临近度岁我就去职回家了,他们跟本身壹样走了多少个,剩下的想再坚贞不屈一下,笔者未曾劝他们什么的,人各有志,也许喜欢安静平静的生存模式啊,但本人正是受持续那种叁点一线的生活,感觉自个儿便是机器人1样,也不知道她们将来怎么了。 
                                               
在家过了年,又要思考找工作的事了,但又不清楚能做怎么着,苦思苦想也没着落,作者爸看不下去了,就让作者去自个儿三姑哪个地方做政工,叁个月三千,作者姑是我们县里的三个品牌的经销商,就好像此在笔者姑那里呆了7个月多,因为是自小编亲姑嘛,我的工钱各样月都会多500,而且人家还不知晓,每一趟发笔者工钱的时候都以人家都下班了走了,笔者婆婆把本身留到最后,伸手叫住自个儿,“来,博儿”,然后手里拿着1打钞票给自个儿,并且再嘱咐一句“别都给你妈,本身留点花”,因为是吃住都在家里,所以薪水必须交纳,没得协商,后来跟笔者妈协商过各种月留500块零钱,我妈是不知情2500的事的,这样作者每一个月都有一千块的零用钱,天天中午玖点到地点,露个脸,意思是自家来了,然后骑上自作者那吱吱呀呀的电高铁跑市镇,县城能有多大?再说小编个人比较新鲜,嗯(⊙_⊙)正是超过常规规,所以本身的天职很轻,壹晚上就ok了,中午吃个饭,然后一早晨泡在网吧了打lol,dnf,5点一到一向回家,第二个月小编很拼命干活的,表明自身是实用的,每日回去报个到,后来皮了,一到5点一向的走向回家的路,回家继续玩^O^。嘻滋滋又欢腾的活着,但自身晓得那毫无自身想要的生活,那样的生存平静安逸跟在此以前在工厂里其实大概,固然小编不通晓本身想要的,但作者驾驭四个男孩毕竟要成为娃他爹的,究竟要独立,顶天立地的,既然早晚的事,不比提前好了。

流程图

图片 1

Notification_seq_diagram.jpg

最后

a pic is worth a thousands words,   tow pics worth double, lol

答案

contentView固定高度

expanded.setContractedChild主意前,传递进入的ContentView都还是自义定的view,未有做中度限制或许系统私下认可的view.
最终展现的时候却被限定了,说明在setContractedChild方法里做了手脚

public void setContractedChild(View child) {
    ...
    sanitizeContractedLayoutParams(child);
    addView(child);
    ...
}

private void sanitizeContractedLayoutParams(View contractedChild) {
    LayoutParams lp = (LayoutParams) contractedChild.getLayoutParams();
    lp.height = mSmallHeight;
    contractedChild.setLayoutParams(lp);
}

能够看出在sanitizeContractedLayoutParams艺术里面,不论传递进入的contentView有多高最后的会被改成mSmallHeight的高度。这些mSmallHeight的值就是在SystemUI里面配置的,64dp

BaseStatusBar

frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java

@Override
public void onNotificationPosted(final StatusBarNotification sbn,
        final RankingMap rankingMap) {
    mHandler.post(new Runnable() {
        @Override
        public void run() {
             ...
             boolean isUpdate = mNotificationData.get(sbn.getKey()) != null
                            || isHeadsUp(sbn.getKey());
             ...
            if (isUpdate) {
                updateNotification(sbn, rankingMap);
            } else {
                addNotification(sbn, rankingMap);
            }
        }
    });
}

状态栏会依照通告的唯壹key值来判断该通告是还是不是是更新还是新增的。
咱俩以新增的为例来讲.addNotification是多个虚无方法,达成是在BaseStatusBar的子类PhoneStatusBar

bigview最大中度

expanded.setExpandedChild的秘诀里面却从未做最大惊人的限制,那么最大惊人是在哪限制的吗?
以此时候就要看看ExpandableNotificationRow这一个根view了
ExpandableNotificationRow继承自ExpandableView,来看看onMeasure方法

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    //mMaxNotificationHeight是systemui中配置的值,256dp
    int ownMaxHeight = mMaxNotificationHeight;
    ...
    for (int i = 0; i < childCount; i++) {
        View child = getChildAt(i);
        int childHeightSpec = newHeightSpec;
        ViewGroup.LayoutParams layoutParams = child.getLayoutParams();
        if (layoutParams.height != ViewGroup.LayoutParams.MATCH_PARENT) {
            if (layoutParams.height >= 0) {
                // An actual height is set
                childHeightSpec = layoutParams.height > ownMaxHeight
                    ? MeasureSpec.makeMeasureSpec(ownMaxHeight, MeasureSpec.EXACTLY)
                    : MeasureSpec.makeMeasureSpec(layoutParams.height, MeasureSpec.EXACTLY);
            }
            child.measure(
                    getChildMeasureSpec(widthMeasureSpec, 0 /* padding */, layoutParams.width),
                    childHeightSpec);
            int childHeight = child.getMeasuredHeight();
            maxChildHeight = Math.max(maxChildHeight, childHeight);
        } else {
            mMatchParentViews.add(child);
        }
    }
    int ownHeight = hasFixedHeight ? ownMaxHeight : maxChildHeight;
    newHeightSpec = MeasureSpec.makeMeasureSpec(ownHeight, MeasureSpec.EXACTLY);
    for (View child : mMatchParentViews) {
        child.measure(getChildMeasureSpec(
                widthMeasureSpec, 0 /* padding */, child.getLayoutParams().width),
                newHeightSpec);
    }
   ...

如果bigviewlayoutParams.height == ViewGroup.LayoutParams.MATCH_PARENT则中度便是newHeightSpec。这么些newHeightSpec要么是own马克斯Height
要么是maxChildHeight,而那三个值的最大值正是25陆dp
如果bigviewlayoutParams.height != ViewGroup.LayoutParams.MATCH_PARENT,最大值也是maxChildHeight
也正是25陆dp

注意:
那里并不曾呈现bigview的极小高度,所以bigview的万丈范围是能够在(0,25六dp
] 区间的

INotificationListener

notifyPostedLocked方法最后调用notifyPosted方法,我们一贯来看望该办法

private void notifyPosted(final ManagedServiceInfo info,
    final StatusBarNotification sbn, NotificationRankingUpdate rankingUpdate) {
    final INotificationListener listener = (INotificationListener)info.service;
    ...
    listener.onNotificationPosted(sbnHolder, rankingUpdate);
    ...
}

那边有一个INotificationListener对象,壹看到以I始发的就足以领略,这里一定又是三个IPC通讯。
查看源码能够知晓,onNotificationPosted的达成是在SystemUI进度中,也正是我们的地方栏进度。

NotificationManagerService

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

public void enqueueNotificationWithTag(String pkg, String opPkg, String tag, int id,
        Notification notification, int[] idOut, int userId) throws RemoteException {
    enqueueNotificationInternal(pkg, opPkg, Binder.getCallingUid(),
            Binder.getCallingPid(), tag, id, notification, idOut, userId);
}

从而最首要的是enqueueNotificationInternal方法

void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid,
        final int callingPid, final String tag, final int id, final Notification notification,
        int[] idOut, int incomingUserId) {
    ...

    if (!isSystemNotification && !isNotificationFromListener) {
        ...
        //MAX_PACKAGE_NOTIFICATIONS = 50;
        if (count >= MAX_PACKAGE_NOTIFICATIONS) {
            return;
        }
    }

    ...

    mHandler.post(new Runnable() {
        @Override
        public void run() {
            synchronized (mNotificationList) {
                ...
                // blocked apps
                //如果用户设置了该引用不显示通知,并且不是系统通知的话,直接将该通知打分为-1000
                if (ENABLE_BLOCKED_NOTIFICATIONS && !noteNotificationOp(pkg, callingUid)) {
                    if (!isSystemNotification) {
                        //JUNK_SCORE = -1000;
                        r.score = JUNK_SCORE;
                    }
                }

                //SCORE_DISPLAY_THRESHOLD = -20;
                //打分小于阈值的通知不显示
                if (r.score < SCORE_DISPLAY_THRESHOLD) {
                    // Notification will be blocked because the score is too low.
                    return;
                }

                //垃圾通知,也不会显示
                if (isNotificationSpam(notification, pkg)) {
                    mArchive.record(r.sbn);
                    return;
                }

                ...
                //只显示有图标的通知
                if (notification.icon != 0) {
                    StatusBarNotification oldSbn = (old != null) ? old.sbn : null;
                    mListeners.notifyPostedLocked(n, oldSbn);
                }
                ...
                //声音,震动,闪光灯的控制
                buzzBeepBlinkLocked(r);
            }
        }
    });
}

能够见见要想产生公告必须得满足以下多少个标准

  1. 非系统采用,最四只好发送四拾柒个关照音信
  2. 用户设置了允许使用发送公告
  3. 被系统判定为非垃圾通知(该意义是cm本人丰硕的,系统中会有四个数据库,然后依据通知栏的Extra音信来协作,假诺成功则判定为垃圾布告,可是该功用今后并未完结)
  4. 照会必须得有icon

反省通过后再利用notifyPostedLocked措施做实在的出殡和埋葬动作。buzzBeepBlink洛克d很简短,不浪费篇幅讲述了。

概述

前文教学了Notification的协会,今后来讲讲notification的出殡,以及发布前文留下的疑点(自定义view不论中度是多高,最后只得展现为6肆dp,why?)

连锁阅读

Notification之—NotificationListener瑟维斯五.0达成原理
Notification之—-Android五.0落到实处原理(一)
Notification之—-自定义样式
Notification之—-私下认可样式
Notification之—-任务栈

PhoneStatusBar

frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java

public void addNotification(StatusBarNotification notification, RankingMap ranking) {
    ...
    Entry shadeEntry = createNotificationViews(notification);
    if (shadeEntry == null) {
        return;
    }
    ...
    addNotificationViews(shadeEntry, ranking);
    ...
}

该办法做了二个基本点的事体,三个便是创设Entry实例,其它四个便是将Entry添加到状态栏上,然后就显得成功了。
因为createNotificationViews的落到实处是在父类中,并且该方式丰富第三,所以大家先跳过该方法。
先把Entry精通成一条通告,来讲addNotificationViews的落到实处。

protected void addNotificationViews(Entry entry, RankingMap ranking) {
     if (entry == null) {
         return;
     }
     // Add the expanded view and icon.
    mNotificationData.add(entry, ranking);
    updateNotifications();
}

先直接将取得的Entry添加到mNotificationData里面
最终updateNotifications会调用PhoneStatusBar中的updateNotificationShade方法

private void updateNotificationShade() {
    ...
    ArrayList<Entry> activeNotifications = mNotificationData.getActiveNotifications();
    ArrayList<ExpandableNotificationRow> toShow = new ArrayList<>(activeNotifications.size());
    ...
    for (int i=0; i<N; i++) {
       Entry ent = activeNotifications.get(i);
       ...
       toShow.add(ent.row);
    }

    for (int i=0; i<toShow.size(); i++) {
            View v = toShow.get(i);
            if (v.getParent() == null) {
                mStackScroller.addView(v);
            }
    }
    ...
}
  1. 从mNotificationData对象中收获一个list<Entry>对象
  2. 将mNotificationData中的每贰个Entry对象的row属性添加到List<ExpandableNotificationRow>中
  3. 将ExpandableNotificationRow添加到mStackScroller里面

本条mStackScroller是NotificationStackScrollLayout的对象,而以此NotificationStackScrollLayout是2个无冕自ViewGroup的,也正是大家下拉状态栏看到的整片view的根view.
那么ExpandableNotificationRow也便是对应着每3个通报了.
ExpandableNotificationRow是延续自FrameLayout的

大家前面聊到把Entry先精晓为一条通告,看到此间,其实添加的是Entry对象里面包车型客车row属性到界面上,也就是ExpandableNotificationRow

类图

图片 2

Notification_class_diagram.jpg

createNotificationViews

其1是解答开端疑问的最首要。 该办法是BaseStatusBar类的艺术。

protected NotificationData.Entry createNotificationViews(StatusBarNotification sbn) {
    ...
    // Construct the expanded view.
    NotificationData.Entry entry = new NotificationData.Entry(sbn, iconView);
    if (!inflateViews(entry, mStackScroller)) {
        handleNotificationError(sbn, "Couldn't expand RemoteViews for: " + sbn);
        return null;
    }
    return entry;
}

此处首先实例化了NotificationData的中间类Entry。
NotificationData是多个要命至关心注重要的类,里面有几个相比较根本的数据结构
<pre>
ArrayMap<String, Entry> mEntries = new ArrayMap<>();
//所有Entry的集合
ArrayList<Entry> mSortedAndFiltered = new ArrayList<>();
//排序后的Entry集合
</pre>
那那几个Entry到底是个什么样东西啊?先来探望那几个类的定义

public static final class Entry {
       ...
       public ExpandableNotificationRow row; // the outer expanded view
       public View expanded; // the inflated RemoteViews
       public View expandedPublic; // for insecure lockscreens
       public View expandedBig;
       ...
 }

从概念里面能够看到,一个Entry对应了一条文告栏的保有Data音信,在那之中相比主要的是row属性,后边已经碰着过了。最后添加界面上的也正是那么些row。
inflateViews方法里面,那些row会被赋值,大家来看看row是怎么被赋值的

private boolean inflateViews(NotificationData.Entry entry, ViewGroup parent, boolean isHeadsUp) {
    ...
    //contentView和bigContentView是我们构造Notification时传过来的view
    RemoteViews contentView = sbn.getNotification().contentView;
    RemoteViews bigContentView = sbn.getNotification().bigContentView;
    ...
    ExpandableNotificationRow row;
    ...
    //使用指定view填充
    row = (ExpandableNotificationRow) inflater.inflate(R.layout.status_bar_notification_row,
                    parent, false);
    ...
    //这个expanded view就是我们在下拉状态栏中看到的每一条view,这里命名为expanded 应该是状态栏展开,而不是通知展开
    //NotificationContentView是继承自FrameLayout的,会根据不同状态来控制显示哪个view(默认通知/展开通知)
    NotificationContentView expanded =
                (NotificationContentView) row.findViewById(R.id.expanded);
    ...

    //给每一条通知设置onClick的点击事件,以来相应我们设置的动作.
    PendingIntent contentIntent = sbn.getNotification().contentIntent;
    final View.OnClickListener listener = makeClicker(contentIntent, sbn.getKey(),
                    isHeadsUp);
    row.setOnClickListener(listener);
    ...

    ///////关键////////////
    View contentViewLocal = null;
    View bigContentViewLocal = null;
    //将构造通知栏时设置的contentView & bigContentView(RemoteView)转换为view
    contentViewLocal = contentView.apply(mContext, expanded,
                    mOnClickHandler, themePackageName);
    if (bigContentView != null) {
       bigContentViewLocal = bigContentView.apply(mContext, expanded,
                          mOnClickHandler, themePackageName);
    }
    ...
    //因为expanded 是一个FrameLayout的ViewGroup,所以往里面塞了2个view
    expanded.setContractedChild(contentViewLocal);
    expanded.setExpandedChild(bigContentViewLocal);
}

看完上边的代码,先来坐个小节,整理下思路。在Entry.row添加到显示屏上前,做了如下的习性赋值

  1. inflate布局文件status_bar_notification_row(那是各样文告栏的根view)
  2. 给根view设置监听器
  3. 将在结构文告进度中的bigContentView 和 contentView
    塞到通知栏的根view里面

到那里,一个文告栏从早先化到展示的流水线就讲完了,不过最开始的疑问不是还尚无解答吗?来看答案

NotificationManager

在Notification构造实现后,会调用NotificationManager的notify办法来发送公告,大家就来探望该方法
frameworks/base/core/java/android/app/NotificationManager.java

public void notify(String tag, int id, Notification notification)
{
    ...
    INotificationManager service = getService();
    ...
    service.enqueueNotificationWithTag(pkg, mContext.getOpPackageName(), tag, id,
        stripped, idOut, UserHandle.myUserId());
    ...
}

能够看出NotificationManager只是叁个空壳,未有做什么样实际的事情,只是把notify的动作交给了service来做。
为了主干的明领悟白,直接给出enqueueNotificationWithTag的达成在NotificationManagerService中

相关文章

发表评论

电子邮件地址不会被公开。 必填项已用*标注

*
*
Website