Postpone setting background when window is set.

The DecorView background is the same as the window background.
If a background is set before the DecorView's window is set,
setWindowBackground will throw an NPE.

This happens when the default theme has android:view set with a
non-null value, so the background is set within the super constructor
(in View.java) before the PhoneWindow is set in the constructor of
DecorView.

Fixes: 137764086
Test: regression test DecoreViewTest.setBackgroundWithNoWindow()
Change-Id: I3b3c31cfe50ffa7284a1b37ca4b2f864be77c838
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index 480ff4d..599c354 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -249,6 +249,14 @@
     private Drawable mOriginalBackgroundDrawable;
     private Drawable mLastOriginalBackgroundDrawable;
     private Drawable mResizingBackgroundDrawable;
+
+    /**
+     * Temporary holder for a window background when it is set before {@link #mWindow} is
+     * initialized. It will be set as the actual background once {@link #setWindow(PhoneWindow)} is
+     * called.
+     */
+    @Nullable
+    private Drawable mPendingWindowBackground;
     private Drawable mCaptionBackgroundDrawable;
     private Drawable mUserCaptionBackgroundDrawable;
 
@@ -961,6 +969,10 @@
     }
 
     public void setWindowBackground(Drawable drawable) {
+        if (mWindow == null) {
+            mPendingWindowBackground = drawable;
+            return;
+        }
         if (mOriginalBackgroundDrawable != drawable) {
             mOriginalBackgroundDrawable = drawable;
             updateBackgroundDrawable();
@@ -2003,6 +2015,11 @@
             DecorContext decorContext = (DecorContext) context;
             decorContext.setPhoneWindow(mWindow);
         }
+        if (mPendingWindowBackground != null) {
+            Drawable background = mPendingWindowBackground;
+            mPendingWindowBackground = null;
+            setWindowBackground(background);
+        }
     }
 
     @Override
diff --git a/core/tests/coretests/res/values/styles.xml b/core/tests/coretests/res/values/styles.xml
index dbc4626..0bf4b92 100644
--- a/core/tests/coretests/res/values/styles.xml
+++ b/core/tests/coretests/res/values/styles.xml
@@ -39,4 +39,7 @@
         <item name="android:colorBackground">@null</item>
         <item name="android:windowBackgroundFallback">#0000FF</item>
     </style>
+    <style name="ViewDefaultBackground">
+        <item name="android:background">#00000000</item>
+    </style>
 </resources>
diff --git a/core/tests/coretests/src/com/android/internal/policy/DecorViewTest.java b/core/tests/coretests/src/com/android/internal/policy/DecorViewTest.java
index f66717e..62e4efe 100644
--- a/core/tests/coretests/src/com/android/internal/policy/DecorViewTest.java
+++ b/core/tests/coretests/src/com/android/internal/policy/DecorViewTest.java
@@ -76,4 +76,13 @@
         expectedBitmap.getPixels(expPixels, 0, w, 0, 0, w, h);
         assertThat(Arrays.toString(expPixels)).isEqualTo(Arrays.toString(resPixels));
     }
+
+    @Test
+    public void setBackgroundWithNoWindow() {
+        PhoneWindow phoneWindow = new PhoneWindow(mContext);
+        // Set a theme that defines a non-null value for android:background
+        mContext.setTheme(R.style.ViewDefaultBackground);
+        DecorView decorView = (DecorView) phoneWindow.getDecorView();
+        assertThat(decorView.getBackground()).isNotNull();
+    }
 }