赞
踩
目录
源码路径:frameworks/base/packages/SystemUI/
安装路径:system/priv-app/-SystemUI
SystemUI是以apk的形势在Android系统中存在的
1.Status bars(状态栏):通知消息提示和状态展示
2.Notification(通知面板):展示系统或应用的通知内容,提供快速系统设置开关
3.Navigation bars(导航栏):返回,HOME,Recent
4.KeyGuard(键盘锁):锁屏模块
5.Recents 近期应用管理,以堆叠的形式展示
6.ScreenShot (截屏):长按电源键+音量下键后截屏,用以展示截取的屏幕照片/内容
7.VolumeUI 展示或控制音量的变化:媒体、铃音、通知、通话音量
8.PowerUI 主要处理和Power相关的事件
9.RingtonePlayer 铃音播放
10.StackDivider 控制管理分屏
启动分析
首选调用com.android.systemui.SystemBars的start方法
frameworks/base/packages/SystemUI/src/com/android/systemui/SystemBars.java
- @Override
- 40 public void start() {
- 41 if (DEBUG) Log.d(TAG, "start");
- 42 createStatusBarFromConfig();
- 43 }
-
-
- private void createStatusBarFromConfig() {
- 53 if (DEBUG) Log.d(TAG, "createStatusBarFromConfig");
- //取出className
- 54 final String clsName = mContext.getString(R.string.config_statusBarComponent);
- 55 if (clsName == null || clsName.length() == 0) {
- 56 throw andLog("No status bar component configured", null);
- 57 }
- // 通过反射获取该对象
- 58 Class<?> cls = null;
- 59 try {
- 60 cls = mContext.getClassLoader().loadClass(clsName);
- 61 } catch (Throwable t) {
- 62 throw andLog("Error loading status bar component: " + clsName, t);
- 63 }
- 64 try {
- 65 mStatusBar = (SystemUI) cls.newInstance();
- 66 } catch (Throwable t) {
- 67 throw andLog("Error creating status bar component: " + clsName, t);
- 68 }
- //填充信息并启动 StatusBar start() 方法
- 69 mStatusBar.mContext = mContext;
- 70 mStatusBar.mComponents = mComponents;
- 71 mStatusBar.start();
- 72 if (DEBUG) Log.d(TAG, "started " + mStatusBar.getClass().getSimpleName());
- 73 }
主要是通过反射获取config_statusBarComponent
中定义的对象,并启动该对象的start方法。config_statusBarComponent
的值有3种,默认是phone布局,另外两个是tv和car。
接下来是StautsBar中的start方法
frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
着重看下start中的createAndAddWindows方法,在此之前先了解下状态栏的显示信息
状态栏显示
需要显示的信息分为以下5种:
继续了解createAndAddWindows
- public void createAndAddWindows() {
- addStatusBarWindow();
- }
-
- private void addStatusBarWindow() {
- //创建状态栏的控件树
- makeStatusBarView();
- mStatusBarWindowManager = Dependency.get(StatusBarWindowManager.class);
- mRemoteInputController = new RemoteInputController(mHeadsUpManager);
- //通过StatusBarWindowManager.add创建状态栏的窗口
- mStatusBarWindowManager.add(mStatusBarWindow, getStatusBarHeight());
- }
- /*
- *获取statusbar高度,在framework/base/core/res/res/values/diamens.xml中设置
- */
- public int getStatusBarHeight() {
- if (mNaturalBarHeight < 0) {
- final Resources res = mContext.getResources();
- mNaturalBarHeight =
- res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height);
- }
- return mNaturalBarHeight;
- }
-
- // ================================================================================
- // Constructing the view
- // ================================================================================
- protected void makeStatusBarView() {
- final Context context = mContext;
- //获取屏幕参数
- updateDisplaySize(); // populates mDisplayMetrics
- //更新Panels资源数据,statusbar包含很多panel,在创建PhoneStatusBarView时需要更新panel数据
- updateResources();
- updateTheme();
-
- inflateStatusBarWindow(context); //加载布局
- mStatusBarWindow.setService(this);
- mStatusBarWindow.setOnTouchListener(getStatusBarWindowTouchListener()); //mStatusBarWindow的点击事件
- Dependency.get(DarkIconDispatcher.class).addDarkReceiver(mNotificationIconAreaController);
- FragmentHostManager.get(mStatusBarWindow)
- .addTagListener(CollapsedStatusBarFragment.TAG, (tag, fragment) -> {
- CollapsedStatusBarFragment statusBarFragment =
- (CollapsedStatusBarFragment) fragment;
- statusBarFragment.initNotificationIconArea(mNotificationIconAreaController);
- mStatusBarView = (PhoneStatusBarView) fragment.getView();
- mStatusBarView.setBar(this);
- mStatusBarView.setPanel(mNotificationPanel);
- mStatusBarView.setScrimController(mScrimController);
- mStatusBarView.setBouncerShowing(mBouncerShowing);
- setAreThereNotifications();
- checkBarModes();
- }).getFragmentManager()
- .beginTransaction()
- .replace(R.id.status_bar_container, new CollapsedStatusBarFragment(),
- CollapsedStatusBarFragment.TAG) //替换为CollapsedStatusBarFragment
- .commit();
- mIconController = Dependency.get(StatusBarIconController.class);
- }
- /*
- *加载布局
- */
- protected void inflateStatusBarWindow(Context context) {
- mStatusBarWindow = (StatusBarWindowView) View.inflate(context,
- R.layout.super_status_bar, null);
- }
调用流程是createAndAddWindows——>addStatusBarWindow——>makeStatusBarView
- /**
- 87 * Adds the status bar view to the window manager.
- 88 *
- 89 * @param statusBarView The view to add.
- 90 * @param barHeight The height of the status bar in collapsed state.
- 91 */
- 92 public void add(View statusBarView, int barHeight) {
- 93
- 94 // Now that the status bar window encompasses the sliding panel and its
- 95 // translucent backdrop, the entire thing is made TRANSLUCENT and is
- 96 // hardware-accelerated.
- 97 mLp = new WindowManager.LayoutParams(
- 98 ViewGroup.LayoutParams.MATCH_PARENT,
- 99 barHeight,
- 100 WindowManager.LayoutParams.TYPE_STATUS_BAR,
- 101 WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
- 102 | WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING
- 103 | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
- 104 | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
- 105 | WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
- 106 PixelFormat.TRANSLUCENT);
- 107 mLp.token = new Binder();
- 108 mLp.gravity = Gravity.TOP;
- 109 mLp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
- 110 mLp.setTitle("StatusBar");
- 111 mLp.packageName = mContext.getPackageName();
- 112 mLp.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
- 113 mStatusBarView = statusBarView;
- 114 mBarHeight = barHeight;
- 115 mWindowManager.addView(mStatusBarView, mLp);
- 116 mLpChanged = new WindowManager.LayoutParams();
- 117 mLpChanged.copyFrom(mLp);
- 118 }
状态栏的高度是从frameworks/base/core/res/res/values/dimens.xml中获取的,默认为25dp。
TYPE_STATUS_BAR使得PhomeWindowManager为状态栏的窗口分配了较大的layer值,使其可以显示在其它应用窗口上。
FLAG_NOT_FOCUSABLE、FLAG_TOUCHABLE_WHEN_WAKING、FLAG_SPLIT_TOUCH
定义了输入事件的响应行为。另外当窗口创建后LayoutParams是会反生变化的。状态栏窗口创建时高度为25dip,flags描述为其不可接受按键事件。不过当用户按下状态栏导致卷帘下拉时,StatusBar会通过WindowManager.updateViewLayout()方法修改窗口的LayoutParams高度为match_parent,即充满整个屏幕使得卷帘可以满屏显示,并且移除FLAG_NOT_FOCUSABLE,使得StatusBar可以监听back按钮
状态栏控件树结构
不管是发出一个新的通知还是对已经存在的通知进行更新,调用的都是NotificationManager.notify(int id,Notification notification)。最后走到SystemUI的时候首先调用StatusBar中的成员变量mNotificationListener的onNotificationPosted(final StatusBarNotification sbn, final RankingMap rankingMap)方法。
- public void onNotificationPosted(final StatusBarNotification sbn,
- final RankingMap rankingMap) {
- if (sbn != null && !onPluginNotificationPosted(sbn, rankingMap)) {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- processForRemoteInput(sbn.getNotification());
- String key = sbn.getKey();
- mKeysKeptForRemoteInput.remove(key);
- boolean isUpdate = mNotificationData.get(key) != null;
- ......
- // Remove existing notification to avoid stale data.
- if (isUpdate) {
- removeNotification(key, rankingMap);
- } else {
- mNotificationData.updateRanking(rankingMap);
- }
- return;
- }
- try {
- if (isUpdate) {
- updateNotification(sbn, rankingMap);
- } else {
- addNotification(sbn, rankingMap);
- }
- } catch (InflationException e) {
- handleInflationException(sbn, e);
- }
- }
- });
- }
- }
首先来看方法中的两个参数:1.StatusBarNotification sbn;2.RankingMap rankingMap。
StatusBarNotification点进去看,发现其实是由Notification组装而成,里面比较重要的属性有String pkg,int id,String key,Notification notification,保存着通知的内容,发出通知的报名信息,以及id等。StatusBarNotification 具体的组装生成过程不是在SystemUI包中进行,暂不关注。
RankingMap则是NotificationListenerService的一个静态内部类,里面保存着所有Notification相关的信息。
boolean isUpdate = mNotificationData.get(sbn.getKey()) != null;
mNotificationData是StatusBar的一个protected成员变量,可被子类继承,自己本身的类是NotificationData,位于SystemUI工程下的com.android.systemui.statusbar
mNotificationData.get(key) 返回了Entry对象,是NotificationData的一个内部类。其中包含的几个重要的属性的属性:
- public String key;
- public StatusBarNotification notification;
- public NotificationChannel channel;
- public StatusBarIconView icon;
- public StatusBarIconView expandedIcon;
- public ExpandableNotificationRow row; // the outer expanded view
如果mNotificationData能通过sbn的key拿到的Entry不为空,说明这个通知已经存在了,isUpdate为true走更新流程,否则走添加流程。到此,onNotificationPosted方法就结束了
接着看添加流程addNotification(sbn, rankingMap)。
- public void addNotification(StatusBarNotification notification, RankingMap ranking)
- throws InflationException {
- String key = notification.getKey();
- mNotificationData.updateRanking(ranking);
- Entry shadeEntry = createNotificationViews(notification);
- boolean isHeadsUped = shouldPeek(shadeEntry);
- ......
- abortExistingInflation(key);
-
- mForegroundServiceController.addNotification(notification,
- mNotificationData.getImportance(key));
-
- mPendingNotifications.put(key, shadeEntry);
- }
首先通过传来的StatusBarNotification notification封装构造出一个Entry对象
Entry shadeEntry = createNotificationViews(notification);
跟过去看createNotificationViews(notification)方法,这里又跳回了StatusBar。
- protected NotificationData.Entry createNotificationViews(StatusBarNotification sbn)
- throws InflationException {
- NotificationData.Entry entry = new NotificationData.Entry(sbn);
- Dependency.get(LeakDetector.class).trackInstance(entry);
- entry.createIcons(mContext, sbn);
- // Construct the expanded view.
- inflateViews(entry, mStackScroller);
- return entry;
- }
inflateViews(entry, mStackScroller)。第二个参数mStackScroller,就是SystemUI中的下拉通知栏里面所有通知以及一些其他view的父view,是StatusBar中一个成员变量。
- protected void inflateViews(Entry entry, ViewGroup parent) {
- PackageManager pmUser = getPackageManagerForUser(mContext,
- entry.notification.getUser().getIdentifier());
-
- final StatusBarNotification sbn = entry.notification;
- if (entry.row != null) {
- entry.reset();
- updateNotification(entry, pmUser, sbn, entry.row);
- } else {
- new RowInflaterTask().inflate(mContext, parent, entry,
- row -> {
- bindRow(entry, pmUser, sbn, row);
- updateNotification(entry, pmUser, sbn, row);
- });
- }
-
- }
看RowInflaterTask().inflate方法,该方法在RowInflaterTask中
- public void inflate(Context context, ViewGroup parent, NotificationData.Entry entry,
- RowInflationFinishedListener listener) {
- mListener = listener;
- AsyncLayoutInflater inflater = new AsyncLayoutInflater(context);
- mEntry = entry;
- entry.setInflationTask(this);
- inflater.inflate(R.layout.status_bar_notification_row, parent, this);
- }
row(ExpandableNotificationRow)就是最终添加到通知栏上的通知对应的view,它的布局文件是R.layout.status_bar_notification_row。
AsyncLayoutInflater这个类是NotificationInflater的静态内部类,其中有方onAsyncInflationFinished如下
- public void onAsyncInflationFinished(NotificationData.Entry entry) {
- mRow.getEntry().onInflationTaskFinished();
- mRow.onNotificationUpdated();
- mCallback.onAsyncInflationFinished(mRow.getEntry());
- }
onAsyncInflationFinished的实现在StatusBar中
- public void onAsyncInflationFinished(Entry entry) {
- mPendingNotifications.remove(entry.key);
- // If there was an async task started after the removal, we don't want to add it back to
- // the list, otherwise we might get leaks.
- boolean isNew = mNotificationData.get(entry.key) == null;
- if (isNew && !entry.row.isRemoved()) {
- addEntry(entry);//重点
- } else if (!isNew && entry.row.hasLowPriorityStateUpdated()) {
- mVisualStabilityManager.onLowPriorityUpdated(entry);
- updateNotificationShade();
- }
- entry.row.setLowPriorityStateUpdated(false);
- }
addEntry是重点,如下
- private void addEntry(Entry shadeEntry) {
- boolean isHeadsUped = shouldPeek(shadeEntry);
- if (isHeadsUped) {
- mHeadsUpManager.showNotification(shadeEntry);
- // Mark as seen immediately
- setNotificationShown(shadeEntry.notification);
- }
- addNotificationViews(shadeEntry);//重点
- // Recalculate the position of the sliding windows and the titles.
- setAreThereNotifications();
- }
addNotificationViews的内容如下
- protected void addNotificationViews(Entry entry) {
- if (entry == null) {
- return;
- }
- // Add the expanded view and icon.
- mNotificationData.add(entry);
- updateNotifications();
- }
mNotificationData.add(entry);对应了前面分析的boolean isUpdate = mNotificationData.get(key) != null;
进入updateNotifications()方法,内容如下
- protected void updateNotifications() {
- mNotificationData.filterAndSort();
-
- updateNotificationShade();
- }
重点在updateNotificationShade()(可以在这个方法里进行修改达到想要的需求)
- private void updateNotificationShade() {
- if (mStackScroller == null) return;
-
- // Do not modify the notifications during collapse.
- if (isCollapsing()) {
- addPostCollapseAction(new Runnable() {
- @Override
- public void run() {
- updateNotificationShade();
- }
- });
- return;
- }
-
- ArrayList<Entry> activeNotifications = mNotificationData.getActiveNotifications();
- ArrayList<ExpandableNotificationRow> toShow = new ArrayList<>(activeNotifications.size());
- final int N = activeNotifications.size();
- for (int i=0; i<N; i++) {
- Entry ent = activeNotifications.get(i);
- if (ent.row.isDismissed() || ent.row.isRemoved()) {
- // we don't want to update removed notifications because they could
- // temporarily become children if they were isolated before.
- continue;
- }
- int userId = ent.notification.getUserId();
-
- // Display public version of the notification if we need to redact.
- boolean devicePublic = isLockscreenPublicMode(mCurrentUserId);
- boolean userPublic = devicePublic || isLockscreenPublicMode(userId);
- boolean needsRedaction = needsRedaction(ent);
- boolean sensitive = userPublic && needsRedaction;
- boolean deviceSensitive = devicePublic
- && !userAllowsPrivateNotificationsInPublic(mCurrentUserId);
- ent.row.setSensitive(sensitive, deviceSensitive);
- ent.row.setNeedsRedaction(needsRedaction);
- if (mGroupManager.isChildInGroupWithSummary(ent.row.getStatusBarNotification())) {
- ExpandableNotificationRow summary = mGroupManager.getGroupSummary(
- ent.row.getStatusBarNotification());
- List<ExpandableNotificationRow> orderedChildren =
- mTmpChildOrderMap.get(summary);
- if (orderedChildren == null) {
- orderedChildren = new ArrayList<>();
- mTmpChildOrderMap.put(summary, orderedChildren);
- }
- orderedChildren.add(ent.row);
- } else {
- toShow.add(ent.row);
- }
-
- }
-
- ArrayList<ExpandableNotificationRow> toRemove = new ArrayList<>();
- for (int i=0; i< mStackScroller.getChildCount(); i++) {
- View child = mStackScroller.getChildAt(i);
- if (!toShow.contains(child) && child instanceof ExpandableNotificationRow) {
- toRemove.add((ExpandableNotificationRow) child);
- }
- }
-
- for (ExpandableNotificationRow remove : toRemove) {
- if (mGroupManager.isChildInGroupWithSummary(remove.getStatusBarNotification())) {
- // we are only transfering this notification to its parent, don't generate an animation
- mStackScroller.setChildTransferInProgress(true);
- }
- if (remove.isSummaryWithChildren()) {
- remove.removeAllChildren();
- }
- mStackScroller.removeView(remove);
- mStackScroller.setChildTransferInProgress(false);
- }
-
- removeNotificationChildren();
-
- for (int i=0; i<toShow.size(); i++) {
- View v = toShow.get(i);
- if (v.getParent() == null) {
- //*/ freeme.biantao, 20180207. Theme.Freeme 8.1 - notification.
- if (v instanceof ExpandableNotificationRow) {
- ExpandableNotificationRow row = (ExpandableNotificationRow) v;
- if (row.isStyleInGroup()) {
- row.setStyleInGroup(false);
- }
- }
- //*/
- mVisualStabilityManager.notifyViewAddition(v);
- mStackScroller.addView(v);
- }
- }
-
- addNotificationChildrenAndSort();
-
- // So after all this work notifications still aren't sorted correctly.
- // Let's do that now by advancing through toShow and mStackScroller in
- // lock-step, making sure mStackScroller matches what we see in toShow.
- int j = 0;
- for (int i = 0; i < mStackScroller.getChildCount(); i++) {
- View child = mStackScroller.getChildAt(i);
- if (!(child instanceof ExpandableNotificationRow)) {
- // We don't care about non-notification views.
- continue;
- }
-
- ExpandableNotificationRow targetChild = toShow.get(j);
- if (child != targetChild) {
- // Oops, wrong notification at this position. Put the right one
- // here and advance both lists.
- if (mVisualStabilityManager.canReorderNotification(targetChild)) {
- mStackScroller.changeViewPosition(targetChild, i);
- } else {
- mVisualStabilityManager.addReorderingAllowedCallback(this);
- }
- }
- j++;
-
- }
-
- mVisualStabilityManager.onReorderingFinished();
- // clear the map again for the next usage
- mTmpChildOrderMap.clear();
-
- updateRowStates();
- updateSpeedBumpIndex();
- updateClearAll();
- updateEmptyShadeView();
-
- updateQsExpansionEnabled();
-
- // Let's also update the icons
- mNotificationIconAreaController.updateNotificationIcons(mNotificationData);
- }
显示做mStackScroller的空判断,然后是通知栏动画状态的判断。一切OK,就:
1.mNotificationData获取数据Entry集合,构造一个大小和这个Entry集合一样的ExpandableNotificationRow集合toShow
2.遍历entry,把entry.row添加到toshow里面
3.原有的通知,但是toshow里没有的则移除,然后toshow里没添加上的添加上去
bindRow(entry, pmUser, sbn, row)方法
- private void bindRow(Entry entry, PackageManager pmUser,
- StatusBarNotification sbn, ExpandableNotificationRow row) {
- row.setExpansionLogger(this, entry.notification.getKey());
- row.setGroupManager(mGroupManager);
- row.setHeadsUpManager(mHeadsUpManager);
- row.setAboveShelfChangedListener(mAboveShelfObserver);
- row.setRemoteInputController(mRemoteInputController);
- row.setOnExpandClickListener(this);
- row.setRemoteViewClickHandler(mOnClickHandler);
- row.setInflationCallback(this);
- row.setSecureStateProvider(this::isKeyguardCurrentlySecure);
- final String pkg = sbn.getPackageName();
- String appname = pkg;
- try {
- final ApplicationInfo info = pmUser.getApplicationInfo(pkg,
- PackageManager.MATCH_UNINSTALLED_PACKAGES
- | PackageManager.MATCH_DISABLED_COMPONENTS);
- if (info != null) {
- appname = String.valueOf(pmUser.getApplicationLabel(info));
- }
- } catch (NameNotFoundException e) {
- // Do nothing
- }
- row.setAppName(appname);
- row.setOnDismissRunnable(() ->
- performRemoveNotification(row.getStatusBarNotification()));
- row.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
- //该句实现了焦点的策略,row(也就是我们的通知)有子控件需要焦点则把焦点交给子控件,否则给row。
- if (ENABLE_REMOTE_INPUT) {
- row.setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS);
- }
- }
updateNotification(entry,pmUser,sbn,entry.row)方法
- private void updateNotification(Entry entry, PackageManager pmUser,
- StatusBarNotification sbn, ExpandableNotificationRow row) {
- row.setNeedsRedaction(needsRedaction(entry));
- boolean isLowPriority = mNotificationData.isAmbient(sbn.getKey());
- boolean isUpdate = mNotificationData.get(entry.key) != null;
- boolean wasLowPriority = row.isLowPriority();
- row.setIsLowPriority(isLowPriority);
- row.setLowPriorityStateUpdated(isUpdate && (wasLowPriority != isLowPriority));
- // bind the click event to the content area
- mNotificationClicker.register(row, sbn);//给通知栏注册点击事件
-
- // Extract target SDK version.
- try {
- ApplicationInfo info = pmUser.getApplicationInfo(sbn.getPackageName(), 0);
- entry.targetSdk = info.targetSdkVersion;
- } catch (NameNotFoundException ex) {
- Log.e(TAG, "Failed looking up ApplicationInfo for " + sbn.getPackageName(), ex);
- }
- row.setLegacy(entry.targetSdk >= Build.VERSION_CODES.GINGERBREAD
- && entry.targetSdk < Build.VERSION_CODES.LOLLIPOP);
- entry.setIconTag(R.id.icon_is_pre_L, entry.targetSdk < Build.VERSION_CODES.LOLLIPOP);
- entry.autoRedacted = entry.notification.getNotification().publicVersion == null;
-
- entry.row = row;
- entry.row.setOnActivatedListener(this);
-
- boolean useIncreasedCollapsedHeight = mMessagingUtil.isImportantMessaging(sbn,
- mNotificationData.getImportance(sbn.getKey()));
- boolean useIncreasedHeadsUp = useIncreasedCollapsedHeight && mPanelExpanded;
- row.setUseIncreasedCollapsedHeight(useIncreasedCollapsedHeight);
- row.setUseIncreasedHeadsUpHeight(useIncreasedHeadsUp);
- row.updateNotification(entry);
- }
mNotificationClicker.register(row, sbn);mNotificationClicker是StatusBar的一个私有成员,对应的类是NotificationClicker,是一个StatusBar的内部类,实现了View.OnClickListener接口,它就是row的监听类,实现的功能是row被点击时,启动相应的pendingIntent.注册操作代码如下
- public void register(ExpandableNotificationRow row, StatusBarNotification sbn) {
- Notification notification = sbn.getNotification();
- if (notification.contentIntent != null || notification.fullScreenIntent != null) {
- row.setOnClickListener(this);
- } else {
- row.setOnClickListener(null);
- }
- }
进入ExpandableNotificationRow的updateNotification方法
- public void updateNotification(NotificationData.Entry entry) {
- mEntry = entry;
- mStatusBarNotification = entry.notification;
- mNotificationInflater.inflateNotificationViews();
- }
至此inflateViews()结束,Entry生成完毕,Entry中的row生成完毕。
移除通知
首先还是StatusBar中的mNotificationListener但是和notification的添加/更新不同的是,走的不再是onNotificationPosted方法,而是onNotificationRemoved
- public void onNotificationRemoved(StatusBarNotification sbn,
- final RankingMap rankingMap) {
- if (true/**DEBUG*/) Log.d(TAG, "onNotificationRemoved: " + sbn);
- if (sbn != null && !onPluginNotificationRemoved(sbn, rankingMap)) {
- final String key = sbn.getKey();
- mHandler.post(() -> removeNotification(key, rankingMap));
- }
- }
这个方法就是很简单地拿个key,然后走removeNotification(key, rankingMap)方法
- public void removeNotification(String key, RankingMap ranking) {
- boolean deferRemoval = false;
- abortExistingInflation(key);
- if (mHeadsUpManager.isHeadsUp(key)) {
- // A cancel() in repsonse to a remote input shouldn't be delayed, as it makes the
- // sending look longer than it takes.
- // Also we should not defer the removal if reordering isn't allowed since otherwise
- // some notifications can't disappear before the panel is closed.
- boolean ignoreEarliestRemovalTime = mRemoteInputController.isSpinning(key)
- && !FORCE_REMOTE_INPUT_HISTORY
- || !mVisualStabilityManager.isReorderingAllowed();
- deferRemoval = !mHeadsUpManager.removeNotification(key, ignoreEarliestRemovalTime);
- }
- if (key.equals(mMediaNotificationKey)) {
- clearCurrentMediaNotification();
- updateMediaMetaData(true, true);
- }
- if (FORCE_REMOTE_INPUT_HISTORY && mRemoteInputController.isSpinning(key)) {
- Entry entry = mNotificationData.get(key);
- StatusBarNotification sbn = entry.notification;
-
- Notification.Builder b = Notification.Builder
- .recoverBuilder(mContext, sbn.getNotification().clone());
- CharSequence[] oldHistory = sbn.getNotification().extras
- .getCharSequenceArray(Notification.EXTRA_REMOTE_INPUT_HISTORY);
- CharSequence[] newHistory;
- if (oldHistory == null) {
- newHistory = new CharSequence[1];
- } else {
- newHistory = new CharSequence[oldHistory.length + 1];
- for (int i = 0; i < oldHistory.length; i++) {
- newHistory[i + 1] = oldHistory[i];
- }
- }
- newHistory[0] = String.valueOf(entry.remoteInputText);
- b.setRemoteInputHistory(newHistory);
-
- Notification newNotification = b.build();
-
- // Undo any compatibility view inflation
- newNotification.contentView = sbn.getNotification().contentView;
- newNotification.bigContentView = sbn.getNotification().bigContentView;
- newNotification.headsUpContentView = sbn.getNotification().headsUpContentView;
-
- StatusBarNotification newSbn = new StatusBarNotification(sbn.getPackageName(),
- sbn.getOpPkg(),
- sbn.getId(), sbn.getTag(), sbn.getUid(), sbn.getInitialPid(),
- newNotification, sbn.getUser(), sbn.getOverrideGroupKey(), sbn.getPostTime());
- boolean updated = false;
- try {
- updateNotification(newSbn, null);
- updated = true;
- } catch (InflationException e) {
- deferRemoval = false;
- }
- if (updated) {
- mKeysKeptForRemoteInput.add(entry.key);
- return;
- }
- }
- if (deferRemoval) {
- mLatestRankingMap = ranking;
- mHeadsUpEntriesToRemoveOnSwitch.add(mHeadsUpManager.getEntry(key));
- return;
- }
- Entry entry = mNotificationData.get(key);
-
- if (entry != null && mRemoteInputController.isRemoteInputActive(entry)
- && (entry.row != null && !entry.row.isDismissed())) {
- mLatestRankingMap = ranking;
- mRemoteInputEntriesToRemoveOnCollapse.add(entry);
- return;
- }
- if (entry != null && mNotificationGutsExposed != null
- && mNotificationGutsExposed == entry.row.getGuts() && entry.row.getGuts() != null
- && !entry.row.getGuts().isLeavebehind()) {
- Log.w(TAG, "Keeping notification because it's showing guts. " + key);
- mLatestRankingMap = ranking;
- mKeyToRemoveOnGutsClosed = key;
- return;
- }
-
- if (entry != null) {
- mForegroundServiceController.removeNotification(entry.notification);
- }
-
- if (entry != null && entry.row != null) {
- entry.row.setRemoved();
- mStackScroller.cleanUpViewState(entry.row);
- }
- // Let's remove the children if this was a summary
- handleGroupSummaryRemoved(key, ranking);
- StatusBarNotification old = removeNotificationViews(key, ranking);
- /// M: Enable this log for unusual case debug.
- if (true/**SPEW*/) Log.d(TAG, "removeNotification key=" + key + " old=" + old);
-
- if (old != null) {
- if (CLOSE_PANEL_WHEN_EMPTIED && !hasActiveNotifications()
- && !mNotificationPanel.isTracking() && !mNotificationPanel.isQsExpanded()) {
- if (mState == StatusBarState.SHADE) {
- animateCollapsePanels();
- } else if (mState == StatusBarState.SHADE_LOCKED && !isCollapsing()) {
- goToKeyguard();
- }
- }
- }
- setAreThereNotifications();
- }
removeNotificationViews(key, ranking)方法是在StatusBar中定义的
- protected StatusBarNotification removeNotificationViews(String key, RankingMap ranking) {
- NotificationData.Entry entry = mNotificationData.remove(key, ranking);
- if (entry == null) {
- Log.w(TAG, "removeNotification for unknown key: " + key);
- return null;
- }
- updateNotifications();
- Dependency.get(LeakDetector.class).trackGarbage(entry);
- return entry.notification;
- }
里面逻辑也很简单,根据key,从mNotificationData移除entry,然后就是走回updateNotifications()刷新UI。
导航栏的创建
StatusBar.makeStatusBarView
- try {
- //创建导航栏
- boolean showNav = mWindowManagerService.hasNavigationBar();
- if (DEBUG) Log.v(TAG, "hasNavigationBar=" + showNav);
- if (showNav) {
- createNavigationBar();
- }
- } catch (RemoteException ex) {
- // no window manager? good luck with that
- }
- protected void createNavigationBar() {
- mNavigationBarView = NavigationBarFragment.create(mContext, (tag, fragment) -> {
- mNavigationBar = (NavigationBarFragment) fragment;
- if (mLightBarController != null) {
- mNavigationBar.setLightBarController(mLightBarController);
- }
- mNavigationBar.setCurrentSysuiVisibility(mSystemUiVisibility);
- });
- }
NavigationBarFragment.create
- public static View create(Context context, FragmentListener listener) {
- WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
- LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT,
- WindowManager.LayoutParams.TYPE_NAVIGATION_BAR,
- WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING
- | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
- | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
- | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
- | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
- | WindowManager.LayoutParams.FLAG_SLIPPERY,
- PixelFormat.TRANSLUCENT);
- lp.token = new Binder();
- lp.setTitle("NavigationBar");
- lp.accessibilityTitle = context.getString(R.string.nav_bar);
- lp.windowAnimations = 0;
-
- View navigationBarView = LayoutInflater.from(context).inflate(
- R.layout.navigation_bar_window, null);
-
- if (DEBUG) Log.v(TAG, "addNavigationBar: about to add " + navigationBarView);
- if (navigationBarView == null) return null;
-
- context.getSystemService(WindowManager.class).addView(navigationBarView, lp);
- FragmentHostManager fragmentHost = FragmentHostManager.get(navigationBarView);
- NavigationBarFragment fragment = new NavigationBarFragment();
- fragmentHost.getFragmentManager().beginTransaction()
- .replace(R.id.navigation_bar_frame, fragment, TAG)
- .commit();
- fragmentHost.addTagListener(TAG, listener);
- return navigationBarView;
- }
上述代码做了两件事:
1.创建navigationBarView 并且把navigationBarView添加到windowManager中。
2.创建NavigationBarFragment 替换navigation_bar_window的布局文件,改成navigation_bar
navigation_bar.xml
- <com.android.systemui.statusbar.phone.NavigationBarView
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:systemui="http://schemas.android.com/apk/res-auto"
- android:layout_height="match_parent"
- android:layout_width="match_parent"
- android:background="@drawable/system_bar_background">
-
- <com.android.systemui.statusbar.phone.NavigationBarInflaterView
- android:id="@+id/navigation_inflater"
- android:layout_width="match_parent"
- android:layout_height="match_parent" />
-
- </com.android.systemui.statusbar.phone.NavigationBarView>
NavigationBarView 完成资源文件添加
NavigationBarFragment 添加点击事件和触摸事件的处理逻辑
NavigationBarFragment
- public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
- super.onViewCreated(view, savedInstanceState);
- mNavigationBarView = (NavigationBarView) view;
-
- mNavigationBarView.setDisabledFlags(mDisabledFlags1);
- mNavigationBarView.setComponents(mRecents, mDivider, mStatusBar.getPanel());
- mNavigationBarView.setOnVerticalChangedListener(this::onVerticalChanged);
- mNavigationBarView.setOnTouchListener(this::onNavigationTouch);
- if (savedInstanceState != null) {
- mNavigationBarView.getLightTransitionsController().restoreState(savedInstanceState);
- }
-
- prepareNavigationBarView();//添加home ,recent触摸事件回调
- checkNavBarModes();
-
- setDisabled2Flags(mDisabledFlags2);
-
- IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_OFF);
- filter.addAction(Intent.ACTION_SCREEN_ON);
- filter.addAction(Intent.ACTION_USER_SWITCHED);
- getContext().registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter, null, null);
- notifyNavigationBarScreenOn();
- mOverviewProxyService.addCallback(mOverviewProxyListener);
- }
- private void prepareNavigationBarView() {
- mNavigationBarView.reorient();
- //近期列表安静控制
- ButtonDispatcher recentsButton = mNavigationBarView.getRecentsButton();
- recentsButton.setOnClickListener(this::onRecentsClick);
- recentsButton.setOnTouchListener(this::onRecentsTouch);
- recentsButton.setLongClickable(true);
- recentsButton.setOnLongClickListener(this::onLongPressBackRecents);
-
- ButtonDispatcher backButton = mNavigationBarView.getBackButton();
- backButton.setLongClickable(true);
-
- ButtonDispatcher homeButton = mNavigationBarView.getHomeButton();
- homeButton.setOnTouchListener(this::onHomeTouch);
- homeButton.setOnLongClickListener(this::onHomeLongClick);
-
- ButtonDispatcher accessibilityButton = mNavigationBarView.getAccessibilityButton();
- accessibilityButton.setOnClickListener(this::onAccessibilityClick);
- accessibilityButton.setOnLongClickListener(this::onAccessibilityLongClick);
- updateAccessibilityServicesState(mAccessibilityManager);
-
- ButtonDispatcher rotateSuggestionButton = mNavigationBarView.getRotateSuggestionButton();
- rotateSuggestionButton.setOnClickListener(this::onRotateSuggestionClick);
- rotateSuggestionButton.setOnHoverListener(this::onRotateSuggestionHover);
- updateScreenPinningGestures();
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。