The evolution of mobile phones towards a full screen has brought many new adaptation problems for developers, including the virtual navigation bar. Recently, in the project of Qiusbai.com, there are relevant adaptation problems. I have checked the relevant articles about the virtual navigation bar adaptation, and basically there are various degrees of failure in full-screen mobile phones, which makes me start to think about this problem.

Why do our assumptions about virtual navigation fail in full screen? Today we will talk about the adaptation of the virtual navigation bar in detail from the origin and development of the virtual navigation bar.

About virtual navigation

In the beginning, Android phones used a full keyboard (physical keys), but later manufacturers found that they did not need so many keys, and gradually reduced it to three functional keys: return /Home/Task,

Almost all Android phones, whether native or proprietary roMs, come with these buttons.

Later, In order to improve the screen ratio and reduce the height of the phone chin, Android allows phone manufacturers to integrate these keys into the screen.

That’s where the virtual navigation bar is today.

Before the full screen became popular, the virtual navigation bar promoted by Android was not the mainstream of mobile phones, and many phones still had three function buttons as physical buttons on the chin of the phone. The market for phones with physical buttons and virtual navigation bars is 50/50. What? Have you ever seen both virtual and physical buttons? Don’t worry, such manufacturers have basically gone out of business

At this point, we can confirm that the three features featured on Android phones are either physical buttons or integrated into the screen as virtual buttons.

About the adaptation of the virtual navigation bar

Let’s start with a question:

– Do we need a virtual navigation bar adaptation?

– The answer is: not necessarily.

There are ways to avoid the problems that virtual navigation causes. This is to completely separate the screen of the virtual navigation bar from the display area of the APP through various Settings. Like this:

The two display areas do not interfere with each other, so the presence or absence of a virtual navigation bar does not matter.

However, although this is easy, it often leads to the lack of aesthetic feeling of the APP (this is what the designer told me). Designers often want the display area of the APP to be extended into the virtual navigation bar to achieve a sense of immersion:

Like this:

Can we say no to this little request from designers? Obviously not. So at this point, you need to think about adaptation.

We need to know if there is a virtual navigation bar in the current interface, and how high it is, so that we can make some adjustments to our layout, otherwise the two will overlap. This is where the virtual navigation bar fits in.

About the adaptation of the virtual navigation bar, we need to make it clear that the core problem of the adaptation of the virtual navigation bar is not how to obtain the height of the virtual navigation bar, but to determine whether the current virtual navigation bar exists or is displayed, because the height of the navigation bar is a value set by the system and cannot be changed. There is no difficulty in obtaining this size, we just need to read the value. The real core is how to determine whether the current virtual navigation bar exists.

The old way to judge a virtual navigation bar

Before full-screen phones, we had a lot of ways to judge the virtual navigation bar,

For example, method 1:

{// Determine whether the system has written a height dependent variable to define the virtual navigation bar. Resources res = activity.getResources(); // If the height is greater than 0, the phone has a virtual navigation bar. int resourceId = res.getIdentifier("status_bar_height"."dimen"."android");
            if (resourceId > 0) {
                returnres.getDimensionPixelSize(resourceId)>0; }}Copy the code

Or this method 2:

{
    int id = resources.getIdentifier("config_showNavigationBar"."bool"."android"); // Determine whether the system has written variables related to whether to display the virtual navigation bar, if sotrue"Indicates that the virtual navigation bar is availablereturn id > 0 && resources.getBoolean(id);
}
Copy the code

Or method 3:

    
        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { Display display = context.getWindowManager().getDefaultDisplay(); Point size = new Point(); Point realSize = new Point(); display.getSize(size); // app draws the area display.getrealsize (realSize);returnrealSize.y ! = size.y; }else{ boolean menu = ViewConfiguration.get(context).hasPermanentMenuKey(); boolean back = KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_BACK); // Check whether there is a physical buttonif (menu || back) {
                return false; 
            } else {
                return true; }}Copy the code

The above three methods are basically to see whether there are relevant definitions of the virtual navigation bar in the system. That is, if we can find relevant definitions of the virtual navigation bar in the system, the virtual navigation bar exists. This way of thinking comes from the fact that the physical navigation button and the virtual navigation button of mobile phones have always been opposite, that is, if the physical navigation button is removed, the virtual navigation bar will be used; if the virtual navigation bar exists, there will be no physical buttons. If there is A, there is no B. If there is B, there is no A. In that context, there’s nothing wrong with that way of thinking.

However, the all-screen phone breaks this contradictory pattern by removing the physical navigation button, but also removing the virtual navigation bar (i.e. the phone does integrate the virtual navigation bar, but does not use it), and instead realizing the three-button function through the all-screen gesture. So, full screen phone + full screen gestures. Is the cause of the failure of the previous judgment method.

