Merge "Make nav bar customizable through Tunable"
diff --git a/packages/SystemUI/res/layout-sw600dp/navigation_bar.xml b/packages/SystemUI/res/layout-sw600dp/navigation_bar.xml
deleted file mode 100644
index 1fcb2df..0000000
--- a/packages/SystemUI/res/layout-sw600dp/navigation_bar.xml
+++ /dev/null
@@ -1,322 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-**
-** Copyright 2012, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
--->
-
-<!--  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-auto"
-    android:layout_height="match_parent"
-    android:layout_width="match_parent"
-    android:background="@drawable/system_bar_background"
-    >
-
-    <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="horizontal"
-            android:clipChildren="false"
-            android:clipToPadding="false"
-            android:id="@+id/nav_buttons"
-            android:animateLayoutChanges="true"
-            >
-
-            <!-- navigation controls -->
-            <View
-                android:layout_width="@dimen/navigation_extra_key_width"
-                android:layout_height="match_parent"
-                android:layout_weight="0"
-                android:layout_marginStart="2dp"
-                android:visibility="invisible"
-                />
-            <Space
-                android:layout_width="match_parent"
-                android:layout_height="match_parent"
-                android:layout_weight="1"
-                />
-            <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/back"
-                android:layout_width="128dp" android:paddingStart="25dp" android:paddingEnd="25dp"
-                android:layout_height="match_parent"
-                android:src="@drawable/ic_sysbar_back"
-                android:scaleType="centerInside"
-                systemui:keyCode="4"
-                android:layout_weight="0"
-                android:contentDescription="@string/accessibility_back"
-                />
-            <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/home"
-                android:layout_width="128dp" android:paddingStart="25dp" android:paddingEnd="25dp"
-                android:layout_height="match_parent"
-                android:src="@drawable/ic_sysbar_home"
-                android:scaleType="centerInside"
-                systemui:keyCode="3"
-                systemui:keyRepeat="true"
-                android:layout_weight="0"
-                android:contentDescription="@string/accessibility_home"
-                />
-            <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/recent_apps"
-                android:layout_width="128dp" android:paddingStart="25dp" android:paddingEnd="25dp"
-                android:layout_height="match_parent"
-                android:src="@drawable/ic_sysbar_recent"
-                android:scaleType="centerInside"
-                android:layout_weight="0"
-                android:contentDescription="@string/accessibility_recent"
-                />
-            <Space
-                android:layout_width="match_parent"
-                android:layout_height="match_parent"
-                android:layout_weight="1"
-                />
-            <FrameLayout
-                android:layout_width="@dimen/navigation_extra_key_width"
-                android:layout_height="match_parent"
-                android:layout_weight="0"
-                android:layout_marginEnd="2dp" >
-                <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/menu"
-                    android:layout_width="@dimen/navigation_extra_key_width"
-                    android:layout_height="match_parent"
-                    android:src="@drawable/ic_sysbar_menu"
-                    android:scaleType="centerInside"
-                    android:layout_marginEnd="2dp"
-                    systemui:keyCode="82"
-                    android:visibility="invisible"
-                    android:contentDescription="@string/accessibility_menu"
-                    />
-                <com.android.systemui.statusbar.policy.KeyButtonView
-                    android:id="@+id/ime_switcher"
-                    android:layout_width="@dimen/navigation_extra_key_width"
-                    android:layout_height="match_parent"
-                    android:layout_marginEnd="2dp"
-                    android:scaleType="centerInside"
-                    android:src="@drawable/ic_ime_switcher_default"
-                    android:visibility="invisible"
-                    android:contentDescription="@string/accessibility_ime_switch_button" />
-            </FrameLayout>
-        </LinearLayout>
-
-        <!-- lights out layout to match exactly -->
-        <LinearLayout
-            android:layout_height="match_parent"
-            android:layout_width="match_parent"
-            android:orientation="horizontal"
-            android:id="@+id/lights_out"
-            android:visibility="gone"
-            >
-            <Space
-                android:layout_width="match_parent"
-                android:layout_height="match_parent"
-                android:layout_weight="1"
-                />
-            <ImageView
-                android:layout_width="128dp" android:paddingStart="25dp" android:paddingEnd="25dp"
-                android:layout_height="match_parent"
-                android:layout_marginStart="40dp"
-                android:src="@drawable/ic_sysbar_lights_out_dot_small"
-                android:scaleType="center"
-                android:layout_weight="0"
-                android:contentDescription="@string/accessibility_back"
-                />
-            <ImageView
-                android:layout_width="128dp" android:paddingStart="25dp" android:paddingEnd="25dp"
-                android:layout_height="match_parent"
-                android:src="@drawable/ic_sysbar_lights_out_dot_large"
-                android:scaleType="center"
-                android:layout_weight="0"
-                android:contentDescription="@string/accessibility_home"
-                />
-            <ImageView
-                android:layout_width="128dp" android:paddingStart="25dp" android:paddingEnd="25dp"
-                android:layout_marginEnd="40dp"
-                android:layout_height="match_parent"
-                android:src="@drawable/ic_sysbar_lights_out_dot_small"
-                android:scaleType="center"
-                android:layout_weight="0"
-                android:contentDescription="@string/accessibility_recent"
-                />
-            <Space
-                android:layout_width="match_parent"
-                android:layout_height="match_parent"
-                android:layout_weight="1"
-                />
-        </LinearLayout>
-
-        <com.android.systemui.statusbar.policy.DeadZone
-            android:id="@+id/deadzone"
-            android:layout_height="match_parent"
-            android:layout_width="match_parent"
-            systemui:minSize="@dimen/navigation_bar_deadzone_size"
-            systemui:maxSize="@dimen/navigation_bar_deadzone_size_max"
-            systemui:holdTime="@integer/navigation_bar_deadzone_hold"
-            systemui:decayTime="@integer/navigation_bar_deadzone_decay"
-            systemui:orientation="horizontal"
-            android:layout_gravity="top"
-            />
-    </FrameLayout>
-
-    <FrameLayout android:id="@+id/rot90"
-        android:layout_height="match_parent"
-        android:layout_width="match_parent"
-        android:visibility="gone"
-        android:paddingTop="0dp"
-        >
-
-        <LinearLayout
-            android:layout_height="match_parent"
-            android:layout_width="match_parent"
-            android:orientation="horizontal"
-            android:clipChildren="false"
-            android:clipToPadding="false"
-            android:id="@+id/nav_buttons"
-            android:animateLayoutChanges="true"
-            >
-
-            <!-- navigation controls -->
-            <View
-                android:layout_width="@dimen/navigation_extra_key_width"
-                android:layout_height="match_parent"
-                android:layout_weight="0"
-                android:layout_marginStart="2dp"
-                android:visibility="invisible"
-                />
-            <Space
-                android:layout_width="match_parent"
-                android:layout_height="match_parent"
-                android:layout_weight="1"
-                />
-            <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/back"
-                android:layout_width="162dp" android:paddingStart="42dp" android:paddingEnd="42dp"
-                android:layout_height="match_parent"
-                android:src="@drawable/ic_sysbar_back"
-                android:scaleType="centerInside"
-                systemui:keyCode="4"
-                android:layout_weight="0"
-                android:contentDescription="@string/accessibility_back"
-                />
-            <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/home"
-                android:layout_width="162dp" android:paddingStart="42dp" android:paddingEnd="42dp"
-                android:layout_height="match_parent"
-                android:src="@drawable/ic_sysbar_home"
-                android:scaleType="centerInside"
-                systemui:keyCode="3"
-                systemui:keyRepeat="true"
-                android:layout_weight="0"
-                android:contentDescription="@string/accessibility_home"
-                />
-            <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/recent_apps"
-                android:layout_width="162dp" android:paddingStart="42dp" android:paddingEnd="42dp"
-                android:layout_height="match_parent"
-                android:src="@drawable/ic_sysbar_recent"
-                android:scaleType="centerInside"
-                android:layout_weight="0"
-                android:contentDescription="@string/accessibility_recent"
-                />
-            <Space
-                android:layout_width="match_parent"
-                android:layout_height="match_parent"
-                android:layout_weight="1"
-                />
-            <FrameLayout
-                android:layout_width="@dimen/navigation_extra_key_width"
-                android:layout_height="match_parent"
-                android:layout_marginEnd="2dp"
-                android:layout_weight="0" >
-                <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/menu"
-                    android:layout_width="@dimen/navigation_extra_key_width"
-                    android:layout_height="match_parent"
-                    android:layout_marginEnd="2dp"
-                    android:src="@drawable/ic_sysbar_menu"
-                    android:scaleType="centerInside"
-                    systemui:keyCode="82"
-                    android:visibility="invisible"
-                    android:contentDescription="@string/accessibility_menu" />
-                <com.android.systemui.statusbar.policy.KeyButtonView
-                    android:id="@+id/ime_switcher"
-                    android:layout_width="@dimen/navigation_extra_key_width"
-                    android:layout_height="match_parent"
-                    android:layout_marginEnd="2dp"
-                    android:src="@drawable/ic_ime_switcher_default"
-                    android:visibility="invisible"
-                    android:contentDescription="@string/accessibility_ime_switch_button"
-                    android:scaleType="centerInside" />
-            </FrameLayout>
-        </LinearLayout>
-
-        <!-- lights out layout to match exactly -->
-        <LinearLayout
-            android:layout_height="match_parent"
-            android:layout_width="match_parent"
-            android:orientation="horizontal"
-            android:id="@+id/lights_out"
-            android:visibility="gone"
-            >
-            <Space
-                android:layout_width="match_parent"
-                android:layout_height="match_parent"
-                android:layout_weight="1"
-                />
-            <ImageView
-                android:layout_width="162dp" android:paddingStart="42dp" android:paddingEnd="42dp"
-                android:layout_height="match_parent"
-                android:layout_marginStart="40dp"
-                android:src="@drawable/ic_sysbar_lights_out_dot_small"
-                android:scaleType="center"
-                android:layout_weight="0"
-                android:contentDescription="@string/accessibility_back"
-                />
-            <ImageView
-                android:layout_width="162dp" android:paddingStart="42dp" android:paddingEnd="42dp"
-                android:layout_height="match_parent"
-                android:src="@drawable/ic_sysbar_lights_out_dot_large"
-                android:scaleType="center"
-                android:layout_weight="0"
-                android:contentDescription="@string/accessibility_home"
-                />
-            <ImageView
-                android:layout_width="162dp" android:paddingStart="42dp" android:paddingEnd="42dp"
-                android:layout_marginEnd="40dp"
-                android:layout_height="match_parent"
-                android:src="@drawable/ic_sysbar_lights_out_dot_small"
-                android:scaleType="center"
-                android:layout_weight="0"
-                android:contentDescription="@string/accessibility_recent"
-                />
-            <Space
-                android:layout_width="match_parent"
-                android:layout_height="match_parent"
-                android:layout_weight="1"
-                />
-        </LinearLayout>
-
-        <!-- On tablets in landscape the navbar is on the bottom, so use a
-             horizontal dead zone. -->
-        <com.android.systemui.statusbar.policy.DeadZone
-            android:id="@+id/deadzone"
-            android:layout_height="match_parent"
-            android:layout_width="match_parent"
-            systemui:minSize="@dimen/navigation_bar_deadzone_size"
-            systemui:maxSize="@dimen/navigation_bar_deadzone_size_max"
-            systemui:holdTime="@integer/navigation_bar_deadzone_hold"
-            systemui:decayTime="@integer/navigation_bar_deadzone_decay"
-            systemui:orientation="horizontal"
-            android:layout_gravity="top"
-            />
-    </FrameLayout>
-</com.android.systemui.statusbar.phone.NavigationBarView>
diff --git a/packages/SystemUI/res/layout-sw600dp/navigation_layout_rot90.xml b/packages/SystemUI/res/layout-sw600dp/navigation_layout_rot90.xml
new file mode 100644
index 0000000..dd559c5
--- /dev/null
+++ b/packages/SystemUI/res/layout-sw600dp/navigation_layout_rot90.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:systemui="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <FrameLayout
+        android:id="@+id/nav_buttons"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
+
+        <LinearLayout
+            android:id="@+id/start_group"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:gravity="start"
+            android:orientation="horizontal" />
+
+        <LinearLayout
+            android:id="@+id/center_group"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:gravity="center"
+            android:orientation="horizontal" />
+
+        <LinearLayout
+            android:id="@+id/end_group"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:gravity="end"
+            android:orientation="horizontal" />
+
+    </FrameLayout>
+
+    <FrameLayout
+        android:id="@+id/lights_out"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
+
+        <LinearLayout
+            android:id="@+id/start_group_lightsout"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:gravity="start"
+            android:orientation="horizontal" />
+
+        <LinearLayout
+            android:id="@+id/center_group_lightsout"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:gravity="center"
+            android:orientation="horizontal" />
+
+        <LinearLayout
+            android:id="@+id/end_group_lightsout"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:gravity="end"
+            android:orientation="horizontal" />
+
+    </FrameLayout>
+
+    <com.android.systemui.statusbar.policy.DeadZone
+        android:id="@+id/deadzone"
+        android:layout_height="match_parent"
+        android:layout_width="match_parent"
+        android:layout_gravity="top"
+        systemui:minSize="@dimen/navigation_bar_deadzone_size"
+        systemui:maxSize="@dimen/navigation_bar_deadzone_size_max"
+        systemui:holdTime="@integer/navigation_bar_deadzone_hold"
+        systemui:decayTime="@integer/navigation_bar_deadzone_decay"
+        systemui:orientation="horizontal"
+        />
+
+</FrameLayout>
diff --git a/packages/SystemUI/res/layout/back.xml b/packages/SystemUI/res/layout/back.xml
new file mode 100644
index 0000000..d256622
--- /dev/null
+++ b/packages/SystemUI/res/layout/back.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<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"
+    android:src="@drawable/ic_sysbar_back"
+    systemui:keyCode="4"
+    android:scaleType="center"
+    android:contentDescription="@string/accessibility_back"
+    android:paddingStart="@dimen/navigation_key_padding"
+    android:paddingEnd="@dimen/navigation_key_padding"
+    />
+
diff --git a/packages/SystemUI/res/layout/home.xml b/packages/SystemUI/res/layout/home.xml
new file mode 100644
index 0000000..f11592d
--- /dev/null
+++ b/packages/SystemUI/res/layout/home.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<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"
+    android:src="@drawable/ic_sysbar_home"
+    systemui:keyCode="3"
+    android:scaleType="center"
+    android:contentDescription="@string/accessibility_home"
+    android:paddingStart="@dimen/navigation_key_padding"
+    android:paddingEnd="@dimen/navigation_key_padding"
+    />
+
diff --git a/packages/SystemUI/res/layout/menu_ime.xml b/packages/SystemUI/res/layout/menu_ime.xml
new file mode 100644
index 0000000..90b74d0
--- /dev/null
+++ b/packages/SystemUI/res/layout/menu_ime.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:systemui="http://schemas.android.com/apk/res-auto"
+    android:layout_width="@dimen/navigation_side_padding"
+    android:layout_height="match_parent"
+    android:layout_weight="0"
+    >
+    <com.android.systemui.statusbar.policy.KeyButtonView
+        android:id="@+id/menu"
+        android:layout_width="@dimen/navigation_extra_key_width"
+        android:layout_height="match_parent"
+        android:layout_marginEnd="2dp"
+        android:src="@drawable/ic_sysbar_menu"
+        android:scaleType="centerInside"
+        systemui:keyCode="82"
+        android:visibility="invisible"
+        android:contentDescription="@string/accessibility_menu"
+        />
+    <com.android.systemui.statusbar.policy.KeyButtonView
+        android:id="@+id/ime_switcher"
+        android:layout_width="@dimen/navigation_extra_key_width"
+        android:layout_height="match_parent"
+        android:layout_marginEnd="2dp"
+        android:src="@drawable/ic_ime_switcher_default"
+        android:visibility="invisible"
+        android:contentDescription="@string/accessibility_ime_switch_button"
+        android:scaleType="centerInside"
+        />
+</FrameLayout>
diff --git a/packages/SystemUI/res/layout/nav_key_space.xml b/packages/SystemUI/res/layout/nav_key_space.xml
new file mode 100644
index 0000000..3986841
--- /dev/null
+++ b/packages/SystemUI/res/layout/nav_key_space.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+** Copyright 2016, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<Space xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:systemui="http://schemas.android.com/apk/res-auto"
+    android:layout_width="@dimen/navigation_side_padding"
+    android:layout_height="match_parent"
+    android:layout_weight="0"
+    >
+</Space>
diff --git a/packages/SystemUI/res/layout/navigation_bar.xml b/packages/SystemUI/res/layout/navigation_bar.xml
index 8498a4f..36e937d 100644
--- a/packages/SystemUI/res/layout/navigation_bar.xml
+++ b/packages/SystemUI/res/layout/navigation_bar.xml
@@ -22,309 +22,17 @@
     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"
