久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

Android 4.0 ICS SystemUI淺析——StatusBar加載流程之Not...

 lifei_szdz 2013-06-05

前面三篇文章《Android 4.0 ICS SystemUI淺析——SystemUI啟動流程》,、《Android 4.0 ICS SystemUI淺析——StatusBar結構分析》、《Android 4.0 ICS SystemUI淺析——StatusBar加載流程分析》逐步分析了SystemUI中StatusBar的啟動以及加載流程,,本文主要分析StatusBar上的Notification的加載,,如有不正之處還懇請各位幫忙指正。

        本文來自:http://blog.csdn.net/yihongyuelan 歡迎轉載 請務必注明出處,!

        在上一篇文章《Android 4.0 ICS SystemUI淺析——StatusBar加載流程分析》中,我們主要分析了StatusBar上的系統(tǒng)Icons加載的過程,,包括了耳機圖標,、藍牙圖標、禁音圖標等等,,此文是緊接著上文分析的,,因此我們首先看到/SourceCode/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/StatusBar.java的start():

  1.      public void start() {  
  2.     // First set up our views and stuff.首先準備我們需要顯示的view以及原材料  
  3.     //我們先跟蹤這里的makeStatusBarView  
  4.     View sb = makeStatusBarView();  
  5.   
  6.     // Connect in to the status bar manager service  
  7.     //初始化各個存儲器,用于存儲各類信息,,這些信息通過StatusBarManagerService獲取  
  8.     //iconsList用于存放icons  
  9.     StatusBarIconList iconList = new StatusBarIconList();  
  10.     //nodificationKeys保存以Binder為Key的notification  
  11.     ArrayList<IBinder> notificationKeys = new ArrayList<IBinder>();  
  12.     //保存StatusBarNotification類型的notifications  
  13.     ArrayList<StatusBarNotification> notifications = new ArrayList<StatusBarNotification>();  
  14.     //mCommandQueue是和IStatusBarService進行交互的IBinder  
  15.     mCommandQueue = new CommandQueue(this, iconList);  
  16.     //這里實際上獲取的是StatusBarManagerService  
  17.     mBarService = IStatusBarService.Stub.asInterface(  
  18.             ServiceManager.getService(Context.STATUS_BAR_SERVICE));  
  19.     int[] switches = new int[7];  
  20.     ArrayList<IBinder> binders = new ArrayList<IBinder>();  
  21.     try {  
  22.         //通過StatusBarManagerService中的registerStatusBar來獲取初始設置  
  23.         mBarService.registerStatusBar(mCommandQueue, iconList, notificationKeys, notifications,  
  24.                 switches, binders);  
  25.     } catch (RemoteException ex) {  
  26.         // If the system process isn't there we're doomed anyway.  
  27.     }  
  28.     ... ...  
  29.   
  30.     // Set up the initial notification state  
  31.     //加載notifications,,本文的分析主要從這里開始,!  
  32.     N = notificationKeys.size();  
  33.     if (N == notifications.size()) {  
  34.         for (int i=0; i<N; i++) {  
  35.             addNotification(notificationKeys.get(i), notifications.get(i));  
  36.         }  
  37.     } else {  
  38.         Log.wtf(TAG, "Notification list length mismatch: keys=" + N  
  39.                 + " notifications=" + notifications.size());  
  40.     }  
  41.   
  42.     ... ...  
  43.     lp.gravity = getStatusBarGravity();  
  44.     lp.setTitle("StatusBar");  
  45.     lp.packageName = mContext.getPackageName();  
  46.     lp.windowAnimations = R.style.Animation_StatusBar;  
  47.     //在Window上顯示StatusBar界面  
  48.     WindowManagerImpl.getDefault().addView(sb, lp);  
  49.     mDoNotDisturb = new DoNotDisturb(mContext);  
  50. }  

    我們可以看到addNotification()方法主要完成Notification圖標的加載。跟進去看看(因為我們分析的是Phone因此選擇PhoneStatusBar),,代碼如下:

  1.    
  2. public void addNotification(IBinder key, StatusBarNotification notification) {  
  3.      //該方法主要構造Notification Icons以及Expaned View  
  4.      StatusBarIconView iconView = addNotificationViews(key, notification);  
  5.      if (iconView == nullreturn;  
  6.   
  7.      boolean immersive = false;  
  8.      try {  
  9.          //判斷當前棧頂Activity是否具有android:immersive屬性,。該屬性在Android 4.0中新加入的屬性,如果該屬性為true則該Activity不能被其他Activity或者Notification所打斷,。  
  10.          immersive = ActivityManagerNative.getDefault().isTopActivityImmersive();  
  11.          if (DEBUG) {  
  12.              Slog.d(TAG, "Top activity is " + (immersive?"immersive":"not immersive"));  
  13.          }  
  14.      } catch (RemoteException ex) {  
  15.      }  
  16.      //因為這里我們返回的是false,,所以不會執(zhí)行  
  17.      if (immersive) {  
  18.          if ((notification.notification.flags & Notification.FLAG_HIGH_PRIORITY) != 0) {  
  19.              Slog.d(TAG, "Presenting high-priority notification in immersive activity");  
  20.              // special new transient ticker mode  
  21.              // 1. Populate mIntruderAlertView  
  22.   
  23.              ImageView alertIcon = (ImageView) mIntruderAlertView.findViewById(R.id.alertIcon);  
  24.              TextView alertText = (TextView) mIntruderAlertView.findViewById(R.id.alertText);  
  25.              alertIcon.setImageDrawable(StatusBarIconView.getIcon(  
  26.                  alertIcon.getContext(),  
  27.                  iconView.getStatusBarIcon()));  
  28.              alertText.setText(notification.notification.tickerText);  
  29.   
  30.              View button = mIntruderAlertView.findViewById(R.id.intruder_alert_content);  
  31.              button.setOnClickListener(  
  32.                  new NotificationClicker(notification.notification.contentIntent,  
  33.                      notification.pkg, notification.tag, notification.id));  
  34.   
  35.              // 2. Animate mIntruderAlertView in  
  36.              mHandler.sendEmptyMessage(MSG_SHOW_INTRUDER);  
  37.   
  38.              // 3. Set alarm to age the notification off (TODO)  
  39.              mHandler.removeMessages(MSG_HIDE_INTRUDER);  
  40.              mHandler.sendEmptyMessageDelayed(MSG_HIDE_INTRUDER, INTRUDER_ALERT_DECAY_MS);  
  41.          }  
  42.      //這里的fullScreenIntent=null因此也不執(zhí)行  
  43.      } else if (notification.notification.fullScreenIntent != null) {  
  44.          // not immersive & a full-screen alert should be shown  
  45.          Slog.d(TAG, "Notification has fullScreenIntent; sending fullScreenIntent");  
  46.          try {  
  47.              notification.notification.fullScreenIntent.send();  
  48.          } catch (PendingIntent.CanceledException e) {  
  49.          }  
  50.      } else {  
  51.          // usual case: status bar visible & not immersive  
  52.   
  53.          // show the ticker  
  54.          //因此StatusBar可見同時不具有immersive屬性,因此顯示tiker  
  55.          tick(notification);  
  56.      }  
  57.   
  58.      // Recalculate the position of the sliding windows and the titles.  
  59.      // 重新計算滑動窗口的位置和標題  
  60.      setAreThereNotifications();  
  61.      // 更新ExpanedView  
  62.      updateExpandedViewPos(EXPANDED_LEAVE_ALONE);  
  63.  }  

通過對以上代碼的分析,,我們可以大致知道,,Notification的加載主要分為三步:

1.addNotificationViews(key, notification);

2.tick(notification);

3.setAreThereNotifications()和updateExpandedViewPos(EXPANDED_LEAVE_ALONE);

那么接下來我們就通過這三個方法來分析Notification的加載。

 (1). addNotificationViews(key, notification);

 跟蹤查看代碼如下:

  1.    
  2. StatusBarIconView addNotificationViews(IBinder key, StatusBarNotification notification) {  
  3.      if (DEBUG) {  
  4.          Slog.d(TAG, "addNotificationViews(key=" + key + ", notification=" + notification);  
  5.      }  
  6.      // Construct the icon.  
  7.      // 初始化iconView  
  8.      final StatusBarIconView iconView = new StatusBarIconView(mContext,  
  9.              notification.pkg + "/0x" + Integer.toHexString(notification.id),  
  10.              notification.notification);  
  11.      //設置icons按照什么方式顯示  
  12.      iconView.setScaleType(ImageView.ScaleType.CENTER_INSIDE);  
  13.      // 對全局變量賦值  
  14.      final StatusBarIcon ic = new StatusBarIcon(notification.pkg,  
  15.                  notification.notification.icon,  
  16.                  notification.notification.iconLevel,  
  17.                  notification.notification.number,  
  18.                  notification.notification.tickerText);  
  19.      // 設置顯示icons 和上一篇文章提到的系統(tǒng)icons圖標設置是一樣的 如果返回true則表示設置成功  
  20.      if (!iconView.set(ic)) {  
  21.          handleNotificationError(key, notification, "Couldn't create icon: " + ic);  
  22.          return null;  
  23.      }  
  24.      // Construct the expanded view.  
  25.      // 將Notification在ExpandedView上顯示出來  
  26.      NotificationData.Entry entry = new NotificationData.Entry(key, notification, iconView);  
  27.      if (!inflateViews(entry, mPile)) {  
  28.          handleNotificationError(key, notification, "Couldn't expand RemoteViews for: "  
  29.                  + notification);  
  30.          return null;  
  31.      }  
  32.   
  33.      // Add the expanded view and icon.  
  34.      //mNotificationData中保存著當前顯示的Notification的數量及其屬性  
  35.      int pos = mNotificationData.add(entry);  
  36.      if (DEBUG) {  
  37.          Slog.d(TAG, "addNotificationViews: added at " + pos);  
  38.      }  
  39.      //更新圖標  
  40.      updateNotificationIcons();  
  41.   
  42.      return iconView;  
  43.  }  

根據以上代碼,,我們可以知道在addNotificationViews()中,,又可以細分為三步:設置icons,設置ExpanedView,,更新圖標,。其中,設置icons實際上和上一篇文章中設置系統(tǒng)Icons類似,。主要區(qū)別在設置ExpandedView和更新圖標,。那跟蹤inflateViews()方法可以看到:

  1.    private boolean inflateViews(NotificationData.Entry entry, ViewGroup parent) {  
  2.         StatusBarNotification sbn = entry.notification;  
  3.         //初始化remoteViews(如果有過自定義Notification經驗的朋友肯定對這個很熟悉,不了解的朋友可以自己去試試)  
  4.         RemoteViews remoteViews = sbn.notification.contentView;  
  5.         if (remoteViews == null) {  
  6.             return false;  
  7.         }  
  8.   
  9.         // create the row view  
  10.         LayoutInflater inflater = (LayoutInflater)mContext.getSystemService(  
  11.                 Context.LAYOUT_INFLATER_SERVICE);  
  12.         // 加載布局文件,,默認的通知信息在ExpandedView中是以一行來顯示的,,左側是圖標,右側是通知標題和內容  
  13.         View row = inflater.inflate(R.layout.status_bar_notification_row, parent, false);  
  14.         //這個所謂的button實際上是在清除單個通知信息時調用的  
  15.         View vetoButton = updateNotificationVetoButton(row, sbn);  
  16.         //設置vetoButton的備注說明,,作為一種輔助功能提供,為一些沒有文字描述的View提供說明,。這在界面上不會有效果,可臨時放一點字符串數據  
  17.         vetoButton.setContentDescription(mContext.getString(  
  18.                 R.string.accessibility_remove_notification));  
  19.   
  20.         // the large icon  
  21.         //如果有l(wèi)argeIcon則進行設置,。這里提到的largeIcon我也不知道具體用處是什么  
  22.         ImageView largeIcon = (ImageView)row.findViewById(R.id.large_icon);  
  23.         if (sbn.notification.largeIcon != null) {  
  24.             largeIcon.setImageBitmap(sbn.notification.largeIcon);  
  25.             largeIcon.setContentDescription(sbn.notification.tickerText);  
  26.         } else {  
  27.             largeIcon.getLayoutParams().width = 0;  
  28.             largeIcon.setVisibility(View.INVISIBLE);  
  29.         }  
  30.         largeIcon.setContentDescription(sbn.notification.tickerText);  
  31.   
  32.         // bind the click event to the content area  
  33.         ViewGroup content = (ViewGroup)row.findViewById(R.id.content);  
  34.         // XXX: update to allow controls within notification views  
  35.         content.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);  
  36. //        content.setOnFocusChangeListener(mFocusChangeListener);  
  37.         PendingIntent contentIntent = sbn.notification.contentIntent;  
  38.         if (contentIntent != null) {  
  39.             //綁定largIcons和content區(qū)域的點擊事件  
  40.             final View.OnClickListener listener = new NotificationClicker(contentIntent,  
  41.                     sbn.pkg, sbn.tag, sbn.id);  
  42.             largeIcon.setOnClickListener(listener);  
  43.             content.setOnClickListener(listener);  
  44.         } else {  
  45.             largeIcon.setOnClickListener(null);  
  46.             content.setOnClickListener(null);  
  47.         }  
  48.   
  49.         View expanded = null;  
  50.         Exception exception = null;  
  51.         try {  
  52.             //  Inflates視圖對象并且應用到所有的動作中  
  53.             expanded = remoteViews.apply(mContext, content);  
  54.         }  
  55.         catch (RuntimeException e) {  
  56.             exception = e;  
  57.         }  
  58.         if (expanded == null) {  
  59.             final String ident = sbn.pkg + "/0x" + Integer.toHexString(sbn.id);  
  60.             Slog.e(TAG, "couldn't inflate view for notification " + ident, exception);  
  61.             return false;  
  62.         } else {  
  63.             //content 添加顯示view  
  64.             content.addView(expanded);  
  65.             // 獲取view中的圖像前需要設為true  
  66.             row.setDrawingCacheEnabled(true);  
  67.         }  
  68.         // 設置這些通知信息原始背景  
  69.         applyLegacyRowBackground(sbn, content);  
  70.         // 將設置好的屬性回傳給entry  
  71.         entry.row = row;  
  72.         entry.content = content;  
  73.         entry.expanded = expanded;  
  74.         entry.largeIcon = largeIcon;  
  75.   
  76.         return true;  
  77.     }  

