SystemUI NavigationBar process


Zygote -> SystemServer /SystemServer中会初始化一些Android的java层的服务,如ActivityManagerService、WindowManagerService..

SystemServer的run方法中startOtherServices来启动SystemUIService服务

frameworks\base\services\java\com\android\server\SystemServer.java中进行启动

static final void startSystemUi(Context context) {
    Intent intent = new Intent();
    intent.setComponent(new ComponentName("com.android.systemui",
                "com.android.systemui.SystemUIService"));
    //Slog.d(TAG, "Starting service: " + intent);
    context.startServiceAsUser(intent, UserHandle.OWNER);
}


SystemUIService 的onCreate中获取SystemUIApplication对象来初始化SystemUI相关的服务

SystemUIApplication.java{

   public void onCreate() {
      startServicesIfNeeded();
   }

   //初始化 SERVICES 数据中的 服务,for循环调用 onstart方法
   startServicesIfNeeded(){
      TunerService(定制状态栏服务)
      KeyguardViewMediator(锁屏相关)
      Recents(近期任务)
      VolumeUI(音量条)
      SystemBars(状态栏,导航栏)
      StorageNotification(通知栏)
      PowerUI(电源相关)
      RingtonePlayer(铃声播放相关)类
      它们都是继承与SystemUI抽象类
   }

}

  然后就走到了 SystemBar 这个类中

SystemBars.java{

   public void start() {
       ...
       createStatusBarFromConfig();  
    }

   createStatusBarFromConfig(){
      //通过config中配置的 类名实例化
      ...
      ...
      mStatusBar.mContext = mContext;
      mStatusBar.mComponents = mComponents;
      mStatusBar.start();//调用类的start方法
   }

}

  SystemBar 中去创建  statusbar.java 对象

StatusBar.java  {

     public void onStart(){

         //位置控制
        mLocationController
	  //电池
        mBatteryController
	 //网络
        mNetworkController 
	//热点
        mHotspotController
	//蓝牙
        mBluetoothController 
        mSecurityController 
	 //手电筒
        mFlashlightController
	 //键盘
        mKeyguardBottomArea
	.....

	createAndAddWindows()


	//Set up the quick settings tile panel
	
	mQSPanel
	mQSBarControll
	QSFragment.

	}


        createAndAddWindows --> addStatusBarWindow --> makeStatusBarView 

        // 这里就是处理 状态栏的一些加载和逻辑
        makeStatusBarView{


	//加载StartBarWindowView视图
	mStatusBarWindow = (StatusBarWindowView) View.inflate(context,
		R.layout.super_status_bar, null);

        mStatusBarWindow.setService(this);
        //监听下拉事件
        mStatusBarWindow.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                checkUserAutohide(v, event);
                if (event.getAction() == MotionEvent.ACTION_DOWN) {
                    if (mExpandedVisible) {
                        animateCollapsePanels();
                    }
                }
                return mStatusBarWindow.onTouchEvent(event);
            }
        });

        
	 //通知栏
        mNotificationPanel = (NotificationPanelView) mStatusBarWindow.findViewById(R.id.notification_panel);
        mNotificationPanel.setStatusBar(this);

         //状态栏
        mStatusBarView = (PhoneStatusBarView) mStatusBarWindow.findViewById(R.id.status_bar);
        mStatusBarView.setBar(this);


	//****** 是否显示导航栏 ******//
	boolean showNav = mWindowManagerService.hasNavigationBar();
	//**** 实际调用地方  
	 frameworks\base\service\core\java\com\android\server\PhoneWindowManager.java
         PhoneWindowManager{
	   
	    @Override
	    public boolean hasNavigationBar() {
		return mHasNavigationBar;
	    }

	    mHasNavigationBar = res.getBoolean(com.android.internal.R.bool.config_showNavigationBar);
	    // Allow a system property to override this. Used by the emulator.
	    // See also hasNavigationBar().
	    String navBarOverride = SystemProperties.get("qemu.hw.mainkeys");
	    if ("1".equals(navBarOverride)) {
		 mHasNavigationBar = false;
	     } else if ("0".equals(navBarOverride)) {
		 mHasNavigationBar = true;
	    }
	 } ***//


	if(showNav){
	   //创建导航栏
	   createNavigationBar();
	}
	.....



        //下拉通知栏
        mStackScroller = (NotificationStackScrollLayout) mStatusBarWindow.findViewById(
                R.id.notification_stack_scroller);
        mStackScroller.setLongPressListener(getNotificationLongClicker());
        mStackScroller.setPhoneStatusBar(this);
        mStackScroller.setGroupManager(mGroupManager);
        mStackScroller.setHeadsUpManager(mHeadsUpManager);
        mGroupManager.setOnGroupChangeListener(mStackScroller);
        ....
	.....

	
	//下拉清除键,代码位置不同版本会变,搜索 mDismissView
        mDismissView = (DismissView) LayoutInflater.from(mContext).inflate(
                R.layout.status_bar_notification_dismiss_all, mStackScroller, false);


	//锁屏相关,,代码位置不同版本会变,搜索 mKeyguardStatusBar
        mKeyguardStatusBar = (KeyguardStatusBarView) mStatusBarWindow.findViewById(R.id.keyguard_header);
        mKeyguardStatusView = mStatusBarWindow.findViewById(R.id.keyguard_status_view);
        mKeyguardBottomArea =
                (KeyguardBottomAreaView) mStatusBarWindow.findViewById(R.id.keyguard_bottom_area);
        mKeyguardBottomArea.setActivityStarter(this);
        mKeyguardBottomArea.setAssistManager(mAssistManager);
        mKeyguardIndicationController = new KeyguardIndicationController(mContext,
                (KeyguardIndicationTextView) mStatusBarWindow.findViewById(
                        R.id.keyguard_indication_text),
                mKeyguardBottomArea.getLockIcon());
        mKeyguardBottomArea.setKeyguardIndicationController(mKeyguardIn


	//主要是控制一些系统图标,第三方图标等的显示和更新
        mIconController = new StatusBarIconController(
                mContext, mStatusBarView, mKeyguardStatusBar, this);

        // Background thread for any controllers that need it.
        mHandlerThread = new HandlerThread(TAG, Process.THREAD_PRIORITY_BACKGROUND);
        mHandlerThread.start();

      }

      createNavigationBar{
           //创建 Nav
	   NavigationBarFragment.create()
      }
}

 NavigationBarFragment.java  这个类, 调用静态 oncreate() 去实例化