-    >
+    android:background="@drawable/system_bar_background">
 
-    <FrameLayout android:id="@+id/rot0"
-        android:layout_height="match_parent"
+    <com.android.systemui.statusbar.phone.NavigationBarInflaterView
+        android:id="@+id/navigation_inflater"
         android:layout_width="match_parent"
-        >
+        android:layout_height="match_parent">
 
-        <LinearLayout
-            android:layout_height="match_parent"
-            android:layout_width="match_parent"
-            android:orientation="horizontal"
-            android:clipChildren="false"
-            android:clipToPadding="false"
-            android:id="@+id/nav_buttons"
-            android:animateLayoutChanges="true"
-            >
+        <include android:id="@+id/rot0" layout="@layout/navigation_layout" />
 
-            <!-- navigation controls -->
-            <View
-                android:layout_width="@dimen/navigation_side_padding"
-                android:layout_height="match_parent"
-                android:layout_weight="0"
-                android:visibility="invisible"
-                />
-            <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/back"
-                android:layout_width="@dimen/navigation_key_width"
-                android:layout_height="match_parent"
-                android:src="@drawable/ic_sysbar_back"
-                systemui:keyCode="4"
-                android:layout_weight="0"
-                android:scaleType="center"
-                android:contentDescription="@string/accessibility_back"
-                />
-            <View
-                android:layout_width="0dp"
-                android:layout_height="match_parent"
-                android:layout_weight="1"
-                android:visibility="invisible"
-                />
-            <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/home"
-                android:layout_width="@dimen/navigation_key_width"
-                android:layout_height="match_parent"
-                android:src="@drawable/ic_sysbar_home"
-                systemui:keyCode="3"
-                systemui:keyRepeat="false"
-                android:layout_weight="0"
-                android:scaleType="center"
-                android:contentDescription="@string/accessibility_home"
-                />
-            <View
-                android:layout_width="0dp"
-                android:layout_height="match_parent"
-                android:layout_weight="1"
-                android:visibility="invisible"
-                />
-            <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/recent_apps"
-                android:layout_width="@dimen/navigation_key_width"
-                android:layout_height="match_parent"
-                android:src="@drawable/ic_sysbar_recent"
-                android:layout_weight="0"
-                android:scaleType="center"
-                android:contentDescription="@string/accessibility_recent"
-                />
-            <FrameLayout
-                android:layout_width="@dimen/navigation_side_padding"
-                android:layout_height="match_parent"
-                android:layout_weight="0" >
-                <com.android.systemui.statusbar.policy.KeyButtonView
-                    android:id="@+id/menu"
-                    android:layout_width="@dimen/navigation_extra_key_width"
-                    android:layout_height="match_parent"
-                    android:contentDescription="@string/accessibility_menu"
-                    android:src="@drawable/ic_sysbar_menu"
-                    android:visibility="invisible"
-                    android:scaleType="centerInside"
-                    android:layout_gravity="end"
-                    systemui:keyCode="82" />
+        <include android:id="@+id/rot90" layout="@layout/navigation_layout_rot90" />
 