對于ExpanedView中的Notification設置,,可能這里有點模糊,那請看以下圖1和圖2:

圖 1

圖2

通過圖1和圖2我們可以看到largeIcon以及vetoButton觸發(fā)時間,。對于ExpandedView,,后面會有較為詳細的分析。

       上面分析了ExpandedView中的Notification的設置,,在addNotificationViews(key, notification);中就還剩下最后一個步驟了,,即更新圖標,那么查看addNotificationView()中的updateNotificationIcons()方法,,代碼如下:

  1. private void updateNotificationIcons() {  
  2.     // 該方法主要用于將通知信息在ExpandedView中顯示 如果注釋掉則通知將不會在ExpandedView中顯示  
  3.     loadNotificationShade();  
  4.     // 下面的操作主要完成在StatusBar添加通知提示圖標  
  5.     final LinearLayout.LayoutParams params  
  6.         = new LinearLayout.LayoutParams(mIconSize + 2*mIconHPadding, mNaturalBarHeight);  
  7.   
  8.     int N = mNotificationData.size();  
  9.   
  10.     if (DEBUG) {  
  11.         Slog.d(TAG, "refreshing icons: " + N + " notifications, mNotificationIcons=" + mNotificationIcons);  
  12.     }  
  13.   
  14.     ArrayList<View> toShow = new ArrayList<View>();  
  15.   
  16.     for (int i=0; i<N; i++) {  
  17.         toShow.add(mNotificationData.get(N-i-1).icon);  
  18.     }  
  19.   
  20.     ArrayList<View> toRemove = new ArrayList<View>();  
  21.     for (int i=0; i<mNotificationIcons.getChildCount(); i++) {  
  22.         View child = mNotificationIcons.getChildAt(i);  
  23.         if (!toShow.contains(child)) {  
  24.             toRemove.add(child);  
  25.         }  
  26.     }  
  27.   
  28.     for (View remove : toRemove) {  
  29.         mNotificationIcons.removeView(remove);  
  30.     }  
  31.   
  32.     for (int i=0; i<toShow.size(); i++) {  
  33.         View v = toShow.get(i);  
  34.         if (v.getParent() == null) {  
  35.             mNotificationIcons.addView(v, i, params);  
  36.         }  
  37.     }  
  38. }  

