Subtract the navigation bar from DisplayMetrics.

Its region is now treated like the system bar: inaccessible
to applications and therefore not worth reporting as part of
the display.

(Note that using setSystemUiVisibility you can gain
temporary access to the navigation bar region, unlike the
sempiternal system bar.)

The navigation bar is now considerably less in control of
its own behavior (the window manager assumes it will be a
certain size and in a certain position in landscape and
portrait). This change also fixes the navbar so that it
becomes GONE instead of merely INVISIBLE (allowing
underlying windows to expand in size accordingly).

Bug: 5052456 // the feature
Bug: 5067627 // notification shade falling behind the navbar
Bug: 4959805 // fix third-party apps relying on DisplayMetrics
Change-Id: I60257fc5c858e0edcaba8cfc1f8d58dd99a68258
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index e534e9b..829f757 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -32,8 +32,12 @@
     <dimen name="toast_y_offset">64dip</dimen>
     <!-- Height of the status bar -->
     <dimen name="status_bar_height">25dip</dimen>
-    <!-- Height of the system bar -->
+    <!-- Height of the system bar (combined status + navigation, used on large screens) -->
     <dimen name="system_bar_height">48dip</dimen>
+    <!-- Height of the horizontal navigation bar on devices that require it -->
+    <dimen name="navigation_bar_height">48dp</dimen>
+    <!-- Width of the vertical navigation bar on devices that require it -->
+    <dimen name="navigation_bar_width">42dp</dimen>
     <!-- Height of notification icons in the status bar -->
     <dimen name="status_bar_icon_size">24dip</dimen>
     <!-- Size of the giant number (unread count) in the notifications -->
diff --git a/packages/SystemUI/res/values-land/dimens.xml b/packages/SystemUI/res/values-land/dimens.xml
index 0219a77..3919685 100644
--- a/packages/SystemUI/res/values-land/dimens.xml
+++ b/packages/SystemUI/res/values-land/dimens.xml
@@ -17,7 +17,7 @@
 -->
 <resources>
     <!-- thickness (width) of the navigation bar on phones that require it -->
-    <dimen name="navigation_bar_size">42dp</dimen>
+    <dimen name="navigation_bar_size">@*android:dimen/navigation_bar_width</dimen>
 
     <!-- Recent Applications parameters -->
     <!-- Width of a recent app view, including all content -->
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index ba1aea3..ef9b8dd 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -40,7 +40,7 @@
     <dimen name="peek_window_y_offset">-12dp</dimen>
 
     <!-- thickness (height) of the navigation bar on phones that require it -->
-    <dimen name="navigation_bar_size">48dp</dimen>
+    <dimen name="navigation_bar_size">@*android:dimen/navigation_bar_height</dimen>
 
     <!-- thickness (height) of the dead zone at the top of the navigation bar,
          reducing false presses on navbar buttons; approx 2mm -->
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 2740898..abf505c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -112,7 +112,7 @@
             public void onAnimationEnd(Animator _a) {
                 mLastAnimator = null;
                 if (hide) {
-                    setVisibility(View.INVISIBLE);
+                    setVisibility(View.GONE);
                 }
             }
         });
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 e14317b..823efae 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -42,6 +42,7 @@
 import android.os.SystemClock;
 import android.provider.Settings;
 import android.text.TextUtils;
+import android.util.DisplayMetrics;
 import android.util.Slog;
 import android.util.Log;
 import android.view.Display;