-                <com.android.systemui.statusbar.policy.KeyButtonView
-                    android:id="@+id/ime_switcher"
-                    android:layout_width="@dimen/navigation_extra_key_width"
-                    android:layout_height="match_parent"
-                    android:contentDescription="@string/accessibility_ime_switch_button"
-                    android:scaleType="centerInside"
-                    android:src="@drawable/ic_ime_switcher_default"
-                    android:visibility="invisible"
-                    android:layout_gravity="end" />
-            </FrameLayout>
-
-        </LinearLayout>
-
-        <!-- lights out layout to match exactly -->
-        <LinearLayout
-            android:layout_height="match_parent"
-            android:layout_width="match_parent"
-            android:orientation="horizontal"
-            android:id="@+id/lights_out"
-            android:visibility="gone"
-            >
-            <ImageView
-                android:layout_width="@dimen/navigation_key_width"
-                android:layout_height="match_parent"
-                android:layout_marginStart="@dimen/navigation_side_padding"
-                android:src="@drawable/ic_sysbar_lights_out_dot_small"
-                android:scaleType="center"
-                android:layout_weight="0"
-                android:contentDescription="@string/accessibility_back"
-                />
-            <View
-                android:layout_width="match_parent"
-                android:layout_height="match_parent"
-                android:layout_weight="1"
-                android:visibility="invisible"
-                />
-            <ImageView
-                android:layout_width="@dimen/navigation_key_width"
-                android:layout_height="match_parent"
-                android:src="@drawable/ic_sysbar_lights_out_dot_large"
-                android:scaleType="center"
-                android:layout_weight="0"
-                android:contentDescription="@string/accessibility_home"
-                />
-            <View
-                android:layout_width="match_parent"
-                android:layout_height="match_parent"
-                android:layout_weight="1"
-                android:visibility="invisible"
-                />
-            <ImageView
-                android:layout_width="@dimen/navigation_key_width"
-                android:layout_marginEnd="@dimen/navigation_side_padding"
-                android:layout_height="match_parent"
-                android:src="@drawable/ic_sysbar_lights_out_dot_small"
-                android:scaleType="center"
-                android:layout_weight="0"
-                android:contentDescription="@string/accessibility_recent"
-                />
-        </LinearLayout>
-
-        <com.android.systemui.statusbar.policy.DeadZone
-            android:id="@+id/deadzone"
-            android:layout_height="match_parent"
-            android:layout_width="match_parent"
-            systemui:minSize="@dimen/navigation_bar_deadzone_size"
-            systemui:maxSize="@dimen/navigation_bar_deadzone_size_max"
-            systemui:holdTime="@integer/navigation_bar_deadzone_hold"
-            systemui:decayTime="@integer/navigation_bar_deadzone_decay"
-            systemui:orientation="horizontal"
-            android:layout_gravity="top"
-            />
-    </FrameLayout>
-
-    <FrameLayout android:id="@+id/rot90"
-        android:layout_height="match_parent"
-        android:layout_width="match_parent"
-        android:visibility="gone"
-        android:paddingTop="0dp"
-        >
-
-        <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 -->
-            <FrameLayout
-                android:layout_weight="0"
-                android:layout_width="match_parent"
-                android:layout_height="@dimen/navigation_side_padding" >
-                <com.android.systemui.statusbar.policy.KeyButtonView
-                    android:id="@+id/ime_switcher"
-                    android:layout_width="match_parent"
-                    android:layout_height="@dimen/navigation_extra_key_width"
-                    android:contentDescription="@string/accessibility_ime_switch_button"
-                    android:scaleType="centerInside"
-                    android:src="@drawable/ic_ime_switcher_default"
-                    android:layout_gravity="top"
-                    android:visibility="invisible" />
-
-                <com.android.systemui.statusbar.policy.KeyButtonView
-                    android:id="@+id/menu"
-                    android:layout_width="match_parent"
-                    android:layout_height="40dp"
-                    android:contentDescription="@string/accessibility_menu"
-                    android:src="@drawable/ic_sysbar_menu"
-                    android:scaleType="centerInside"
-                    android:layout_gravity="top"
-                    android:visibility="invisible"
-                    systemui:keyCode="82" />
-            </FrameLayout>
-
-            <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/recent_apps"
-                android:layout_height="@dimen/navigation_key_width"
-                android:layout_width="match_parent"
-                android:src="@drawable/ic_sysbar_recent"
-                android:scaleType="center"
-                android:layout_weight="0"
-                android:contentDescription="@string/accessibility_recent"
-                />
-            <View
-                android:layout_height="match_parent"
-                android:layout_width="match_parent"
-                android:layout_weight="1"
-                android:visibility="invisible"
-                />
-            <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/home"
-                android:layout_height="@dimen/navigation_key_width"
-                android:layout_width="match_parent"
-                android:src="@drawable/ic_sysbar_home"
-                android:scaleType="center"
-                systemui:keyCode="3"
-                systemui:keyRepeat="false"
-                android:layout_weight="0"
-                android:contentDescription="@string/accessibility_home"
-                />
-            <View
-                android:layout_height="match_parent"
-                android:layout_width="match_parent"
-                android:layout_weight="1"
-                android:visibility="invisible"
-                />
-            <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/back"
-                android:layout_height="@dimen/navigation_key_width"
-                android:layout_width="match_parent"
-                android:src="@drawable/ic_sysbar_back"
-                android:scaleType="center"
-                systemui:keyCode="4"
-                android:layout_weight="0"
-                android:contentDescription="@string/accessibility_back"
-                />
-            <View
-                android:layout_height="@dimen/navigation_side_padding"
-                android:layout_width="match_parent"
-                android:layout_weight="0"
-                android:visibility="invisible"
-                />
-        </LinearLayout>
-
-        <!-- lights out layout to match exactly -->
-        <LinearLayout
-            android:layout_height="match_parent"
-            android:layout_width="match_parent"
-            android:orientation="vertical"
-            android:id="@+id/lights_out"
-            android:visibility="gone"
-            >
-            <ImageView
-                android:layout_height="@dimen/navigation_key_width"
-                android:layout_marginTop="@dimen/navigation_side_padding"
-                android:layout_width="match_parent"
-                android:src="@drawable/ic_sysbar_lights_out_dot_small"
-                android:scaleType="center"
-                android:layout_weight="0"
-                android:contentDescription="@string/accessibility_recent"
-                />
-            <View
-                android:layout_height="match_parent"
-                android:layout_width="match_parent"
-                android:layout_weight="1"
-                android:visibility="invisible"
-                />
-            <ImageView
-                android:layout_height="@dimen/navigation_key_width"
-                android:layout_width="match_parent"
-                android:src="@drawable/ic_sysbar_lights_out_dot_large"
-                android:scaleType="center"
-                android:layout_weight="0"
-                android:contentDescription="@string/accessibility_home"
-                />
-            <View
-                android:layout_height="match_parent"
-                android:layout_width="match_parent"
-                android:layout_weight="1"
-                android:visibility="invisible"
-                />
-            <ImageView
-                android:layout_height="@dimen/navigation_key_width"
-                android:layout_marginBottom="@dimen/navigation_side_padding"
-                android:layout_width="match_parent"
-                android:src="@drawable/ic_sysbar_lights_out_dot_small"
-                android:scaleType="center"
-                android:layout_weight="0"
-                android:contentDescription="@string/accessibility_back"
-                />
-        </LinearLayout>
-
-        <com.android.systemui.statusbar.policy.DeadZone
-            android:id="@+id/deadzone"
-            android:layout_height="match_parent"
-            android:layout_width="match_parent"
-            systemui:minSize="@dimen/navigation_bar_deadzone_size"
-            systemui:maxSize="@dimen/navigation_bar_deadzone_size_max"
-            systemui:holdTime="@integer/navigation_bar_deadzone_hold"
-            systemui:decayTime="@integer/navigation_bar_deadzone_decay"
-            systemui:orientation="vertical"
-            android:layout_gravity="top"
-            />
-    </FrameLayout>
+    </com.android.systemui.statusbar.phone.NavigationBarInflaterView>
 
 </com.android.systemui.statusbar.phone.NavigationBarView>
