am 0eeb3bb8: am 33aa55b1: am 127d0b80: Merge "Revert "Revert "During early boot, send LOCALE_CHANGED only to registered receivers""" into lmp-mr1-dev

* commit '0eeb3bb8eb211af642b25bc494931bcc47786be7':
  Revert "Revert "During early boot, send LOCALE_CHANGED only to registered receivers""
diff --git a/core/java/android/app/ActivityView.java b/core/java/android/app/ActivityView.java
index a7864f4..3018fe2 100644
--- a/core/java/android/app/ActivityView.java
+++ b/core/java/android/app/ActivityView.java
@@ -24,7 +24,10 @@
 import android.content.Intent;
 import android.content.IntentSender;
 import android.graphics.SurfaceTexture;
+import android.os.Handler;
+import android.os.HandlerThread;
 import android.os.IBinder;
+import android.os.Message;
 import android.os.OperationCanceledException;
 import android.os.RemoteException;
 import android.util.AttributeSet;
@@ -48,7 +51,9 @@
     private static final String TAG = "ActivityView";
     private static final boolean DEBUG = false;
 
-    DisplayMetrics mMetrics;
+    private static final int MSG_SET_SURFACE = 1;
+
+    DisplayMetrics mMetrics = new DisplayMetrics();
     private final TextureView mTextureView;
     private ActivityContainerWrapper mActivityContainer;
     private Activity mActivity;
@@ -58,6 +63,9 @@
     private int mLastVisibility;
     private ActivityViewCallback mActivityViewCallback;
 
+    private HandlerThread mThread = new HandlerThread("ActivityViewThread");
+    private Handler mHandler;
+
     public ActivityView(Context context) {
         this(context, null);
     }
@@ -89,12 +97,27 @@
                     + e);
         }
 
+        mThread.start();
+        mHandler = new Handler(mThread.getLooper()) {
+            @Override
+            public void handleMessage(Message msg) {
+                super.handleMessage(msg);
+                if (msg.what == MSG_SET_SURFACE) {
+                    try {
+                        mActivityContainer.setSurface((Surface) msg.obj, msg.arg1, msg.arg2,
+                                mMetrics.densityDpi);
+                    } catch (RemoteException e) {
+                        throw new RuntimeException(
+                                "ActivityView: Unable to set surface of ActivityContainer. " + e);
+                    }
+                }
+            }
+        };
         mTextureView = new TextureView(context);
         mTextureView.setSurfaceTextureListener(new ActivityViewSurfaceTextureListener());
         addView(mTextureView);
 
         WindowManager wm = (WindowManager)mActivity.getSystemService(Context.WINDOW_SERVICE);
-        mMetrics = new DisplayMetrics();
         wm.getDefaultDisplay().getMetrics(mMetrics);
 
         mLastVisibility = getVisibility();
@@ -111,18 +134,12 @@
     protected void onVisibilityChanged(View changedView, int visibility) {
         super.onVisibilityChanged(changedView, visibility);
 
-        if (mSurface != null) {
-            try {
-                if (visibility == View.GONE) {
-                    mActivityContainer.setSurface(null, mWidth, mHeight, mMetrics.densityDpi);
-                } else if (mLastVisibility == View.GONE) {
-                    // Don't change surface when going between View.VISIBLE and View.INVISIBLE.
-                    mActivityContainer.setSurface(mSurface, mWidth, mHeight, mMetrics.densityDpi);
-                }
-            } catch (RemoteException e) {
-                throw new RuntimeException(
-                        "ActivityView: Unable to set surface of ActivityContainer. " + e);
-            }
+        if (mSurface != null && (visibility == View.GONE || mLastVisibility == View.GONE)) {
+            Message msg = Message.obtain(mHandler, MSG_SET_SURFACE);
+            msg.obj = (visibility == View.GONE) ? null : mSurface;
+            msg.arg1 = mWidth;
+            msg.arg2 = mHeight;
+            mHandler.sendMessage(msg);
         }
         mLastVisibility = visibility;
     }
diff --git a/core/java/android/database/DatabaseUtils.java b/core/java/android/database/DatabaseUtils.java
index c125544..c23e7b2 100644
--- a/core/java/android/database/DatabaseUtils.java
+++ b/core/java/android/database/DatabaseUtils.java
@@ -272,7 +272,7 @@
         window.setStartPosition(position);
         window.setNumColumns(numColumns);
         if (cursor.moveToPosition(position)) {
-            do {
+            rowloop: do {
                 if (!window.allocRow()) {
                     break;
                 }
@@ -309,7 +309,7 @@
                     }
                     if (!success) {
                         window.freeLastRow();
-                        break;
+                        break rowloop;
                     }
                 }
                 position += 1;
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index 016541f..5420cad 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();
@@ -270,7 +271,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);
@@ -661,30 +662,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;
@@ -708,9 +714,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();
@@ -770,13 +781,20 @@
 
                         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, mWindowIsRound);
