Android P Auto版本Home画面解析

版权声明: https://blog.csdn.net/Sunxiaolin2016/article/details/91450210

一、Auto版简介

从Android O系统后,安卓发布了针对车机的Auto版本系统。

比较Android P的的Auto比起Android O来说,更加成熟,逻辑功能更加完善。

Auto系统启动后第一页是用户界面:
在这里插入图片描述
选择用户后,进入Home画面:
在这里插入图片描述

二、Auto版SystemUI分析

Auto版本的导航栏和抬头栏也是在SystemUI中实现的。

1.加载SystemBar

代码路径:frameworks\base\packages\SystemUI\src\com\android\systemui\SystemBars.java

private void createStatusBarFromConfig() {
    if (DEBUG) Log.d(TAG, "createStatusBarFromConfig");
    //根据config_statusBarComponent配置来决定选择哪个StatusBar
    final String clsName = mContext.getString(R.string.config_statusBarComponent);
    if (clsName == null || clsName.length() == 0) {
        throw andLog("No status bar component configured", null);
    }
    Class<?> cls = null;
    try {
        cls = mContext.getClassLoader().loadClass(clsName);
    } catch (Throwable t) {
        throw andLog("Error loading status bar component: " + clsName, t);
    }
    try {
        mStatusBar = (SystemUI) cls.newInstance();
    } catch (Throwable t) {
        throw andLog("Error creating status bar component: " + clsName, t);
    }
    mStatusBar.mContext = mContext;
    mStatusBar.mComponents = mComponents;
    mStatusBar.start();
    if (DEBUG) Log.d(TAG, "started " + mStatusBar.getClass().getSimpleName());
}

手机版xml文件:\frameworks\base\packages\SystemUI\res\values\config.xml

<string name="config_statusBarComponent" translatable="false">com.android.systemui.statusbar.phone.StatusBar
</string>

Auto版xml文件:\packages\services\Car\car_product\overlay\frameworks\base\packages\SystemUI\res\values\config.xml

<string name="config_statusBarComponent" translatable="false">com.android.systemui.statusbar.car.CarStatusBar
</string>

可以看到两个版本的差异化,在我们编译系统时,会进行lunch选择:

//...
33. mek_8q-eng
34. mek_8q-userdebug
35. mek_8q_car-eng
36. mek_8q_car-userdebug
37. mek_8q_car2-eng
38. mek_8q_car2-userdebug
//...

如果选择lunch 36则是进行Auto版本编译,会自动根据Auto版本编译配置进行区分,所以Auto版使用的是com.android.systemui.statusbar.car.CarStatusBar的状态栏。

2.分析NavigationBar

底部那一栏就是我们的NavigationBar。

代码路径:
\frameworks\base\packages\SystemUI\src\com\android\systemui\statusbar\car\CarStatusBar.java
\frameworks\base\packages\SystemUI\res\layout\navigation_bar_window.xml
\packages\services\Car\car_product\overlay\frameworks\base\packages\SystemUI\res\layout\car_navigation_bar.xml