NavigationBarFragment.java{

	public void onCreateView(){
	   //这里就是  navigation_bar.xml 的布局 
	   //这个布局老版本是画好的
	   //8.0 是在 NavigationBarInflaterView 中按照config 配置加载的
	   return inflater.inflat(R.layout.navigation_bar, container, false);
	}

    public void  onViewCreated(View view, Bundle ){
	      mNavigationBarView = (mNavigationBarView)view
	      mNavigationBarView.setOntouchListener();
	}

	private void prepareNavigationBarView() {
		//决定导航栏的显示
		mNavigationBarView.reorient(); 
		//设置导航栏三个图标的点击事件
		mNavigationBarView.getRecentsButton().setOnClickListener(mRecentsClickListener);
		mNavigationBarView.getRecentsButton().setOnTouchListener(mRecentsPreloadOnTouchListener);
		mNavigationBarView.getRecentsButton().setLongClickable(true);
		mNavigationBarView.getRecentsButton().setOnLongClickListener(mLongPressBackRecentsListener);
		mNavigationBarView.getBackButton().setLongClickable(true);
		mNavigationBarView.getBackButton().setOnLongClickListener(mLongPressBackRecentsListener);
		mNavigationBarView.getHomeButton().setOnTouchListener(mHomeActionListener);
		mNavigationBarView.getHomeButton().setOnLongClickListener(mLongPressHomeListener);
	       .....
	}

        //创建 navigationbar
        public static View create(){
	
	   //设置 Nav  LayoutParams
           WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
                LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT,
                WindowManager.LayoutParams.TYPE_NAVIGATION_BAR,//导航栏
                    0
                    | WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING//当手机处于睡眠状态时,如果屏幕被按下,那么该window将第一个收到到事件
                    | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE//不获取焦点
                    | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL//即使在该window在可获得焦点情况下,仍然把该window之外的任何event发送到该window之后的其他window
                    | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH//不接受事件,转发到其他window
                    | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,//当该window在可以接受触摸屏情况下,让因在该window之外,而发送到后面的window的触摸屏可以支持split touch.

      
	        lp.setTitle("NavigationBar");
	
	}

}

 NavigationBarFragment.java 加载的 navigation_bar.xml  --- (关键词 keybuttonview 的使用地方)

  8.0 是加载的  NavigationBarView , NavigationBarInflaterView.java