+                            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 9fc80fc..b738ba0 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 63e1a85..ed60985 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 3c05872..aeb4ac6e 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -6667,6 +6667,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}.
@@ -20312,6 +20321,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 113ad8d..a182ef1 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -261,6 +261,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();
 
@@ -1222,8 +1223,14 @@
     void dispatchApplyInsets(View host) {
         mDispatchContentInsets.set(mAttachInfo.mContentInsets);
         mDispatchStableInsets.set(mAttachInfo.mStableInsets);
-        host.dispatchApplyWindowInsets(new WindowInsets(
-                mDispatchContentInsets, null /* windowDecorInsets */,
+        Rect outsets = mAttachInfo.mOutsets;
+        Rect contentInsets = mDispatchContentInsets;
+        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);
+        }
+        host.dispatchApplyWindowInsets(new WindowInsets(contentInsets, null /* windowDecorInsets */,
                 mDispatchStableInsets, mWindowIsRound));
     }
 
@@ -1369,6 +1376,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;
@@ -1545,6 +1555,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)
@@ -1628,9 +1639,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);
                 }
@@ -3201,6 +3214,7 @@
                         && mPendingContentInsets.equals(args.arg2)
                         && mPendingStableInsets.equals(args.arg6)
                         && mPendingVisibleInsets.equals(args.arg3)
+                        && mPendingOutsets.equals(args.arg7)
                         && args.arg4 == null) {
                     break;
                 }
@@ -3219,6 +3233,7 @@
                     mPendingContentInsets.set((Rect) args.arg2);
                     mPendingStableInsets.set((Rect) args.arg6);
                     mPendingVisibleInsets.set((Rect) args.arg3);
+                    mPendingOutsets.set((Rect) args.arg7);
 
                     args.recycle();
 
@@ -5317,7 +5332,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();
@@ -5593,7 +5608,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()
@@ -5613,6 +5629,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);
     }