通過以上代碼的分析,,我們可以知道updateNotificationIcons()主要做了兩件事:更新ExpanddeView上的通知信息;更新StatusBar上的通知圖標。更新方法都類似,,先查通知看是否有效,,如果不是則刪除,如果是則添加,。以上完成了加載Notification的第一步,,那么我來看第二步tick(notification)

          (2).tick(notification),,跟蹤代碼如下:

  1. private void tick(StatusBarNotification n) {  
  2.     // Show the ticker if one is requested. Also don't do this  
  3.     // until status bar window is attached to the window manager,  
  4.     // because...  well, what's the point otherwise?  And trying to  
  5.     // run a ticker without being attached will crash!  
  6.     if (n.notification.tickerText != null && mStatusBarView.getWindowToken() != null) {  
  7.         if (0 == (mDisabled & (StatusBarManager.DISABLE_NOTIFICATION_ICONS  
  8.                         | StatusBarManager.DISABLE_NOTIFICATION_TICKER))) {  
  9.             //ticker執(zhí)行方法  
  10.             mTicker.addEntry(n);  
  11.         }  
  12.     }  
  13. }  

跳轉到mTicker.addEntry();方法中,,代碼路徑:SourceCode/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/Ticker.java中,代碼如下:

  1. public void addEntry(StatusBarNotification n) {  
  2.     int initialCount = mSegments.size();  
  3.   
  4.     // If what's being displayed has the same text and icon, just drop it  
  5.     // (which will let the current one finish, this happens when apps do  
  6.     // a notification storm).  
  7.     if (initialCount > 0) {  
  8.         final Segment seg = mSegments.get(0);  
  9.         //判斷該Notififacation是不是已經在StatusBar上顯示了的(同一個Notification發(fā)送兩次這里并么有執(zhí)行,,為什么,?)  
  10.         if (n.pkg.equals(seg.notification.pkg)  
  11.                 && n.notification.icon == seg.notification.notification.icon  
  12.                 && n.notification.iconLevel == seg.notification.notification.iconLevel  
  13.                 && CharSequences.equals(seg.notification.notification.tickerText,  
  14.                     n.notification.tickerText)) {  
  15.             return;  
  16.         }  
  17.     }  
  18.     // 獲取該Notification的icon  
  19.     final Drawable icon = StatusBarIconView.getIcon(mContext,  
  20.             new StatusBarIcon(n.pkg, n.notification.icon, n.notification.iconLevel, 0,  
  21.                     n.notification.tickerText));  
  22.     // 將Notification的一些信息放入對象newSegment中,這里的Segment翻譯過來是片段和部分的意思  
  23.     // Segment是Ticker類的內部類,,用于存放notification的部分信息以及對信息的一些處理,,比如tickerText  
  24.     final Segment newSegment = new Segment(n, icon, n.notification.tickerText);  
  25.   
  26.     // If there's already a notification schedule for this package and id, remove it.  
  27.     // 若果該信息在Segment中已經存在,則刪除掉  
  28.     for (int i=0; i<mSegments.size(); i++) {  
  29.         Segment seg = mSegments.get(i);  
  30.         if (n.id == seg.notification.id && n.pkg.equals(seg.notification.pkg)) {  
  31.             // just update that one to use this new data instead(什么時候觸發(fā),?)  
  32.             mSegments.remove(i--); // restart iteration here  
  33.         }  
  34.     }  
  35.     // 將Notification的部分信息放到mSegments鏈表中,。  
  36.     mSegments.add(newSegment);  
  37.   
  38.     if (initialCount == 0 && mSegments.size() > 0) {  
  39.         Segment seg = mSegments.get(0);  
  40.         seg.first = false;  
  41.         //初始化id/tickerIcon  
  42.         mIconSwitcher.setAnimateFirstView(false);  
  43.         mIconSwitcher.reset();  
  44.         mIconSwitcher.setImageDrawable(seg.icon);  
  45.         //初始化id/tickerText  
  46.         mTextSwitcher.setAnimateFirstView(false);  
  47.         mTextSwitcher.reset();  
  48.         mTextSwitcher.setText(seg.getText());  
  49.         //啟動ticker  
  50.         tickerStarting();  
  51.         scheduleAdvance();  
  52.     }  
  53. }  