<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.java 

  在NavigationBarView导航栏这个布局加载的时候就会设置图片资源,和长度改变,屏幕旋转都有可能引起重新设置

NavigationBarView(){

  NavigationBarInflateView

  public NavigationBarView(Context context, AttributeSet attrs) {
        super(context, attrs);

        mDisplay = ((WindowManager) context.getSystemService(
                Context.WINDOW_SERVICE)).getDefaultDisplay();
        ...
        /********   更新icon   *****/
        updateIcons(context, Configuration.EMPTY, mConfiguration);
        /********   更新icon   *****/

        mBarTransitions = new NavigationBarTransitions(this);

        //mButtonDispatchers 是维护这些home back recent图标view的管理类,
	//传递到他的child,NavigationBarInflaterView类中
        mButtonDispatchers.put(R.id.back, new ButtonDispatcher(R.id.back));
        mButtonDispatchers.put(R.id.home, new ButtonDispatcher(R.id.home));
        mButtonDispatchers.put(R.id.recent_apps, new ButtonDispatcher(R.id.recent_apps));
        mButtonDispatchers.put(R.id.menu, new ButtonDispatcher(R.id.menu));
        mButtonDispatchers.put(R.id.ime_switcher, new ButtonDispatcher(R.id.ime_switcher));
        mButtonDispatchers.put(R.id.accessibility_button,
                new ButtonDispatcher(R.id.accessibility_button));
    }


    private void updateIcons(Context ctx, Configuration oldConfig, Configuration newConfig) {

           ...
            mHomeDefaultIcon = getDrawable(ctx,
                    R.drawable.ic_sysbar_home, R.drawable.ic_sysbar_home_dark);
            mHomeDefaultIcon = getDrawable(iconLight,iconDark);
            ...
   }

  public void reorient() {
        //获取屏幕方向
        final int rot = mDisplay.getRotation();
        //隐藏导航栏布局
        for (int i=0; i<4; i++) {
            mRotatedViews[i].setVisibility(View.GONE);
        }
        //根据屏幕方向显示导航栏布局
        mCurrentView = mRotatedViews[rot];
        mCurrentView.setVisibility(View.VISIBLE);
        setLayoutTransitionsEnabled(mLayoutTransitionsEnabled);
 
        getImeSwitchButton().setOnClickListener(mImeSwitcherClickListener);
        mDeadZone = (DeadZone) mCurrentView.findViewById(R.id.deadzone);
        // force the low profile & disabled states into compliance
        mBarTransitions.init();
        setDisabledFlags(mDisabledFlags, true /* force */);
        setMenuVisibility(mShowMenu, true /* force */);
        updateTaskSwitchHelper();
        setNavigationIconHints(mNavigationIconHints, true);
    }


    @Override
    public void onFinishInflate() {
        //屏幕方位0和180方向显示的导航栏为rot0
        mRotatedViews[Surface.ROTATION_0] =
        mRotatedViews[Surface.ROTATION_180] = findViewById(R.id.rot0);
        //屏幕访问90和270显示的导航栏为rot90
        mRotatedViews[Surface.ROTATION_90] = findViewById(R.id.rot90);
 
        mRotatedViews[Surface.ROTATION_270] = mRotatedViews[Surface.ROTATION_90];
 
        //mCurrentView = mRotatedViews[Surface.ROTATION_0];
        mCurrentView = mRotatedViews[Surface.ROTATION_90];
        getImeSwitchButton().setOnClickListener(mImeSwitcherClickListener);
 
        updateRTLOrder();
    }
   
}

  NavigationBarInflaterView.java  ,去创建每个具体的按钮  KeyButtonView