@@ -6492,12 +6509,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 780ca99..71cb889 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/util/ScreenShapeHelper.java b/core/java/com/android/internal/util/ScreenShapeHelper.java
index 1bcc7a0..e06bec5 100644
--- a/core/java/com/android/internal/util/ScreenShapeHelper.java
+++ b/core/java/com/android/internal/util/ScreenShapeHelper.java
@@ -18,20 +18,14 @@
 
     /**
      * 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;
     }
 
     /**
@@ -41,8 +35,7 @@
         if (IS_EMULATOR) {
             return SystemProperties.getBoolean(ViewRootImpl.PROPERTY_EMULATOR_CIRCULAR, false);
         } else {
-            return resources.getBoolean(
-                    com.android.internal.R.bool.config_windowIsRound);
+            return resources.getBoolean(com.android.internal.R.bool.config_windowIsRound);
         }
     }
 }
diff --git a/core/java/com/android/internal/view/BaseIWindow.java b/core/java/com/android/internal/view/BaseIWindow.java
index 993ab58..b55aabb 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/java/com/android/internal/widget/SwipeDismissLayout.java b/core/java/com/android/internal/widget/SwipeDismissLayout.java
index 6d4e058..35ed63b 100644
--- a/core/java/com/android/internal/widget/SwipeDismissLayout.java
+++ b/core/java/com/android/internal/widget/SwipeDismissLayout.java
@@ -16,9 +16,11 @@
 
 package com.android.internal.widget;
 
-import android.animation.TimeInterpolator;
 import android.app.Activity;
+import android.content.BroadcastReceiver;
 import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.res.TypedArray;
 import android.util.AttributeSet;
 import android.util.Log;
@@ -28,8 +30,6 @@
 import android.view.ViewConfiguration;
 import android.view.ViewGroup;
 import android.view.ViewTreeObserver;
-import android.view.animation.AccelerateInterpolator;
-import android.view.animation.DecelerateInterpolator;
 import android.widget.FrameLayout;
 
 /**
@@ -62,10 +62,6 @@
     // Cached ViewConfiguration and system-wide constant values
     private int mSlop;
     private int mMinFlingVelocity;
-    private int mMaxFlingVelocity;
-    private long mAnimationTime;
-    private TimeInterpolator mCancelInterpolator;
-    private TimeInterpolator mDismissInterpolator;
 
     // Transient properties
     private int mActiveTouchId;
@@ -92,6 +88,18 @@
                     }
                 }
             };
+    private BroadcastReceiver mScreenOffReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (mDismissed) {
+                dismiss();
+            } else {
+                cancel();
+            }
+            resetMembers();
+        }
+    };
+    private IntentFilter mScreenOffFilter = new IntentFilter(Intent.ACTION_SCREEN_OFF);
 
     private float mLastX;
 
@@ -114,11 +122,6 @@
         ViewConfiguration vc = ViewConfiguration.get(context);
         mSlop = vc.getScaledTouchSlop();
         mMinFlingVelocity = vc.getScaledMinimumFlingVelocity();
-        mMaxFlingVelocity = vc.getScaledMaximumFlingVelocity();
-        mAnimationTime = getContext().getResources().getInteger(
-                android.R.integer.config_shortAnimTime);
-        mCancelInterpolator = new DecelerateInterpolator(1.5f);
-        mDismissInterpolator = new AccelerateInterpolator(1.5f);
         TypedArray a = context.getTheme().obtainStyledAttributes(
                 com.android.internal.R.styleable.Theme);
         mUseDynamicTranslucency = !a.hasValue(
@@ -141,15 +144,17 @@
             getViewTreeObserver().addOnEnterAnimationCompleteListener(
                     mOnEnterAnimationCompleteListener);
         }
+        getContext().registerReceiver(mScreenOffReceiver, mScreenOffFilter);
     }
 
     @Override
     protected void onDetachedFromWindow() {
-        super.onDetachedFromWindow();
+        getContext().unregisterReceiver(mScreenOffReceiver);
         if (getContext() instanceof Activity) {
             getViewTreeObserver().removeOnEnterAnimationCompleteListener(
                     mOnEnterAnimationCompleteListener);
         }
+        super.onDetachedFromWindow();
     }
 
     @Override
diff --git a/core/jni/android/graphics/Region.cpp b/core/jni/android/graphics/Region.cpp
index 6b99de8..912968a 100644
--- a/core/jni/android/graphics/Region.cpp
+++ b/core/jni/android/graphics/Region.cpp
@@ -212,13 +212,9 @@
 
     android::Parcel* p = android::parcelForJavaObject(env, parcel);
 
-    const size_t size = p->readInt32();
-    const void* regionData = p->readInplace(size);
-    if (regionData == NULL) {
-        return NULL;
-    }
     SkRegion* region = new SkRegion;
-    region->readFromMemory(regionData, size);
+    size_t size = p->readInt32();
+    region->readFromMemory(p->readInplace(size), size);
 
     return reinterpret_cast<jlong>(region);
 }
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index f923d50..251e3af 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1826,6 +1826,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>
 
@@ -2100,6 +2105,10 @@
     <!-- Keyguard component -->
     <string name="config_keyguardComponent" translatable="false">com.android.systemui/com.android.systemui.keyguard.KeyguardService</string>
 
+    <!-- This config is used to force VoiceInteractionService to start on certain low ram devices.
+         It declares the package name of VoiceInteractionService that should be started. -->
+    <string translatable="false" name="config_forceVoiceInteractionServicePackage"></string>
+
     <!-- This config is ued to determine whether animations are allowed in low power mode. -->
     <bool name="config_allowAnimationsInLowPowerMode">false</bool>
 </resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index f0e56e7..3049544 100755
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -374,6 +374,7 @@
   <java-symbol type="integer" name="config_wifi_supplicant_scan_interval" />
   <java-symbol type="integer" name="config_wifi_disconnected_scan_interval" />
   <java-symbol type="integer" name="config_wifi_scan_interval_p2p_connected" />
+  <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" />
@@ -552,6 +553,7 @@
   <java-symbol type="string" name="chooseActivity" />
   <java-symbol type="string" name="config_default_dns_server" />
   <java-symbol type="string" name="config_ethernet_iface_regex" />
+  <java-symbol type="string" name="config_forceVoiceInteractionServicePackage" />
   <java-symbol type="string" name="config_mms_user_agent" />
   <java-symbol type="string" name="config_mms_user_agent_profile_url" />
   <java-symbol type="string" name="config_ntpServer" />
diff --git a/core/res/res/values/themes_micro.xml b/core/res/res/values/themes_micro.xml
index 112afa6..8bf635e 100644
--- a/core/res/res/values/themes_micro.xml
+++ b/core/res/res/values/themes_micro.xml
@@ -14,7 +14,7 @@
      limitations under the License.
 -->
 <resources>
-    <style name="Theme.Micro" parent="Theme.Material.NoActionBar">
+    <style name="Theme.MicroBase" parent="Theme.Material.NoActionBar">
         <item name="alertDialogTheme">@style/Theme.Micro.Dialog.Alert</item>
         <item name="alertDialogStyle">@style/AlertDialog.Micro</item>
         <item name="dialogTheme">@style/Theme.Micro.Dialog</item>
@@ -29,7 +29,10 @@
         <item name="windowOverscan">true</item>
     </style>
 
-    <style name="Theme.Micro.Light" parent="Theme.Material.Light.NoActionBar">
+    <style name="Theme.Micro" parent="Theme.MicroBase">
+    </style>
+
+    <style name="Theme.Micro.LightBase" parent="Theme.Material.Light.NoActionBar">
         <item name="alertDialogTheme">@style/Theme.Micro.Dialog.Alert</item>
         <item name="alertDialogStyle">@style/AlertDialog.Micro</item>
         <item name="dialogTheme">@style/Theme.Micro.Dialog</item>
@@ -44,7 +47,11 @@
         <item name="windowOverscan">true</item>
     </style>
 
-    <style name="Theme.Micro.Dialog" parent="Theme.Material.Light.Dialog">
+    <!-- Indirection needed for overlays to make sure there is a common base parent -->
+    <style name="Theme.Micro.Light" parent="Theme.Micro.LightBase">
+    </style>
+
+    <style name="Theme.Micro.DialogBase" parent="Theme.Material.Light.Dialog">
         <item name="windowTitleStyle">@android:style/DialogWindowTitle.Micro</item>
         <item name="windowIsFloating">false</item>
         <item name="windowFullscreen">true</item>
@@ -54,6 +61,10 @@
         <item name="windowOverscan">true</item>
     </style>
 
+    <!-- Indirection needed for overlays to make sure there is a common base parent -->
+    <style name="Theme.Micro.Dialog" parent="Theme.Micro.DialogBase">
+    </style>
+
     <style name="Theme.Micro.Dialog.Alert">
         <item name="windowTitleStyle">@style/DialogWindowTitle.Micro</item>
         <item name="alertDialogStyle">@style/AlertDialog.Micro</item>
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index c9028c4..09766e4 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -25,7 +25,6 @@
 import android.app.SearchManager;
 import android.os.UserHandle;
 import com.android.internal.R;
-import com.android.internal.util.ScreenShapeHelper;
 import com.android.internal.view.RootViewSurfaceTaker;
 import com.android.internal.view.StandaloneActionMode;
 import com.android.internal.view.menu.ContextMenuBuilder;
@@ -62,7 +61,6 @@
 import android.os.Parcelable;
 import android.os.RemoteException;
 import android.os.ServiceManager;
-import android.os.SystemProperties;
 import android.transition.Scene;
 import android.transition.Transition;
 import android.transition.TransitionInflater;
@@ -76,7 +74,6 @@
 import android.util.TypedValue;
 import android.view.ActionMode;
 import android.view.ContextThemeWrapper;
-import android.view.Display;
 import android.view.Gravity;
 import android.view.IRotationWatcher;
 import android.view.IWindowManager;
@@ -280,6 +277,7 @@
     private Boolean mSharedElementsUseOverlay;
 
     private Rect mTempRect;
+    private Rect mOutsets = new Rect();
 
     static class WindowManagerHolder {
         static final IWindowManager sWindowManager = IWindowManager.Stub.asInterface(
@@ -2380,19 +2378,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);
         }
@@ -2603,11 +2588,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);
                 }
             }
 
@@ -2645,6 +2640,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);
 
@@ -3433,19 +3440,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/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index a509706..37e1109 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -109,6 +109,7 @@
 import com.android.internal.policy.impl.keyguard.KeyguardServiceDelegate;
 import com.android.internal.policy.impl.keyguard.KeyguardServiceDelegate.ShowListener;
 import com.android.internal.statusbar.IStatusBarService;
+import com.android.internal.util.ScreenShapeHelper;
 import com.android.internal.widget.PointerLocationView;
 import com.android.server.LocalServices;
 
@@ -459,6 +460,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;
     HashSet<IApplicationToken> mAppsToBeHidden = new HashSet<IApplicationToken>();
@@ -3328,6 +3330,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;
@@ -3439,7 +3442,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;
@@ -3464,7 +3467,7 @@
                 mStatusBarLayer = mStatusBar.getSurfaceLayer();
 
                 // Let the status bar determine its size.
-                mStatusBar.computeFrameLw(pf, df, vf, vf, vf, dcf, vf);
+                mStatusBar.computeFrameLw(pf, df, vf, vf, vf, dcf, vf, osf);
 
                 // For layout, the status bar is always at the top with our fixed height.
                 mStableTop = mUnrestrictedScreenTop + mStatusBarHeight;
@@ -3638,6 +3641,7 @@
         final Rect vf = mTmpVisibleFrame;
         final Rect dcf = mTmpDecorFrame;
         final Rect sf = mTmpStableFrame;
+        Rect osf = null;
         dcf.setEmpty();
 
         final boolean hasNavBar = (isDefaultDisplay && mHasNavigationBar
@@ -4022,6 +4026,37 @@
             }
         }
 
+        // 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.
+        // We only want to apply outsets to certain types of windows. For example, we never want to
+        // apply the outsets to floating dialogs, because they wouldn't make sense there.
+        final boolean useOutsets = attrs.type == TYPE_WALLPAPER
+                || (fl & (WindowManager.LayoutParams.FLAG_FULLSCREEN
+                        | WindowManager.LayoutParams.FLAG_LAYOUT_IN_OVERSCAN)) != 0;
+        if (isDefaultDisplay && useOutsets) {
+            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
@@ -4030,9 +4065,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/display/DisplayDevice.java b/services/core/java/com/android/server/display/DisplayDevice.java
index 61631d4..0d5e6bc 100644
--- a/services/core/java/com/android/server/display/DisplayDevice.java
+++ b/services/core/java/com/android/server/display/DisplayDevice.java
@@ -47,6 +47,10 @@
     // within a transaction from performTraversalInTransactionLocked.
     private Surface mCurrentSurface;
 
+    // DEBUG STATE: Last device info which was written to the log, or null if none.
+    // Do not use for any other purpose.
+    DisplayDeviceInfo mDebugLastLoggedDeviceInfo;
+
     public DisplayDevice(DisplayAdapter displayAdapter, IBinder displayToken, String uniqueId) {
         mDisplayAdapter = displayAdapter;
         mDisplayToken = displayToken;
diff --git a/services/core/java/com/android/server/display/DisplayDeviceInfo.java b/services/core/java/com/android/server/display/DisplayDeviceInfo.java
index d1e73f0..ebf6e4e 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceInfo.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceInfo.java
@@ -104,6 +104,16 @@
     public static final int TOUCH_EXTERNAL = 2;
 
     /**
+     * Diff result: The {@link #state} fields differ.
+     */
+    public static final int DIFF_STATE = 1 << 0;
+
+    /**
+     * Diff result: Other fields differ.
+     */
+    public static final int DIFF_OTHER = 1 << 1;
+
+    /**
      * Gets the name of the display device, which may be derived from EDID or
      * other sources. The name may be localized and displayed to the user.
      */
