Android Navigation Bar on side by editing AOSP

10.2k views Asked by At

I want to put the Navigation Bar (has system soft keys like back, home and menu. not Navigation Drawer!) on the (right) side, like below, by editing AOSP.

+-------------------------------------------------+---+
| Status bar (always)                             |   |
+-------------------------------------------------+ N |
| (Layout with background drawable)               | a |
| +---------------------------------------------+ | v |
| | Title/Action bar (optional)                 | |   |
| +---------------------------------------------+ | B |
| | Content, vertical extending                 | | a |
| |                                             | | r |
| +---------------------------------------------+ |   |
+-------------------------------------------------+---+

So far I assume RenderSessionImpl.java is the file to edit to accomplish this since it renders the screen layout depends on the given screen orientation value.

I found the next snippet and edited the orientation parameter(HORIZONTAL -> VERTICAL) so it would creates a horizontal layout, with the nav bar on the right.

if (mNavigationBarOrientation == LinearLayout.HORIZONTAL &&
        mNavigationBarSize > 0) {
    // system bar
    try {
        NavigationBar navigationBar = new NavigationBar(context,
                hardwareConfig.getDensity(), LinearLayout.VERTICAL); // was LinearLayout.HORIZONTAL originallly
        navigationBar.setLayoutParams(
                new LinearLayout.LayoutParams(
                        LayoutParams.MATCH_PARENT, mNavigationBarSize));
        topLayout.addView(navigationBar);
    } catch (XmlPullParserException e) {

    }
}

Original AOSP code snippets are below.

/**
 * Inflates the layout.
 * <p>
 * {@link #acquire(long)} must have been called before this.
 *
 * @throws IllegalStateException if the current context is different than the one owned by
 *      the scene, or if {@link #init(long)} was not called.
 */
