[Android][SystemUI]navigationbar 3个虚拟键隐藏与显示

源码流程追踪

1.三个虚拟键的显示初始化是在Frameworks下的SystemUI中。

/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java

    // ================================================================================
    // Constructing the view
    // ================================================================================
    protected PhoneStatusBarView makeStatusBarView() {
        final Context context = mContext;
        Resources res = context.getResources();

        ......
        mNotificationPanel.setHeadsUpManager(mHeadsUpManager);
        mNotificationData.setHeadsUpManager(mHeadsUpManager);

        if (MULTIUSER_DEBUG) {
            mNotificationPanelDebugText = (TextView) mNotificationPanel.findViewById(
                    R.id.header_debug_info);
            mNotificationPanelDebugText.setVisibility(View.VISIBLE);
        }

        try {
            boolean showNav = mWindowManagerService.hasNavigationBar();//控制Navigationbar中是否显示3个虚拟按键
            if (DEBUG) Log.v(TAG, "hasNavigationBar=" + showNav);
            if (showNav) {
                mNavigationBarView =
                    (NavigationBarView) View.inflate(context, R.layout.navigation_bar, null);//本布局中定义了3个虚拟键

                mNavigationBarView.setDisabledFlags(mDisabled1);
                mNavigationBarView.setBar(this);
                mNavigationBarView.setOnVerticalChangedListener(
                        new NavigationBarView.OnVerticalChangedListener() {
                    @Override
                    public void onVerticalChanged(boolean isVertical) {
                        if (mAssistManager != null) {
                            mAssistManager.onConfigurationChanged();
                        }
                        mNotificationPanel.setQsScrimEnabled(!isVertical);
                    }
                });
                mNavigationBarView.setOnTouchListener(new View.OnTouchListener() {
                    @Override
                    public boolean onTouch(View v, MotionEvent event) {
                        checkUserAutohide(v, event);
                        return false;
                    }});
            }
        } catch (RemoteException ex) {
            // no window manager? good luck with that
        }

        mAssistManager = new AssistManager(this, context);

2.由以上代码可知,3个虚拟键的显示与否取决于showNav,而这又取决于mWindowManagerService和它的方法hasNavigationBar()返回的值。而mWindowManagerService并非再本类中声明,而是从其父类中继承而来,并在父类中初始化。

/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java

public abstract class BaseStatusBar extends SystemUI implements
        CommandQueue.Callbacks, ActivatableNotificationView.OnActivatedListener,
        RecentsComponent.Callbacks, ExpandableNotificationRow.ExpansionLogger,
        NotificationData.Environment {
    public static final String TAG = "StatusBar";
    public static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
    public static final boolean MULTIUSER_DEBUG = false;
    ......

    private UserManager mUserManager;

    // UI-specific methods

    /**
     * Create all windows necessary for the status bar (including navigation, overlay panels, etc)
     * and add them to the window manager.
     */
    protected abstract void createAndAddWindows();

    protected WindowManager mWindowManager;
    protected IWindowManager mWindowManagerService;

mWindowManagerService = WindowManagerGlobal.getWindowManagerService();

3.在WindowManagerGlobal中获取IWindowManager实例。

/frameworks/base/core/java/android/view/WindowManagerGlobal.java

public static IWindowManager getWindowManagerService() {
        synchronized (WindowManagerGlobal.class) {
            if (sWindowManagerService == null) {
                sWindowManagerService = IWindowManager.Stub.asInterface(
                        ServiceManager.getService("window"));//
                try {
                    sWindowManagerService = getWindowManagerService();
                    ValueAnimator.setDurationScale(sWindowManagerService.getCurrentAnimatorScale());
                } catch (RemoteException e) {
                    Log.e(TAG, "Failed to get WindowManagerService, cannot set animator scale", e);
                }
            }
            return sWindowManagerService;
        }
    }

4.上面的sWindowManagerService也是IWindowManager声明的,可以看出上面方法中,sWindowManagerService递归从IWindowManager.Stub中获取实例。我们来看看IWindowManager中的声明。

/frameworks/base/core/java/android/view/IWindowManager.aidl

/**
 * System private interface to the window manager.
 *
 * {@hide}
 */
interface IWindowManager
{
    /**
     * ===== NOTICE =====
     * The first three methods must remain the first three methods. Scripts
     * and tools rely on their transaction number to work properly.
     */
    // This is used for debugging
    boolean startViewServer(int port);   // Transaction #1
    boolean stopViewServer();            // Transaction #2
    boolean isViewServerRunning();       // Transaction #3

    ......

    /**
     * Device has a software navigation bar (separate from the status bar).
     */
    boolean hasNavigationBar();
    ......
}

5.回归到PhoneStatusBar中调用的hasNavigationBar()方法,正是IWindowManager接口中的,至于如何返回值怎么来决定,还得取决于实现此接口的方法实现。

6.经过查找,有两个类实现了IWindowManager接口,分别为IWindowManagerImpl和WindowManagerService,先看IWindowManagerImpl类。

/frameworks/base/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java

public class IWindowManagerImpl implements IWindowManager {

    private final Configuration mConfig;
    private final DisplayMetrics mMetrics;
    private final int mRotation;
    private final boolean mHasNavigationBar;

    public IWindowManagerImpl(Configuration config, DisplayMetrics metrics, int rotation,
            boolean hasNavigationBar) {
        mConfig = config;
        mMetrics = metrics;
        mRotation = rotation;
        mHasNavigationBar = hasNavigationBar;//在IWindowManagerImpl初始化时传入
    }

    // custom API.

    public DisplayMetrics getMetrics() {
        return mMetrics;
    }

    // ---- implementation of IWindowManager that we care about ----

    @Override
    public int getRotation() throws RemoteException {
        return mRotation;
    }

    @Override
    public boolean hasNavigationBar() {
        return mHasNavigationBar;//直接返回类属性
    }
    ......
}

7.IWindowManagerImpl先看到这里,再看一下WindowManagerService类,它是个隐藏类,不对上层应用开放。

/frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java

/** {@hide} */
public class WindowManagerService extends IWindowManager.Stub
        implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs {
    static final String TAG = "WindowManager";
    /// M: Enable/Disable WMS log
    static boolean DEBUG = false;
    static boolean DEBUG_ADD_REMOVE = false;
    ......

    final WindowManagerPolicy mPolicy = MtkPhoneWindowUtility.makeNewWindowManager();//MTK
    //final WindowManagerPolicy mPolicy = new PhoneWindowManager();//QCOM
    @Override
    public boolean hasNavigationBar() {
        return mPolicy.hasNavigationBar();
    }
    ......
}

8.从上方可以看出,最终使用的是PhoneWindowManager中实现的hasNavigationBar方法。而PhoneWindowManager实现了WindowManagerPolicy接口中的方法。

/local/sdb/talkback/frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java

package com.android.server.policy;

/**
 * WindowManagerPolicy implementation for the Android phone UI.  This
 * introduces a new method suffix, Lp, for an internal lock of the
 * PhoneWindowManager.  This is used to protect some internal state, and
 * can be acquired with either the Lw and Li lock held, so has the restrictions
 * of both of those when held.
 */
public class PhoneWindowManager implements WindowManagerPolicy {
    static final String TAG = "WindowManager";
    /// M: runtime switch debug flags @{
    static boolean DEBUG = false;
    ......

    boolean mHasNavigationBar = false;

    @Override
    public void setInitialDisplaySize(Display display, int width, int height, int density) {
        // This method might be called before the policy has been fully initialized
        // or for other displays we don't care about.
        if (mContext == null || display.getDisplayId() != Display.DEFAULT_DISPLAY) {
            return;
        }
        mDisplay = display;

        ......

        // SystemUI (status bar) layout policy
        int shortSizeDp = shortSize * DisplayMetrics.DENSITY_DEFAULT / density;
        int longSizeDp = longSize * DisplayMetrics.DENSITY_DEFAULT / density;

        // Allow the navigation bar to move on non-square small devices (phones).
        mNavigationBarCanMove = width != height && shortSizeDp < 600;

        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;
        }

        // For demo purposes, allow the rotation of the HDMI display to be controlled.
        // By default, HDMI locks rotation to landscape.
        if ("portrait".equals(SystemProperties.get("persist.demo.hdmirotation"))) {
            mDemoHdmiRotation = mPortraitRotation;
        } else {
            mDemoHdmiRotation = mLandscapeRotation;
        }
        mDemoHdmiRotationLock = SystemProperties.getBoolean("persist.demo.hdmirotationlock", false);

        // For demo purposes, allow the rotation of the remote display to be controlled.
        // By default, remote display locks rotation to landscape.
        if ("portrait".equals(SystemProperties.get("persist.demo.remoterotation"))) {
            mDemoRotation = mPortraitRotation;
        } else {
            mDemoRotation = mLandscapeRotation;
        }
        mDemoRotationLock = SystemProperties.getBoolean(
                "persist.demo.rotationlock", false);

        // Only force the default orientation if the screen is xlarge, at least 960dp x 720dp, per
        // http://developer.android.com/guide/practices/screens_support.html#range
        mForceDefaultOrientation = longSizeDp >= 960 && shortSizeDp >= 720 &&
                res.getBoolean(com.android.internal.R.bool.config_forceDefaultOrientation) &&
                // For debug purposes the next line turns this feature off with:
                // $ adb shell setprop config.override_forced_orient true
                // $ adb shell wm size reset
                !"true".equals(SystemProperties.get("config.override_forced_orient"));
    }

    // Use this instead of checking config_showNavigationBar so that it can be consistently
    // overridden by qemu.hw.mainkeys in the emulator.
    @Override
    public boolean hasNavigationBar() {
        return mHasNavigationBar;//返回的boolean值
    }
    ......
}

9.如此,需要跟踪系统属性从那里来。经过查询,该系统属性是编译时加入。

/device/{XXXX}/{Project_name}/system.prop

# temporary enables NAV bar (soft keys)
qemu.hw.mainkeys=0

涉及类关联

经过流程跟踪,大致涉及的类关联如下:
《[Android][SystemUI]navigationbar 3个虚拟键隐藏与显示》

    原文作者:小小写
    原文地址: https://blog.csdn.net/u013398960/article/details/60469629
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