赞
踩
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);
- });
- }
- 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
- <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>
我们先看NavigationBarInflaterView
- public NavigationBarInflaterView(Context context, AttributeSet attrs) {
- super(context, attrs);
- createInflaters();
- mDisplay = ((WindowManager)
- context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
- Mode displayMode = mDisplay.getMode();
- isRot0Landscape = displayMode.getPhysicalWidth() > displayMode.getPhysicalHeight();
-
- mOverviewProxyService = Dependency.get(OverviewProxyService.class);
- }
-
- private void createInflaters() {
- mLayoutInflater = LayoutInflater.from(mContext);
- Configuration landscape = new Configuration();
- landscape.setTo(mContext.getResources().getConfiguration());
- landscape.orientation = Configuration.ORIENTATION_LANDSCAPE;
- mLandscapeInflater = LayoutInflater.from(mContext.createConfigurationContext(landscape));
- }
-
- @Override
- protected void onFinishInflate() {
- super.onFinishInflate();
- inflateChildren();//添加mRot0和mRot90,就是横竖屏的布局
- clearViews();//清空所有的view
-
- inflateLayout(getDefaultLayout());
- }
-
- private void inflateChildren() {
- removeAllViews();
- mRot0 = (FrameLayout) mLayoutInflater.inflate(R.layout.navigation_layout, this, false);
- mRot0.setId(R.id.rot0);
- addView(mRot0);
- mRot90 = (FrameLayout) mLayoutInflater.inflate(R.layout.navigation_layout_rot90, this,
- false);
- mRot90.setId(R.id.rot90);
- addView(mRot90);
- updateAlternativeOrder();
- }
上述代码就是在加载导航栏布局文件,如果是0度的时候加载navigation_layout,如果是90度的时候加载navigation_layout_rot90,横屏竖屏加载的layout不同。
- protected void inflateLayout(String newLayout) {
- mCurrentLayout = newLayout;
- if (newLayout == null) {
- newLayout = getDefaultLayout();
- }
- String[] sets = newLayout.split(GRAVITY_SEPARATOR, 3);
- if (sets.length != 3) {
- Log.d(TAG, "Invalid layout.");
- newLayout = getDefaultLayout();
- sets = newLayout.split(GRAVITY_SEPARATOR, 3);
- }
- String[] start = sets[0].split(BUTTON_SEPARATOR);
- String[] center = sets[1].split(BUTTON_SEPARATOR);
- String[] end = sets[2].split(BUTTON_SEPARATOR);
- // Inflate these in start to end order or accessibility traversal will be messed up.
- inflateButtons(start, mRot0.findViewById(R.id.ends_group), isRot0Landscape, true);
- inflateButtons(start, mRot90.findViewById(R.id.ends_group), !isRot0Landscape, true);
-
- inflateButtons(center, mRot0.findViewById(R.id.center_group), isRot0Landscape, false);
- inflateButtons(center, mRot90.findViewById(R.id.center_group), !isRot0Landscape, false);
-
- addGravitySpacer(mRot0.findViewById(R.id.ends_group));
- addGravitySpacer(mRot90.findViewById(R.id.ends_group));
-
- inflateButtons(end, mRot0.findViewById(R.id.ends_group), isRot0Landscape, false);
- inflateButtons(end, mRot90.findViewById(R.id.ends_group), !isRot0Landscape, false);
-
- updateButtonDispatchersCurrentView();
- }
- protected String getDefaultLayout() {
- final int defaultResource = mOverviewProxyService.shouldShowSwipeUpUI()
- ? R.string.config_navBarLayoutQuickstep
- : R.string.config_navBarLayout;
- return mContext.getString(defaultResource);
- }
- protected View inflateButton(String buttonSpec, ViewGroup parent, boolean landscape,
- boolean start) {
-
- LayoutInflater inflater = landscape ? mLandscapeInflater : mLayoutInflater;
- View v = createView(buttonSpec, parent, inflater);
- if (v == null) return null;
-
- v = applySize(v, buttonSpec, landscape, start);//计算view的宽的大小
- parent.addView(v);
- addToDispatchers(v);
- View lastView = landscape ? mLastLandscape : mLastPortrait;
- View accessibilityView = v;
- if (v instanceof ReverseRelativeLayout) {
- accessibilityView = ((ReverseRelativeLayout) v).getChildAt(0);
- }
- if (lastView != null) {
- accessibilityView.setAccessibilityTraversalAfter(lastView.getId());
- }
- if (landscape) {
- mLastLandscape = accessibilityView;
- } else {
- mLastPortrait = accessibilityView;
- }
- return v;
- }
- private View createView(String buttonSpec, ViewGroup parent, LayoutInflater inflater) {
- View v = null;
- String button = extractButton(buttonSpec);
- if (LEFT.equals(button)) {
- String s = Dependency.get(TunerService.class).getValue(NAV_BAR_LEFT, NAVSPACE);
- button = extractButton(s);
- } else if (RIGHT.equals(button)) {
- String s = Dependency.get(TunerService.class).getValue(NAV_BAR_RIGHT, MENU_IME_ROTATE);
- button = extractButton(s);
- }
- // Let plugins go first so they can override a standard view if they want.
- for (NavBarButtonProvider provider : mPlugins) {
- v = provider.createView(buttonSpec, parent);
- if (v != null) return v;
- }
- 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);
- }
- //laiyw add for volume Up/Down
- else if (VOLUME_DOWN.equals(button)) {
- v = inflater.inflate(R.layout.volume_down, parent, false);
- }
- else if (VOLUME_UP.equals(button)) {
- v = inflater.inflate(R.layout.volume_up, parent, false);
-
- //laiyw add for volume Up/Down
- } else if (RECENT.equals(button)) {
- v = inflater.inflate(R.layout.recent_apps, parent, false);
- } else if (MENU_IME_ROTATE.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);
- } else if (CONTEXTUAL.equals(button)) {
- v = inflater.inflate(R.layout.contextual, parent, false);
- } else if (button.startsWith(KEY)) {
- String uri = extractImage(button);
- int code = extractKeycode(button);
- v = inflater.inflate(R.layout.custom_key, parent, false);
- ((KeyButtonView) v).setCode(code);
- if (uri != null) {
- if (uri.contains(":")) {
- ((KeyButtonView) v).loadAsync(Icon.createWithContentUri(uri));
- } else if (uri.contains("/")) {
- int index = uri.indexOf('/');
- String pkg = uri.substring(0, index);
- int id = Integer.parseInt(uri.substring(index + 1));
- ((KeyButtonView) v).loadAsync(Icon.createWithResource(pkg, id));
- }
- }
- }
- return v;
- }
上述的代码都比较简单,有两点:
第一、导航栏显示哪些控件是由getDefaultLayout来决定。
<string name="config_navBarLayout" translatable="false">left[.5W],back[1WC];home;recent[1WC],right[.5W]</string>
一般情况下我们是home,recent,back这三个键,如果你需要加其他的就在这个配置文件夹。同时在createView添加对应的布局文件。
第二、createView方法创建对应的布局文件,并且添加到导航栏中。
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"
- android:layout_height="match_parent"
- android:layout_weight="0"
- systemui:keyCode="3"
- android:scaleType="center"
- android:contentDescription="@string/accessibility_home"
- android:paddingStart="@dimen/navigation_key_padding"
- android:paddingEnd="@dimen/navigation_key_padding"
- />
back.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/back"
- android:layout_width="@dimen/navigation_key_width"
- android:layout_height="match_parent"
- android:layout_weight="0"
- systemui:keyCode="4"
- android:scaleType="center"
- android:contentDescription="@string/accessibility_back"
- android:paddingStart="@dimen/navigation_key_padding"
- android:paddingEnd="@dimen/navigation_key_padding"
- />
recent_app.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/recent_apps"
- android:layout_width="@dimen/navigation_key_width"
- android:layout_height="match_parent"
- android:layout_weight="0"
- android:scaleType="center"
- android:contentDescription="@string/accessibility_recent"
- android:paddingStart="@dimen/navigation_key_padding"
- android:paddingEnd="@dimen/navigation_key_padding"
- />
那么我们现在布局文件都添加完成了,但是你会发现在NavigationBarInflaterView没有对资源文件添加的代码已经控件点击触摸事件处理逻辑。那么这两部分代码在哪里呢?
答案是:
1.NavigationBarView 完成资源文件添加。
2.NavigationBarFragment 添加点击事件和触摸事件的处理逻辑。
- public NavigationBarView(Context context, AttributeSet attrs) {
- super(context, attrs);
-
- mDisplay = ((WindowManager) context.getSystemService(
- Context.WINDOW_SERVICE)).getDefaultDisplay();
-
- mVertical = false;
- mShowMenu = false;
-
- mShowAccessibilityButton = false;
- mLongClickableAccessibilityButton = false;
-
- mOverviewProxyService = Dependency.get(OverviewProxyService.class);
- mRecentsOnboarding = new RecentsOnboarding(context, mOverviewProxyService);
-
- mConfiguration = new Configuration();
- mConfiguration.updateFrom(context.getResources().getConfiguration());
-
- M : New plugin architecture - Navigation bar plugin
- try {
- mSystemUICustomizationFactory =
- OpSystemUICustomizationFactoryBase.getOpFactory(context);
- mNavBarPlugin = mSystemUICustomizationFactory.makeNavigationBar(context);
- } catch (Exception e) {
- if (DEBUG) Log.d(TAG,"mNavBarPlugin init fail");
- e.printStackTrace();
- }
- reloadNavIcons();//初始化加载资源,主要是图片。
-
- mBarTransitions = new NavigationBarTransitions(this);
-
- 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.volume_down, new ButtonDispatcher(R.id.volume_down));
- mButtonDispatchers.put(R.id.volume_up, new ButtonDispatcher(R.id.volume_up));
- getVolumeDownButton().setLongClickable(false);
- getVolumeUpButton().setLongClickable(false);
-
- 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));
- mButtonDispatchers.put(R.id.rotate_suggestion,
- new ButtonDispatcher(R.id.rotate_suggestion));
- mButtonDispatchers.put(R.id.menu_container,
- new ButtonDispatcher(R.id.menu_container));
- mDeadZone = new DeadZone(this);
- }
- private void reloadNavIcons() {
- updateIcons(mContext, Configuration.EMPTY, mConfiguration);
- }
- private void updateIcons(Context ctx, Configuration oldConfig, Configuration newConfig) {
- int dualToneDarkTheme = Utils.getThemeAttr(ctx, R.attr.darkIconTheme);
- int dualToneLightTheme = Utils.getThemeAttr(ctx, R.attr.lightIconTheme);
- Context lightContext = new ContextThemeWrapper(ctx, dualToneLightTheme);
- Context darkContext = new ContextThemeWrapper(ctx, dualToneDarkTheme);
-
- if (oldConfig.orientation != newConfig.orientation
- || oldConfig.densityDpi != newConfig.densityDpi) {
- mDockedIcon = getDrawable(lightContext, darkContext, R.drawable.ic_sysbar_docked);
- mHomeDefaultIcon = getHomeDrawable(lightContext, darkContext);
- }
- if (oldConfig.densityDpi != newConfig.densityDpi
- || oldConfig.getLayoutDirection() != newConfig.getLayoutDirection()) {
-
- Log.d("yangxiucheng", "oldConfig.densityDpi != newConfig.densityDpi");
- mBackIcon = getBackDrawable(lightContext, darkContext);
- mRecentIcon = getDrawable(lightContext, darkContext, R.drawable.ic_sysbar_recent);
- mMenuIcon = getDrawable(lightContext, darkContext, R.drawable.ic_sysbar_menu);
-
- mAccessibilityIcon = getDrawable(lightContext, darkContext,
- R.drawable.ic_sysbar_accessibility_button, false /* hasShadow */);
-
- //mImeIcon = getDrawable(lightContext, darkContext, R.drawable.ic_ime_switcher_default,
- //false /* hasShadow */);
-
- updateRotateSuggestionButtonStyle(mRotateBtnStyle, false);
-
- if (ALTERNATE_CAR_MODE_UI) {
- updateCarModeIcons(ctx);
- }
- }
-
- mVolumeDown = getDrawable(ctx,R.drawable.ic_sysbar_volume_down,R.drawable.ic_sysbar_volume_down_dark);
- mVolumeUp = getDrawable(ctx,R.drawable.ic_sysbar_volume_up,R.drawable.ic_sysbar_volume_up_dark);
-
- }
上述代码都比较简单,可以结合源码看一些细节,就不做太多说明
- 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();
- }
上述代码中的setOnClickListener,setOnTouchListener,setLongClickable,setOnLongClickListener就是给对应的控件添加控制代码
到现在为止整个导航栏的View的添加,资源图片的加载,以及点击触摸事件的响应逻辑都讲了,其中还有一些细节,结合源码看应该不难,导航栏的讲解也就到此结束。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。