Merge "Revert "Revert "resolved conflicts for merge of 47249f2a to mnc-dev""" into mnc-dev
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index b93a4a5..8952807 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -18,7 +18,6 @@
 
 import android.content.res.TypedArray;
 import android.graphics.Canvas;
-import android.os.SystemProperties;
 import android.view.WindowInsets;
 
 import com.android.internal.R;
@@ -161,9 +160,11 @@
         final Rect mOverscanInsets = new Rect();
         final Rect mContentInsets = new Rect();
         final Rect mStableInsets = new Rect();
+        final Rect mOutsets = new Rect();
         final Rect mDispatchedOverscanInsets = new Rect();
         final Rect mDispatchedContentInsets = new Rect();
         final Rect mDispatchedStableInsets = new Rect();
+        final Rect mDispatchedOutsets = new Rect();
         final Rect mFinalSystemInsets = new Rect();
         final Rect mFinalStableInsets = new Rect();
         final Configuration mConfiguration = new Configuration();
@@ -268,7 +269,7 @@
         final BaseIWindow mWindow = new BaseIWindow() {
             @Override
             public void resized(Rect frame, Rect overscanInsets, Rect contentInsets,
-                    Rect visibleInsets, Rect stableInsets, boolean reportDraw,
+                    Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw,
                     Configuration newConfig) {
                 Message msg = mCaller.obtainMessageI(MSG_WINDOW_RESIZED,
                         reportDraw ? 1 : 0);
@@ -658,30 +659,35 @@
                         mInputEventReceiver = new WallpaperInputEventReceiver(
                                 mInputChannel, Looper.myLooper());
                     }
-                    
+
                     mSurfaceHolder.mSurfaceLock.lock();
                     mDrawingAllowed = true;
 
                     if (!fixedSize) {
                         mLayout.surfaceInsets.set(mIWallpaperEngine.mDisplayPadding);
+                        mLayout.surfaceInsets.left += mOutsets.left;
+                        mLayout.surfaceInsets.top += mOutsets.top;
+                        mLayout.surfaceInsets.right += mOutsets.right;
+                        mLayout.surfaceInsets.bottom += mOutsets.bottom;
                     } else {
                         mLayout.surfaceInsets.set(0, 0, 0, 0);
                     }
                     final int relayoutResult = mSession.relayout(
                         mWindow, mWindow.mSeq, mLayout, mWidth, mHeight,
                             View.VISIBLE, 0, mWinFrame, mOverscanInsets, mContentInsets,
-                            mVisibleInsets, mStableInsets, mConfiguration, mSurfaceHolder.mSurface);
+                            mVisibleInsets, mStableInsets, mOutsets, mConfiguration,
+                            mSurfaceHolder.mSurface);
 
                     if (DEBUG) Log.v(TAG, "New surface: " + mSurfaceHolder.mSurface
                             + ", frame=" + mWinFrame);
-                    
+
                     int w = mWinFrame.width();
                     int h = mWinFrame.height();
 
                     if (!fixedSize) {
                         final Rect padding = mIWallpaperEngine.mDisplayPadding;
-                        w += padding.left + padding.right;
-                        h += padding.top + padding.bottom;
+                        w += padding.left + padding.right + mOutsets.left + mOutsets.right;
+                        h += padding.top + padding.bottom + mOutsets.top + mOutsets.bottom;
                         mOverscanInsets.left += padding.left;
                         mOverscanInsets.top += padding.top;
                         mOverscanInsets.right += padding.right;
@@ -705,9 +711,14 @@
                         mCurHeight = h;
                     }
 
+                    if (DEBUG) {
+                        Log.v(TAG, "Wallpaper size has changed: (" + mCurWidth + ", " + mCurHeight);
+                    }
+
                     insetsChanged |= !mDispatchedOverscanInsets.equals(mOverscanInsets);
                     insetsChanged |= !mDispatchedContentInsets.equals(mContentInsets);
                     insetsChanged |= !mDispatchedStableInsets.equals(mStableInsets);
+                    insetsChanged |= !mDispatchedOutsets.equals(mOutsets);
 
                     mSurfaceHolder.setSurfaceFrameSize(w, h);
                     mSurfaceHolder.mSurfaceLock.unlock();
@@ -767,14 +778,21 @@
 
                         if (insetsChanged) {
                             mDispatchedOverscanInsets.set(mOverscanInsets);
+                            mDispatchedOverscanInsets.left += mOutsets.left;
+                            mDispatchedOverscanInsets.top += mOutsets.top;
+                            mDispatchedOverscanInsets.right += mOutsets.right;
+                            mDispatchedOverscanInsets.bottom += mOutsets.bottom;
                             mDispatchedContentInsets.set(mContentInsets);
                             mDispatchedStableInsets.set(mStableInsets);
+                            mDispatchedOutsets.set(mOutsets);
                             mFinalSystemInsets.set(mDispatchedOverscanInsets);
                             mFinalStableInsets.set(mDispatchedStableInsets);
-                            mFinalSystemInsets.bottom = mIWallpaperEngine.mDisplayPadding.bottom;
                             WindowInsets insets = new WindowInsets(mFinalSystemInsets,
                                     null, mFinalStableInsets,
                                     getResources().getConfiguration().isScreenRound());
+                            if (DEBUG) {
+                                Log.v(TAG, "dispatching insets=" + insets);
+                            }
                             onApplyWindowInsets(insets);
                         }
 