diff --git a/packages/SystemUI/res/layout/navigation_layout.xml b/packages/SystemUI/res/layout/navigation_layout.xml
new file mode 100644
index 0000000..7ebf4ed
--- /dev/null
+++ b/packages/SystemUI/res/layout/navigation_layout.xml
@@ -0,0 +1,91 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:systemui="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <FrameLayout
+        android:id="@+id/nav_buttons"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
+
+        <LinearLayout
+            android:id="@+id/start_group"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:gravity="start"
+            android:orientation="horizontal" />
+
+        <LinearLayout
+            android:id="@+id/center_group"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:gravity="center"
+            android:orientation="horizontal" />
+
+        <LinearLayout
+            android:id="@+id/end_group"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:gravity="end"
+            android:orientation="horizontal" />
+
+    </FrameLayout>
+
+    <FrameLayout
+        android:id="@+id/lights_out"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
+
+        <LinearLayout
+            android:id="@+id/start_group_lightsout"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:gravity="start"
+            android:orientation="horizontal" />
+
+        <LinearLayout
+            android:id="@+id/center_group_lightsout"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:gravity="center"
+            android:orientation="horizontal" />
+
+        <LinearLayout
+            android:id="@+id/end_group_lightsout"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:gravity="end"
+            android:orientation="horizontal" />
+
+    </FrameLayout>
+
+    <com.android.systemui.statusbar.policy.DeadZone
+        android:id="@+id/deadzone"
+        android:layout_height="match_parent"
+        android:layout_width="match_parent"
+        android:layout_gravity="top"
+        systemui:minSize="@dimen/navigation_bar_deadzone_size"
+        systemui:maxSize="@dimen/navigation_bar_deadzone_size_max"
+        systemui:holdTime="@integer/navigation_bar_deadzone_hold"
+        systemui:decayTime="@integer/navigation_bar_deadzone_decay"
+        systemui:orientation="horizontal"
+        />
+
+</FrameLayout>
diff --git a/packages/SystemUI/res/layout/navigation_layout_rot90.xml b/packages/SystemUI/res/layout/navigation_layout_rot90.xml
new file mode 100644
index 0000000..46df973
--- /dev/null
+++ b/packages/SystemUI/res/layout/navigation_layout_rot90.xml
@@ -0,0 +1,91 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:systemui="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <FrameLayout
+        android:id="@+id/nav_buttons"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
+
+        <com.android.systemui.statusbar.phone.ReverseLinearLayout
+            android:id="@+id/start_group"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:gravity="bottom"
+            android:orientation="vertical" />
+
+        <com.android.systemui.statusbar.phone.ReverseLinearLayout
+            android:id="@+id/center_group"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:gravity="center"
+            android:orientation="vertical" />
+
+        <com.android.systemui.statusbar.phone.ReverseLinearLayout
+            android:id="@+id/end_group"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:gravity="top"
+            android:orientation="vertical" />
+
+    </FrameLayout>
+
+    <FrameLayout
+        android:id="@+id/lights_out"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
+
+        <com.android.systemui.statusbar.phone.ReverseLinearLayout
+            android:id="@+id/start_group_lightsout"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:gravity="bottom"
+            android:orientation="vertical" />
+
+        <com.android.systemui.statusbar.phone.ReverseLinearLayout
+            android:id="@+id/center_group_lightsout"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:gravity="center"
+            android:orientation="vertical" />
+
+        <com.android.systemui.statusbar.phone.ReverseLinearLayout
+            android:id="@+id/end_group_lightsout"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:gravity="top"
+            android:orientation="vertical" />
+
+    </FrameLayout>
+
+    <com.android.systemui.statusbar.policy.DeadZone
+        android:id="@+id/deadzone"
+        android:layout_height="match_parent"
+        android:layout_width="match_parent"
+        android:layout_gravity="top"
+        systemui:minSize="@dimen/navigation_bar_deadzone_size"
+        systemui:maxSize="@dimen/navigation_bar_deadzone_size_max"
+        systemui:holdTime="@integer/navigation_bar_deadzone_hold"
+        systemui:decayTime="@integer/navigation_bar_deadzone_decay"
+        systemui:orientation="vertical"
+        />
+
+</FrameLayout>
diff --git a/packages/SystemUI/res/layout/recent_apps.xml b/packages/SystemUI/res/layout/recent_apps.xml
new file mode 100644
index 0000000..eb8ee43c
--- /dev/null
+++ b/packages/SystemUI/res/layout/recent_apps.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<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:src="@drawable/ic_sysbar_recent"
+    android:scaleType="center"
+    android:contentDescription="@string/accessibility_recent"
+    android:paddingStart="@dimen/navigation_key_padding"
+    android:paddingEnd="@dimen/navigation_key_padding"
+    />
+
diff --git a/packages/SystemUI/res/values-sw600dp-land/dimens.xml b/packages/SystemUI/res/values-sw600dp-land/dimens.xml
index f084bc2..be5b856 100644
--- a/packages/SystemUI/res/values-sw600dp-land/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp-land/dimens.xml
@@ -34,4 +34,7 @@
          In sw600dp we want the buttons centered so this fills the space,
          (screen_pinning_request_width - 3 * screen_pinning_request_button_width) / 2 -->
     <dimen name="screen_pinning_request_side_width">2dp</dimen>
+
+    <dimen name="navigation_key_width">162dp</dimen>
+    <dimen name="navigation_key_padding">42dp</dimen>
 </resources>
diff --git a/packages/SystemUI/res/values-sw600dp/config.xml b/packages/SystemUI/res/values-sw600dp/config.xml
index 17ff195..db4da10 100644
--- a/packages/SystemUI/res/values-sw600dp/config.xml
+++ b/packages/SystemUI/res/values-sw600dp/config.xml
@@ -42,4 +42,8 @@
          while the stack is not focused. -->
     <item name="recents_layout_unfocused_range_min" format="float" type="integer">-2</item>
     <item name="recents_layout_unfocused_range_max" format="float" type="integer">2.5</item>