通過Open Implementation我們跳轉到PhoneStatusBar中的tickerStatrting()中,代碼如下:

  1. @Override  
  2. public void tickerStarting() {  
  3.     mTicking = true;  
  4.     //這里的mIcons和ticker組成了整個StatusBar的布局,,因此這里要線將它置為GONE  
  5.     mIcons.setVisibility(View.GONE);  
  6.     //顯示tickerText  
  7.     mTickerView.setVisibility(View.VISIBLE);  
  8.     //加載ticker彈出時的動畫  
  9.     mTickerView.startAnimation(loadAnim(com.android.internal.R.anim.push_up_in, null));  
  10.     mIcons.startAnimation(loadAnim(com.android.internal.R.anim.push_up_out, null));  
  11. }  
這里可以發(fā)現ticker開加載動畫并顯示了,,實際上Notification在StatusBar上的顯示效果是加載了動畫的原因。繼續(xù)查看scheduleAdvance()方法:
  1. private void scheduleAdvance() {  
  2.     mHandler.postDelayed(mAdvanceTicker, TICKER_SEGMENT_DELAY);  
  3. }  

通過Handler的PostDelay方法執(zhí)行mAdvanceTicker這個Runnable中的run方法,,代碼如下:
  1. private Runnable mAdvanceTicker = new Runnable() {  
  2.     public void run() {  
  3.         while (mSegments.size() > 0) {  
  4.             Segment seg = mSegments.get(0);  
  5.   
  6.             if (seg.first) {  
  7.                 // this makes the icon slide in for the first one for a given  
  8.                 // notification even if there are two notifications with the  
  9.                 // same icon in a row  
  10.                 // 第一次顯示時,,設置tickerIcon的值,這里就是ticker最前方顯示的那個icon  
  11.                 mIconSwitcher.setImageDrawable(seg.icon);  
  12.             }  
  13.             CharSequence text = seg.advance();  
  14.             if (text == null) {  
  15.                 mSegments.remove(0);  
  16.                 continue;  
  17.             }  
  18.             // 顯示用戶設置的tickerText內容  
  19.             mTextSwitcher.setText(text);  
  20.   
  21.             scheduleAdvance();  
  22.             break;  
  23.         }  
  24.         if (mSegments.size() == 0) {  
  25.             // 完成ticker的一次顯示  
  26.             tickerDone();  
  27.         }  
  28.     }  
  29. };  