diff --git a/core/java/android/view/IWindow.aidl b/core/java/android/view/IWindow.aidl
index 0fefdc7..9cf3759 100644
--- a/core/java/android/view/IWindow.aidl
+++ b/core/java/android/view/IWindow.aidl
@@ -46,7 +46,7 @@
     void executeCommand(String command, String parameters, in ParcelFileDescriptor descriptor);
 
     void resized(in Rect frame, in Rect overscanInsets, in Rect contentInsets,
-            in Rect visibleInsets, in Rect stableInsets, boolean reportDraw,
+            in Rect visibleInsets, in Rect stableInsets, in Rect outsets, boolean reportDraw,
             in Configuration newConfig);
     void moved(int newX, int newY);
     void dispatchAppVisibility(boolean visible);
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index fc0148f..19253dd 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -79,11 +79,13 @@
      * contents to make sure the user can see it.  This is different than
      * <var>outContentInsets</var> in that these insets change transiently,
      * so complex relayout of the window should not happen based on them.
+     * @param outOutsets Rect in which is placed the dead area of the screen that we would like to
+     * treat as real display. Example of such area is a chin in some models of wearable devices.
      * @param outConfiguration New configuration of window, if it is now
      * becoming visible and the global configuration has changed since it
      * was last displayed.
      * @param outSurface Object in which is placed the new display surface.
-     * 
+     *
      * @return int Result flags: {@link WindowManagerGlobal#RELAYOUT_SHOW_FOCUS},
      * {@link WindowManagerGlobal#RELAYOUT_FIRST_TIME}.
      */
@@ -91,7 +93,7 @@
             int requestedWidth, int requestedHeight, int viewVisibility,
             int flags, out Rect outFrame, out Rect outOverscanInsets,
             out Rect outContentInsets, out Rect outVisibleInsets, out Rect outStableInsets,
-            out Configuration outConfig, out Surface outSurface);
+            out Rect outOutsets, out Configuration outConfig, out Surface outSurface);
 
     /**
      * If a call to relayout() asked to have the surface destroy deferred,
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 49be57d..160c662 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -106,6 +106,7 @@
     final Rect mOverscanInsets = new Rect();
     final Rect mContentInsets = new Rect();
     final Rect mStableInsets = new Rect();
+    final Rect mOutsets = new Rect();
     final Configuration mConfiguration = new Configuration();
 
     static final int KEEP_SCREEN_ON_MSG = 1;
@@ -519,7 +520,8 @@
                             visible ? VISIBLE : GONE,
                             WindowManagerGlobal.RELAYOUT_DEFER_SURFACE_DESTROY,
                             mWinFrame, mOverscanInsets, mContentInsets,
-                            mVisibleInsets, mStableInsets, mConfiguration, mNewSurface);
+                            mVisibleInsets, mStableInsets, mOutsets, mConfiguration,
+                            mNewSurface);
                     if ((relayoutResult & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
                         mReportDrawNeeded = true;
                     }
@@ -654,7 +656,7 @@
 
         @Override
         public void resized(Rect frame, Rect overscanInsets, Rect contentInsets,
-                Rect visibleInsets, Rect stableInsets, boolean reportDraw,
+                Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw,
                 Configuration newConfig) {
             SurfaceView surfaceView = mSurfaceView.get();
             if (surfaceView != null) {
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 3e50695..0c55632 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -7376,6 +7376,15 @@
     }
 
     /**
+     * Returns the outsets, which areas of the device that aren't a surface, but we would like to
+     * treat them as such.
+     * @hide
+     */
+    public void getOutsets(Rect outOutsetRect) {
+        outOutsetRect.set(mAttachInfo.mOutsets);
+    }
+
+    /**
      * Returns the visibility status for this view.
      *
      * @return One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}.
@@ -21566,6 +21575,12 @@
         final Rect mStableInsets = new Rect();
 
         /**
+         * For windows that include areas that are not covered by real surface these are the outsets
+         * for real surface.
+         */
+        final Rect mOutsets = new Rect();
+
+        /**
          * The internal insets given by this window.  This value is
          * supplied by the client (through
          * {@link ViewTreeObserver.OnComputeInternalInsetsListener}) and will
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 8d94de3..e1e0154 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -268,6 +268,7 @@
     final Rect mPendingVisibleInsets = new Rect();
     final Rect mPendingStableInsets = new Rect();
     final Rect mPendingContentInsets = new Rect();
+    final Rect mPendingOutsets = new Rect();
     final ViewTreeObserver.InternalInsetsInfo mLastGivenInsets
             = new ViewTreeObserver.InternalInsetsInfo();
 
@@ -1267,6 +1268,12 @@
                 contentInsets = mPendingContentInsets;
                 stableInsets = mPendingStableInsets;
             }
+            Rect outsets = mAttachInfo.mOutsets;
+            if (outsets.left > 0 || outsets.top > 0 || outsets.right > 0 || outsets.bottom > 0) {
+                contentInsets = new Rect(contentInsets.left + outsets.left,
+                        contentInsets.top + outsets.top, contentInsets.right + outsets.right,
+                        contentInsets.bottom + outsets.bottom);
+            }
             mLastWindowInsets = new WindowInsets(contentInsets,
                     null /* windowDecorInsets */, stableInsets,
                     mContext.getResources().getConfiguration().isScreenRound());
