当前位置:   article > 正文

Android SystemUI之导航栏(四)_android 11 systemui 导航栏添加按钮

android 11 systemui 导航栏添加按钮

一、View结构

 

 二、导航栏的创建

1.SystemUI\src\com\android\systemui\statusbar\phone\StatusBar.java

从导航栏的入口看。

  1. protected void makeStatusBarView(@Nullable RegisterStatusBarResult result) {
  2. final Context context = mContext;
  3. updateDisplaySize(); // populates mDisplayMetrics
  4. updateResources();
  5. updateTheme();
  6. inflateStatusBarWindow(); //将R.layout.super_status_bar布局文件构建成对应的视图。
  7. ....
  8. createNavigationBar(result); //创建导航栏
  1. // TODO(b/117478341): This was left such that CarStatusBar can override this method.
  2. // Try to remove this.
  3. protected void createNavigationBar(@Nullable RegisterStatusBarResult result) {
  4. mNavigationBarController.createNavigationBars(true /* includeDefaultDisplay */, result);
  5. }

2.SystemUI\src\com\android\systemui\statusbar\NavigationBarController.java

进入createNavigationBar方法,发现主要是用NavigationBarFragment来管理。

  1. void createNavigationBar(Display display, RegisterStatusBarResult result) {
  2. if (display == null) {
  3. return;
  4. }
  5. final int displayId = display.getDisplayId();
  6. final boolean isOnDefaultDisplay = displayId == DEFAULT_DISPLAY;
  7. final IWindowManager wms = WindowManagerGlobal.getWindowManagerService();
  8. try {
  9. if (!wms.hasNavigationBar(displayId)) {
  10. return;
  11. }
  12. } catch (RemoteException e) {
  13. // Cannot get wms, just return with warning message.
  14. Log.w(TAG, "Cannot get WindowManager.");
  15. return;
  16. }
  17. final Context context = isOnDefaultDisplay
  18. ? mContext
  19. : mContext.createDisplayContext(display);
  20. NavigationBarFragment.create(context, (tag, fragment) -> {
  21. NavigationBarFragment navBar = (NavigationBarFragment) fragment;
  22. // Unfortunately, we still need it because status bar needs LightBarController
  23. // before notifications creation. We cannot directly use getLightBarController()
  24. // from NavigationBarFragment directly.
  25. LightBarController lightBarController = isOnDefaultDisplay
  26. ? Dependency.get(LightBarController.class)
  27. : new LightBarController(context,
  28. Dependency.get(DarkIconDispatcher.class),
  29. Dependency.get(BatteryController.class),
  30. Dependency.get(NavigationModeController.class));
  31. navBar.setLightBarController(lightBarController);
  32. // TODO(b/118592525): to support multi-display, we start to add something which is
  33. // per-display, while others may be global. I think it's time to add
  34. // a new class maybe named DisplayDependency to solve per-display
  35. // Dependency problem.
  36. AutoHideController autoHideController = isOnDefaultDisplay
  37. ? Dependency.get(AutoHideController.class)
  38. : new AutoHideController(context, mHandler,
  39. Dependency.get(IWindowManager.class));
  40. navBar.setAutoHideController(autoHideController);
  41. navBar.restoreAppearanceAndTransientState();
  42. mNavigationBars.append(displayId, navBar);
  43. if (result != null) {
  44. navBar.setImeWindowStatus(display.getDisplayId(), result.mImeToken,
  45. result.mImeWindowVis, result.mImeBackDisposition,
  46. result.mShowImeSwitcher);
  47. }
  48. });
  49. }

3.SystemUI\src\com\android\systemui\statusbar\phone\NavigationBarFragment.java

创建navigationBarView 并且把navigationBarView添加到windowManager中。

  1. public static View create(Context context, FragmentListener listener) {
  2. WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
  3. LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT,
  4. WindowManager.LayoutParams.TYPE_NAVIGATION_BAR,
  5. WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING
  6. | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
  7. | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
  8. | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
  9. | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
  10. | WindowManager.LayoutParams.FLAG_SLIPPERY,
  11. PixelFormat.TRANSLUCENT);
  12. lp.token = new Binder();
  13. lp.setTitle("NavigationBar" + context.getDisplayId());
  14. lp.accessibilityTitle = context.getString(R.string.nav_bar);
  15. lp.windowAnimations = 0;
  16. lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC;
  17. View navigationBarView = LayoutInflater.from(context).inflate(
  18. R.layout.navigation_bar_window, null);
  19. if (DEBUG) Log.v(TAG, "addNavigationBar: about to add " + navigationBarView);
  20. if (navigationBarView == null) return null;
  21. final NavigationBarFragment fragment = FragmentHostManager.get(navigationBarView)
  22. .create(NavigationBarFragment.class);
  23. navigationBarView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
  24. @Override
  25. public void onViewAttachedToWindow(View v) {
  26. final FragmentHostManager fragmentHost = FragmentHostManager.get(v);
  27. fragmentHost.getFragmentManager().beginTransaction()
  28. .replace(R.id.navigation_bar_frame, fragment, TAG)
  29. .commit();
  30. fragmentHost.addTagListener(TAG, listener);
  31. }
  32. @Override
  33. public void onViewDetachedFromWindow(View v) {
  34. FragmentHostManager.removeAndDestroy(v);
  35. navigationBarView.removeOnAttachStateChangeListener(this);
  36. }
  37. });
  38. context.getSystemService(WindowManager.class).addView(navigationBarView, lp);
  39. return navigationBarView;
  40. }