@@ -238,26 +248,39 @@
     }
 
     public boolean equals(DisplayDeviceInfo other) {
-        return other != null
-                && Objects.equal(name, other.name)
-                && Objects.equal(uniqueId, other.uniqueId)
-                && width == other.width
-                && height == other.height
-                && refreshRate == other.refreshRate
-                && Arrays.equals(supportedRefreshRates, other.supportedRefreshRates)
-                && densityDpi == other.densityDpi
-                && xDpi == other.xDpi
-                && yDpi == other.yDpi
-                && appVsyncOffsetNanos == other.appVsyncOffsetNanos
-                && presentationDeadlineNanos == other.presentationDeadlineNanos
-                && flags == other.flags
-                && touch == other.touch
-                && rotation == other.rotation
-                && type == other.type
-                && Objects.equal(address, other.address)
-                && state == other.state
-                && ownerUid == other.ownerUid
-                && Objects.equal(ownerPackageName, other.ownerPackageName);
+        return other != null && diff(other) == 0;
+    }
+
+    /**
+     * Computes the difference between display device infos.
+     * Assumes other is not null.
+     */
+    public int diff(DisplayDeviceInfo other) {
+        int diff = 0;
+        if (state != other.state) {
+            diff |= DIFF_STATE;
+        }
+        if (!Objects.equal(name, other.name)
+                || !Objects.equal(uniqueId, other.uniqueId)
+                || width != other.width
+                || height != other.height
+                || refreshRate != other.refreshRate
+                || !Arrays.equals(supportedRefreshRates, other.supportedRefreshRates)
+                || densityDpi != other.densityDpi
+                || xDpi != other.xDpi
+                || yDpi != other.yDpi
+                || appVsyncOffsetNanos != other.appVsyncOffsetNanos
+                || presentationDeadlineNanos != other.presentationDeadlineNanos
+                || flags != other.flags
+                || touch != other.touch
+                || rotation != other.rotation
+                || type != other.type
+                || !Objects.equal(address, other.address)
+                || ownerUid != other.ownerUid
+                || !Objects.equal(ownerPackageName, other.ownerPackageName)) {
+            diff |= DIFF_OTHER;
+        }
+        return diff;
     }
 
     @Override
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 5f0ad9f..96ff702 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -640,13 +640,14 @@
     }
 
     private void handleDisplayDeviceAddedLocked(DisplayDevice device) {
+        DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
         if (mDisplayDevices.contains(device)) {
-            Slog.w(TAG, "Attempted to add already added display device: "
-                    + device.getDisplayDeviceInfoLocked());
+            Slog.w(TAG, "Attempted to add already added display device: " + info);
             return;
         }
 
-        Slog.i(TAG, "Display device added: " + device.getDisplayDeviceInfoLocked());
+        Slog.i(TAG, "Display device added: " + info);
+        device.mDebugLastLoggedDeviceInfo = info;
 
         mDisplayDevices.add(device);
         addLogicalDisplayLocked(device);
@@ -659,13 +660,20 @@
 
     private void handleDisplayDeviceChanged(DisplayDevice device) {
         synchronized (mSyncRoot) {
+            DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
             if (!mDisplayDevices.contains(device)) {
-                Slog.w(TAG, "Attempted to change non-existent display device: "
-                        + device.getDisplayDeviceInfoLocked());
+                Slog.w(TAG, "Attempted to change non-existent display device: " + info);
                 return;
             }
 
-            Slog.i(TAG, "Display device changed: " + device.getDisplayDeviceInfoLocked());
+            int diff = device.mDebugLastLoggedDeviceInfo.diff(info);
+            if (diff == DisplayDeviceInfo.DIFF_STATE) {
+                Slog.i(TAG, "Display device changed state: \"" + info.name
+                        + "\", " + Display.stateToString(info.state));
+            } else if (diff != 0) {
+                Slog.i(TAG, "Display device changed: " + info);
+            }
+            device.mDebugLastLoggedDeviceInfo = info;
 
             device.applyPendingDisplayDeviceInfoChangesLocked();
             if (updateLogicalDisplaysLocked()) {
@@ -680,13 +688,14 @@
         }
     }
     private void handleDisplayDeviceRemovedLocked(DisplayDevice device) {
+        DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
         if (!mDisplayDevices.remove(device)) {
-            Slog.w(TAG, "Attempted to remove non-existent display device: "
-                    + device.getDisplayDeviceInfoLocked());
+            Slog.w(TAG, "Attempted to remove non-existent display device: " + info);
             return;
         }
 
-        Slog.i(TAG, "Display device removed: " + device.getDisplayDeviceInfoLocked());
+        Slog.i(TAG, "Display device removed: " + info);
+        device.mDebugLastLoggedDeviceInfo = info;
 
         updateLogicalDisplaysLocked();
         scheduleTraversalLocked(false);
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index a1d145c..40e6d58 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;
@@ -536,4 +537,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 ad6aa75..b75622b 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -3012,7 +3012,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;
@@ -3293,6 +3293,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
@@ -9456,6 +9457,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 b621c52..9b3bc6c 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -179,6 +179,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.
      */
@@ -259,6 +267,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
@@ -517,7 +529,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;
 
         TaskStack stack = mAppToken != null ? getStack() : null;
@@ -585,6 +598,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();
@@ -647,6 +664,15 @@
                 Math.max(mFrame.right - mStableFrame.right, 0),
                 Math.max(mFrame.bottom - mStableFrame.bottom, 0));
 
+        if (hasOutsets) {
+            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
@@ -656,6 +682,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.
@@ -678,7 +705,8 @@
                 + "): frame=" + mFrame.toShortString()
                 + " ci=" + mContentInsets.toShortString()
                 + " vi=" + mVisibleInsets.toShortString()
-                + " vi=" + mStableInsets.toShortString());
+                + " vi=" + mStableInsets.toShortString()
+                + " of=" + mOutsets.toShortString());
     }
 
     @Override