+
+    <!-- Nav bar button default ordering/layout -->
+    <string name="config_navBarLayout" translatable="false">space;back,home,recent;menu_ime</string>
+
 </resources>
diff --git a/packages/SystemUI/res/values-sw600dp/dimens.xml b/packages/SystemUI/res/values-sw600dp/dimens.xml
index 49dbac2..71f92fd 100644
--- a/packages/SystemUI/res/values-sw600dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp/dimens.xml
@@ -90,4 +90,7 @@
     <dimen name="screen_pinning_request_side_width">8dp</dimen>
 
     <dimen name="fab_margin">24dp</dimen>
+
+    <dimen name="navigation_key_width">128dp</dimen>
+    <dimen name="navigation_key_padding">25dp</dimen>
 </resources>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 7a87314..aedc2c5 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -288,5 +288,8 @@
     <!-- SystemUIFactory component -->
     <string name="config_systemUIFactoryComponent" translatable="false">com.android.systemui.SystemUIFactory</string>
 
+    <!-- Nav bar button default ordering/layout -->
+    <string name="config_navBarLayout" translatable="false">space,back;home;recent,menu_ime</string>
+
 </resources>
 
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index d7bd86f..46a0f2a 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -96,6 +96,11 @@
     <!-- The width of the view containing navigation buttons -->
     <dimen name="navigation_key_width">70dp</dimen>
 