4.看下NavigationBarFragment的生命周期。onCreateView()里,导航栏的真正的rootView。

  1. @Override
  2. public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
  3. Bundle savedInstanceState) {
  4. return inflater.inflate(R.layout.navigation_bar, container, false);
  5. }

5.SystemUI\res\layout\navigation_bar.xml。

进入导航栏的真正根布局:navigation_bar.xml,好吧又是自定义view,NavigationBarView和NavigationBarInflaterView都要仔细研读。

  1. <com.android.systemui.statusbar.phone.NavigationBarView
  2. xmlns:android="http://schemas.android.com/apk/res/android"
  3. xmlns:systemui="http://schemas.android.com/apk/res-auto"
  4. android:layout_height="match_parent"
  5. android:layout_width="match_parent"
  6. android:background="@drawable/system_bar_background">
  7. <com.android.systemui.CornerHandleView
  8. android:id="@+id/assist_hint_left"
  9. android:layout_width="36dp"
  10. android:layout_height="36dp"
  11. android:layout_gravity="left|bottom"
  12. android:rotation="270"
  13. android:visibility="gone"/>
  14. <com.android.systemui.CornerHandleView
  15. android:id="@+id/assist_hint_right"
  16. android:layout_width="36dp"
  17. android:layout_height="36dp"
  18. android:layout_gravity="right|bottom"
  19. android:rotation="180"
  20. android:visibility="gone"/>
  21. <com.android.systemui.statusbar.phone.NavigationBarInflaterView
  22. android:id="@+id/navigation_inflater"
  23. android:layout_width="match_parent"
  24. android:layout_height="match_parent" />
  25. </com.android.systemui.statusbar.phone.NavigationBarView>

6.SystemUI\src\com\android\systemui\statusbar\phone\NavigationBarInflaterView.java;继承自FrameLayout

看下onFinishInflate()方法,这是view的生命周期,每个view被inflate之后都会回调。

  1. @Override
  2. protected void onFinishInflate() {
  3. super.onFinishInflate();
  4. inflateChildren();
  5. clearViews();
  6. inflateLayout(getDefaultLayout());
  7. }
  8. private void inflateChildren() {
  9. removeAllViews();
  10. mHorizontal = (FrameLayout) mLayoutInflater.inflate(R.layout.navigation_layout,
  11. this /* root */, false /* attachToRoot */);
  12. addView(mHorizontal);
  13. mVertical = (FrameLayout) mLayoutInflater.inflate(R.layout.navigation_layout_vertical,
  14. this /* root */, false /* attachToRoot */);
  15. addView(mVertical);
  16. updateAlternativeOrder();
  17. }
  1. protected String getDefaultLayout() {
  2. final int defaultResource = R.string.config_navBarLayout;/*QuickStepContract.isGesturalMode(mNavBarMode)
  3. ? R.string.config_navBarLayoutHandle
  4. : mOverviewProxyService.shouldShowSwipeUpUI()
  5. ? R.string.config_navBarLayoutQuickstep
  6. : R.string.config_navBarLayout;*/
  7. return getContext().getString(defaultResource);
  8. }
  9. //<!-- Nav bar button default ordering/layout -->
  10. <string name="config_navBarLayout" translatable="false">left;back,home,recent,screenshot;right</string>