最后我們再來看看tickerDone()方法,,該方法主要對應于tickerStarting()方法,,代碼如下:

  1. @Override  
  2. public void tickerDone() {  
  3.     //顯示mIcons布局  
  4.     mIcons.setVisibility(View.VISIBLE);  
  5.     //tickerText消失  
  6.     mTickerView.setVisibility(View.GONE);  
  7.     //加載ticker消失的動畫  
  8.     mIcons.startAnimation(loadAnim(com.android.internal.R.anim.push_down_in, null));  
  9.     mTickerView.startAnimation(loadAnim(com.android.internal.R.anim.push_down_out,  
  10.                 mTickingDoneListener));  
  11. }  

至此,我們完成了Notification加載的前兩步,,分別是addNotificationViews(key, notification)和tick(notification),。剩下最后一步,即:setAreThereNotifications()和updateExpandedViewPos(EXPANDED_LEAVE_ALONE);

          (3).setAreThereNotifications()updateExpandedViewPos().這里先說一下setAreThereNotifications()方法,,代碼如下:

  1. private void setAreThereNotifications() {  
  2.     //是否有Notification  
  3.     final boolean any = mNotificationData.size() > 0;  
  4.     //該Notification是否可被清除  
  5.     final boolean clearable = any && mNotificationData.hasClearableItems();  
  6.   
  7.     if (DEBUG) {  
  8.         Slog.d(TAG, "setAreThereNotifications: N=" + mNotificationData.size()  
  9.                 + " any=" + any + " clearable=" + clearable);  
  10.     }  
  11.     //對"清除所有通知"按鈕進行設置  
  12.     if (mClearButton.isShown()) {  
  13.         if (clearable != (mClearButton.getAlpha() == 1.0f)) {  
  14.             ObjectAnimator.ofFloat(mClearButton, "alpha",  
  15.                     clearable ? 1.0f : 0.0f)  
  16.                 .setDuration(250)  
  17.                 .start();  
  18.         }  
  19.     } else {  
  20.         mClearButton.setAlpha(clearable ? 1.0f : 0.0f);  
  21.     }  
  22.     mClearButton.setEnabled(clearable);  
  23.   
  24. ...  
  25. }  