+    <dimen name="navigation_key_padding">0dp</dimen>
+
+    <dimen name="navigation_key_width_sw600dp_land">162dp</dimen>
+    <dimen name="navigation_key_padding_sw600dp_land">42dp</dimen>
+
     <!-- The width of the view containing the menu/ime navigation bar icons -->
     <dimen name="navigation_extra_key_width">36dp</dimen>
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java
new file mode 100644
index 0000000..8e3886b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import com.android.systemui.statusbar.policy.KeyButtonView;
+
+import android.graphics.drawable.Drawable;
+import android.view.View;
+import android.widget.ImageView;
+
+import java.util.ArrayList;
+
+/**
+ * Dispatches common view calls to multiple views.  This is used to handle
+ * multiples of the same nav bar icon appearing.
+ */
+public class ButtonDispatcher {
+
+    private final ArrayList<View> mViews = new ArrayList<>();
+
+    private final int mId;
+
+    private View.OnClickListener mClickListener;
+    private View.OnTouchListener mTouchListener;
+    private View.OnLongClickListener mLongClickListener;
+    private Boolean mLongClickable;
+    private Integer mAlpha;
+    private Integer mVisibility = -1;
+    private int mImageResource = -1;
+    private Drawable mImageDrawable;
+    private View mCurrentView;
+
+    public ButtonDispatcher(int id) {
+        mId = id;
+    }
+
+    void clear() {
+        mViews.clear();
+    }
+
+    void addView(View view) {
+        mViews.add(view);
+        view.setOnClickListener(mClickListener);
+        view.setOnTouchListener(mTouchListener);
+        view.setOnLongClickListener(mLongClickListener);
+        if (mLongClickable != null) {
+            view.setLongClickable(mLongClickable);
+        }
+        if (mAlpha != null) {
+            view.setAlpha(mAlpha);
+        }
+        if (mVisibility != null) {
+            view.setVisibility(mVisibility);
+        }
+        if (mImageResource > 0) {
+            ((ImageView) view).setImageResource(mImageResource);
+        } else if (mImageDrawable != null) {
+            ((ImageView) view).setImageDrawable(mImageDrawable);
+        }
+    }
+
+    public int getId() {
+        return mId;
+    }
+
+    public int getVisibility() {
+        return mVisibility;
+    }
+
+    public float getAlpha() {
+        return mAlpha;
+    }
+
+    public void setImageDrawable(Drawable drawable) {
+        mImageDrawable = drawable;
+        mImageResource = -1;
+        final int N = mViews.size();
+        for (int i = 0; i < N; i++) {
+            ((ImageView) mViews.get(i)).setImageDrawable(mImageDrawable);
+        }
+    }
+
+    public void setImageResource(int resource) {
+        mImageResource = resource;
+        mImageDrawable = null;
+        final int N = mViews.size();
+        for (int i = 0; i < N; i++) {
+            ((ImageView) mViews.get(i)).setImageResource(mImageResource);
+        }
+    }
+
+    public void setVisibility(int visibility) {
+        if (mVisibility == visibility) return;
+        mVisibility = visibility;
+        final int N = mViews.size();
+        for (int i = 0; i < N; i++) {
+            mViews.get(i).setVisibility(mVisibility);
+        }
+    }
+
+    public void abortCurrentGesture() {
+        // This seems to be an instantaneous thing, so not going to persist it.
+        final int N = mViews.size();
+        for (int i = 0; i < N; i++) {
+            ((KeyButtonView) mViews.get(i)).abortCurrentGesture();
+        }
+    }
+
+    public void setAlpha(int alpha) {
+        mAlpha = alpha;
+        final int N = mViews.size();
+        for (int i = 0; i < N; i++) {
+            mViews.get(i).setAlpha(alpha);
+        }
+    }
+
+    public void setOnClickListener(View.OnClickListener clickListener) {
+        mClickListener = clickListener;
+        final int N = mViews.size();
+        for (int i = 0; i < N; i++) {
+            mViews.get(i).setOnClickListener(mClickListener);
+        }
+    }
+
+    public void setOnTouchListener(View.OnTouchListener touchListener) {
+        mTouchListener = touchListener;
+        final int N = mViews.size();
+        for (int i = 0; i < N; i++) {
+            mViews.get(i).setOnTouchListener(mTouchListener);
+        }
+    }
+
+    public void setLongClickable(boolean isLongClickable) {
+        mLongClickable = isLongClickable;
+        final int N = mViews.size();
+        for (int i = 0; i < N; i++) {
+            mViews.get(i).setLongClickable(mLongClickable);
+        }
+    }
+
+    public void setOnLongClickListener(View.OnLongClickListener longClickListener) {
+        mLongClickListener = longClickListener;
+        final int N = mViews.size();
+        for (int i = 0; i < N; i++) {
+            mViews.get(i).setOnLongClickListener(mLongClickListener);
+        }
+    }
+
+    public View getCurrentView() {
+        return mCurrentView;
+    }
+
+    public void setCurrentView(View currentView) {
+        mCurrentView = currentView.findViewById(mId);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
index ae6a11f..abe357a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
@@ -164,12 +164,14 @@
         mTouchDownY = (int) event.getY();
 
         if (mNavigationBarView != null) {
-            View recentsButton = mNavigationBarView.getRecentsButton();
+            View recentsButton = mNavigationBarView.getRecentsButton().getCurrentView();
             if (recentsButton != null) {
                 mDownOnRecents = mTouchDownX >= recentsButton.getLeft()
                         && mTouchDownX <= recentsButton.getRight()
                         && mTouchDownY >= recentsButton.getTop()
                         && mTouchDownY <= recentsButton.getBottom();
+            } else {
+                mDownOnRecents = false;
             }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
new file mode 100644
index 0000000..b8ae81f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
@@ -0,0 +1,266 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import android.content.Context;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.util.AttributeSet;
+import android.util.SparseArray;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.Space;
+import com.android.systemui.R;
+import com.android.systemui.tuner.TunerService;
+
+import java.util.Objects;
+
+public class NavigationBarInflaterView extends FrameLayout implements TunerService.Tunable {
+
+    private static final String TAG = "NavBarInflater";
+
+    public static final String NAV_BAR_VIEWS = "sysui_nav_bar";
+
+    private static final String MENU_IME = "menu_ime";
+    private static final String BACK = "back";
+    private static final String HOME = "home";
+    private static final String RECENT = "recent";
+    private static final String NAVSPACE = "space";
+
+    public static final String GRAVITY_SEPARATOR = ";";
+    public static final String BUTTON_SEPARATOR = ",";
+
+    private final LayoutInflater mLayoutInflater;
+    private final LayoutInflater mLandscapeInflater;
+
+    private FrameLayout mRot0;
+    private FrameLayout mRot90;
+    private SparseArray<ButtonDispatcher> mButtonDispatchers;
+    private String mCurrentLayout;
+
+    public NavigationBarInflaterView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        mLayoutInflater = LayoutInflater.from(context);
+        Configuration landscape = new Configuration();
+        landscape.setTo(context.getResources().getConfiguration());
+        landscape.orientation = Configuration.ORIENTATION_LANDSCAPE;
+        mLandscapeInflater = LayoutInflater.from(context.createConfigurationContext(landscape));
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        mRot0 = (FrameLayout) findViewById(R.id.rot0);
+        mRot90 = (FrameLayout) findViewById(R.id.rot90);
+        clearViews();
+        inflateLayout(getDefaultLayout());
+    }
+
+    private String getDefaultLayout() {
+        return mContext.getString(R.string.config_navBarLayout);
+    }
+
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        TunerService.get(getContext()).addTunable(this, NAV_BAR_VIEWS);
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        TunerService.get(getContext()).removeTunable(this);
+        super.onDetachedFromWindow();
+    }
+
+    @Override
+    public void onTuningChanged(String key, String newValue) {
+        if (NAV_BAR_VIEWS.equals(key)) {
+            if (newValue == null) {
+                newValue = getDefaultLayout();
+            }
+            if (!Objects.equals(mCurrentLayout, newValue)) {
+                clearViews();
+                inflateLayout(newValue);
+            }
+        }
+    }
+
+    public void setButtonDispatchers(SparseArray<ButtonDispatcher> buttonDisatchers) {
+        mButtonDispatchers = buttonDisatchers;
+        for (int i = 0; i < buttonDisatchers.size(); i++) {
+            initiallyFill(buttonDisatchers.valueAt(i));
+        }
+    }
+
+    private void initiallyFill(ButtonDispatcher buttonDispatcher) {
+        addAll(buttonDispatcher, (ViewGroup) mRot0.findViewById(R.id.start_group));
+        addAll(buttonDispatcher, (ViewGroup) mRot0.findViewById(R.id.center_group));
+        addAll(buttonDispatcher, (ViewGroup) mRot0.findViewById(R.id.end_group));
+        addAll(buttonDispatcher, (ViewGroup) mRot90.findViewById(R.id.start_group));
+        addAll(buttonDispatcher, (ViewGroup) mRot90.findViewById(R.id.center_group));
+        addAll(buttonDispatcher, (ViewGroup) mRot90.findViewById(R.id.end_group));
+    }
+
+    private void addAll(ButtonDispatcher buttonDispatcher, ViewGroup parent) {
+        for (int i = 0; i < parent.getChildCount(); i++) {
+            // Need to manually search for each id, just in case each group has more than one
+            // of a single id.  It probably mostly a waste of time, but shouldn't take long
+            // and will only happen once.
+            if (parent.getChildAt(i).getId() == buttonDispatcher.getId()) {
+                buttonDispatcher.addView(parent.getChildAt(i));
+            } else if (parent.getChildAt(i) instanceof ViewGroup) {
+                addAll(buttonDispatcher, (ViewGroup) parent.getChildAt(i));
+            }
+        }
+    }
+
+    private void inflateLayout(String newLayout) {
+        mCurrentLayout = newLayout;
+        String[] sets = newLayout.split(GRAVITY_SEPARATOR);
+        String[] start = sets[0].split(BUTTON_SEPARATOR);
+        String[] center = sets[1].split(BUTTON_SEPARATOR);
+        String[] end = sets[2].split(BUTTON_SEPARATOR);
+        inflateButtons(start, (ViewGroup) mRot0.findViewById(R.id.start_group),
+                (ViewGroup) mRot0.findViewById(R.id.start_group_lightsout), false);
+        inflateButtons(start, (ViewGroup) mRot90.findViewById(R.id.start_group),
+                (ViewGroup) mRot90.findViewById(R.id.start_group_lightsout), true);
+        inflateButtons(center, (ViewGroup) mRot0.findViewById(R.id.center_group),
+                (ViewGroup) mRot0.findViewById(R.id.start_group_lightsout), false);
+        inflateButtons(center, (ViewGroup) mRot90.findViewById(R.id.center_group),
+                (ViewGroup) mRot90.findViewById(R.id.start_group_lightsout), true);
+        inflateButtons(end, (ViewGroup) mRot0.findViewById(R.id.end_group),
+                (ViewGroup) mRot0.findViewById(R.id.start_group_lightsout), false);
+        inflateButtons(end, (ViewGroup) mRot90.findViewById(R.id.end_group),
+                (ViewGroup) mRot90.findViewById(R.id.start_group_lightsout), true);
+    }
+
+    private void inflateButtons(String[] buttons, ViewGroup parent, ViewGroup lightsOutParent,
+            boolean landscape) {
+        for (int i = 0; i < buttons.length; i++) {
+            copyToLightsout(inflateButton(buttons[i], parent, landscape), lightsOutParent);
+        }
+    }
+
+    private void copyToLightsout(View view, ViewGroup lightsOutParent) {
+        if (view instanceof FrameLayout) {
+            // The only ViewGroup we support in here is a FrameLayout, so copy those manually.
+            FrameLayout original = (FrameLayout) view;
+            FrameLayout layout = new FrameLayout(view.getContext());
+            for (int i = 0; i < original.getChildCount(); i++) {
+                copyToLightsout(original.getChildAt(i), layout);
+            }
+            lightsOutParent.addView(layout, copy(view.getLayoutParams()));
+        } else if (view instanceof Space) {
+            lightsOutParent.addView(new Space(view.getContext()), copy(view.getLayoutParams()));
+        } else {
+            lightsOutParent.addView(generateLightsOutView(view), copy(view.getLayoutParams()));
+        }
+    }
+
+    private View generateLightsOutView(View view) {
+        ImageView imageView = new ImageView(view.getContext());
+        // Copy everything we can about the original view.
+        imageView.setPadding(view.getPaddingLeft(), view.getPaddingTop(), view.getPaddingRight(),
+                view.getPaddingBottom());
+        imageView.setContentDescription(view.getContentDescription());
+        imageView.setId(view.getId());
+        // Only home gets a big dot, everything else will be little.
+        imageView.setImageResource(view.getId() == R.id.home
+                ? R.drawable.ic_sysbar_lights_out_dot_large
+                : R.drawable.ic_sysbar_lights_out_dot_small);
+        return imageView;
+    }
+
+    private ViewGroup.LayoutParams copy(ViewGroup.LayoutParams layoutParams) {
+        return new LayoutParams(layoutParams.width, layoutParams.height);
+    }
+
+    private View inflateButton(String button, ViewGroup parent, boolean landscape) {
+        View v = null;
+        if (HOME.equals(button)) {
+            v = (landscape ? mLandscapeInflater : mLayoutInflater)
+                    .inflate(R.layout.home, parent, false);
+            if (landscape && isSw600Dp()) {
+                setupLandButton(v);
+            }
+        } else if (BACK.equals(button)) {
+            v = (landscape ? mLandscapeInflater : mLayoutInflater)
+                    .inflate(R.layout.back, parent, false);
+            if (landscape && isSw600Dp()) {
+                setupLandButton(v);
+            }
+        } else if (RECENT.equals(button)) {
+            v = (landscape ? mLandscapeInflater : mLayoutInflater)
+                    .inflate(R.layout.recent_apps, parent, false);
+            if (landscape && isSw600Dp()) {
+                setupLandButton(v);
+            }
+        } else if (MENU_IME.equals(button)) {
+            v = (landscape ? mLandscapeInflater : mLayoutInflater)
+                    .inflate(R.layout.menu_ime, parent, false);
+        } else if (NAVSPACE.equals(button)) {
+            v = (landscape ? mLandscapeInflater : mLayoutInflater)
+                    .inflate(R.layout.nav_key_space, parent, false);
+        } else {
+            throw new IllegalArgumentException("Unknown button " + button);
+        }
+        parent.addView(v);
+        if (mButtonDispatchers != null) {
+            final int indexOfKey = mButtonDispatchers.indexOfKey(v.getId());
+            if (indexOfKey >= 0) {
+                mButtonDispatchers.valueAt(indexOfKey).addView(v);
+            }
+        }
+        return v;
+    }
+
+    private boolean isSw600Dp() {
+        Configuration configuration = mContext.getResources().getConfiguration();
+        return (configuration.smallestScreenWidthDp >= 600);
+    }
+
+    /**
+     * This manually sets the width of sw600dp landscape buttons because despite
+     * overriding the configuration from the overridden resources aren't loaded currently.
+     */
+    private void setupLandButton(View v) {
+        Resources res = mContext.getResources();
+        v.getLayoutParams().width = res.getDimensionPixelOffset(
+                R.dimen.navigation_key_width_sw600dp_land);
+        int padding = res.getDimensionPixelOffset(R.dimen.navigation_key_padding_sw600dp_land);
+        v.setPadding(padding, v.getPaddingTop(), padding, v.getPaddingBottom());
+    }
+
+    private void clearViews() {
+        if (mButtonDispatchers != null) {
+            for (int i = 0; i < mButtonDispatchers.size(); i++) {
+                mButtonDispatchers.valueAt(i).clear();
+            }
+        }
+        clearAllChildren((ViewGroup) mRot0.findViewById(R.id.nav_buttons));
+        clearAllChildren((ViewGroup) mRot0.findViewById(R.id.lights_out));
+        clearAllChildren((ViewGroup) mRot90.findViewById(R.id.nav_buttons));
+        clearAllChildren((ViewGroup) mRot90.findViewById(R.id.lights_out));
+    }
+
+    private void clearAllChildren(ViewGroup group) {
+        for (int i = 0; i < group.getChildCount(); i++) {
+            ((ViewGroup) group.getChildAt(i)).removeAllViews();
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 5309903..9e66584 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -35,6 +35,7 @@
 import android.os.RemoteException;
 import android.util.AttributeSet;
 import android.util.Log;
+import android.util.SparseArray;
 import android.view.Display;
 import android.view.Gravity;
 import android.view.IDockedStackListener.Stub;
@@ -45,15 +46,11 @@
 import android.view.WindowManager;
 import android.view.WindowManagerGlobal;
 import android.view.inputmethod.InputMethodManager;
-import android.widget.FrameLayout;
-import android.widget.ImageView;
 import android.widget.LinearLayout;
-
 import com.android.systemui.R;
 import com.android.systemui.RecentsComponent;
 import com.android.systemui.stackdivider.Divider;
 import com.android.systemui.statusbar.policy.DeadZone;
-import com.android.systemui.statusbar.policy.KeyButtonView;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -101,6 +98,8 @@
     private boolean mWakeAndUnlocking;
     private boolean mCarMode = false;
 
+    private final SparseArray<ButtonDispatcher> mButtonDisatchers = new SparseArray<>();
+
     private class NavTransitionListener implements TransitionListener {
         private boolean mBackTransitioning;
         private boolean mHomeAppearing;
@@ -132,13 +131,12 @@
         }
 
         public void onBackAltCleared() {
-            View backButton = getBackButton();
-            View homeButton = getHomeButton();
+            ButtonDispatcher backButton = getBackButton();
 
             // When dismissing ime during unlock, force the back button to run the same appearance
             // animation as home (if we catch this condition early enough).
-            if (backButton != null && !mBackTransitioning && backButton.getVisibility() == VISIBLE
-                    && mHomeAppearing && homeButton != null && getHomeButton().getAlpha() == 0) {
+            if (!mBackTransitioning && backButton.getVisibility() == VISIBLE
+                    && mHomeAppearing && getHomeButton().getAlpha() == 0) {
                 getBackButton().setAlpha(0);
                 ValueAnimator a = ObjectAnimator.ofFloat(backButton, "alpha", 0, 1);
                 a.setStartDelay(mStartDelay);
@@ -194,6 +192,12 @@
         getIcons(context);
 
         mBarTransitions = new NavigationBarTransitions(this);
+
+        mButtonDisatchers.put(R.id.back, new ButtonDispatcher(R.id.back));
+        mButtonDisatchers.put(R.id.home, new ButtonDispatcher(R.id.home));
+        mButtonDisatchers.put(R.id.recent_apps, new ButtonDispatcher(R.id.recent_apps));
+        mButtonDisatchers.put(R.id.menu, new ButtonDispatcher(R.id.menu));
+        mButtonDisatchers.put(R.id.ime_switcher, new ButtonDispatcher(R.id.ime_switcher));
     }
 
     public BarTransitions getBarTransitions() {
@@ -226,10 +230,7 @@
     }
 
     public void abortCurrentGesture() {
-        View homeButton = getHomeButton();
-        if (homeButton != null) {
-            getHomeButton().abortCurrentGesture();
-        }
+        getHomeButton().abortCurrentGesture();
     }
 
     private H mHandler = new H();
@@ -242,31 +243,24 @@
         return mRotatedViews;
     }
 
-    // The following Buttons can possibly return null if NavigationBarView is extended to provide
-    // a different layout and the buttons do not exist in that new layout.
-    @Nullable
-    public KeyButtonView getRecentsButton() {
-        return (KeyButtonView) getCurrentView().findViewById(R.id.recent_apps);
+    public ButtonDispatcher getRecentsButton() {
+        return mButtonDisatchers.get(R.id.recent_apps);
     }
 
-    @Nullable
-    public View getMenuButton() {
-        return getCurrentView().findViewById(R.id.menu);
+    public ButtonDispatcher getMenuButton() {
+        return mButtonDisatchers.get(R.id.menu);
     }
 
-    @Nullable
-    public View getBackButton() {
-        return getCurrentView().findViewById(R.id.back);
+    public ButtonDispatcher getBackButton() {
+        return mButtonDisatchers.get(R.id.back);
     }
 
-    @Nullable
-    public KeyButtonView getHomeButton() {
-        return (KeyButtonView) getCurrentView().findViewById(R.id.home);
+    public ButtonDispatcher getHomeButton() {
+        return mButtonDisatchers.get(R.id.home);
     }
 
-    @Nullable
-    public View getImeSwitchButton() {
-        return getCurrentView().findViewById(R.id.ime_switcher);
+    public ButtonDispatcher getImeSwitchButton() {
+        return mButtonDisatchers.get(R.id.ime_switcher);
     }
 
     @Nullable
@@ -344,26 +338,19 @@
                 ? getBackIconWithAlt(mCarMode, mVertical)
                 : getBackIcon(mCarMode, mVertical);
 
-        View backButton = getBackButton();
-        if (backButton != null && backButton instanceof ImageView) {
-            ((ImageView) backButton).setImageDrawable(backIcon);
-        }
+        getBackButton().setImageDrawable(backIcon);
 
-        ImageView recentsButton = getRecentsButton();
-        if (recentsButton != null) {
-            recentsButton.setImageDrawable(mVertical ? mRecentLandIcon : mRecentIcon);
-        }
+        getRecentsButton().setImageDrawable(
+                mVertical ? mRecentLandIcon : mRecentIcon);
 
-        ImageView homeButton = getHomeButton();
-        if (homeButton != null) {
-            homeButton.setImageDrawable(mCarMode ? mHomeCarModeIcon : mHomeDefaultIcon);
+        if (mCarMode) {
+            getHomeButton().setImageDrawable(mHomeCarModeIcon);
+        } else {
+            getHomeButton().setImageDrawable(mHomeDefaultIcon);
         }
 
         final boolean showImeButton = ((hints & StatusBarManager.NAVIGATION_HINT_IME_SHOWN) != 0);
-        View imeSwitchButton = getImeSwitchButton();
-        if (imeSwitchButton != null) {
-            imeSwitchButton.setVisibility(showImeButton ? View.VISIBLE : View.INVISIBLE);
-        }
+        getImeSwitchButton().setVisibility(showImeButton ? View.VISIBLE : View.INVISIBLE);
 
         // Update menu button in case the IME state has changed.
         setMenuVisibility(mShowMenu, true);
@@ -405,20 +392,9 @@
             disableRecent = false;
         }
 
-        View backButton = getBackButton();
-        if (backButton != null) {
-            backButton.setVisibility(disableBack ? View.INVISIBLE : View.VISIBLE);
-        }
-
-        View homeButton = getHomeButton();
-        if (homeButton != null) {
-            homeButton.setVisibility(disableHome ? View.INVISIBLE : View.VISIBLE);
-        }
-
-        View recentsButton = getRecentsButton();
-        if (recentsButton != null) {
-            recentsButton.setVisibility(disableRecent ? View.INVISIBLE : View.VISIBLE);
-        }
+        getBackButton().setVisibility(disableBack      ? View.INVISIBLE : View.VISIBLE);
+        getRecentsButton().setVisibility(disableHome   ? View.INVISIBLE : View.VISIBLE);
+        getRecentsButton().setVisibility(disableRecent ? View.INVISIBLE : View.VISIBLE);
 
         // The app shelf, if it exists, follows the visibility of the home button.
         View appShelf = getAppShelf();
@@ -510,10 +486,7 @@
         final boolean shouldShow = mShowMenu &&
                 ((mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_IME_SHOWN) == 0);
 
-        View menuButton = getMenuButton();
-        if (menuButton != null) {
-            menuButton.setVisibility(shouldShow ? View.VISIBLE : View.INVISIBLE);
-        }
+        getMenuButton().setVisibility(shouldShow ? View.VISIBLE : View.INVISIBLE);
     }
 
     @Override
@@ -526,11 +499,13 @@
         mRotatedViews[Surface.ROTATION_270] = mRotatedViews[Surface.ROTATION_90];
 
         mCurrentView = mRotatedViews[Surface.ROTATION_0];
-
-        View imeSwitchButton = getImeSwitchButton();
-        if (imeSwitchButton != null) {
-            imeSwitchButton.setOnClickListener(mImeSwitcherClickListener);
+        for (int i = 0; i < mButtonDisatchers.size(); i++) {
+            mButtonDisatchers.valueAt(i).setCurrentView(mCurrentView);
         }
+        ((NavigationBarInflaterView) findViewById(R.id.navigation_inflater)).setButtonDispatchers(
+                mButtonDisatchers);
+
+        getImeSwitchButton().setOnClickListener(mImeSwitcherClickListener);
 
         updateRTLOrder();
 
@@ -556,13 +531,9 @@
     }
 
     private void updateRecentsIcon(boolean dockedStackExists) {
-        ImageView recentsButton = getRecentsButton();
-
-        if (recentsButton != null) {
-            recentsButton.setImageResource(dockedStackExists
-                    ? R.drawable.ic_sysbar_docked
-                    : R.drawable.ic_sysbar_recent);
-        }
+        getRecentsButton().setImageResource(dockedStackExists
+                ? R.drawable.ic_sysbar_docked
+                : R.drawable.ic_sysbar_recent);
     }
 
     public boolean isVertical() {
@@ -576,12 +547,12 @@
         }
         mCurrentView = mRotatedViews[rot];
         mCurrentView.setVisibility(View.VISIBLE);
+        for (int i = 0; i < mButtonDisatchers.size(); i++) {
+            mButtonDisatchers.valueAt(i).setCurrentView(mCurrentView);
+        }
         updateLayoutTransitionsEnabled();
 
-        View imeSwitchButton = getImeSwitchButton();
-        if (imeSwitchButton != null) {
-            imeSwitchButton.setOnClickListener(mImeSwitcherClickListener);
-        }
+        getImeSwitchButton().setOnClickListener(mImeSwitcherClickListener);
 
         mDeadZone = (DeadZone) mCurrentView.findViewById(R.id.deadzone);
 
@@ -669,33 +640,16 @@
 
             // We swap all children of the 90 and 270 degree layouts, since they are vertical
             View rotation90 = mRotatedViews[Surface.ROTATION_90];
-            swapChildrenOrderIfVertical(rotation90.findViewById(R.id.nav_buttons));
-            adjustExtraKeyGravity(rotation90, isLayoutRtl);
+            swapChildrenOrderIfVertical(rotation90);
 
             View rotation270 = mRotatedViews[Surface.ROTATION_270];
             if (rotation90 != rotation270) {
-                swapChildrenOrderIfVertical(rotation270.findViewById(R.id.nav_buttons));
-                adjustExtraKeyGravity(rotation270, isLayoutRtl);
+                swapChildrenOrderIfVertical(rotation270);
             }
             mIsLayoutRtl = isLayoutRtl;
         }
     }
 
-    private void adjustExtraKeyGravity(View navBar, boolean isLayoutRtl) {
-        View menu = navBar.findViewById(R.id.menu);
-        View imeSwitcher = navBar.findViewById(R.id.ime_switcher);
-        if (menu != null) {
-            FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) menu.getLayoutParams();
-            lp.gravity = isLayoutRtl ? Gravity.BOTTOM : Gravity.TOP;
-            menu.setLayoutParams(lp);
-        }
-        if (imeSwitcher != null) {
-            FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) imeSwitcher.getLayoutParams();
-            lp.gravity = isLayoutRtl ? Gravity.BOTTOM : Gravity.TOP;
-            imeSwitcher.setLayoutParams(lp);
-        }
-    }
-
     /**
      * Swaps the children order of a LinearLayout if it's orientation is Vertical
      *
@@ -705,6 +659,11 @@
         if (group instanceof LinearLayout) {
             LinearLayout linearLayout = (LinearLayout) group;
             if (linearLayout.getOrientation() == VERTICAL) {
+                if ((linearLayout.getGravity() & Gravity.TOP) != 0) {
+                    linearLayout.setGravity(Gravity.BOTTOM);
+                } else if ((linearLayout.getGravity() & Gravity.BOTTOM) != 0) {
+                    linearLayout.setGravity(Gravity.TOP);
+                }
                 int childCount = linearLayout.getChildCount();
                 ArrayList<View> childList = new ArrayList<>(childCount);
                 for (int i = 0; i < childCount; i++) {
@@ -715,6 +674,11 @@
                     linearLayout.addView(childList.get(i));
                 }
             }
+        } else if (group instanceof ViewGroup) {
+            ViewGroup viewGroup = (ViewGroup) group;
+            for (int i = 0; i < viewGroup.getChildCount(); i++) {
+                swapChildrenOrderIfVertical(viewGroup.getChildAt(i));
+            }
         }
     }
 
@@ -802,13 +766,12 @@
         pw.println("    }");
     }
 
-    private static void dumpButton(PrintWriter pw, String caption, View button) {
+    private static void dumpButton(PrintWriter pw, String caption, ButtonDispatcher button) {
         pw.print("      " + caption + ": ");
         if (button == null) {
             pw.print("null");
         } else {
-            pw.print(PhoneStatusBar.viewInfo(button)
-                    + " " + visibilityToString(button.getVisibility())
+            pw.print(visibilityToString(button.getVisibility())
                     + " alpha=" + button.getAlpha()
                     );
         }
@@ -818,4 +781,5 @@
     public interface OnVerticalChangedListener {
         void onVerticalChanged(boolean isVertical);
     }
+
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 71b6713..b2c03c4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -1185,25 +1185,19 @@
     private void prepareNavigationBarView() {
         mNavigationBarView.reorient();
 
-        View recentsButton = mNavigationBarView.getRecentsButton();
-        if (recentsButton != null) {
-            recentsButton.setOnClickListener(mRecentsClickListener);
-            recentsButton.setOnTouchListener(mRecentsPreloadOnTouchListener);
-            recentsButton.setLongClickable(true);
-            recentsButton.setOnLongClickListener(mRecentsLongClickListener);
-        }
+        ButtonDispatcher recentsButton = mNavigationBarView.getRecentsButton();
+        recentsButton.setOnClickListener(mRecentsClickListener);
+        recentsButton.setOnTouchListener(mRecentsPreloadOnTouchListener);
+        recentsButton.setLongClickable(true);
+        recentsButton.setOnLongClickListener(mRecentsLongClickListener);
 
-        View backButton = mNavigationBarView.getBackButton();
-        if (backButton != null) {
-            backButton.setLongClickable(true);
-            backButton.setOnLongClickListener(mLongPressBackListener);
-        }
+        ButtonDispatcher backButton = mNavigationBarView.getBackButton();
+        backButton.setLongClickable(true);
+        backButton.setOnLongClickListener(mLongPressBackListener);
 
-        View homeButton = mNavigationBarView.getHomeButton();
-        if (homeButton != null) {
-            homeButton.setOnTouchListener(mHomeActionListener);
-            homeButton.setOnLongClickListener(mLongPressHomeListener);
-        }
+        ButtonDispatcher homeButton = mNavigationBarView.getHomeButton();
+        homeButton.setOnTouchListener(mHomeActionListener);
+        homeButton.setOnLongClickListener(mLongPressHomeListener);
 
         mAssistManager.onConfigurationChanged();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ReverseLinearLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ReverseLinearLayout.java
new file mode 100644
index 0000000..da16954
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ReverseLinearLayout.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.LinearLayout;
+
+/**
+ * Automatically reverses the order of children as they are added.
+ * Also reverse the width and height values of layout params
+ */
+public class ReverseLinearLayout extends LinearLayout {
+
+    public ReverseLinearLayout(Context context, @Nullable AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    @Override
+    public void addView(View child) {
+        reversParams(child.getLayoutParams());
+        super.addView(child, 0);
+    }
+
+    @Override
+    public void addView(View child, ViewGroup.LayoutParams params) {
+        reversParams(params);
+        super.addView(child, 0, params);
+    }
+
+    private void reversParams(ViewGroup.LayoutParams params) {
+        if (params == null) {
+            return;
+        }
+        int width = params.width;
+        params.width = params.height;
+        params.height = width;
+    }
+
+}