看inflateLayout():里面的newLayout参数很重要!!!根据上一个方法看到getDefaultLayout(),他return了一个在xml写死的字符串。再看inflateLayout方法,他解析分割了xml里配置的字符串,并传给了inflateButtons方法。

  1. protected void inflateLayout(String newLayout) {
  2. mCurrentLayout = newLayout;
  3. if (newLayout == null) {
  4. newLayout = getDefaultLayout();
  5. }
  6. String[] sets = newLayout.split(GRAVITY_SEPARATOR, 3);
  7. if (sets.length != 3) {
  8. Log.d(TAG, "Invalid layout.");
  9. newLayout = getDefaultLayout();
  10. sets = newLayout.split(GRAVITY_SEPARATOR, 3);
  11. }
  12. String[] start = sets[0].split(BUTTON_SEPARATOR);
  13. String[] center = sets[1].split(BUTTON_SEPARATOR);
  14. String[] end = sets[2].split(BUTTON_SEPARATOR);
  15. // Inflate these in start to end order or accessibility traversal will be messed up.
  16. inflateButtons(start, mHorizontal.findViewById(R.id.ends_group),
  17. false /* landscape */, true /* start */);
  18. inflateButtons(start, mVertical.findViewById(R.id.ends_group),
  19. true /* landscape */, true /* start */);
  20. inflateButtons(center, mHorizontal.findViewById(R.id.center_group),
  21. false /* landscape */, false /* start */);
  22. inflateButtons(center, mVertical.findViewById(R.id.center_group),
  23. true /* landscape */, false /* start */);
  24. addGravitySpacer(mHorizontal.findViewById(R.id.ends_group));
  25. addGravitySpacer(mVertical.findViewById(R.id.ends_group));
  26. inflateButtons(end, mHorizontal.findViewById(R.id.ends_group),
  27. false /* landscape */, false /* start */);
  28. inflateButtons(end, mVertical.findViewById(R.id.ends_group),
  29. true /* landscape */, false /* start */);
  30. updateButtonDispatchersCurrentView();
  31. }

再看inflateButtons()方法,遍历加载inflateButton:

  1. private void inflateButtons(String[] buttons, ViewGroup parent, boolean landscape,
  2. boolean start) {
  3. for (int i = 0; i < buttons.length; i++) {
  4. inflateButton(buttons[i], parent, landscape, start);
  5. }
  6. }
  1. @Nullable
  2. protected View inflateButton(String buttonSpec, ViewGroup parent, boolean landscape,
  3. boolean start) {
  4. LayoutInflater inflater = landscape ? mLandscapeInflater : mLayoutInflater;
  5. View v = createView(buttonSpec, parent, inflater);
  6. if (v == null) return null;
  7. v = applySize(v, buttonSpec, landscape, start);
  8. parent.addView(v);
  9. addToDispatchers(v);
  10. View lastView = landscape ? mLastLandscape : mLastPortrait;
  11. View accessibilityView = v;
  12. if (v instanceof ReverseRelativeLayout) {
  13. accessibilityView = ((ReverseRelativeLayout) v).getChildAt(0);
  14. }
  15. if (lastView != null) {
  16. accessibilityView.setAccessibilityTraversalAfter(lastView.getId());
  17. }
  18. if (landscape) {
  19. mLastLandscape = accessibilityView;
  20. } else {
  21. mLastPortrait = accessibilityView;
  22. }
  23. return v;
  24. }