public Result inflate() {
    checkLock();

    try {

        SessionParams params = getParams();
        HardwareConfig hardwareConfig = params.getHardwareConfig();
        BridgeContext context = getContext();


        // the view group that receives the window background.
        ViewGroup backgroundView = null;

        if (mWindowIsFloating || params.isForceNoDecor()) {
            backgroundView = mViewRoot = mContentRoot = new FrameLayout(context);
        } else {
            if (hasSoftwareButtons() && mNavigationBarOrientation == LinearLayout.VERTICAL) {
                /*
                 * This is a special case where the navigation bar is on the right.
                   +-------------------------------------------------+---+
                   | Status bar (always)                             |   |
                   +-------------------------------------------------+   |
                   | (Layout with background drawable)               |   |
                   | +---------------------------------------------+ |   |
                   | | Title/Action bar (optional)                 | |   |
                   | +---------------------------------------------+ |   |
                   | | Content, vertical extending                 | |   |
                   | |                                             | |   |
                   | +---------------------------------------------+ |   |
                   +-------------------------------------------------+---+

                   So we create a horizontal layout, with the nav bar on the right,
                   and the left part is the normal layout below without the nav bar at
                   the bottom
                 */
                LinearLayout topLayout = new LinearLayout(context);
                mViewRoot = topLayout;
                topLayout.setOrientation(LinearLayout.HORIZONTAL);

                try {
                    NavigationBar navigationBar = new NavigationBar(context,
                            hardwareConfig.getDensity(), LinearLayout.VERTICAL);
                    navigationBar.setLayoutParams(
                            new LinearLayout.LayoutParams(
                                    mNavigationBarSize,
                                    LayoutParams.MATCH_PARENT));
                    topLayout.addView(navigationBar);
                } catch (XmlPullParserException e) {

                }
            }

            /*
             * we're creating the following layout
             *
               +-------------------------------------------------+
               | Status bar (always)                             |
               +-------------------------------------------------+
               | (Layout with background drawable)               |
               | +---------------------------------------------+ |
               | | Title/Action bar (optional)                 | |
               | +---------------------------------------------+ |
               | | Content, vertical extending                 | |
               | |                                             | |
               | +---------------------------------------------+ |
               +-------------------------------------------------+
               | Navigation bar for soft buttons, maybe see above|
               +-------------------------------------------------+

             */

            LinearLayout topLayout = new LinearLayout(context);
            topLayout.setOrientation(LinearLayout.VERTICAL);
            // if we don't already have a view root this is it
            if (mViewRoot == null) {
                mViewRoot = topLayout;
            } else {
                LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
                        LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
                layoutParams.weight = 1;
                topLayout.setLayoutParams(layoutParams);

                // this is the case of soft buttons + vertical bar.
                // this top layout is the first layout in the horizontal layout. see above)
                mViewRoot.addView(topLayout, 0);
            }

            if (mStatusBarSize > 0) {
                // system bar
                try {
                    StatusBar systemBar = new StatusBar(context, hardwareConfig.getDensity());
                    systemBar.setLayoutParams(
                            new LinearLayout.LayoutParams(
                                    LayoutParams.MATCH_PARENT, mStatusBarSize));
                    topLayout.addView(systemBar);
                } catch (XmlPullParserException e) {

                }
            }

            LinearLayout backgroundLayout = new LinearLayout(context);
            backgroundView = backgroundLayout;
            backgroundLayout.setOrientation(LinearLayout.VERTICAL);
            LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
                    LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
            layoutParams.weight = 1;
            backgroundLayout.setLayoutParams(layoutParams);
            topLayout.addView(backgroundLayout);


            // if the theme says no title/action bar, then the size will be 0
            if (mActionBarSize > 0) {
                try {
                    FakeActionBar actionBar = new FakeActionBar(context,
                            hardwareConfig.getDensity(),
                            params.getAppLabel(), params.getAppIcon());
                    actionBar.setLayoutParams(
                            new LinearLayout.LayoutParams(
                                    LayoutParams.MATCH_PARENT, mActionBarSize));
                    backgroundLayout.addView(actionBar);
                } catch (XmlPullParserException e) {

                }
            } else if (mTitleBarSize > 0) {
                try {
                    TitleBar titleBar = new TitleBar(context,
                            hardwareConfig.getDensity(), params.getAppLabel());
                    titleBar.setLayoutParams(
                            new LinearLayout.LayoutParams(
                                    LayoutParams.MATCH_PARENT, mTitleBarSize));
                    backgroundLayout.addView(titleBar);
                } catch (XmlPullParserException e) {

                }
            }

            // content frame
            mContentRoot = new FrameLayout(context);
            layoutParams = new LinearLayout.LayoutParams(
                    LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
            layoutParams.weight = 1;
            mContentRoot.setLayoutParams(layoutParams);
            backgroundLayout.addView(mContentRoot);

if (mNavigationBarOrientation == LinearLayout.HORIZONTAL &&
        mNavigationBarSize > 0) {
    // system bar
    try {
        NavigationBar navigationBar = new NavigationBar(context,
                hardwareConfig.getDensity(), LinearLayout.HORIZONTAL);
        navigationBar.setLayoutParams(
                new LinearLayout.LayoutParams(
                        LayoutParams.MATCH_PARENT, mNavigationBarSize));
        topLayout.addView(navigationBar);
    } catch (XmlPullParserException e) {

    }
}
        }


        // Sets the project callback (custom view loader) to the fragment delegate so that
        // it can instantiate the custom Fragment.
        Fragment_Delegate.setProjectCallback(params.getProjectCallback());

        View view = mInflater.inflate(mBlockParser, mContentRoot);

        // done with the parser, pop it.
        context.popParser();

        Fragment_Delegate.setProjectCallback(null);

        // set the AttachInfo on the root view.
        AttachInfo_Accessor.setAttachInfo(mViewRoot);

        // post-inflate process. For now this supports TabHost/TabWidget
        postInflateProcess(view, params.getProjectCallback());

        // get the background drawable
        if (mWindowBackground != null && backgroundView != null) {
            Drawable d = ResourceHelper.getDrawable(mWindowBackground, context);
            backgroundView.setBackground(d);
        }

        return SUCCESS.createResult();
    } catch (PostInflateException e) {
        return ERROR_INFLATION.createResult(e.getMessage(), e);
    } catch (Throwable e) {
        // get the real cause of the exception.
        Throwable t = e;
        while (t.getCause() != null) {
            t = t.getCause();
        }

        return ERROR_INFLATION.createResult(t.getMessage(), t);
    }
}

But the screen layout shows no difference. Any insight for this? Wrong file to edit or wrong logic? I know this kind of tweak is not recommended but I really need to do it.

1

There are 1 answers

0
HUKS On

Navigation Bar can be placed on right side by editing PhoneWindowManager.java and navigation_bar.xml.

Set mNavigationBarOnBottom to false in PhoneWindowManager then the following code will run.

// PhoneWindowManager.java
// if mNavigationBarOnBottom = false
// Landscape screen; nav bar goes to the right
int left = displayWidth - mNavigationBarWidthForRotation[displayRotation];
mTmpNavigationFrame.set(left, 0, displayWidth, displayHeight);
mStableRight = mStableFullscreenRight = mTmpNavigationFrame.left;
if (navVisible) {
    mNavigationBar.showLw(true);
    mDockRight = mTmpNavigationFrame.left;
    mRestrictedScreenWidth = mDockRight - mDockLeft;
} else {
    // We currently want to hide the navigation UI.
    mNavigationBar.hideLw(true);
}
if (navVisible && !mNavigationBar.isAnimatingLw()) {
    // If the nav bar is currently requested to be visible,
    // and not in the process of animating on or off, then
    // we can tell the app that it is covered by it.
    mSystemRight = mTmpNavigationFrame.left;
}

This creates the frame for navigation bar on right instead of bottom, now layout needs to be edited to display system buttons vertically(navigation_bar.xml).

<!--  navigation bar for sw600dp (small tablets) -->
<com.android.systemui.statusbar.phone.NavigationBarView
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui"
    android:layout_height="match_parent"
    android:layout_width="match_parent"
    android:background="#FF000000"
    >    
    <FrameLayout android:id="@+id/rot0"
        android:layout_height="match_parent"
        android:layout_width="match_parent"
        >    
        <LinearLayout
            android:layout_height="match_parent"
            android:layout_width="match_parent"
            android:orientation="vertical"
            android:clipChildren="false"
            android:clipToPadding="false"
            android:id="@+id/nav_buttons"
            android:animateLayoutChanges="true"
            >    
            <!-- navigation controls -->
            ~
            <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/back"
                android:layout_width="match_parent"
                android:layout_height="128dp"
                android:src="@drawable/ic_sysbar_back"
                systemui:keyCode="4"
                android:layout_weight="0"
                systemui:glowBackground="@drawable/ic_sysbar_highlight"
                android:contentDescription="@string/accessibility_back"
                />
            ~
        </LinearLayout>
    </FrameLayout>
</com.android.systemui.statusbar.phone.NavigationBarView>