@@ -784,7 +812,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() {
@@ -1329,7 +1359,7 @@
         }
         return displayContent.isDefaultDisplay;
     }
-
+    
     public void setShowToOwnerOnlyLocked(boolean showToOwnerOnly) {
         mShowToOwnerOnly = showToOwnerOnly;
     }
@@ -1439,6 +1469,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
@@ -1449,7 +1480,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.
                         }
@@ -1457,7 +1488,7 @@
                 });
             } else {
                 mClient.resized(frame, overscanInsets, contentInsets, visibleInsets, stableInsets,
-                        reportDraw, newConfig);
+                        outsets, reportDraw, newConfig);
             }
 
             //TODO (multidisplay): Accessibility supported only for the default display.
@@ -1470,6 +1501,7 @@
             mContentInsetsChanged = false;
             mVisibleInsetsChanged = false;
             mStableInsetsChanged = false;
+            mOutsetsChanged = false;
             mWinAnimator.mSurfaceResized = false;
         } catch (RemoteException e) {
             mOrientationChanging = false;
@@ -1615,17 +1647,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/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index f5d4867..2fe36707 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -28,6 +28,7 @@
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
+import android.content.res.Resources;
 import android.database.ContentObserver;
 import android.hardware.soundtrigger.IRecognitionStatusCallback;
 import android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel;
@@ -79,6 +80,7 @@
         mResolver = context.getContentResolver();
         mDbHelper = new DatabaseHelper(context);
         mSoundTriggerHelper = new SoundTriggerHelper(context);
+        mServiceStub = new VoiceInteractionManagerServiceStub();
     }
 
     @Override