我们来看createView()方法:以home按键为例,加载了home的button,其实是加载了R.layout.home的layout布局。

  1. private View createView(String buttonSpec, ViewGroup parent, LayoutInflater inflater) {
  2. View v = null;
  3. String button = extractButton(buttonSpec);
  4. if (LEFT.equals(button)) {
  5. button = extractButton(NAVSPACE);
  6. } else if (RIGHT.equals(button)) {
  7. button = extractButton(MENU_IME_ROTATE);
  8. }
  9. if (HOME.equals(button)) {
  10. v = inflater.inflate(R.layout.home, parent, false);
  11. } else if (BACK.equals(button)) {
  12. v = inflater.inflate(R.layout.back, parent, false);
  13. } else if (RECENT.equals(button)) {
  14. v = inflater.inflate(R.layout.recent_apps, parent, false);
  15. } else if (SCREENSHOT.equals(button)) { //laiyw
  16. v = inflater.inflate(R.layout.screenshot, parent, false);
  17. } else if (MENU_IME_ROTATE.equals(button)) {
  18. v = inflater.inflate(R.layout.menu_ime, parent, false);
  19. } else if (NAVSPACE.equals(button)) {
  20. v = inflater.inflate(R.layout.nav_key_space, parent, false);
  21. } else if (CLIPBOARD.equals(button)) {
  22. v = inflater.inflate(R.layout.clipboard, parent, false);
  23. } else if (CONTEXTUAL.equals(button)) {
  24. v = inflater.inflate(R.layout.contextual, parent, false);
  25. } else if (HOME_HANDLE.equals(button)) {
  26. v = inflater.inflate(R.layout.home_handle, parent, false);
  27. } else if (IME_SWITCHER.equals(button)) {
  28. v = inflater.inflate(R.layout.ime_switcher, parent, false);
  29. } else if (button.startsWith(KEY)) {
  30. String uri = extractImage(button);
  31. int code = extractKeycode(button);
  32. v = inflater.inflate(R.layout.custom_key, parent, false);
  33. ((KeyButtonView) v).setCode(code);
  34. if (uri != null) {
  35. if (uri.contains(":")) {
  36. ((KeyButtonView) v).loadAsync(Icon.createWithContentUri(uri));
  37. } else if (uri.contains("/")) {
  38. int index = uri.indexOf('/');
  39. String pkg = uri.substring(0, index);
  40. int id = Integer.parseInt(uri.substring(index + 1));
  41. ((KeyButtonView) v).loadAsync(Icon.createWithResource(pkg, id));
  42. }
  43. }
  44. }
  45. return v;
  46. }

7.SystemUI\res\layout\home.xml

  1. <com.android.systemui.statusbar.policy.KeyButtonView
  2. xmlns:android="http://schemas.android.com/apk/res/android"
  3. xmlns:systemui="http://schemas.android.com/apk/res-auto"
  4. android:id="@+id/home"
  5. android:layout_width="@dimen/navigation_key_width"
  6. android:layout_height="match_parent"
  7. android:layout_weight="0"
  8. systemui:keyCode="3"
  9. android:scaleType="center"
  10. android:contentDescription="@string/accessibility_home"
  11. android:paddingStart="@dimen/navigation_key_padding"
  12. android:paddingEnd="@dimen/navigation_key_padding"
  13. />

8.SystemUI\src\com\android\systemui\statusbar\policy\KeyButtonView.java

先来看KeyButtonView的构造方法:我们之前xml的systemui:keyCode="3"方法在这里获取。再来看Touch事件,通过sendEvent()方法可以看出,back等view的点击touch事件不是自己处理的,而是交由系统以实体按键(keycode)的形式处理的。