CarStatusBar中加载NavigationBar的代码逻辑:

    @Override
    protected void createNavigationBar() {
        mShowBottom = mContext.getResources().getBoolean(R.bool.config_enableBottomNavigationBar);
        mShowLeft = mContext.getResources().getBoolean(R.bool.config_enableLeftNavigationBar);
        mShowRight = mContext.getResources().getBoolean(R.bool.config_enableRightNavigationBar);

        buildNavBarWindows();
        buildNavBarContent();
        attachNavBarWindows();
    }

    private void buildNavBarContent() {
        if (mShowBottom) {
            buildBottomBar((mDeviceIsProvisioned) ? R.layout.car_navigation_bar :
                    R.layout.car_navigation_bar_unprovisioned);
        }

		//省略一部分代码
		//...
    }

    private void buildNavBarWindows() {
        if (mShowBottom) {
			 //navigation_bar_window这个布局文件是kong
             mNavigationBarWindow = (ViewGroup) View.inflate(mContext,
                    R.layout.navigation_bar_window, null);
        }
        if (mShowLeft) {
            mLeftNavigationBarWindow = (ViewGroup) View.inflate(mContext,
                R.layout.navigation_bar_window, null);
        }
        if (mShowRight) {
            mRightNavigationBarWindow = (ViewGroup) View.inflate(mContext,
                    R.layout.navigation_bar_window, null);
        }

    }

    private void attachNavBarWindows() {
		//可以看到最终的窗口是放在TYPE_NAVIGATION_BAR这个系统窗口中的
        if (mShowBottom) {
            WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
                    LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT,
                    WindowManager.LayoutParams.TYPE_NAVIGATION_BAR,
                    WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                            | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
                            | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
                            | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
                    PixelFormat.TRANSLUCENT);
            lp.setTitle("CarNavigationBar");
            lp.windowAnimations = 0;
            mWindowManager.addView(mNavigationBarWindow, lp);
        }
		
		//省略一部分代码
		//...
    }

	//得到mNavigationBarView 
	private void buildBottomBar(int layout) {
        // SystemUI requires that the navigation bar view have a parent. Since the regular
        // StatusBar inflates navigation_bar_window as this parent view, use the same view for the
        // CarNavigationBarView.
        View.inflate(mContext, layout, mNavigationBarWindow);
        mNavigationBarView = (CarNavigationBarView) mNavigationBarWindow.getChildAt(0);
        if (mNavigationBarView == null) {
            Log.e(TAG, "CarStatusBar failed inflate for R.layout.car_navigation_bar");
            throw new RuntimeException("Unable to build botom nav bar due to missing layout");
        }
        mNavigationBarView.setStatusBar(this);
    }

根据上面的代码,最终layout\car_navigation_bar.xml的布局是放到navigation_bar_window.xml中去,加载到TYPE_NAVIGATION_BAR的系统窗口中去。

分析\packages\services\Car\car_product\overlay\frameworks\base\packages\SystemUI\res\layout\car_navigation_bar.xml代码可以看到,Auto版本的布局都在这个文件里。

从左到右的布局:Home,地图,音乐,电话,菜单,空调,通知,设置和时间。

3.分析Home

布局:\packages\services\Car\car_product\overlay\frameworks\base\packages\SystemUI\res\layout\car_navigation_bar.xml

其中Home的按钮:

 <com.android.systemui.statusbar.car.CarNavigationButton
    android:id="@+id/home"
    style="@style/NavigationBarButton"
    systemui:intent="intent:#Intent;action=android.intent.action.MAIN;category=android.intent.category.HOME;launchFlags=0x14000000;end"
    android:src="@drawable/car_ic_overview"
    android:background="?android:attr/selectableItemBackground"
/>

intent指定跳转界面就是我们的Launcher。

HOME界面其实就是上面我们看到的 Let’s Driver界面。就是Auto版本的Launcher。

Auto版本代码路径:\packages\apps\Car\Launcher
Carlauncher这个应用的代码比较简单,就不多讲了。

4.分析StatusBar

CarStatusBar的代码中,CarStatusBar类是继承自phone/StatusBar 这个类的。
所以车机版的状态栏加载跟手机版的加载差不多,不错,在、、、、、、\packages\services\Car\car_product\overlay\frameworks\base\packages\SystemUI\res\layout\status_bar.xml对状态栏的功能做了简化。

/**
 * A status bar (and navigation bar) tailored for the automotive use case.
 */