@@ -1425,6 +1432,9 @@
                     if (DEBUG_LAYOUT) Log.v(TAG, "Visible insets changing to: "
                             + mAttachInfo.mVisibleInsets);
                 }
+                if (!mPendingOutsets.equals(mAttachInfo.mOutsets)) {
+                    insetsChanged = true;
+                }
                 if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT
                         || lp.height == ViewGroup.LayoutParams.WRAP_CONTENT) {
                     windowSizeMayChange = true;
@@ -1598,6 +1608,7 @@
                         mAttachInfo.mVisibleInsets);
                 final boolean stableInsetsChanged = !mPendingStableInsets.equals(
                         mAttachInfo.mStableInsets);
+                final boolean outsetsChanged = !mPendingOutsets.equals(mAttachInfo.mOutsets);
                 if (contentInsetsChanged) {
                     if (mWidth > 0 && mHeight > 0 && lp != null &&
                             ((lp.systemUiVisibility|lp.subtreeSystemUiVisibility)
@@ -1681,9 +1692,11 @@
                 }
                 if (contentInsetsChanged || mLastSystemUiVisibility !=
                         mAttachInfo.mSystemUiVisibility || mApplyInsetsRequested
-                        || mLastOverscanRequested != mAttachInfo.mOverscanRequested) {
+                        || mLastOverscanRequested != mAttachInfo.mOverscanRequested
+                        || outsetsChanged) {
                     mLastSystemUiVisibility = mAttachInfo.mSystemUiVisibility;
                     mLastOverscanRequested = mAttachInfo.mOverscanRequested;
+                    mAttachInfo.mOutsets.set(mPendingOutsets);
                     mApplyInsetsRequested = false;
                     dispatchApplyInsets(host);
                 }
@@ -3263,6 +3276,7 @@
                         && mPendingContentInsets.equals(args.arg2)
                         && mPendingStableInsets.equals(args.arg6)
                         && mPendingVisibleInsets.equals(args.arg3)
+                        && mPendingOutsets.equals(args.arg7)
                         && args.arg4 == null) {
                     break;
                 }
@@ -3281,6 +3295,7 @@
                     mPendingContentInsets.set((Rect) args.arg2);
                     mPendingStableInsets.set((Rect) args.arg6);
                     mPendingVisibleInsets.set((Rect) args.arg3);
+                    mPendingOutsets.set((Rect) args.arg7);
 
                     args.recycle();
 
@@ -5391,7 +5406,7 @@
                 (int) (mView.getMeasuredHeight() * appScale + 0.5f),
                 viewVisibility, insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0,
                 mWinFrame, mPendingOverscanInsets, mPendingContentInsets, mPendingVisibleInsets,
-                mPendingStableInsets, mPendingConfiguration, mSurface);
+                mPendingStableInsets, mPendingOutsets, mPendingConfiguration, mSurface);
         //Log.d(TAG, "<<<<<< BACK FROM relayout");
         if (restore) {
             params.restore();
@@ -5660,7 +5675,8 @@
     }
 
     public void dispatchResized(Rect frame, Rect overscanInsets, Rect contentInsets,
-            Rect visibleInsets, Rect stableInsets, boolean reportDraw, Configuration newConfig) {
+            Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw,
+            Configuration newConfig) {
         if (DEBUG_LAYOUT) Log.v(TAG, "Resizing " + this + ": frame=" + frame.toShortString()
                 + " contentInsets=" + contentInsets.toShortString()
                 + " visibleInsets=" + visibleInsets.toShortString()
@@ -5680,6 +5696,7 @@
         args.arg4 = sameProcessCall && newConfig != null ? new Configuration(newConfig) : newConfig;
         args.arg5 = sameProcessCall ? new Rect(overscanInsets) : overscanInsets;
         args.arg6 = sameProcessCall ? new Rect(stableInsets) : stableInsets;
+        args.arg7 = sameProcessCall ? new Rect(outsets) : outsets;
         msg.obj = args;
         mHandler.sendMessage(msg);
     }
@@ -6654,12 +6671,12 @@
 
         @Override
         public void resized(Rect frame, Rect overscanInsets, Rect contentInsets,
-                Rect visibleInsets, Rect stableInsets, boolean reportDraw,
+                Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw,
                 Configuration newConfig) {
             final ViewRootImpl viewAncestor = mViewAncestor.get();
             if (viewAncestor != null) {
                 viewAncestor.dispatchResized(frame, overscanInsets, contentInsets,
-                        visibleInsets, stableInsets, reportDraw, newConfig);
+                        visibleInsets, stableInsets, outsets, reportDraw, newConfig);
             }
         }
 
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index 57121ddd..f7b6405 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -158,10 +158,12 @@
          * @param decorFrame The decor frame specified by policy specific to this window,
          * to use for proper cropping during animation.
          * @param stableFrame The frame around which stable system decoration is positioned.