当然KeyButtonView类还处理了支持长按的button,按键的响声等。

  1. @VisibleForTesting
  2. public KeyButtonView(Context context, AttributeSet attrs, int defStyle, InputManager manager,
  3. UiEventLogger uiEventLogger) {
  4. super(context, attrs);
  5. mUiEventLogger = uiEventLogger;
  6. TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.KeyButtonView,
  7. defStyle, 0);
  8. mCode = a.getInteger(R.styleable.KeyButtonView_keyCode, KEYCODE_UNKNOWN);
  9. mPlaySounds = a.getBoolean(R.styleable.KeyButtonView_playSound, true);
  10. TypedValue value = new TypedValue();
  11. if (a.getValue(R.styleable.KeyButtonView_android_contentDescription, value)) {
  12. mContentDescriptionRes = value.resourceId;
  13. }
  14. a.recycle();
  15. setClickable(true);
  16. mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
  17. mRipple = new KeyButtonRipple(context, this);
  18. mOverviewProxyService = Dependency.get(OverviewProxyService.class);
  19. mInputManager = manager;
  20. setBackground(mRipple);
  21. setWillNotDraw(false);
  22. forceHasOverlappingRendering(false);
  23. }
  1. @Override
  2. public boolean onTouchEvent(MotionEvent ev) {
  3. final boolean showSwipeUI = mOverviewProxyService.shouldShowSwipeUpUI();
  4. final int action = ev.getAction();
  5. int x, y;
  6. if (action == MotionEvent.ACTION_DOWN) {
  7. mGestureAborted = false;
  8. }
  9. if (mGestureAborted) {
  10. setPressed(false);
  11. return false;
  12. }
  13. switch (action) {
  14. case MotionEvent.ACTION_DOWN:
  15. mDownTime = SystemClock.uptimeMillis();
  16. mLongClicked = false;
  17. setPressed(true);
  18. // Use raw X and Y to detect gestures in case a parent changes the x and y values
  19. mTouchDownX = (int) ev.getRawX();
  20. mTouchDownY = (int) ev.getRawY();
  21. if (mCode != KEYCODE_UNKNOWN) {
  22. sendEvent(KeyEvent.ACTION_DOWN, 0, mDownTime);
  23. } else {
  24. // Provide the same haptic feedback that the system offers for virtual keys.
  25. performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
  26. }
  27. if (!showSwipeUI) {
  28. playSoundEffect(SoundEffectConstants.CLICK);
  29. }
  30. removeCallbacks(mCheckLongPress);
  31. postDelayed(mCheckLongPress, ViewConfiguration.getLongPressTimeout());
  32. break;
  33. case MotionEvent.ACTION_MOVE:
  34. x = (int)ev.getRawX();
  35. y = (int)ev.getRawY();
  36. float slop = QuickStepContract.getQuickStepTouchSlopPx(getContext());
  37. if (Math.abs(x - mTouchDownX) > slop || Math.abs(y - mTouchDownY) > slop) {
  38. // When quick step is enabled, prevent animating the ripple triggered by
  39. // setPressed and decide to run it on touch up
  40. setPressed(false);
  41. removeCallbacks(mCheckLongPress);
  42. }
  43. break;
  44. case MotionEvent.ACTION_CANCEL:
  45. setPressed(false);
  46. if (mCode != KEYCODE_UNKNOWN) {
  47. sendEvent(KeyEvent.ACTION_UP, KeyEvent.FLAG_CANCELED);
  48. }
  49. removeCallbacks(mCheckLongPress);
  50. break;
  51. case MotionEvent.ACTION_UP:
  52. final boolean doIt = isPressed() && !mLongClicked;
  53. setPressed(false);
  54. final boolean doHapticFeedback = (SystemClock.uptimeMillis() - mDownTime) > 150;
  55. if (showSwipeUI) {
  56. if (doIt) {
  57. // Apply haptic feedback on touch up since there is none on touch down
  58. performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
  59. playSoundEffect(SoundEffectConstants.CLICK);
  60. }
  61. } else if (doHapticFeedback && !mLongClicked) {
  62. // Always send a release ourselves because it doesn't seem to be sent elsewhere
  63. // and it feels weird to sometimes get a release haptic and other times not.
  64. performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY_RELEASE);
  65. }
  66. if (mCode != KEYCODE_UNKNOWN) {
  67. if (doIt) {
  68. sendEvent(KeyEvent.ACTION_UP, 0);
  69. sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
  70. } else {
  71. sendEvent(KeyEvent.ACTION_UP, KeyEvent.FLAG_CANCELED);
  72. }
  73. } else {
  74. // no key code, just a regular ImageView
  75. if (doIt && mOnClickListener != null) {
  76. mOnClickListener.onClick(this);
  77. sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
  78. }
  79. }
  80. removeCallbacks(mCheckLongPress);
  81. break;
  82. }
  83. return true;
  84. }
  1. private void sendEvent(int action, int flags, long when) {
  2. mMetricsLogger.write(new LogMaker(MetricsEvent.ACTION_NAV_BUTTON_EVENT)
  3. .setType(MetricsEvent.TYPE_ACTION)
  4. .setSubtype(mCode)
  5. .addTaggedData(MetricsEvent.FIELD_NAV_ACTION, action)
  6. .addTaggedData(MetricsEvent.FIELD_FLAGS, flags));
  7. logSomePresses(action, flags);
  8. if (mCode == KeyEvent.KEYCODE_BACK && flags != KeyEvent.FLAG_LONG_PRESS) {
  9. Log.i(TAG, "Back button event: " + KeyEvent.actionToString(action));
  10. if (action == MotionEvent.ACTION_UP) {
  11. mOverviewProxyService.notifyBackAction((flags & KeyEvent.FLAG_CANCELED) == 0,
  12. -1, -1, true /* isButton */, false /* gestureSwipeLeft */);
  13. }
  14. }
  15. final int repeatCount = (flags & KeyEvent.FLAG_LONG_PRESS) != 0 ? 1 : 0;
  16. final KeyEvent ev = new KeyEvent(mDownTime, when, action, mCode, repeatCount,
  17. 0, KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
  18. flags | KeyEvent.FLAG_FROM_SYSTEM | KeyEvent.FLAG_VIRTUAL_HARD_KEY,
  19. InputDevice.SOURCE_KEYBOARD);
  20. int displayId = INVALID_DISPLAY;
  21. // Make KeyEvent work on multi-display environment
  22. if (getDisplay() != null) {
  23. displayId = getDisplay().getDisplayId();
  24. }
  25. // Bubble controller will give us a valid display id if it should get the back event
  26. BubbleController bubbleController = Dependency.get(BubbleController.class);
  27. int bubbleDisplayId = bubbleController.getExpandedDisplayId(mContext);
  28. if (mCode == KeyEvent.KEYCODE_BACK && bubbleDisplayId != INVALID_DISPLAY) {
  29. displayId = bubbleDisplayId;
  30. }
  31. if (displayId != INVALID_DISPLAY) {
  32. ev.setDisplayId(displayId);
  33. }
  34. mInputManager.injectInputEvent(ev, InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
  35. }

9.那么我们现在布局文件都添加完成了,但是你会发现在NavigationBarInflaterView没有对资源文件添加的代码已经控件点击触摸事件处理逻辑。那么这两部分代码在哪里呢?

答案是:

1.NavigationBarView 完成资源文件添加。

2.NavigationBarFragment  添加点击事件和触摸事件的处理逻辑。

9.1.SystemUI\src\com\android\systemui\statusbar\phone\NavigationBarView.java

进入NavigationBarView类里,找到构造方法。

  1. public NavigationBarView(Context context, AttributeSet attrs) {
  2. super(context, attrs);
  3. ...
  4. ....
  5. //mButtonDispatchers 是维护这些home back recent图标view的管理类,会传递到他的child,NavigationBarInflaterView类中
  6. mButtonDispatchers.put(R.id.back, new ButtonDispatcher(R.id.back));
  7. mButtonDispatchers.put(R.id.home, new ButtonDispatcher(R.id.home));
  8. mButtonDispatchers.put(R.id.screenshot, new ButtonDispatcher(R.id.screenshot));
  9. mButtonDispatchers.put(R.id.home_handle, new ButtonDispatcher(R.id.home_handle));
  10. mButtonDispatchers.put(R.id.recent_apps, new ButtonDispatcher(R.id.recent_apps));
  11. mButtonDispatchers.put(R.id.ime_switcher, imeSwitcherButton);
  12. mButtonDispatchers.put(R.id.accessibility_button, accessibilityButton);
  13. mButtonDispatchers.put(R.id.rotate_suggestion, rotateSuggestionButton);
  14. mButtonDispatchers.put(R.id.menu_container, mContextualButtonGroup);
  15. mDeadZone = new DeadZone(this);
  16. ......
  17. }
  1. @Override
  2. public void onFinishInflate() {
  3. super.onFinishInflate();
  4. mNavigationInflaterView = findViewById(R.id.navigation_inflater);
  5. mNavigationInflaterView.setButtonDispatchers(mButtonDispatchers);
  6. getImeSwitchButton().setOnClickListener(mImeSwitcherClickListener);
  7. Divider divider = Dependency.get(Divider.class);
  8. divider.registerInSplitScreenListener(mDockedListener);
  9. updateOrientationViews();
  10. reloadNavIcons(); //加载图片
  11. }
  1. private void updateIcons(Configuration oldConfig) {
  2. final boolean orientationChange = oldConfig.orientation != mConfiguration.orientation;
  3. final boolean densityChange = oldConfig.densityDpi != mConfiguration.densityDpi;
  4. final boolean dirChange = oldConfig.getLayoutDirection() != mConfiguration.getLayoutDirection();
  5. if (orientationChange || densityChange) {
  6. mDockedIcon = getDrawable(R.drawable.ic_sysbar_docked);
  7. mHomeDefaultIcon = getHomeDrawable();
  8. }
  9. if (densityChange || dirChange) {
  10. mRecentIcon = getDrawable(R.drawable.ic_sysbar_recent);
  11. mScreenshot = getDrawable(R.drawable.ic_sysbar_shotscreen);
  12. mContextualButtonGroup.updateIcons();
  13. }
  14. if (orientationChange || densityChange || dirChange) {
  15. mBackIcon = getBackDrawable();
  16. }
  17. }

9.2.SystemUI\src\com\android\systemui\statusbar\phone\NavigationBarFragment.java

  1. @Override
  2. public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
  3. super.onViewCreated(view, savedInstanceState);
  4. mNavigationBarView = (NavigationBarView) view;
  5. final Display display = view.getDisplay();
  6. // It may not have display when running unit test.
  7. if (display != null) {
  8. mDisplayId = display.getDisplayId();
  9. mIsOnDefaultDisplay = mDisplayId == Display.DEFAULT_DISPLAY;
  10. }
  11. mNavigationBarView.setComponents(mStatusBarLazy.get().getPanelController());
  12. mNavigationBarView.setDisabledFlags(mDisabledFlags1);
  13. mNavigationBarView.setOnVerticalChangedListener(this::onVerticalChanged);
  14. mNavigationBarView.setOnTouchListener(this::onNavigationTouch);
  15. if (savedInstanceState != null) {
  16. mNavigationBarView.getLightTransitionsController().restoreState(savedInstanceState);
  17. }
  18. mNavigationBarView.setNavigationIconHints(mNavigationIconHints);
  19. mNavigationBarView.setWindowVisible(isNavBarWindowVisible());
  20. prepareNavigationBarView(); //事件处理
  21. checkNavBarModes();
  1. private void prepareNavigationBarView() {
  2. mNavigationBarView.reorient();
  3. ButtonDispatcher recentsButton = mNavigationBarView.getRecentsButton();
  4. recentsButton.setOnClickListener(this::onRecentsClick);
  5. recentsButton.setOnTouchListener(this::onRecentsTouch);
  6. recentsButton.setLongClickable(true);
  7. recentsButton.setOnLongClickListener(this::onLongPressBackRecents);
  8. ButtonDispatcher backButton = mNavigationBarView.getBackButton();
  9. backButton.setLongClickable(true);
  10. ButtonDispatcher homeButton = mNavigationBarView.getHomeButton();
  11. homeButton.setOnTouchListener(this::onHomeTouch);
  12. homeButton.setOnLongClickListener(this::onHomeLongClick);
  13. ButtonDispatcher accessibilityButton = mNavigationBarView.getAccessibilityButton();
  14. accessibilityButton.setOnClickListener(this::onAccessibilityClick);
  15. accessibilityButton.setOnLongClickListener(this::onAccessibilityLongClick);
  16. updateAccessibilityServicesState(mAccessibilityManager);
  17. updateScreenPinningGestures();
  18. }

至此,SystemUI的虚拟导航栏模块代码流程结束。

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号