Merge "DisplayCutout: Add xml wrapper for layoutInDisplayCutoutMode"
diff --git a/api/current.txt b/api/current.txt
index f584e35..fbf1c22 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -1549,6 +1549,7 @@
     field public static final int windowHideAnimation = 16842935; // 0x10100b7
     field public static final int windowIsFloating = 16842839; // 0x1010057
     field public static final int windowIsTranslucent = 16842840; // 0x1010058
+    field public static final int windowLayoutInDisplayCutoutMode = 16844167; // 0x1010587
     field public static final int windowLightNavigationBar = 16844140; // 0x101056c
     field public static final int windowLightStatusBar = 16844000; // 0x10104e0
     field public static final int windowMinWidthMajor = 16843606; // 0x1010356
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index e271701..2354f25 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -2234,6 +2234,7 @@
          * @see #LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
          * @see #LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER
          * @see DisplayCutout
+         * @see android.R.attr#layoutInDisplayCutoutMode
          */
         @LayoutInDisplayCutoutMode
         public int layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT;
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index 50c9d6c..528888f 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -2464,6 +2464,15 @@
             decor.setSystemUiVisibility(
                     decor.getSystemUiVisibility() | View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR);
         }
+        if (a.hasValue(R.styleable.Window_windowLayoutInDisplayCutoutMode)) {
+            int mode = a.getInt(R.styleable.Window_windowLayoutInDisplayCutoutMode, -1);
+            if (mode < LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT
+                    || mode > LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER) {
+                throw new UnsupportedOperationException("Unknown windowLayoutInDisplayCutoutMode: "
+                        + a.getString(R.styleable.Window_windowLayoutInDisplayCutoutMode));
+            }
+            params.layoutInDisplayCutoutMode = mode;
+        }
 
         if (mAlwaysReadCloseOnTouchAttr || getContext().getApplicationInfo().targetSdkVersion
                 >= android.os.Build.VERSION_CODES.HONEYCOMB) {
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 7bf3e0e..ffabdab 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -2116,6 +2116,45 @@
              Corresponds to setting {@link android.view.View#SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR} on
              the decor view. -->
         <attr name="windowLightNavigationBar" format="boolean" />
+
+        <!-- Controls how the window is laid out if there is a {@code DisplayCutout}.
+        <p>
+        Defaults to {@code default}.
+
+        @see android.view.WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT
+        @see android.view.WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
+        @see android.view.WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER
+        @see android.view.DisplayCutout
+        @see android.R.attr#layoutInDisplayCutoutMode -->
+        <attr name="windowLayoutInDisplayCutoutMode">
+            <!-- The window is allowed to extend into the {@code DisplayCutout} area, only if the
+            {@code DisplayCutout} is fully contained within the status bar. Otherwise, the window is
+            laid out such that it does not overlap with the {@code DisplayCutout} area.
+
+            @see android.view.DisplayCutout
+            @see android.view.WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT
+            -->
+            <enum name="default" value="0" />
+            <!-- The window is always allowed to extend into the {@code DisplayCutout} area,
+            even if fullscreen or in landscape.
+            <p>
+            The window must make sure that no important content overlaps with the
+            {@link DisplayCutout}.
+
+            @see android.view.DisplayCutout
+            @see android.view.WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
+            -->
+            <enum name="always" value="1" />
+            <!-- The window is never allowed to overlap with the DisplayCutout area.
+            <p>
+            This should be used with windows that transiently set {@code SYSTEM_UI_FLAG_FULLSCREEN}
+            to avoid a relayout of the window when the flag is set or cleared.
+
+            @see android.view.DisplayCutout
+            @see android.view.WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER
+            -->
+            <enum name="never" value="2" />
+        </attr>
     </declare-styleable>
 
     <!-- The set of attributes that describe a AlertDialog's theme. -->
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index c4006b3..7d5d1ba 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2873,6 +2873,7 @@
       <!-- @hide @SystemApi -->
       <public name="userRestriction" />
       <public name="textFontWeight" />
+      <public name="windowLayoutInDisplayCutoutMode" />
     </public-group>
 
     <public-group type="style" first-id="0x010302e0">
diff --git a/core/tests/coretests/res/values/styles.xml b/core/tests/coretests/res/values/styles.xml
index 7a90197..ef3a481 100644
--- a/core/tests/coretests/res/values/styles.xml
+++ b/core/tests/coretests/res/values/styles.xml
@@ -19,4 +19,16 @@
         <item name="android:taskToBackEnterAnimation">@null</item>
         <item name="android:taskToBackExitAnimation">@null</item>
     </style>
+
+    <style name="LayoutInDisplayCutoutModeUnset">
+    </style>
+    <style name="LayoutInDisplayCutoutModeDefault">
+        <item name="android:windowLayoutInDisplayCutoutMode">default</item>
+    </style>
+    <style name="LayoutInDisplayCutoutModeAlways">
+        <item name="android:windowLayoutInDisplayCutoutMode">always</item>
+    </style>
+    <style name="LayoutInDisplayCutoutModeNever">
+        <item name="android:windowLayoutInDisplayCutoutMode">never</item>
+    </style>
 </resources>
diff --git a/core/tests/coretests/src/com/android/internal/policy/PhoneWindowTest.java b/core/tests/coretests/src/com/android/internal/policy/PhoneWindowTest.java
new file mode 100644
index 0000000..c8994dd
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/policy/PhoneWindowTest.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.policy;
+
+import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
+import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT;
+import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER;
+
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertThat;
+
+import android.content.Context;
+import android.platform.test.annotations.Presubmit;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.FlakyTest;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.view.ActionMode;
+import android.view.ContextThemeWrapper;
+
+import com.android.frameworks.coretests.R;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests {@link PhoneWindow}'s {@link ActionMode} related methods.
+ */
+@SmallTest
+@Presubmit
+@FlakyTest(detail = "Promote to presubmit once monitored to be stable.")
+@RunWith(AndroidJUnit4.class)
+public final class PhoneWindowTest {
+
+    private PhoneWindow mPhoneWindow;
+    private Context mContext;
+
+    @Before
+    public void setUp() throws Exception {
+        mContext = InstrumentationRegistry.getContext();
+    }
+
+    @Test
+    public void layoutInDisplayCutoutMode_unset() throws Exception {
+        createPhoneWindowWithTheme(R.style.LayoutInDisplayCutoutModeUnset);
+        installDecor();
+
+        assertThat(mPhoneWindow.getAttributes().layoutInDisplayCutoutMode,
+                is(LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT));
+    }
+
+    @Test
+    public void layoutInDisplayCutoutMode_default() throws Exception {
+        createPhoneWindowWithTheme(R.style.LayoutInDisplayCutoutModeDefault);
+        installDecor();
+
+        assertThat(mPhoneWindow.getAttributes().layoutInDisplayCutoutMode,
+                is(LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT));
+    }
+
+    @Test
+    public void layoutInDisplayCutoutMode_always() throws Exception {
+        createPhoneWindowWithTheme(R.style.LayoutInDisplayCutoutModeAlways);
+        installDecor();
+
+        assertThat(mPhoneWindow.getAttributes().layoutInDisplayCutoutMode,
+                is(LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS));
+    }
+
+    @Test
+    public void layoutInDisplayCutoutMode_never() throws Exception {
+        createPhoneWindowWithTheme(R.style.LayoutInDisplayCutoutModeNever);
+        installDecor();
+
+        assertThat(mPhoneWindow.getAttributes().layoutInDisplayCutoutMode,
+                is(LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER));
+    }
+
+    private void createPhoneWindowWithTheme(int theme) {
+        mPhoneWindow = new PhoneWindow(new ContextThemeWrapper(mContext, theme));
+    }
+
+    private void installDecor() {
+        mPhoneWindow.getDecorView();
+    }
+}
\ No newline at end of file