Return overdo think, lead to determine the cause of the failure is more essential, because actually we are indirect judgment, the judgment method of is to find the necessary conditions, rather than sufficient conditions, as we saw the light of the moon in the night, does not prove that the moon is illuminated object, unless assume a premise: the object giving out light can are illuminated. It takes a proof to be true. And with the advent of a full screen, it breaks that premise, which leads to problems with our derivation.

Now, due to the full screen mobile phone generally exist in the virtual navigation bar and full screen gesture these two operation modes, and the two must take one, therefore, the Internet has appeared another indirect judgment method, that is to judge whether the current mobile phone is using full screen gesture, if not, it means that the virtual navigation bar.

The following is the judgment method for Vivo and Xiaomi’s full-screen virtual navigation bar:

    /**
     * @returnv falseNavigationBar is used,trueIndicates that gesture is used, default isfalse
     */
    public static boolean vivoNavigationGestureEnabled(Context context) {
        int val = Settings.Secure.getInt(context.getContentResolver(), NAVIGATION_GESTURE, NAVIGATION_GESTURE_OFF);
        returnval ! = NAVIGATION_GESTURE_OFF; } public static boolean isXiaoMiNavigationBarShow(Activity context) {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
                    if (Settings.Global.getInt(context.getContentResolver(), "force_fsg_nav_bar", 0). = 0) {// Open the gesture, do not display the virtual keyreturn false; }}}Copy the code

However, this method also has some defects, for example, the judgment method is given by the manufacturer, that is to say, there is no universality, there are other manufacturers system judgment method unknown; Also, it is difficult to identify hidden/exhaled virtual navigation bars. What’s more, there is always a danger of making indirect judgments based on what is necessary.

New solutions

Therefore, in order to find a more general and accurate judgment method, we try to enter the Android system level to try to find a scheme to judge the virtual navigation bar.

The virtual navigation bar is also a View, and if the View draws itself and displays itself in the Window layout, then the virtual navigation bar must exist. In other words, we just need to find the View and prove that it exists.

So we try to analyze the Layout level of the virtual navigation bar using the Layout Inspector. It is found to be the Child View of the DecorView (above Android5.0), and we find the View representing the virtual navigation bar in the DecorView. Now, this is an easy question. The code is as follows:

{
     
    private static final String NAVIGATION= "navigationBarBackground"; // This method needs to be called after the View is completely drawn, Public static Boolean isNavigationBarExist(@nonnull Activity Activity){public static Boolean isNavigationBarExist(@nonnull Activity){ ViewGroup vp = (ViewGroup) activity.getWindow().getDecorView();if(vp ! = null) {for (int i = 0; i < vp.getChildCount(); i++) {
                    vp.getChildAt(i).getContext().getPackageName();
                    if(vp.getChildAt(i).getId()! = NO_ID && NAVIGATION.equals(activity.getResources().getResourceEntryName(vp.getChildAt(i).getId()))) {return true; }}}return false; }}Copy the code

Of course, there’s another judgment scheme, which is also good.


    public static void isNavigationBarExist(Activity activity, final OnNavigationStateListener onNavigationStateListener) {
        if (activity == null) {
            return;
        }
        final int height = getNavigationHeight(activity);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) {
                 activity.getWindow().getDecorView().setOnApplyWindowInsetsListener(new View.OnApplyWindowInsetsListener() {
                @Override
                public WindowInsets onApplyWindowInsets(View v, WindowInsets windowInsets) {
                    boolean isShowing = false;
                    int b = 0;
                    if(windowInsets ! = null) { b = windowInsets.getSystemWindowInsetBottom(); isShowing = (b == height); }if(onNavigationStateListener ! = null && b <= height) { onNavigationStateListener.onNavigationState(isShowing, b); }returnwindowInsets; }}); } } public static int getNavigationHeight(Context activity) {if (activity == null) {
            return 0;
        }
        Resources resources = activity.getResources();
        int resourceId = resources.getIdentifier("navigation_bar_height"."dimen"."android");
        int height = 0;
        if(resourceId > 0) {/ / get the height of the NavigationBar height = resources. GetDimensionPixelSize (resourceId); }return height;
    }

Copy the code

This method is judgment system window occupied area, in addition to the virtual navigation system that may occur at the bottom of the window, may be there is a virtual keyboard, seems not so good, but because we can get the height of the virtual navigation system configuration, so in these systems to take up the window height we can filter out the height of the virtual navigation bar. So, on balance, it’s a good judgment.

Afterword.

The adaptation of the virtual navigation bar was originally just a small problem, but under careful study, found that there is very interesting, so through a large section to help you simply comb out the origin of the entire virtual navigation bar, development and adaptation work,

In fact, the evolution of mobile phone forms has an obvious impact on Android system, APP and users. As developers, we should not underestimate these changes.