+         * @param outsetFrame The frame that includes areas that aren't part of the surface but we
+         * want to treat them as such.
          */
         public void computeFrameLw(Rect parentFrame, Rect displayFrame,
                 Rect overlayFrame, Rect contentFrame, Rect visibleFrame, Rect decorFrame,
-                Rect stableFrame);
+                Rect stableFrame, Rect outsetFrame);
 
         /**
          * Retrieve the current frame of the window that has been assigned by
diff --git a/core/java/com/android/internal/os/SomeArgs.java b/core/java/com/android/internal/os/SomeArgs.java
index c977997..b0d24fd 100644
--- a/core/java/com/android/internal/os/SomeArgs.java
+++ b/core/java/com/android/internal/os/SomeArgs.java
@@ -46,6 +46,7 @@
     public Object arg4;
     public Object arg5;
     public Object arg6;
+    public Object arg7;
     public int argi1;
     public int argi2;
     public int argi3;
@@ -97,6 +98,7 @@
         arg4 = null;
         arg5 = null;
         arg6 = null;
+        arg7 = null;
         argi1 = 0;
         argi2 = 0;
         argi3 = 0;
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index bc64373..a04218a 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -56,7 +56,6 @@
 import android.view.WindowInsets;
 import android.view.WindowManager;
 import com.android.internal.R;
-import com.android.internal.util.ScreenShapeHelper;
 import com.android.internal.view.FloatingActionMode;
 import com.android.internal.view.RootViewSurfaceTaker;
 import com.android.internal.view.StandaloneActionMode;
@@ -156,7 +155,6 @@
     TypedValue mFixedWidthMinor;
     TypedValue mFixedHeightMajor;
     TypedValue mFixedHeightMinor;
-    int mOutsetBottomPx;
 
     // This is the top-level view of the window, containing the window decor.
     private DecorView mDecor;
@@ -289,6 +287,7 @@
     private Boolean mSharedElementsUseOverlay;
 
     private Rect mTempRect;
+    private Rect mOutsets = new Rect();
 
     static class WindowManagerHolder {
         static final IWindowManager sWindowManager = IWindowManager.Stub.asInterface(
@@ -2401,19 +2400,6 @@
         }
 
         @Override
-        public WindowInsets dispatchApplyWindowInsets(WindowInsets insets) {
-            if (mOutsetBottomPx != 0) {
-                WindowInsets newInsets = insets.replaceSystemWindowInsets(
-                        insets.getSystemWindowInsetLeft(), insets.getSystemWindowInsetTop(),
-                        insets.getSystemWindowInsetRight(), mOutsetBottomPx);
-                return super.dispatchApplyWindowInsets(newInsets);
-            } else {
-                return super.dispatchApplyWindowInsets(insets);
-            }
-        }
-
-
-        @Override
         public boolean onTouchEvent(MotionEvent event) {
             return onInterceptTouchEvent(event);
         }
@@ -2624,11 +2610,21 @@
                 }
             }
 
-            if (mOutsetBottomPx != 0) {
+            getOutsets(mOutsets);
+            if (mOutsets.top > 0 || mOutsets.bottom > 0) {
                 int mode = MeasureSpec.getMode(heightMeasureSpec);
                 if (mode != MeasureSpec.UNSPECIFIED) {
                     int height = MeasureSpec.getSize(heightMeasureSpec);
-                    heightMeasureSpec = MeasureSpec.makeMeasureSpec(height + mOutsetBottomPx, mode);
+                    heightMeasureSpec = MeasureSpec.makeMeasureSpec(
+                            height + mOutsets.top + mOutsets.bottom, mode);
+                }
+            }
+            if (mOutsets.left > 0 || mOutsets.right > 0) {
+                int mode = MeasureSpec.getMode(widthMeasureSpec);
+                if (mode != MeasureSpec.UNSPECIFIED) {
+                    int width = MeasureSpec.getSize(widthMeasureSpec);
+                    widthMeasureSpec = MeasureSpec.makeMeasureSpec(
+                            width + mOutsets.left + mOutsets.right, mode);
                 }
             }
 
@@ -2666,6 +2662,18 @@
         }
 
         @Override
+        protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+            super.onLayout(changed, left, top, right, bottom);
+            getOutsets(mOutsets);
+            if (mOutsets.left > 0) {
+                offsetLeftAndRight(-mOutsets.left);
+            }
+            if (mOutsets.top > 0) {
+                offsetTopAndBottom(-mOutsets.top);
+            }
+        }
+
+        @Override
         public void draw(Canvas canvas) {
             super.draw(canvas);
 
@@ -2674,7 +2682,6 @@
             }
         }
 
-
         @Override
         public boolean showContextMenuForChild(View originalView) {
             // Reuse the context menu builder
@@ -3583,19 +3590,6 @@
             requestFeature(FEATURE_ACTIVITY_TRANSITIONS);
         }
 
-        final WindowManager windowService = (WindowManager) getContext().getSystemService(
-                Context.WINDOW_SERVICE);
-        if (windowService != null) {
-            final Display display = windowService.getDefaultDisplay();
-            final boolean shouldUseBottomOutset =
-                    display.getDisplayId() == Display.DEFAULT_DISPLAY
-                            || (getForcedWindowFlags() & FLAG_FULLSCREEN) != 0;
-            if (shouldUseBottomOutset) {
-                mOutsetBottomPx = ScreenShapeHelper.getWindowOutsetBottomPx(
-                        getContext().getResources().getDisplayMetrics(), a);
-            }
-        }
-
         final Context context = getContext();
         final int targetSdk = context.getApplicationInfo().targetSdkVersion;
         final boolean targetPreHoneycomb = targetSdk < android.os.Build.VERSION_CODES.HONEYCOMB;
diff --git a/core/java/com/android/internal/util/ScreenShapeHelper.java b/core/java/com/android/internal/util/ScreenShapeHelper.java
index 58ae853..4a196f8 100644
--- a/core/java/com/android/internal/util/ScreenShapeHelper.java
+++ b/core/java/com/android/internal/util/ScreenShapeHelper.java
@@ -18,19 +18,13 @@
 
     /**
      * Return the bottom pixel window outset of a window given its style attributes.
-     * @param displayMetrics Display metrics of the current device
-     * @param windowStyle Window style attributes for the window.
      * @return An outset dimension in pixels or 0 if no outset should be applied.
      */