NavigationBarInflaterView.java{

	 private View createView(String buttonSpec, ViewGroup parent, LayoutInflater inflater) {
		View v = null;
		...
		//每个按钮
		if (HOME.equals(button)) {
		    v = inflater.inflate(R.layout.home, parent, false);
		} else if (BACK.equals(button)) {
		    v = inflater.inflate(R.layout.back, parent, false);
		} else if (RECENT.equals(button)) {
		    v = inflater.inflate(R.layout.recent_apps, parent, false);
		} else if (MENU_IME.equals(button)) {
		    v = inflater.inflate(R.layout.menu_ime, parent, false);
		} else if (NAVSPACE.equals(button)) {
		    v = inflater.inflate(R.layout.nav_key_space, parent, false);
		} else if (CLIPBOARD.equals(button)) {
		    v = inflater.inflate(R.layout.clipboard, parent, false);
		}
		//如果添加自己的   hide 按钮
                else if(){
		}
		...
		return v;
	    }

	    //*****  KeyButtonView  *********
            R.layout.home.xml,......
	    <com.android.systemui.statusbar.policy.KeyButtonView
	    xmlns:android="http://schemas.android.com/apk/res/android"
	    xmlns:systemui="http://schemas.android.com/apk/res-auto"
	    android:id="@+id/home"
	    android:layout_width="@dimen/navigation_key_width"//引用了dimens.xml里的navigation_key_width
	    android:layout_height="match_parent"
	    android:layout_weight="0"
	    systemui:keyCode="3"//systemui自定义的属性
	    android:scaleType="fitCenter"
	    android:contentDescription="@string/accessibility_home"
	    android:paddingTop="@dimen/home_padding"
	    android:paddingBottom="@dimen/home_padding"
	    android:paddingStart="@dimen/navigation_key_padding"
	    android:paddingEnd="@dimen/navigation_key_padding"
	    />

            KeyButtonView.java{
		     public KeyButtonView(Context context, AttributeSet attrs, int defStyle) {
			super(context, attrs);
		    }

                    //监听导航栏每个keyButton按钮
		    public boolean onTouchEvent(MotionEvent ev) {
			switch (action) {
			    case MotionEvent.ACTION_DOWN:
				mDownTime = SystemClock.uptimeMillis();
				mLongClicked = false;
				setPressed(true);
				if (mCode != 0) {
				    //发送事件
				    sendEvent(KeyEvent.ACTION_DOWN, 0, mDownTime);
				} else {
				    // Provide the same haptic feedback that the system offers for virtual keys.
				    performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
				}
				playSoundEffect(SoundEffectConstants.CLICK);
				removeCallbacks(mCheckLongPress);
				postDelayed(mCheckLongPress, ViewConfiguration.getLongPressTimeout());
				break;
			}

			return true;
		    }

		 void sendEvent(int action, int flags, long when) {
			
			final int repeatCount = (flags & KeyEvent.FLAG_LONG_PRESS) != 0 ? 1 : 0;
			//根据mCode new了一个KeyEvent事件
			final KeyEvent ev = new KeyEvent(mDownTime, when, action, mCode, repeatCount,
				0, KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
				flags | KeyEvent.FLAG_FROM_SYSTEM | KeyEvent.FLAG_VIRTUAL_HARD_KEY,
				InputDevice.SOURCE_KEYBOARD);
			//injectInputEvent使事件生效
			InputManager.getInstance().injectInputEvent(ev,
				InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
		    }
	    }

	    ***/

          onFinishInflate(){
	  inflateLayout();
	 }

	 //加载 Nav 布局
	 inflateLayout(){
	 
	     newLayout = getDefaultLayout();
	     //<string name="config_navBarLayout" translatable="false">left;back,home,recent;right</string>
       
             String[] sets = newLayout.split(GRAVITY_SEPARATOR, 3);//根据“;”号分割成长度为3的数组
             String[] start = sets[0].split(BUTTON_SEPARATOR);//根据“,”号分割,包含 left[.5W]和back[1WC]
             String[] center = sets[1].split(BUTTON_SEPARATOR);//home
             String[] end = sets[2].split(BUTTON_SEPARATOR);//含recent[1WC]和right[.5W]
	     inflateButtons();
	   ...
	 }

         //虚拟键的配置, 是存在在 conif
	 getDefaultLayouts(){
            R.string.config_nav  -- 需要在配置中添加 
	 }

        private void inflateButtons(String[] buttons, ViewGroup parent, boolean landscape,
              boolean start) {
          for (int i = 0; i < buttons.length; i++) {
             inflateButton(buttons[i], parent, landscape, start);
          }
        }

        @Nullable
        protected View inflateButton(String buttonSpec, ViewGroup parent, boolean landscape,
             boolean start) {
          LayoutInflater inflater = landscape ? mLandscapeInflater : mLayoutInflater;
          View v = createView(buttonSpec, parent, inflater);//创建view
          if (v == null) return null;

           v = applySize(v, buttonSpec, landscape, start);
           parent.addView(v);//addView到父布局
           addToDispatchers(v);
	   ...
	   
	   }

}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

空白的泡

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值