public class CarStatusBar extends StatusBar implements
        CarBatteryController.BatteryViewHandler {
    private static final String TAG = "CarStatusBar";
    public static final boolean ENABLE_HVAC_CONNECTION
            = !SystemProperties.getBoolean("android.car.hvac.demo", true);

5.分析用户选择界面

Auto系统启动后,第一个界面是用户选择界面,并不是我们的CarLauncher界面。所以我们来分析一下用户界面的加载过程。

相关代码路径:
\frameworks\base\packages\SystemUI\res\layout\car_fullscreen_user_switcher.xml
\frameworks\base\packages\SystemUI\res\layout\super_status_bar.xml
\frameworks\base\packages\SystemUI\src\com\android\systemui\statusbar\car\UserGridRecyclerView.java
\frameworks\base\packages\SystemUI\src\com\android\systemui\statusbar\car\FullscreenUserSwitcher.java
\frameworks\base\packages\SystemUI\src\com\android\systemui\statusbar\policy\UserSwitcherController.java
\frameworks\base\packages\SystemUI\src\com\android\systemui\statusbar\phone\StatusBar.java

代码\frameworks\base\packages\SystemUI\src\com\android\systemui\statusbar\car\CarStatusBar.java中会去加载car_fullscreen_user_switcher.xml
布局文件,布局默认改界面是隐藏,生成FullscreenUserSwitcher的对象并对用户选择界面进行操作:

    @Override
    protected void createUserSwitcher() {
        UserSwitcherController userSwitcherController =
                Dependency.get(UserSwitcherController.class);
        if (userSwitcherController.useFullscreenUserSwitcher()) {
            mFullscreenUserSwitcher = new FullscreenUserSwitcher(this,
                    mStatusBarWindow.findViewById(R.id.fullscreen_user_switcher_stub), mContext);		//加载fullscreen_user_switcher_stub布局
        } else {
            super.createUserSwitcher();
        }
    }

    @Override
    public void onUserSwitched(int newUserId) {
        super.onUserSwitched(newUserId);
        if (mFullscreenUserSwitcher != null) {
            mFullscreenUserSwitcher.onUserSwitched(newUserId);
        }
    }

    @Override
    public void updateKeyguardState(boolean goingToFullShade, boolean fromShadeLocked) {
        super.updateKeyguardState(goingToFullShade, fromShadeLocked);
        if (mFullscreenUserSwitcher != null) {
        	//是否为FULLSCREEN_USER_SWITCHER状态
            if (mState == StatusBarState.FULLSCREEN_USER_SWITCHER) {
                mFullscreenUserSwitcher.show();		//显示用户选择界面
            } else {
                mFullscreenUserSwitcher.hide();		//隐藏用户选择界面
            }
        }
    }

其中,StatusBar.java中:

    public void showKeyguardImpl() {
        mIsKeyguard = true;
        if (mLaunchTransitionFadingAway) {
            mNotificationPanel.animate().cancel();
            onLaunchTransitionFadingEnded();
        }
        mHandler.removeMessages(MSG_LAUNCH_TRANSITION_TIMEOUT);
        //根据useFullscreenUserSwitcher的状态来决定是否设置FULLSCREEN_USER_SWITCHER状态
        if (mUserSwitcherController != null && mUserSwitcherController.useFullscreenUserSwitcher()) {
            setBarState(StatusBarState.FULLSCREEN_USER_SWITCHER);
        } else {
            setBarState(StatusBarState.KEYGUARD);
        }
        updateKeyguardState(false /* goingToFullShade */, false /* fromShadeLocked */);
        updatePanelExpansionForKeyguard();
        if (mDraggedDownRow != null) {
            mDraggedDownRow.setUserLocked(false);
            mDraggedDownRow.notifyHeightChanged(false  /* needsAnimation */);
            mDraggedDownRow = null;
        }
    }

UserSwitcherController.java中:

    public boolean useFullscreenUserSwitcher() {
        // Use adb to override:
        // adb shell settings put system enable_fullscreen_user_switcher 0  # Turn it off.
        // adb shell settings put system enable_fullscreen_user_switcher 1  # Turn it on.
        // Restart SystemUI or adb reboot.
        final int DEFAULT = -1;
        final int overrideUseFullscreenUserSwitcher =
                Settings.System.getInt(mContext.getContentResolver(),
                        "enable_fullscreen_user_switcher", DEFAULT);
        if (overrideUseFullscreenUserSwitcher != DEFAULT) {
            return overrideUseFullscreenUserSwitcher != 0;
        }
        // Otherwise default to the build setting.
        return mContext.getResources().getBoolean(R.bool.config_enableFullscreenUserSwitcher);
    }

使用以下的命令进行设置
// Use adb to override:
// adb shell settings put system enable_fullscreen_user_switcher 0 # Turn it off.
// adb shell settings put system enable_fullscreen_user_switcher 1 # Turn it on.
// Restart SystemUI or adb reboot.

所以只要使用 adb shell settings put system enable_fullscreen_user_switcher 0 ,就可以开机不显示用户选择界面。直接进入Home画面。

使用adb reboot后生效。

猜你喜欢

转载自blog.csdn.net/Sunxiaolin2016/article/details/91450210