-    public static int getWindowOutsetBottomPx(DisplayMetrics displayMetrics,
-            TypedArray windowStyle) {
+    public static int getWindowOutsetBottomPx(Resources resources) {
         if (IS_EMULATOR) {
             return SystemProperties.getInt(ViewRootImpl.PROPERTY_EMULATOR_WIN_OUTSET_BOTTOM_PX, 0);
-        } else if (windowStyle.hasValue(R.styleable.Window_windowOutsetBottom)) {
-            TypedValue outsetBottom = new TypedValue();
-            windowStyle.getValue(R.styleable.Window_windowOutsetBottom, outsetBottom);
-            return (int) outsetBottom.getDimension(displayMetrics);
+        } else {
+            return resources.getInteger(com.android.internal.R.integer.config_windowOutsetBottom);
         }
-        return 0;
     }
 }
diff --git a/core/java/com/android/internal/view/BaseIWindow.java b/core/java/com/android/internal/view/BaseIWindow.java
index e27ba13..3eeabcd 100644
--- a/core/java/com/android/internal/view/BaseIWindow.java
+++ b/core/java/com/android/internal/view/BaseIWindow.java
@@ -34,8 +34,8 @@
     }
 
     @Override
-    public void resized(Rect frame, Rect overscanInsets, Rect contentInsets,
-            Rect visibleInsets, Rect stableInsets, boolean reportDraw, Configuration newConfig) {
+    public void resized(Rect frame, Rect overscanInsets, Rect contentInsets, Rect visibleInsets,
+            Rect stableInsets, Rect outsets, boolean reportDraw, Configuration newConfig) {
         if (reportDraw) {
             try {
                 mSession.finishDrawing(this);
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index c715652..8066d9f 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1861,6 +1861,11 @@
     <!-- default window inset isRound property -->
     <bool name="config_windowIsRound">false</bool>
 
+    <!-- Override this value if the device has a chin, i.e. area that is not actual part of the
+         screen but you would like to be treated as a real display. The value is the height of the
+         chin. -->
+    <integer name="config_windowOutsetBottom">0</integer>
+
     <!-- Package name for default network scorer app; overridden by product overlays. -->
     <string name="config_defaultNetworkScorerPackageName"></string>
 
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index ff3801f..93fcb2f 100755
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -383,6 +383,7 @@
   <java-symbol type="integer" name="config_wifi_supplicant_scan_interval" />
   <java-symbol type="integer" name="config_wifi_scan_interval_p2p_connected" />
   <java-symbol type="bool" name="config_wifi_hal_pno_enable" />
+  <java-symbol type="integer" name="config_windowOutsetBottom" />
   <java-symbol type="integer" name="db_connection_pool_size" />
   <java-symbol type="integer" name="db_journal_size_limit" />
   <java-symbol type="integer" name="db_wal_autocheckpoint" />
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index a1e1aef..7d383fa 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -108,6 +108,7 @@
 import android.view.animation.AnimationUtils;
 import com.android.internal.R;
 import com.android.internal.statusbar.IStatusBarService;
+import com.android.internal.util.ScreenShapeHelper;
 import com.android.internal.widget.PointerLocationView;
 import com.android.server.LocalServices;
 import com.android.server.policy.keyguard.KeyguardServiceDelegate;
@@ -472,6 +473,7 @@
     static final Rect mTmpDecorFrame = new Rect();
     static final Rect mTmpStableFrame = new Rect();
     static final Rect mTmpNavigationFrame = new Rect();
+    static final Rect mTmpOutsetFrame = new Rect();
 
     WindowState mTopFullscreenOpaqueWindowState;
     WindowState mTopFullscreenOpaqueOrDimmingWindowState;
@@ -3363,6 +3365,7 @@
         final Rect of = mTmpOverscanFrame;
         final Rect vf = mTmpVisibleFrame;
         final Rect dcf = mTmpDecorFrame;
+        final Rect osf = mTmpOutsetFrame;
         pf.left = df.left = of.left = vf.left = mDockLeft;
         pf.top = df.top = of.top = vf.top = mDockTop;
         pf.right = df.right = of.right = vf.right = mDockRight;
@@ -3472,7 +3475,7 @@
                 // And compute the final frame.
                 mNavigationBar.computeFrameLw(mTmpNavigationFrame, mTmpNavigationFrame,
                         mTmpNavigationFrame, mTmpNavigationFrame, mTmpNavigationFrame, dcf,
-                        mTmpNavigationFrame);
+                        mTmpNavigationFrame, mTmpNavigationFrame);
                 if (DEBUG_LAYOUT) Slog.i(TAG, "mNavigationBar frame: " + mTmpNavigationFrame);
                 if (mNavigationBarController.checkHiddenLw()) {
                     updateSysUiVisibility = true;
@@ -3497,7 +3500,9 @@
                 mStatusBarLayer = mStatusBar.getSurfaceLayer();
 
                 // Let the status bar determine its size.
-                mStatusBar.computeFrameLw(pf, df, vf, vf, vf, dcf, vf);
+                mStatusBar.computeFrameLw(pf /* parentFrame */, df /* displayFrame */,
+                        vf /* overlayFrame */, vf /* contentFrame */, vf /* visibleFrame */,
+                        dcf /* decorFrame */, vf /* stableFrame */, vf /* outsetFrame */);
 
                 // For layout, the status bar is always at the top with our fixed height.
                 mStableTop = mUnrestrictedScreenTop + mStatusBarHeight;
@@ -3680,6 +3685,7 @@
         final Rect vf = mTmpVisibleFrame;
         final Rect dcf = mTmpDecorFrame;
         final Rect sf = mTmpStableFrame;
+        Rect osf = null;
         dcf.setEmpty();
 
         final boolean hasNavBar = (isDefaultDisplay && mHasNavigationBar
@@ -4073,6 +4079,32 @@
             }
         }
 
+        // If the device has a chin (e.g. some watches), a dead area at the bottom of the screen we
+        // need to provide information to the clients that want to pretend that you can draw there.
+        if (isDefaultDisplay && (fl & WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0) {
+            osf = mTmpOutsetFrame;
+            osf.set(cf.left, cf.top, cf.right, cf.bottom);
+            int outset = ScreenShapeHelper.getWindowOutsetBottomPx(mContext.getResources());
+            if (outset > 0) {
+                int rotation = Surface.ROTATION_0;
+                try {
+                    rotation = mWindowManager.getRotation();
+                } catch (RemoteException e) {
+                }
+                if (rotation == Surface.ROTATION_0) {
+                    osf.bottom += outset;
+                } else if (rotation == Surface.ROTATION_90) {
+                    osf.right += outset;
+                } else if (rotation == Surface.ROTATION_180) {
+                    osf.top -= outset;
+                } else if (rotation == Surface.ROTATION_270) {
+                    osf.left -= outset;
+                }
+                if (DEBUG_LAYOUT) Slog.v(TAG, "applying bottom outset of " + outset
+                        + " with rotation " + rotation + ", result: " + osf);
+            }
+        }
+
         if (DEBUG_LAYOUT) Slog.v(TAG, "Compute frame " + attrs.getTitle()
                 + ": sim=#" + Integer.toHexString(sim)
                 + " attach=" + attached + " type=" + attrs.type
@@ -4081,9 +4113,10 @@
                 + " of=" + of.toShortString()
                 + " cf=" + cf.toShortString() + " vf=" + vf.toShortString()
                 + " dcf=" + dcf.toShortString()
-                + " sf=" + sf.toShortString());
+                + " sf=" + sf.toShortString()
+                + " osf=" + (osf == null ? "null" : osf.toShortString()));
 
-        win.computeFrameLw(pf, df, of, cf, vf, dcf, sf);
+        win.computeFrameLw(pf, df, of, cf, vf, dcf, sf, osf);
 
         // Dock windows carve out the bottom of the screen, so normal windows
         // can't appear underneath them.
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index 487483e9..e9c5ac7 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -190,14 +190,15 @@
     public int relayout(IWindow window, int seq, WindowManager.LayoutParams attrs,
             int requestedWidth, int requestedHeight, int viewFlags,
             int flags, Rect outFrame, Rect outOverscanInsets, Rect outContentInsets,
-            Rect outVisibleInsets, Rect outStableInsets, Configuration outConfig,
+            Rect outVisibleInsets, Rect outStableInsets, Rect outsets, Configuration
+                    outConfig,
             Surface outSurface) {
         if (false) Slog.d(WindowManagerService.TAG, ">>>>>> ENTERED relayout from "
                 + Binder.getCallingPid());
         int res = mService.relayoutWindow(this, window, seq, attrs,
                 requestedWidth, requestedHeight, viewFlags, flags,
                 outFrame, outOverscanInsets, outContentInsets, outVisibleInsets,
-                outStableInsets, outConfig, outSurface);
+                outStableInsets, outsets, outConfig, outSurface);
         if (false) Slog.d(WindowManagerService.TAG, "<<<<<< EXITING relayout to "
                 + Binder.getCallingPid());
         return res;
@@ -522,4 +523,4 @@
     public String toString() {
         return mStringName;
     }
-}
\ No newline at end of file
+}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 6042c27..7671293 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -3052,7 +3052,7 @@
             WindowManager.LayoutParams attrs, int requestedWidth,
             int requestedHeight, int viewVisibility, int flags,
             Rect outFrame, Rect outOverscanInsets, Rect outContentInsets,
-            Rect outVisibleInsets, Rect outStableInsets, Configuration outConfig,
+            Rect outVisibleInsets, Rect outStableInsets, Rect outOutsets, Configuration outConfig,
             Surface outSurface) {
         boolean toBeDisplayed = false;
         boolean inTouchMode;
@@ -3340,6 +3340,7 @@
             outContentInsets.set(win.mContentInsets);
             outVisibleInsets.set(win.mVisibleInsets);
             outStableInsets.set(win.mStableInsets);
+            outOutsets.set(win.mOutsets);
             if (localLOGV) Slog.v(
                 TAG, "Relayout given client " + client.asBinder()
                 + ", requestedWidth=" + requestedWidth
@@ -9613,6 +9614,7 @@
                 w.mLastContentInsets.set(w.mContentInsets);
                 w.mLastVisibleInsets.set(w.mVisibleInsets);
                 w.mLastStableInsets.set(w.mStableInsets);
+                w.mLastOutsets.set(w.mOutsets);
                 makeWindowFreezingScreenIfNeededLocked(w);
                 // If the orientation is changing, then we need to
                 // hold off on unfreezing the display until this
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 193d812..b8b243c 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -180,6 +180,14 @@
     boolean mStableInsetsChanged;
 
     /**
+     * Outsets determine the area outside of the surface where we want to pretend that it's possible
+     * to draw anyway.
+     */
+    final Rect mOutsets = new Rect();
+    final Rect mLastOutsets = new Rect();
+    boolean mOutsetsChanged = false;
+
+    /**
      * Set to true if we are waiting for this window to receive its
      * given internal insets before laying out other windows based on it.
      */
@@ -261,6 +269,10 @@
     // displays hint text.
     final Rect mVisibleFrame = new Rect();
 
+    // Frame that includes dead area outside of the surface but where we want to pretend that it's
+    // possible to draw.
+    final Rect mOutsetFrame = new Rect();
+
     boolean mContentChanged;
 
     // If a window showing a wallpaper: the requested offset for the
@@ -519,7 +531,8 @@
     }
 
     @Override
-    public void computeFrameLw(Rect pf, Rect df, Rect of, Rect cf, Rect vf, Rect dcf, Rect sf) {
+    public void computeFrameLw(Rect pf, Rect df, Rect of, Rect cf, Rect vf, Rect dcf, Rect sf,
+            Rect osf) {
         mHaveFrame = true;
 
         final TaskStack stack = mAppToken != null ? getStack() : null;
@@ -594,6 +607,10 @@
         mVisibleFrame.set(vf);
         mDecorFrame.set(dcf);
         mStableFrame.set(sf);
+        final boolean hasOutsets = osf != null;
+        if (hasOutsets) {
+            mOutsetFrame.set(osf);
+        }
 
         final int fw = mFrame.width();
         final int fh = mFrame.height();
@@ -658,6 +675,16 @@
                 Math.max(mFrame.right - mStableFrame.right, 0),
                 Math.max(mFrame.bottom - mStableFrame.bottom, 0));
 
+        if (hasOutsets) {
+            // We need to calculate outsets
+            mOutsets.set(Math.max(mContentFrame.left - mOutsetFrame.left, 0),
+                    Math.max(mContentFrame.top - mOutsetFrame.top, 0),
+                    Math.max(mOutsetFrame.right - mContentFrame.right, 0),
+                    Math.max(mOutsetFrame.bottom - mContentFrame.bottom, 0));
+        } else {
+            mOutsets.set(0, 0, 0, 0);
+        }
+
         mCompatFrame.set(mFrame);
         if (mEnforceSizeCompat) {
             // If there is a size compatibility scale being applied to the
@@ -667,6 +694,7 @@
             mContentInsets.scale(mInvGlobalScale);
             mVisibleInsets.scale(mInvGlobalScale);
             mStableInsets.scale(mInvGlobalScale);
+            mOutsets.scale(mInvGlobalScale);
 
             // Also the scaled frame that we report to the app needs to be
             // adjusted to be in its coordinate space.
@@ -689,7 +717,8 @@
                 + "): frame=" + mFrame.toShortString()
                 + " ci=" + mContentInsets.toShortString()
                 + " vi=" + mVisibleInsets.toShortString()
-                + " vi=" + mStableInsets.toShortString());
+                + " vi=" + mStableInsets.toShortString()
+                + " of=" + mOutsets.toShortString());
     }
 
     @Override