繼續(xù)分析updateExpandedViewPos(EXPANDED_LEAVE_ALONE);方法,,代碼如下;

  1. void updateExpandedViewPos(int expandedPosition) {  
  2.     if (SPEW) {  
  3.         Slog.d(TAG, "updateExpandedViewPos before expandedPosition=" + expandedPosition  
  4.                 + " mTrackingParams.y=" + ((mTrackingParams == null) ? "?" : mTrackingParams.y)  
  5.                 + " mTrackingPosition=" + mTrackingPosition);  
  6.     }  
  7.     //獲取StatusBar高度  
  8.     int h = mStatusBarView.getHeight();  
  9.     //獲取當前分辨率高度  
  10.     int disph = mDisplayMetrics.heightPixels;  
  11.   
  12.     // If the expanded view is not visible, make sure they're still off screen.  
  13.     // Maybe the view was resized.  
  14.     //如果ExpanedView不可見則執(zhí)行  
  15.     if (!mExpandedVisible) {  
  16.         //更新mTrackingView屬性,,設置mExpandedDialog屬性  
  17.         updateExpandedInvisiblePosition();  
  18.         return;  
  19.     }  
  20.   
  21.     // tracking view...  
  22.     //設置TriackingView的各種屬性  
  23.     int pos;  
  24.     if (expandedPosition == EXPANDED_FULL_OPEN) {  
  25.         pos = h;  
  26.     }  
  27.     else if (expandedPosition == EXPANDED_LEAVE_ALONE) {  
  28.         //傳遞參數為EXPANDED_LEAVE_ALONE  
  29.         pos = mTrackingPosition;  
  30.     }  
  31.     else {  
  32.         if (expandedPosition <= disph) {  
  33.             pos = expandedPosition;  
  34.         } else {  
  35.             pos = disph;  
  36.         }  
  37.         pos -= disph-h;  
  38.     }  
  39.     mTrackingPosition = mTrackingParams.y = pos;  
  40.     mTrackingParams.height = disph-h;  
  41.     WindowManagerImpl.getDefault().updateViewLayout(mTrackingView, mTrackingParams);  
  42.   
  43.     if (mExpandedParams != null) {  
  44.         if (mCloseView.getWindowVisibility() == View.VISIBLE) {  
  45.             mCloseView.getLocationInWindow(mPositionTmp);  
  46.             final int closePos = mPositionTmp[1];  
  47.   
  48.             mExpandedContents.getLocationInWindow(mPositionTmp);  
  49.             final int contentsBottom = mPositionTmp[1] + mExpandedContents.getHeight();  
  50.   
  51.             mExpandedParams.y = pos + mTrackingView.getHeight()  
  52.                     - (mTrackingParams.height-closePos) - contentsBottom;  
  53.   
  54.             if (SPEW) {  
  55.                 Slog.d(PhoneStatusBar.TAG,  
  56.                         "pos=" + pos +  
  57.                         " trackingHeight=" + mTrackingView.getHeight() +  
  58.                         " (trackingParams.height - closePos)=" +  
  59.                             (mTrackingParams.height - closePos) +  
  60.                         " contentsBottom=" + contentsBottom);  
  61.             }  
  62.   
  63.         } else {  
  64.             // If the tracking view is not yet visible, then we can't have  
  65.             // a good value of the close view location.  We need to wait for  
  66.             // it to be visible to do a layout.  
  67.             mExpandedParams.y = -mDisplayMetrics.heightPixels;  
  68.         }  
  69.         int max = h;  
  70.         if (mExpandedParams.y > max) {  
  71.             mExpandedParams.y = max;  
  72.         }  
  73.         int min = mTrackingPosition;  
  74.         if (mExpandedParams.y < min) {  
  75.             mExpandedParams.y = min;  
  76.         }  
  77.   
  78.         boolean visible = (mTrackingPosition + mTrackingView.getHeight()) > h;  
  79.         if (!visible) {  
  80.             // if the contents aren't visible, move the expanded view way off screen  
  81.             // because the window itself extends below the content view.  
  82.             mExpandedParams.y = -disph;  
  83.         }  
  84.         mExpandedDialog.getWindow().setAttributes(mExpandedParams);  
  85.   
  86.         // As long as this isn't just a repositioning that's not supposed to affect  
  87.         // the user's perception of what's showing, call to say that the visibility  
  88.         // has changed. (Otherwise, someone else will call to do that).  
  89.         if (expandedPosition != EXPANDED_LEAVE_ALONE) {  
  90.             if (SPEW) Slog.d(TAG, "updateExpandedViewPos visibilityChanged(" + visible + ")");  
  91.             visibilityChanged(visible);  
  92.         }  
  93.     }  
  94.   
  95.     if (SPEW) {  
  96.         Slog.d(TAG, "updateExpandedViewPos after  expandedPosition=" + expandedPosition  
  97.                 + " mTrackingParams.y=" + mTrackingParams.y  
  98.                 + " mTrackingPosition=" + mTrackingPosition  
  99.                 + " mExpandedParams.y=" + mExpandedParams.y  
  100.                 + " mExpandedParams.height=" + mExpandedParams.height);  
  101.     }  
  102. }  

以上代碼主要完成對TrackingView的屬性設置,,ExpandedView實際上是包裹在TrackingView中的,因此這里也附帶進行了設置,,最后更新,完成了整個Notification的加載。

       小結

       通過對Notification加載流程的分析,,對Notifification工作流程有了大致的了解,。針對上文中的分析可能部分地方還有所偏頗,還需要加強自己的代碼閱讀能力,。以下是簡單的時序圖,,如圖3:

圖3

    本站是提供個人知識管理的網絡存儲空間,所有內容均由用戶發(fā)布,,不代表本站觀點,。請注意甄別內容中的聯(lián)系方式、誘導購買等信息,,謹防詐騙,。如發(fā)現有害或侵權內容,請點擊一鍵舉報,。
    轉藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多