@@ -104,8 +106,7 @@
     }
 
     // implementation entry point and binder service
-    private final VoiceInteractionManagerServiceStub mServiceStub
-            = new VoiceInteractionManagerServiceStub();
+    private final VoiceInteractionManagerServiceStub mServiceStub;
 
     class VoiceInteractionManagerServiceStub extends IVoiceInteractionManagerService.Stub {
 
@@ -113,6 +114,11 @@
 
         private boolean mSafeMode;
         private int mCurUser;
+        private final boolean mEnableService;
+
+        VoiceInteractionManagerServiceStub() {
+            mEnableService = shouldEnableService(mContext.getResources());
+        }
 
         @Override
         public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
@@ -136,15 +142,14 @@
                     Settings.Secure.VOICE_INTERACTION_SERVICE, userHandle);
             ComponentName curRecognizer = getCurRecognizer(userHandle);
             VoiceInteractionServiceInfo curInteractorInfo = null;
-            if (curInteractorStr == null && curRecognizer != null
-                    && !ActivityManager.isLowRamDeviceStatic()) {
+            if (curInteractorStr == null && curRecognizer != null && mEnableService) {
                 // If there is no interactor setting, that means we are upgrading
                 // from an older platform version.  If the current recognizer is not
                 // set or matches the preferred recognizer, then we want to upgrade
                 // the user to have the default voice interaction service enabled.
                 // Note that we don't do this for low-RAM devices, since we aren't
                 // supporting voice interaction services there.
-                curInteractorInfo = findAvailInteractor(userHandle, curRecognizer);
+                curInteractorInfo = findAvailInteractor(userHandle, curRecognizer.getPackageName());
                 if (curInteractorInfo != null) {
                     // Looks good!  We'll apply this one.  To make it happen, we clear the
                     // recognizer so that we don't think we have anything set and will
@@ -153,9 +158,21 @@
                 }
             }
 
+            // If forceInteractorPackage exists, try to apply the interactor from this package if
+            // possible and ignore the regular interactor setting.
+            String forceInteractorPackage =
+                    getForceVoiceInteractionServicePackage(mContext.getResources());
+            if (forceInteractorPackage != null) {
+                curInteractorInfo = findAvailInteractor(userHandle, forceInteractorPackage);
+                if (curInteractorInfo != null) {
+                    // We'll apply this one. Clear the recognizer and re-apply the settings.
+                    curRecognizer = null;
+                }
+            }
+
             // If we are on a svelte device, make sure an interactor is not currently
             // enabled; if it is, turn it off.
-            if (ActivityManager.isLowRamDeviceStatic() && curInteractorStr != null) {
+            if (!mEnableService && curInteractorStr != null) {
                 if (!TextUtils.isEmpty(curInteractorStr)) {
                     setCurInteractor(null, userHandle);
                     curInteractorStr = "";
@@ -184,7 +201,7 @@
             }
 
             // Initializing settings, look for an interactor first (but only on non-svelte).
-            if (curInteractorInfo == null && !ActivityManager.isLowRamDeviceStatic()) {
+            if (curInteractorInfo == null && mEnableService) {
                 curInteractorInfo = findAvailInteractor(userHandle, null);
             }
 
@@ -210,6 +227,18 @@
             }
         }
 
+        private boolean shouldEnableService(Resources res) {
+            // VoiceInteractionService should not be enabled on low ram devices unless it has the config flag.
+            return !ActivityManager.isLowRamDeviceStatic() ||
+                    getForceVoiceInteractionServicePackage(res) != null;
+        }
+
+        private String getForceVoiceInteractionServicePackage(Resources res) {
+            String interactorPackage =
+                    res.getString(com.android.internal.R.string.config_forceVoiceInteractionServicePackage);
+            return TextUtils.isEmpty(interactorPackage) ? null : interactorPackage;
+        }
+
         public void systemRunning(boolean safeMode) {
             mSafeMode = safeMode;
 
@@ -260,7 +289,7 @@
             }
         }
 
-        VoiceInteractionServiceInfo findAvailInteractor(int userHandle, ComponentName recognizer) {
+        VoiceInteractionServiceInfo findAvailInteractor(int userHandle, String packageName) {
             List<ResolveInfo> available =
                     mContext.getPackageManager().queryIntentServicesAsUser(
                             new Intent(VoiceInteractionService.SERVICE_INTERFACE), 0, userHandle);
@@ -281,8 +310,8 @@
                             VoiceInteractionServiceInfo info = new VoiceInteractionServiceInfo(
                                     mContext.getPackageManager(), comp, userHandle);
                             if (info.getParseError() == null) {
-                                if (recognizer == null || info.getServiceInfo().packageName.equals(
-                                        recognizer.getPackageName())) {
+                                if (packageName == null || info.getServiceInfo().packageName.equals(
+                                        packageName)) {
                                     if (foundInfo == null) {
                                         foundInfo = info;
                                     } else {
@@ -659,6 +688,7 @@
             }
             synchronized (this) {
                 pw.println("VOICE INTERACTION MANAGER (dumpsys voiceinteraction)\n");
+                pw.println("  mEnableService: " + mEnableService);
                 if (mImpl == null) {
                     pw.println("  (No active implementation)");
                     return;
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 4c4454d..fb5d44f 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.
     }
 
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
index 25f7078..8575839 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
@@ -89,7 +89,7 @@
     @Override
     public int relayout(IWindow iWindow, int i, LayoutParams layoutParams, int i2,
             int i3, int i4, int i5, Rect rect, Rect rect2, Rect rect3, Rect rect4, Rect rect5,
-            Configuration configuration, Surface surface) throws RemoteException {
+            Rect rect6, Configuration configuration, Surface surface) throws RemoteException {
         // pass for now.
         return 0;
     }