@@ -804,7 +833,9 @@
         mContentInsetsChanged |= !mLastContentInsets.equals(mContentInsets);
         mVisibleInsetsChanged |= !mLastVisibleInsets.equals(mVisibleInsets);
         mStableInsetsChanged |= !mLastStableInsets.equals(mStableInsets);
-        return mOverscanInsetsChanged || mContentInsetsChanged || mVisibleInsetsChanged;
+        mOutsetsChanged |= !mLastOutsets.equals(mOutsets);
+        return mOverscanInsetsChanged || mContentInsetsChanged || mVisibleInsetsChanged
+                || mOutsetsChanged;
     }
 
     public DisplayContent getDisplayContent() {
@@ -1472,6 +1503,7 @@
             final Rect contentInsets = mLastContentInsets;
             final Rect visibleInsets = mLastVisibleInsets;
             final Rect stableInsets = mLastStableInsets;
+            final Rect outsets = mLastOutsets;
             final boolean reportDraw = mWinAnimator.mDrawState == WindowStateAnimator.DRAW_PENDING;
             final Configuration newConfig = configChanged ? mConfiguration : null;
             if (mAttrs.type != WindowManager.LayoutParams.TYPE_APPLICATION_STARTING
@@ -1482,7 +1514,7 @@
                     public void run() {
                         try {
                             mClient.resized(frame, overscanInsets, contentInsets,
-                                    visibleInsets, stableInsets,  reportDraw, newConfig);
+                                    visibleInsets, stableInsets, outsets, reportDraw, newConfig);
                         } catch (RemoteException e) {
                             // Not a remote call, RemoteException won't be raised.
                         }
@@ -1490,7 +1522,7 @@
                 });
             } else {
                 mClient.resized(frame, overscanInsets, contentInsets, visibleInsets, stableInsets,
-                        reportDraw, newConfig);
+                        outsets, reportDraw, newConfig);
             }
 
             //TODO (multidisplay): Accessibility supported only for the default display.