@@ -85,8 +86,8 @@
 
 public class PhoneStatusBar extends StatusBar {
     static final String TAG = "PhoneStatusBar";
-    static final boolean SPEW = false;
     public static final boolean DEBUG = false;
+    public static final boolean SPEW = false;
 
     // additional instrumentation for testing purposes; intended to be left on during development
     public static final boolean CHATTY = DEBUG || true;
@@ -201,11 +202,11 @@
     // tracking calls to View.setSystemUiVisibility()
     int mSystemUiVisibility = View.SYSTEM_UI_FLAG_VISIBLE;
 
-    final Point mDisplaySize = new Point();
+    DisplayMetrics mDisplayMetrics = new DisplayMetrics();
 
     private class ExpandedDialog extends Dialog {
         ExpandedDialog(Context context) {
-            super(context, com.android.internal.R.style.Theme_Light_NoTitleBar);
+            super(context, com.android.internal.R.style.Theme_Translucent_NoTitleBar);
         }
 
         @Override
@@ -248,7 +249,12 @@
 
         Resources res = context.getResources();
 
-        mDisplay.getSize(mDisplaySize);
+        mDisplay.getMetrics(mDisplayMetrics);
+        if (DEBUG) {
+            Slog.d(TAG, "makeStatusBarView: mDisplayMetrics=" + mDisplayMetrics);
+            mDisplayMetrics = res.getDisplayMetrics();
+            Slog.d(TAG, "makeStatusBarView: mDisplayMetrics2=" + mDisplayMetrics);
+        }
         loadDimens();
 
         mIconSize = res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_icon_size);
@@ -1110,6 +1116,9 @@
         updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
         mExpandedParams.flags &= ~WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
         mExpandedParams.flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
+        if (DEBUG) {
+            Slog.d(TAG, "makeExpandedVisible: expanded params = " + mExpandedParams);
+        }
         mExpandedDialog.getWindow().setAttributes(mExpandedParams);
         mExpandedView.requestFocus(View.FOCUS_FORWARD);
         mTrackingView.setVisibility(View.VISIBLE);
@@ -1155,7 +1164,7 @@
         if (mAnimating) {
             y = (int)mAnimY;
         } else {
-            y = mDisplaySize.y-1;
+            y = mDisplayMetrics.heightPixels-1;
         }
         // Let the fling think that we're open so it goes in the right direction
         // and doesn't try to re-open the windowshade.
@@ -1210,7 +1219,7 @@
             if (SPEW) Slog.d(TAG, "doAnimation before mAnimY=" + mAnimY);
             incrementAnim();
             if (SPEW) Slog.d(TAG, "doAnimation after  mAnimY=" + mAnimY);
-            if (mAnimY >= mDisplaySize.y-1) {
+            if (mAnimY >= mDisplayMetrics.heightPixels-1) {
                 if (SPEW) Slog.d(TAG, "Animation completed to expanded state.");
                 mAnimating = false;
                 updateExpandedViewPos(EXPANDED_FULL_OPEN);
@@ -1317,7 +1326,7 @@
         if (mExpanded) {
             if (!always && (
                     vel > 200.0f
-                    || (y > (mDisplaySize.y-25) && vel > -200.0f))) {
+                    || (y > (mDisplayMetrics.heightPixels-25) && vel > -200.0f))) {
                 // We are expanded, but they didn't move sufficiently to cause
                 // us to retract.  Animate back to the expanded position.
                 mAnimAccel = 2000.0f;
@@ -1335,7 +1344,7 @@
         } else {
             if (always || (
                     vel > 200.0f
-                    || (y > (mDisplaySize.y/2) && vel > -200.0f))) {
+                    || (y > (mDisplayMetrics.heightPixels/2) && vel > -200.0f))) {
                 // We are collapsed, and they moved enough to allow us to
                 // expand.  Animate in the notifications.
                 mAnimAccel = 2000.0f;
@@ -1393,14 +1402,14 @@
                 mViewDelta = mAbsPos[1] + mTrackingView.getHeight() - y;
             }
             if ((!mExpanded && y < hitSize) ||
-                    (mExpanded && y > (mDisplaySize.y-hitSize))) {
+                    (mExpanded && y > (mDisplayMetrics.heightPixels-hitSize))) {
 
                 // We drop events at the edge of the screen to make the windowshade come
                 // down by accident less, especially when pushing open a device with a keyboard
                 // that rotates (like g1 and droid)
                 int x = (int)event.getRawX();
                 final int edgeBorder = mEdgeBorder;
-                if (x >= edgeBorder && x < mDisplaySize.x - edgeBorder) {
+                if (x >= edgeBorder && x < mDisplayMetrics.widthPixels - edgeBorder) {
                     prepareTracking(y, !mExpanded);// opening if we're not already fully visible
                     mVelocityTracker.addMovement(event);
                 }
@@ -1641,7 +1650,7 @@
                     + " mAnimLastTime=" + mAnimLastTime);
             pw.println("  mAnimatingReveal=" + mAnimatingReveal
                     + " mViewDelta=" + mViewDelta);
-            pw.println("  mDisplaySize=" + mDisplaySize);
+            pw.println("  mDisplayMetrics=" + mDisplayMetrics);
             pw.println("  mExpandedParams: " + mExpandedParams);
             pw.println("  mExpandedView: " + viewInfo(mExpandedView));
             pw.println("  mExpandedDialog: " + mExpandedDialog);
@@ -1717,7 +1726,8 @@
                 ViewGroup.LayoutParams.MATCH_PARENT,
                 ViewGroup.LayoutParams.MATCH_PARENT,
                 WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL,
-                WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+                0
+                | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
                 | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
                 | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
                 pixelFormat);
@@ -1739,9 +1749,10 @@
 
         lp = mExpandedDialog.getWindow().getAttributes();
         lp.x = 0;
-        mTrackingPosition = lp.y = mDisplaySize.y; // sufficiently large negative
+        mTrackingPosition = lp.y = mDisplayMetrics.heightPixels; // sufficiently large negative
         lp.type = WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL;
-        lp.flags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+        lp.flags = 0
+                | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
                 | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
                 | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
                 | WindowManager.LayoutParams.FLAG_DITHER
@@ -1772,14 +1783,14 @@
 
     void updateExpandedInvisiblePosition() {
         if (mTrackingView != null) {
-            mTrackingPosition = -mDisplaySize.y;
+            mTrackingPosition = -mDisplayMetrics.heightPixels;
             if (mTrackingParams != null) {
                 mTrackingParams.y = mTrackingPosition;
                 WindowManagerImpl.getDefault().updateViewLayout(mTrackingView, mTrackingParams);
             }
         }
         if (mExpandedParams != null) {
-            mExpandedParams.y = -mDisplaySize.y;
+            mExpandedParams.y = -mDisplayMetrics.heightPixels;
             mExpandedDialog.getWindow().setAttributes(mExpandedParams);
         }
     }
@@ -1792,7 +1803,7 @@
         }
 
         int h = mStatusBarView.getHeight();
-        int disph = mDisplaySize.y;
+        int disph = mDisplayMetrics.heightPixels;
 
         // If the expanded view is not visible, make sure they're still off screen.
         // Maybe the view was resized.
@@ -1845,7 +1856,7 @@
                 // If the tracking view is not yet visible, then we can't have
                 // a good value of the close view location.  We need to wait for
                 // it to be visible to do a layout.
-                mExpandedParams.y = -mDisplaySize.y;
+                mExpandedParams.y = -mDisplayMetrics.heightPixels;
             }
             int max = h;
             if (mExpandedParams.y > max) {
@@ -1891,7 +1902,10 @@
     }
 
     void updateDisplaySize() {
-        mDisplay.getSize(mDisplaySize);
+        mDisplay.getMetrics(mDisplayMetrics);
+        if (DEBUG) {
+            Slog.d(TAG, "updateDisplaySize: " + mDisplayMetrics);
+        }
         updateExpandedSize();
     }
 
@@ -1899,9 +1913,9 @@
         if (DEBUG) {
             Slog.d(TAG, "updateExpandedSize()");
         }
-        if (mExpandedDialog != null && mExpandedParams != null && mDisplaySize != null) {
-            mExpandedParams.width = mDisplaySize.x;
-            mExpandedParams.height = getExpandedHeight(mDisplaySize.y);
+        if (mExpandedDialog != null && mExpandedParams != null && mDisplayMetrics != null) {
+            mExpandedParams.width = mDisplayMetrics.widthPixels;
+            mExpandedParams.height = getExpandedHeight(mDisplayMetrics.heightPixels);
             if (!mExpandedVisible) {
                 updateExpandedInvisiblePosition();
             } else {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/TrackingView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/TrackingView.java
index fc0f332..cc23afc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/TrackingView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/TrackingView.java
@@ -26,7 +26,6 @@
 
 
 public class TrackingView extends LinearLayout {
-    final Display mDisplay;
     PhoneStatusBar mService;
     boolean mTracking;
     int mStartX, mStartY;
@@ -34,8 +33,6 @@
 
     public TrackingView(Context context, AttributeSet attrs) {
         super(context, attrs);
-        mDisplay = ((WindowManager)context.getSystemService(
-                Context.WINDOW_SERVICE)).getDefaultDisplay();
     }
     
     @Override
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index a2dbb78..ff8dc92 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -243,6 +243,8 @@
     int mStatusBarHeight;
     final ArrayList<WindowState> mStatusBarPanels = new ArrayList<WindowState>();
     WindowState mNavigationBar = null;
+    boolean mHasNavigationBar = false;
+    int mNavigationBarWidth = 0, mNavigationBarHeight = 0;
 
     WindowState mKeyguard = null;
     KeyguardViewMediator mKeyguardMediator;
@@ -796,6 +798,17 @@
                 mStatusBarCanHide
                 ? com.android.internal.R.dimen.status_bar_height
                 : com.android.internal.R.dimen.system_bar_height);
+
+        mHasNavigationBar = mContext.getResources().getBoolean(
+                com.android.internal.R.bool.config_showNavigationBar);
+        mNavigationBarHeight = mHasNavigationBar
+                ? mContext.getResources().getDimensionPixelSize(
+                    com.android.internal.R.dimen.navigation_bar_height)
+                : 0;
+        mNavigationBarWidth = mHasNavigationBar
+                ? mContext.getResources().getDimensionPixelSize(
+                    com.android.internal.R.dimen.navigation_bar_width)
+                : 0;
     }
 
     public void updateSettings() {
@@ -1110,19 +1123,26 @@
     }
 
     public int getNonDecorDisplayWidth(int rotation, int fullWidth) {
-        return fullWidth;
+        // Assumes that the navigation bar appears on the side of the display in landscape.
+        final boolean horizontal
+            = (rotation == Surface.ROTATION_270 || rotation == Surface.ROTATION_90);
+        return fullWidth - (horizontal ? mNavigationBarWidth : 0);
     }
 
     public int getNonDecorDisplayHeight(int rotation, int fullHeight) {
-        return mStatusBarCanHide ? fullHeight : (fullHeight - mStatusBarHeight);
+        final boolean horizontal
+            = (rotation == Surface.ROTATION_270 || rotation == Surface.ROTATION_90);
+        return fullHeight
+            - (mStatusBarCanHide ? 0 : mStatusBarHeight)
+            - (horizontal ? 0 : mNavigationBarHeight);
     }
 
     public int getConfigDisplayWidth(int rotation, int fullWidth) {
-        return fullWidth;
+        return getNonDecorDisplayWidth(rotation, fullWidth);
     }
 
     public int getConfigDisplayHeight(int rotation, int fullHeight) {
-        return fullHeight - mStatusBarHeight;
+        return getNonDecorDisplayHeight(rotation, fullHeight);
     }
 
     public boolean doesForceHide(WindowState win, WindowManager.LayoutParams attrs) {
@@ -1851,7 +1871,8 @@
         final Rect cf = mTmpContentFrame;
         final Rect vf = mTmpVisibleFrame;
         
-        final boolean hasNavBar = (mNavigationBar != null && mNavigationBar.isVisibleLw());
+        final boolean hasNavBar = (mHasNavigationBar 
+                && mNavigationBar != null && mNavigationBar.isVisibleLw());
 
         if (attrs.type == TYPE_INPUT_METHOD) {
             pf.left = df.left = cf.left = vf.left = mDockLeft;
@@ -1943,6 +1964,11 @@
                                           ? mRestrictedScreenTop+mRestrictedScreenHeight
                                           : mUnrestrictedScreenTop+mUnrestrictedScreenHeight;
 
+                    if (DEBUG_LAYOUT) {
+                        Log.v(TAG, String.format(
+                                    "Laying out IN_SCREEN status bar window: (%d,%d - %d,%d)",
+                                    pf.left, pf.top, pf.right, pf.bottom));
+                    }
                 } else if (attrs.type == TYPE_NAVIGATION_BAR) {
                     // The navigation bar has Real Ultimate Power.
                     pf.left = df.left = mUnrestrictedScreenLeft;