@@ -1503,6 +1535,7 @@
             mContentInsetsChanged = false;
             mVisibleInsetsChanged = false;
             mStableInsetsChanged = false;
+            mOutsetsChanged = false;
             mWinAnimator.mSurfaceResized = false;
         } catch (RemoteException e) {
             mOrientationChanging = false;
@@ -1664,17 +1697,22 @@
                     pw.println();
             pw.print(prefix); pw.print("    decor="); mDecorFrame.printShortString(pw);
                     pw.println();
+            pw.print(prefix); pw.print("    outset="); mOutsetFrame.printShortString(pw);
+                    pw.println();
             pw.print(prefix); pw.print("Cur insets: overscan=");
                     mOverscanInsets.printShortString(pw);
                     pw.print(" content="); mContentInsets.printShortString(pw);
                     pw.print(" visible="); mVisibleInsets.printShortString(pw);
                     pw.print(" stable="); mStableInsets.printShortString(pw);
+                    pw.print(" outsets="); mOutsets.printShortString(pw);
                     pw.println();
             pw.print(prefix); pw.print("Lst insets: overscan=");
                     mLastOverscanInsets.printShortString(pw);
                     pw.print(" content="); mLastContentInsets.printShortString(pw);
                     pw.print(" visible="); mLastVisibleInsets.printShortString(pw);
                     pw.print(" stable="); mLastStableInsets.printShortString(pw);
+                    pw.print(" physical="); mLastOutsets.printShortString(pw);
+                    pw.print(" outset="); mLastOutsets.printShortString(pw);
                     pw.println();
         }
         pw.print(prefix); pw.print(mWinAnimator); pw.println(":");
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java
index 66092fc..771c3c8 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java
@@ -47,8 +47,8 @@
     }
 
     @Override
-    public void resized(Rect rect, Rect rect2, Rect rect3, Rect rect4, Rect rect5, boolean b,
-            Configuration configuration) throws RemoteException {
+    public void resized(Rect rect, Rect rect2, Rect rect3, Rect rect4, Rect rect5, Rect rect6,
+            boolean b, Configuration configuration) throws RemoteException {
         // pass for now.
     }