Add convenience method to create a folding feature.

Convert FoldingFeature Orienation to class.
Convert FoldingFeature Type to class.
Convert FoldingFeature State to class.
Add convenience method for creating a test fold.

Relnote: Add helper method to create test display featurs.
Relnote: Change from occlusionMode to occlusionType
Bug: 184266682
Test: ./gradlew window:window:cAT
Test: ./gradlew window:window-java:cAT
Test: ./gradlew window:window-rxjava2:cAT
Test: ./gradlew window:window-rxjava3:cAT
Test: ./gradlew window:window-testing:cAT
Change-Id: I3cf548611ee5838486f817b15c82ede61f442f3d
diff --git a/slidingpanelayout/slidingpanelayout/src/androidTest/java/androidx/slidingpanelayout/widget/helpers/FakeWindowBackend.kt b/slidingpanelayout/slidingpanelayout/src/androidTest/java/androidx/slidingpanelayout/widget/helpers/FakeWindowBackend.kt
index b3760de..5739db9 100644
--- a/slidingpanelayout/slidingpanelayout/src/androidTest/java/androidx/slidingpanelayout/widget/helpers/FakeWindowBackend.kt
+++ b/slidingpanelayout/slidingpanelayout/src/androidTest/java/androidx/slidingpanelayout/widget/helpers/FakeWindowBackend.kt
@@ -31,7 +31,7 @@
  * folding in middle to mimic fold/unfold behavior in real world.
  */
 public class FakeWindowBackend(private val foldAxis: FoldAxis) : WindowBackend {
-    private var foldState = FoldingFeature.STATE_HALF_OPENED
+    private var foldState = FoldingFeature.State.HALF_OPENED
     private var foldWidth: Int = 0
     private var windowLayoutInfoCallback: Consumer<WindowLayoutInfo>? = null
     private var windowLayoutInfoExecutor: Executor? = null
@@ -92,14 +92,14 @@
     }
 
     /**
-     * Toggle folding state between [FoldingFeature.STATE_HALF_OPENED] and [FoldingFeature.STATE_FLAT]
-     * Initial state is [FoldingFeature.STATE_HALF_OPENED]
+     * Toggle folding state between [FoldingFeature.State.HALF_OPENED] and
+     * [FoldingFeature.State.FLAT] Initial state is [FoldingFeature.State.HALF_OPENED]
      */
     public fun toggleFoldState(activity: Activity) {
-        foldState = if (foldState == FoldingFeature.STATE_HALF_OPENED) {
-            FoldingFeature.STATE_FLAT
+        foldState = if (foldState == FoldingFeature.State.HALF_OPENED) {
+            FoldingFeature.State.FLAT
         } else {
-            FoldingFeature.STATE_HALF_OPENED
+            FoldingFeature.State.HALF_OPENED
         }
         windowLayoutInfoExecutor?.execute {
             windowLayoutInfoCallback?.accept(getWindowLayoutInfo(activity))
@@ -109,8 +109,8 @@
     private fun getWindowLayoutInfo(activity: Activity): WindowLayoutInfo {
         val windowSize = WindowManager(activity).getCurrentWindowMetrics().bounds
         val featureRect = midScreenFold(windowSize, foldAxis, foldWidth)
-        val displayFeature = FoldingFeature(featureRect, FoldingFeature.TYPE_FOLD, foldState)
-        if (foldState == FoldingFeature.STATE_FLAT) {
+        val displayFeature = FoldingFeature(featureRect, FoldingFeature.Type.FOLD, foldState)
+        if (foldState == FoldingFeature.State.FLAT) {
             assert(!displayFeature.isSeparating)
         } else {
             assert(displayFeature.isSeparating)
diff --git a/slidingpanelayout/slidingpanelayout/src/main/java/androidx/slidingpanelayout/widget/SlidingPaneLayout.java b/slidingpanelayout/slidingpanelayout/src/main/java/androidx/slidingpanelayout/widget/SlidingPaneLayout.java
index 024d696..33c24b2 100644
--- a/slidingpanelayout/slidingpanelayout/src/main/java/androidx/slidingpanelayout/widget/SlidingPaneLayout.java
+++ b/slidingpanelayout/slidingpanelayout/src/main/java/androidx/slidingpanelayout/widget/SlidingPaneLayout.java
@@ -878,7 +878,7 @@
             // offset for the next child, in order to avoid rendering the content under it.
             int nextXOffset = 0;
             if (mFoldingFeature != null
-                    && mFoldingFeature.getOrientation() == FoldingFeature.ORIENTATION_VERTICAL
+                    && mFoldingFeature.getOrientation() == FoldingFeature.Orientation.VERTICAL
                     && mFoldingFeature.isSeparating()) {
                 nextXOffset = mFoldingFeature.getBounds().width();
             }
diff --git a/window/window-java/src/androidTest/java/androidx/window/java/WindowInfoRepoJavaAdapterTest.kt b/window/window-java/src/androidTest/java/androidx/window/java/WindowInfoRepoJavaAdapterTest.kt
index 688df0e..0317210 100644
--- a/window/window-java/src/androidTest/java/androidx/window/java/WindowInfoRepoJavaAdapterTest.kt
+++ b/window/window-java/src/androidTest/java/androidx/window/java/WindowInfoRepoJavaAdapterTest.kt
@@ -18,6 +18,8 @@
 
 import android.graphics.Rect
 import androidx.window.FoldingFeature
+import androidx.window.FoldingFeature.State.Companion.HALF_OPENED
+import androidx.window.FoldingFeature.Type.Companion.HINGE
 import androidx.window.WindowInfoRepo
 import androidx.window.WindowLayoutInfo
 import androidx.window.WindowMetrics
@@ -64,11 +66,7 @@
 
     @Test
     public fun testRegisterListener() {
-        val feature = FoldingFeature(
-            Rect(0, 100, 100, 100),
-            FoldingFeature.TYPE_HINGE,
-            FoldingFeature.STATE_HALF_OPENED
-        )
+        val feature = FoldingFeature(Rect(0, 100, 100, 100), HINGE, HALF_OPENED)
         val expected = WindowLayoutInfo.Builder().setDisplayFeatures(listOf(feature)).build()
         val mockRepo = mock<WindowInfoRepo>()
         whenever(mockRepo.windowLayoutInfo).thenReturn(flowOf(expected))
@@ -82,11 +80,7 @@
 
     @Test
     public fun testRegisterListener_multipleIsNoOp() {
-        val feature = FoldingFeature(
-            Rect(0, 100, 100, 100),
-            FoldingFeature.TYPE_HINGE,
-            FoldingFeature.STATE_HALF_OPENED
-        )
+        val feature = FoldingFeature(Rect(0, 100, 100, 100), HINGE, HALF_OPENED)
         val expected = WindowLayoutInfo.Builder().setDisplayFeatures(listOf(feature)).build()
         val mockRepo = mock<WindowInfoRepo>()
         whenever(mockRepo.windowLayoutInfo).thenReturn(flowOf(expected))
@@ -102,11 +96,7 @@
     @OptIn(ExperimentalCoroutinesApi::class)
     @Test
     public fun testUnregisterListener() {
-        val feature = FoldingFeature(
-            Rect(0, 100, 100, 100),
-            FoldingFeature.TYPE_HINGE,
-            FoldingFeature.STATE_HALF_OPENED
-        )
+        val feature = FoldingFeature(Rect(0, 100, 100, 100), HINGE, HALF_OPENED)
         val info = WindowLayoutInfo.Builder().setDisplayFeatures(listOf(feature)).build()
         val mockRepo = mock<WindowInfoRepo>()
         val channel = Channel<WindowLayoutInfo>()
diff --git a/window/window-rxjava2/src/androidTest/java/androidx/window/rxjava2/WindowInfoRepoRxTest.kt b/window/window-rxjava2/src/androidTest/java/androidx/window/rxjava2/WindowInfoRepoRxTest.kt
index 214ca23..4b8a2c1 100644
--- a/window/window-rxjava2/src/androidTest/java/androidx/window/rxjava2/WindowInfoRepoRxTest.kt
+++ b/window/window-rxjava2/src/androidTest/java/androidx/window/rxjava2/WindowInfoRepoRxTest.kt
@@ -36,8 +36,8 @@
     public fun testWindowLayoutInfoObservable() {
         val feature = FoldingFeature(
             Rect(0, 100, 100, 100),
-            FoldingFeature.TYPE_HINGE,
-            FoldingFeature.STATE_HALF_OPENED
+            FoldingFeature.Type.HINGE,
+            FoldingFeature.State.HALF_OPENED
         )
         val expected = WindowLayoutInfo.Builder().setDisplayFeatures(listOf(feature)).build()
         val mockRepo = mock<WindowInfoRepo>()
@@ -53,8 +53,8 @@
     public fun testWindowLayoutInfoFlowable() {
         val feature = FoldingFeature(
             Rect(0, 100, 100, 100),
-            FoldingFeature.TYPE_HINGE,
-            FoldingFeature.STATE_HALF_OPENED
+            FoldingFeature.Type.HINGE,
+            FoldingFeature.State.HALF_OPENED
         )
         val expected = WindowLayoutInfo.Builder().setDisplayFeatures(listOf(feature)).build()
         val mockRepo = mock<WindowInfoRepo>()
diff --git a/window/window-rxjava3/src/androidTest/java/androidx/window/rxjava3/WindowInfoRepoRxTest.kt b/window/window-rxjava3/src/androidTest/java/androidx/window/rxjava3/WindowInfoRepoRxTest.kt
index b02f00d..e4b6edb 100644
--- a/window/window-rxjava3/src/androidTest/java/androidx/window/rxjava3/WindowInfoRepoRxTest.kt
+++ b/window/window-rxjava3/src/androidTest/java/androidx/window/rxjava3/WindowInfoRepoRxTest.kt
@@ -38,8 +38,8 @@
     public fun testWindowLayoutInfoObservable() {
         val feature = FoldingFeature(
             Rect(0, 100, 100, 100),
-            FoldingFeature.TYPE_HINGE,
-            FoldingFeature.STATE_HALF_OPENED
+            FoldingFeature.Type.HINGE,
+            FoldingFeature.State.HALF_OPENED
         )
         val expected = WindowLayoutInfo.Builder().setDisplayFeatures(listOf(feature)).build()
         val mockRepo = mock<WindowInfoRepo>()
@@ -55,8 +55,8 @@
     public fun testWindowLayoutInfoFlowable() {
         val feature = FoldingFeature(
             Rect(0, 100, 100, 100),
-            FoldingFeature.TYPE_HINGE,
-            FoldingFeature.STATE_HALF_OPENED
+            FoldingFeature.Type.HINGE,
+            FoldingFeature.State.HALF_OPENED
         )
         val expected = WindowLayoutInfo.Builder().setDisplayFeatures(listOf(feature)).build()
         val mockRepo = mock<WindowInfoRepo>()
diff --git a/window/window-samples/src/main/java/androidx/window/sample/PresentationActivity.kt b/window/window-samples/src/main/java/androidx/window/sample/PresentationActivity.kt
index 57ce8be..43278c3 100644
--- a/window/window-samples/src/main/java/androidx/window/sample/PresentationActivity.kt
+++ b/window/window-samples/src/main/java/androidx/window/sample/PresentationActivity.kt
@@ -151,22 +151,11 @@
 
         info.displayFeatures
             .mapNotNull { it as? FoldingFeature }
-            .forEach { feature ->
-                stateStringBuilder.append(feature.stateString())
-                    .append("\n")
-            }
+            .joinToString(separator = "\n") { feature -> feature.state.toString() }
 
         findViewById<TextView>(R.id.currentState).text = stateStringBuilder.toString()
     }
 
-    private fun FoldingFeature.stateString(): String {
-        return when (state) {
-            FoldingFeature.STATE_FLAT -> "FLAT"
-            FoldingFeature.STATE_HALF_OPENED -> "HALF_OPENED"
-            else -> "Unknown feature state ($state)"
-        }
-    }
-
     inner class WindowLayoutInfoChangeCallback : Consumer<WindowLayoutInfo> {
         override fun accept(info: WindowLayoutInfo) {
             updateCurrentState(info)
diff --git a/window/window-samples/src/main/java/androidx/window/sample/backend/MidScreenFoldBackend.kt b/window/window-samples/src/main/java/androidx/window/sample/backend/MidScreenFoldBackend.kt
index cf7b124..04a929f 100644
--- a/window/window-samples/src/main/java/androidx/window/sample/backend/MidScreenFoldBackend.kt
+++ b/window/window-samples/src/main/java/androidx/window/sample/backend/MidScreenFoldBackend.kt
@@ -66,8 +66,8 @@
         val displayFeature =
             FoldingFeature(
                 featureRect,
-                FoldingFeature.TYPE_FOLD,
-                FoldingFeature.STATE_FLAT
+                FoldingFeature.Type.FOLD,
+                FoldingFeature.State.FLAT
             )
         val featureList = ArrayList<DisplayFeature>()
         featureList.add(displayFeature)
diff --git a/window/window-testing/api/current.txt b/window/window-testing/api/current.txt
index b564bd4..304bfd4 100644
--- a/window/window-testing/api/current.txt
+++ b/window/window-testing/api/current.txt
@@ -1,6 +1,9 @@
 // Signature format: 4.0
 package androidx.window.testing {
 
+  public final class DisplayFeatureTesting {
+  }
+
   public final class WindowLayoutInfoPublisherRule implements org.junit.rules.TestRule {
     ctor public WindowLayoutInfoPublisherRule();
     method public org.junit.runners.model.Statement apply(org.junit.runners.model.Statement base, org.junit.runner.Description description);
diff --git a/window/window-testing/api/public_plus_experimental_current.txt b/window/window-testing/api/public_plus_experimental_current.txt
index 729cf86..b7bc00b 100644
--- a/window/window-testing/api/public_plus_experimental_current.txt
+++ b/window/window-testing/api/public_plus_experimental_current.txt
@@ -1,6 +1,14 @@
 // Signature format: 4.0
 package androidx.window.testing {
 
+  public final class DisplayFeatureTesting {
+    method @kotlinx.coroutines.ExperimentalCoroutinesApi public static androidx.window.FoldingFeature createFoldingFeature(android.app.Activity activity, optional int center, optional int size, optional androidx.window.FoldingFeature.State state, optional androidx.window.FoldingFeature.Orientation orientation);
+    method @kotlinx.coroutines.ExperimentalCoroutinesApi public static androidx.window.FoldingFeature createFoldingFeature(android.app.Activity activity, optional int center, optional int size, optional androidx.window.FoldingFeature.State state);
+    method @kotlinx.coroutines.ExperimentalCoroutinesApi public static androidx.window.FoldingFeature createFoldingFeature(android.app.Activity activity, optional int center, optional int size);
+    method @kotlinx.coroutines.ExperimentalCoroutinesApi public static androidx.window.FoldingFeature createFoldingFeature(android.app.Activity activity, optional int center);
+    method @kotlinx.coroutines.ExperimentalCoroutinesApi public static androidx.window.FoldingFeature createFoldingFeature(android.app.Activity activity);
+  }
+
   public final class WindowLayoutInfoPublisherRule implements org.junit.rules.TestRule {
     ctor public WindowLayoutInfoPublisherRule();
     method @kotlinx.coroutines.ExperimentalCoroutinesApi public org.junit.runners.model.Statement apply(org.junit.runners.model.Statement base, org.junit.runner.Description description);
diff --git a/window/window-testing/api/restricted_current.txt b/window/window-testing/api/restricted_current.txt
index b564bd4..304bfd4 100644
--- a/window/window-testing/api/restricted_current.txt
+++ b/window/window-testing/api/restricted_current.txt
@@ -1,6 +1,9 @@
 // Signature format: 4.0
 package androidx.window.testing {
 
+  public final class DisplayFeatureTesting {
+  }
+
   public final class WindowLayoutInfoPublisherRule implements org.junit.rules.TestRule {
     ctor public WindowLayoutInfoPublisherRule();
     method public org.junit.runners.model.Statement apply(org.junit.runners.model.Statement base, org.junit.runner.Description description);
diff --git a/window/window-testing/src/androidTest/java/androidx/window/testing/DisplayFeatureTestingTest.kt b/window/window-testing/src/androidTest/java/androidx/window/testing/DisplayFeatureTestingTest.kt
new file mode 100644
index 0000000..a2b943c
--- /dev/null
+++ b/window/window-testing/src/androidTest/java/androidx/window/testing/DisplayFeatureTestingTest.kt
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2021 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 androidx.window.testing
+
+import android.graphics.Rect
+import androidx.test.ext.junit.rules.ActivityScenarioRule
+import androidx.window.FoldingFeature
+import androidx.window.FoldingFeature.Orientation.Companion.HORIZONTAL
+import androidx.window.FoldingFeature.Orientation.Companion.VERTICAL
+import androidx.window.FoldingFeature.State.Companion.FLAT
+import androidx.window.FoldingFeature.Type.Companion.FOLD
+import androidx.window.FoldingFeature.Type.Companion.HINGE
+import androidx.window.windowInfoRepository
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import org.junit.Assert.assertEquals
+import org.junit.Rule
+import org.junit.Test
+
+public class DisplayFeatureTestingTest {
+
+    @get:Rule
+    public val activityRule: ActivityScenarioRule<TestActivity> =
+        ActivityScenarioRule(TestActivity::class.java)
+
+    @OptIn(ExperimentalCoroutinesApi::class)
+    @Test
+    public fun testFold_emptyWidthIsFold() {
+        activityRule.scenario.onActivity { activity ->
+            val bounds = activity.windowInfoRepository().currentWindowMetrics.bounds
+            val center = bounds.centerX()
+            val actual = FoldingFeature(
+                activity = activity,
+                state = FLAT,
+                orientation = VERTICAL
+            )
+            val expected = FoldingFeature(Rect(center, 0, center, bounds.height()), FOLD, FLAT)
+            assertEquals(expected, actual)
+        }
+    }
+
+    @OptIn(ExperimentalCoroutinesApi::class)
+    @Test
+    public fun testFold_boundsMatchOrientation() {
+        activityRule.scenario.onActivity { activity ->
+            val bounds = activity.windowInfoRepository().currentWindowMetrics.bounds
+            val center = bounds.centerX()
+            val actual = FoldingFeature(
+                activity = activity,
+                state = FLAT,
+                orientation = HORIZONTAL
+            )
+            val expected = FoldingFeature(Rect(0, center, bounds.width(), center), FOLD, FLAT)
+            assertEquals(expected, actual)
+        }
+    }
+
+    @OptIn(ExperimentalCoroutinesApi::class)
+    @Test
+    public fun testFold_nonEmptyWidthIsFold() {
+        activityRule.scenario.onActivity { activity ->
+            val bounds = activity.windowInfoRepository().currentWindowMetrics.bounds
+            val center = bounds.centerX()
+            val width = 20
+            val actual = FoldingFeature(
+                activity = activity,
+                size = width,
+                state = FLAT,
+                orientation = VERTICAL
+            )
+            val expected = FoldingFeature(
+                Rect(center - width / 2, 0, center + width / 2, bounds.height()),
+                HINGE,
+                FLAT
+            )
+            assertEquals(expected, actual)
+        }
+    }
+}
\ No newline at end of file
diff --git a/window/window-testing/src/main/java/androidx/window/testing/DisplayFeatureTesting.kt b/window/window-testing/src/main/java/androidx/window/testing/DisplayFeatureTesting.kt
new file mode 100644
index 0000000..9c6423f
--- /dev/null
+++ b/window/window-testing/src/main/java/androidx/window/testing/DisplayFeatureTesting.kt
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2021 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.
+ */
+@file:JvmName("DisplayFeatureTesting")
+
+package androidx.window.testing
+
+import android.app.Activity
+import android.graphics.Rect
+import androidx.window.FoldingFeature
+import androidx.window.FoldingFeature.Orientation
+import androidx.window.FoldingFeature.Orientation.Companion.HORIZONTAL
+import androidx.window.FoldingFeature.Orientation.Companion.VERTICAL
+import androidx.window.FoldingFeature.State
+import androidx.window.FoldingFeature.State.Companion.HALF_OPENED
+import androidx.window.FoldingFeature.Type.Companion.FOLD
+import androidx.window.FoldingFeature.Type.Companion.HINGE
+import androidx.window.windowInfoRepository
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+
+/**
+ * A convenience method to get a test fold with default values provided. With the default values
+ * it returns a [FoldingFeature.State.HALF_OPENED] feature that splits the screen along the
+ * [FoldingFeature.Orientation.HORIZONTAL] axis.
+ *
+ * The bounds of the feature are calculated based on [orientation], [center], and [size]. If the
+ * feature is [VERTICAL] then the top-left x-coordinate is [center] - ([size] / 2) and the top-right
+ * x-coordinate is [center] + ([size] / 2). If the feature is [HORIZONTAL] then the top-left
+ * y-coordinate is [center] - ([size] / 2) and the bottom-left y-coordinate is
+ * [center] - ([size] / 2). The folding features always cover the window in one dimension and that
+ * determines the other coordinates.
+ *
+ * @param activity [Activity] that will host the test [FoldingFeature].
+ * @param center The coordinate along the axis matching the [Orientation]. The default is centered
+ * along the [HORIZONTAL] axis.
+ * @param size the smaller dimension  of the fold. The larger dimension  always covers the entire
+ * window.
+ * @param state [State] of the fold. The default value is [HALF_OPENED]
+ * @param orientation [Orientation] of the fold. The default value is [HORIZONTAL]
+ * @return [FoldingFeature] that is splitting if the width is not 0 and runs parallel to the
+ * [Orientation] axis.
+ */
+@Suppress("FunctionName")
+@ExperimentalCoroutinesApi
+@JvmOverloads
+@JvmName("createFoldingFeature")
+public fun FoldingFeature(
+    activity: Activity,
+    center: Int = activity.windowInfoRepository().currentWindowMetrics.bounds.centerX(),
+    size: Int = 0,
+    state: State = HALF_OPENED,
+    orientation: Orientation = HORIZONTAL
+): FoldingFeature {
+    val type = if (size == 0) {
+        FOLD
+    } else {
+        HINGE
+    }
+    val offset = size / 2
+    val start = center - offset
+    val end = center + offset
+    val bounds = if (orientation == VERTICAL) {
+        val windowHeight = activity.windowInfoRepository().currentWindowMetrics.bounds.height()
+        Rect(start, 0, end, windowHeight)
+    } else {
+        val windowWidth = activity.windowInfoRepository().currentWindowMetrics.bounds.width()
+        Rect(0, start, windowWidth, end)
+    }
+    return FoldingFeature(bounds, type, state)
+}
\ No newline at end of file
diff --git a/window/window-testing/src/main/java/androidx/window/testing/PublishLayoutInfoRepo.kt b/window/window-testing/src/main/java/androidx/window/testing/PublishLayoutInfoRepo.kt
index 476f250..fbce22e 100644
--- a/window/window-testing/src/main/java/androidx/window/testing/PublishLayoutInfoRepo.kt
+++ b/window/window-testing/src/main/java/androidx/window/testing/PublishLayoutInfoRepo.kt
@@ -19,12 +19,8 @@
 import androidx.window.WindowInfoRepo
 import androidx.window.WindowLayoutInfo
 import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.MutableSharedFlow
 
 internal class PublishLayoutInfoRepo(
     private val core: WindowInfoRepo,
-    private val flow: MutableSharedFlow<WindowLayoutInfo>
-) : WindowInfoRepo by core {
     override val windowLayoutInfo: Flow<WindowLayoutInfo>
-        get() = flow
-}
\ No newline at end of file
+) : WindowInfoRepo by core
\ No newline at end of file
diff --git a/window/window-testing/src/main/java/androidx/window/testing/PublishWindowInfoRepoDecorator.kt b/window/window-testing/src/main/java/androidx/window/testing/PublishWindowInfoRepoDecorator.kt
index c26b204..630cf39 100644
--- a/window/window-testing/src/main/java/androidx/window/testing/PublishWindowInfoRepoDecorator.kt
+++ b/window/window-testing/src/main/java/androidx/window/testing/PublishWindowInfoRepoDecorator.kt
@@ -19,10 +19,10 @@
 import androidx.window.WindowInfoRepo
 import androidx.window.WindowInfoRepoDecorator
 import androidx.window.WindowLayoutInfo
-import kotlinx.coroutines.flow.MutableSharedFlow
+import kotlinx.coroutines.flow.Flow
 
 internal class PublishWindowInfoRepoDecorator(
-    private val flow: MutableSharedFlow<WindowLayoutInfo>
+    private val flow: Flow<WindowLayoutInfo>
 ) : WindowInfoRepoDecorator {
     override fun decorate(repo: WindowInfoRepo): WindowInfoRepo {
         return PublishLayoutInfoRepo(repo, flow)
diff --git a/window/window/api/current.txt b/window/window/api/current.txt
index d5386e1..f393988 100644
--- a/window/window/api/current.txt
+++ b/window/window/api/current.txt
@@ -10,17 +10,17 @@
   }
 
   public final class FoldingFeature implements androidx.window.DisplayFeature {
-    ctor public FoldingFeature(android.graphics.Rect bounds, int type, int state);
+    ctor public FoldingFeature(android.graphics.Rect bounds, androidx.window.FoldingFeature.Type type, androidx.window.FoldingFeature.State state);
     method public android.graphics.Rect getBounds();
-    method public int getOcclusionMode();
-    method public int getOrientation();
-    method public int getState();
+    method public androidx.window.FoldingFeature.OcclusionType getOcclusionType();
+    method public androidx.window.FoldingFeature.Orientation getOrientation();
+    method public androidx.window.FoldingFeature.State getState();
     method public boolean isSeparating();
     property public android.graphics.Rect bounds;
     property public final boolean isSeparating;
-    property public final int occlusionMode;
-    property public final int orientation;
-    property public final int state;
+    property public final androidx.window.FoldingFeature.OcclusionType occlusionType;
+    property public final androidx.window.FoldingFeature.Orientation orientation;
+    property public final androidx.window.FoldingFeature.State state;
     field public static final androidx.window.FoldingFeature.Companion Companion;
     field public static final int OCCLUSION_FULL = 1; // 0x1
     field public static final int OCCLUSION_NONE = 0; // 0x0
@@ -35,6 +35,42 @@
   public static final class FoldingFeature.Companion {
   }
 
+  public static final class FoldingFeature.OcclusionType {
+    field public static final androidx.window.FoldingFeature.OcclusionType.Companion Companion;
+    field public static final androidx.window.FoldingFeature.OcclusionType FULL;
+    field public static final androidx.window.FoldingFeature.OcclusionType NONE;
+  }
+
+  public static final class FoldingFeature.OcclusionType.Companion {
+  }
+
+  public static final class FoldingFeature.Orientation {
+    field public static final androidx.window.FoldingFeature.Orientation.Companion Companion;
+    field public static final androidx.window.FoldingFeature.Orientation HORIZONTAL;
+    field public static final androidx.window.FoldingFeature.Orientation VERTICAL;
+  }
+
+  public static final class FoldingFeature.Orientation.Companion {
+  }
+
+  public static final class FoldingFeature.State {
+    field public static final androidx.window.FoldingFeature.State.Companion Companion;
+    field public static final androidx.window.FoldingFeature.State FLAT;
+    field public static final androidx.window.FoldingFeature.State HALF_OPENED;
+  }
+
+  public static final class FoldingFeature.State.Companion {
+  }
+
+  public static final class FoldingFeature.Type {
+    field public static final androidx.window.FoldingFeature.Type.Companion Companion;
+    field public static final androidx.window.FoldingFeature.Type FOLD;
+    field public static final androidx.window.FoldingFeature.Type HINGE;
+  }
+
+  public static final class FoldingFeature.Type.Companion {
+  }
+
   public interface WindowBackend {
     method public void registerLayoutChangeCallback(android.app.Activity activity, java.util.concurrent.Executor executor, androidx.core.util.Consumer<androidx.window.WindowLayoutInfo> callback);
     method public void unregisterLayoutChangeCallback(androidx.core.util.Consumer<androidx.window.WindowLayoutInfo> callback);
diff --git a/window/window/api/public_plus_experimental_current.txt b/window/window/api/public_plus_experimental_current.txt
index 5afd4dd..08b7a99 100644
--- a/window/window/api/public_plus_experimental_current.txt
+++ b/window/window/api/public_plus_experimental_current.txt
@@ -11,17 +11,17 @@
   }
 
   public final class FoldingFeature implements androidx.window.DisplayFeature {
-    ctor public FoldingFeature(android.graphics.Rect bounds, int type, int state);
+    ctor public FoldingFeature(android.graphics.Rect bounds, androidx.window.FoldingFeature.Type type, androidx.window.FoldingFeature.State state);
     method public android.graphics.Rect getBounds();
-    method public int getOcclusionMode();
-    method public int getOrientation();
-    method public int getState();
+    method public androidx.window.FoldingFeature.OcclusionType getOcclusionType();
+    method public androidx.window.FoldingFeature.Orientation getOrientation();
+    method public androidx.window.FoldingFeature.State getState();
     method public boolean isSeparating();
     property public android.graphics.Rect bounds;
     property public final boolean isSeparating;
-    property public final int occlusionMode;
-    property public final int orientation;
-    property public final int state;
+    property public final androidx.window.FoldingFeature.OcclusionType occlusionType;
+    property public final androidx.window.FoldingFeature.Orientation orientation;
+    property public final androidx.window.FoldingFeature.State state;
     field public static final androidx.window.FoldingFeature.Companion Companion;
     field public static final int OCCLUSION_FULL = 1; // 0x1
     field public static final int OCCLUSION_NONE = 0; // 0x0
@@ -36,6 +36,42 @@
   public static final class FoldingFeature.Companion {
   }
 
+  public static final class FoldingFeature.OcclusionType {
+    field public static final androidx.window.FoldingFeature.OcclusionType.Companion Companion;
+    field public static final androidx.window.FoldingFeature.OcclusionType FULL;
+    field public static final androidx.window.FoldingFeature.OcclusionType NONE;
+  }
+
+  public static final class FoldingFeature.OcclusionType.Companion {
+  }
+
+  public static final class FoldingFeature.Orientation {
+    field public static final androidx.window.FoldingFeature.Orientation.Companion Companion;
+    field public static final androidx.window.FoldingFeature.Orientation HORIZONTAL;
+    field public static final androidx.window.FoldingFeature.Orientation VERTICAL;
+  }
+
+  public static final class FoldingFeature.Orientation.Companion {
+  }
+
+  public static final class FoldingFeature.State {
+    field public static final androidx.window.FoldingFeature.State.Companion Companion;
+    field public static final androidx.window.FoldingFeature.State FLAT;
+    field public static final androidx.window.FoldingFeature.State HALF_OPENED;
+  }
+
+  public static final class FoldingFeature.State.Companion {
+  }
+
+  public static final class FoldingFeature.Type {
+    field public static final androidx.window.FoldingFeature.Type.Companion Companion;
+    field public static final androidx.window.FoldingFeature.Type FOLD;
+    field public static final androidx.window.FoldingFeature.Type HINGE;
+  }
+
+  public static final class FoldingFeature.Type.Companion {
+  }
+
   public interface WindowBackend {
     method public void registerLayoutChangeCallback(android.app.Activity activity, java.util.concurrent.Executor executor, androidx.core.util.Consumer<androidx.window.WindowLayoutInfo> callback);
     method public void unregisterLayoutChangeCallback(androidx.core.util.Consumer<androidx.window.WindowLayoutInfo> callback);
diff --git a/window/window/api/restricted_current.txt b/window/window/api/restricted_current.txt
index 0f592ee..30cc520 100644
--- a/window/window/api/restricted_current.txt
+++ b/window/window/api/restricted_current.txt
@@ -10,17 +10,17 @@
   }
 
   public final class FoldingFeature implements androidx.window.DisplayFeature {
-    ctor public FoldingFeature(android.graphics.Rect bounds, int type, int state);
+    ctor public FoldingFeature(android.graphics.Rect bounds, androidx.window.FoldingFeature.Type type, androidx.window.FoldingFeature.State state);
     method public android.graphics.Rect getBounds();
-    method public int getOcclusionMode();
-    method public int getOrientation();
-    method public int getState();
+    method public androidx.window.FoldingFeature.OcclusionType getOcclusionType();
+    method public androidx.window.FoldingFeature.Orientation getOrientation();
+    method public androidx.window.FoldingFeature.State getState();
     method public boolean isSeparating();
     property public android.graphics.Rect bounds;
     property public final boolean isSeparating;
-    property public final int occlusionMode;
-    property public final int orientation;
-    property public final int state;
+    property public final androidx.window.FoldingFeature.OcclusionType occlusionType;
+    property public final androidx.window.FoldingFeature.Orientation orientation;
+    property public final androidx.window.FoldingFeature.State state;
     field public static final androidx.window.FoldingFeature.Companion Companion;
     field public static final int OCCLUSION_FULL = 1; // 0x1
     field public static final int OCCLUSION_NONE = 0; // 0x0
@@ -35,6 +35,42 @@
   public static final class FoldingFeature.Companion {
   }
 
+  public static final class FoldingFeature.OcclusionType {
+    field public static final androidx.window.FoldingFeature.OcclusionType.Companion Companion;
+    field public static final androidx.window.FoldingFeature.OcclusionType FULL;
+    field public static final androidx.window.FoldingFeature.OcclusionType NONE;
+  }
+
+  public static final class FoldingFeature.OcclusionType.Companion {
+  }
+
+  public static final class FoldingFeature.Orientation {
+    field public static final androidx.window.FoldingFeature.Orientation.Companion Companion;
+    field public static final androidx.window.FoldingFeature.Orientation HORIZONTAL;
+    field public static final androidx.window.FoldingFeature.Orientation VERTICAL;
+  }
+
+  public static final class FoldingFeature.Orientation.Companion {
+  }
+
+  public static final class FoldingFeature.State {
+    field public static final androidx.window.FoldingFeature.State.Companion Companion;
+    field public static final androidx.window.FoldingFeature.State FLAT;
+    field public static final androidx.window.FoldingFeature.State HALF_OPENED;
+  }
+
+  public static final class FoldingFeature.State.Companion {
+  }
+
+  public static final class FoldingFeature.Type {
+    field public static final androidx.window.FoldingFeature.Type.Companion Companion;
+    field public static final androidx.window.FoldingFeature.Type FOLD;
+    field public static final androidx.window.FoldingFeature.Type HINGE;
+  }
+
+  public static final class FoldingFeature.Type.Companion {
+  }
+
   public interface WindowBackend {
     method public void registerLayoutChangeCallback(android.app.Activity activity, java.util.concurrent.Executor executor, androidx.core.util.Consumer<androidx.window.WindowLayoutInfo> callback);
     method public void unregisterLayoutChangeCallback(androidx.core.util.Consumer<androidx.window.WindowLayoutInfo> callback);
diff --git a/window/window/src/androidTest/java/androidx/window/ExtensionAdapterTest.kt b/window/window/src/androidTest/java/androidx/window/ExtensionAdapterTest.kt
index b67c9ff..9fca4e6 100644
--- a/window/window/src/androidTest/java/androidx/window/ExtensionAdapterTest.kt
+++ b/window/window/src/androidTest/java/androidx/window/ExtensionAdapterTest.kt
@@ -17,8 +17,13 @@
 
 import android.app.Activity
 import android.graphics.Rect
+import androidx.window.FoldingFeature.State.Companion.FLAT
+import androidx.window.FoldingFeature.Type.Companion.FOLD
 import androidx.window.extensions.ExtensionDisplayFeature
 import androidx.window.extensions.ExtensionFoldingFeature
+import androidx.window.extensions.ExtensionFoldingFeature.STATE_FLAT
+import androidx.window.extensions.ExtensionFoldingFeature.TYPE_FOLD
+import androidx.window.extensions.ExtensionFoldingFeature.TYPE_HINGE
 import androidx.window.extensions.ExtensionWindowLayoutInfo
 import com.nhaarman.mockitokotlin2.mock
 import org.junit.After
@@ -54,15 +59,10 @@
     override fun testTranslate_validFeature() {
         val mockActivity = mock<Activity>()
         val bounds = Rect(WINDOW_BOUNDS.left, 0, WINDOW_BOUNDS.right, 0)
-        val foldFeature: ExtensionDisplayFeature = ExtensionFoldingFeature(
-            bounds,
-            ExtensionFoldingFeature.TYPE_FOLD, ExtensionFoldingFeature.STATE_FLAT
-        )
+        val foldFeature = ExtensionFoldingFeature(bounds, TYPE_FOLD, STATE_FLAT)
         val extensionDisplayFeatures = listOf(foldFeature)
         val windowLayoutInfo = ExtensionWindowLayoutInfo(extensionDisplayFeatures)
-        val expectedFeatures = listOf(
-            FoldingFeature(foldFeature.bounds, FoldingFeature.TYPE_FOLD, FoldingFeature.STATE_FLAT)
-        )
+        val expectedFeatures = listOf(FoldingFeature(Bounds(foldFeature.bounds), FOLD, FLAT))
         val expected = WindowLayoutInfo(expectedFeatures)
         val adapter = ExtensionAdapter()
         val actual = adapter.translate(mockActivity, windowLayoutInfo)
@@ -80,14 +80,8 @@
             WINDOW_BOUNDS.bottom / 2
         )
         val extensionDisplayFeatures = listOf(
-            ExtensionFoldingFeature(
-                fullWidthBounds,
-                ExtensionFoldingFeature.TYPE_HINGE, ExtensionFoldingFeature.STATE_FLAT
-            ),
-            ExtensionFoldingFeature(
-                fullHeightBounds,
-                ExtensionFoldingFeature.TYPE_HINGE, ExtensionFoldingFeature.STATE_FLAT
-            )
+            ExtensionFoldingFeature(fullWidthBounds, TYPE_HINGE, STATE_FLAT),
+            ExtensionFoldingFeature(fullHeightBounds, TYPE_HINGE, STATE_FLAT)
         )
         val extensionCallbackAdapter = ExtensionAdapter()
         val windowLayoutInfo = ExtensionWindowLayoutInfo(extensionDisplayFeatures)
@@ -113,14 +107,8 @@
             WINDOW_BOUNDS.bottom / 2
         )
         val extensionDisplayFeatures = listOf(
-            ExtensionFoldingFeature(
-                fullWidthBounds,
-                ExtensionFoldingFeature.TYPE_HINGE, ExtensionFoldingFeature.STATE_FLAT
-            ),
-            ExtensionFoldingFeature(
-                fullHeightBounds,
-                ExtensionFoldingFeature.TYPE_HINGE, ExtensionFoldingFeature.STATE_FLAT
-            )
+            ExtensionFoldingFeature(fullWidthBounds, TYPE_HINGE, STATE_FLAT),
+            ExtensionFoldingFeature(fullHeightBounds, TYPE_HINGE, STATE_FLAT)
         )
         val adapter = ExtensionAdapter()
         val windowLayoutInfo = ExtensionWindowLayoutInfo(extensionDisplayFeatures)
@@ -137,7 +125,7 @@
         val bounds = Rect(WINDOW_BOUNDS.left, 0, WINDOW_BOUNDS.right, 0)
         val foldFeature: ExtensionDisplayFeature = ExtensionFoldingFeature(
             bounds,
-            0 /* unknown */, ExtensionFoldingFeature.STATE_FLAT
+            0 /* unknown */, STATE_FLAT
         )
         val extensionDisplayFeatures = listOf(foldFeature)
         val windowLayoutInfo = ExtensionWindowLayoutInfo(extensionDisplayFeatures)
diff --git a/window/window/src/androidTest/java/androidx/window/ExtensionTranslatingCallbackTest.kt b/window/window/src/androidTest/java/androidx/window/ExtensionTranslatingCallbackTest.kt
index f093695..729ec4c 100644
--- a/window/window/src/androidTest/java/androidx/window/ExtensionTranslatingCallbackTest.kt
+++ b/window/window/src/androidTest/java/androidx/window/ExtensionTranslatingCallbackTest.kt
@@ -18,8 +18,12 @@
 import android.app.Activity
 import android.graphics.Rect
 import androidx.window.ExtensionInterfaceCompat.ExtensionCallbackInterface
+import androidx.window.FoldingFeature.State.Companion.FLAT
+import androidx.window.FoldingFeature.Type.Companion.FOLD
 import androidx.window.extensions.ExtensionDisplayFeature
 import androidx.window.extensions.ExtensionFoldingFeature
+import androidx.window.extensions.ExtensionFoldingFeature.STATE_FLAT
+import androidx.window.extensions.ExtensionFoldingFeature.TYPE_HINGE
 import androidx.window.extensions.ExtensionWindowLayoutInfo
 import com.nhaarman.mockitokotlin2.argThat
 import com.nhaarman.mockitokotlin2.argumentCaptor
@@ -53,16 +57,11 @@
         val bounds = Rect(WINDOW_BOUNDS.left, 0, WINDOW_BOUNDS.right, 0)
         val foldFeature: ExtensionDisplayFeature = ExtensionFoldingFeature(
             bounds,
-            ExtensionFoldingFeature.TYPE_FOLD, ExtensionFoldingFeature.STATE_FLAT
+            ExtensionFoldingFeature.TYPE_FOLD, STATE_FLAT
         )
         val extensionDisplayFeatures = listOf(foldFeature)
         val windowLayoutInfo = ExtensionWindowLayoutInfo(extensionDisplayFeatures)
-        val expectedFeatures = listOf(
-            FoldingFeature(
-                foldFeature.bounds, FoldingFeature.TYPE_FOLD,
-                FoldingFeature.STATE_FLAT
-            )
-        )
+        val expectedFeatures = listOf(FoldingFeature(Bounds(foldFeature.bounds), FOLD, FLAT))
         val expected = WindowLayoutInfo(expectedFeatures)
         val mockCallback = mock<ExtensionCallbackInterface>()
         val extensionTranslatingCallback =
@@ -85,14 +84,8 @@
             WINDOW_BOUNDS.bottom / 2
         )
         val extensionDisplayFeatures = listOf(
-            ExtensionFoldingFeature(
-                fullWidthBounds,
-                ExtensionFoldingFeature.TYPE_HINGE, ExtensionFoldingFeature.STATE_FLAT
-            ),
-            ExtensionFoldingFeature(
-                fullHeightBounds,
-                ExtensionFoldingFeature.TYPE_HINGE, ExtensionFoldingFeature.STATE_FLAT
-            )
+            ExtensionFoldingFeature(fullWidthBounds, TYPE_HINGE, STATE_FLAT),
+            ExtensionFoldingFeature(fullHeightBounds, TYPE_HINGE, STATE_FLAT)
         )
         val mockCallback = mock<ExtensionCallbackInterface>()
         val extensionTranslatingCallback =
@@ -119,11 +112,11 @@
         val extensionDisplayFeatures = listOf(
             ExtensionFoldingFeature(
                 fullWidthBounds,
-                ExtensionFoldingFeature.TYPE_HINGE, ExtensionFoldingFeature.STATE_FLAT
+                TYPE_HINGE, STATE_FLAT
             ),
             ExtensionFoldingFeature(
                 fullHeightBounds,
-                ExtensionFoldingFeature.TYPE_HINGE, ExtensionFoldingFeature.STATE_FLAT
+                TYPE_HINGE, STATE_FLAT
             )
         )
         val mockCallback = mock<ExtensionCallbackInterface>()
diff --git a/window/window/src/androidTest/java/androidx/window/ExtensionWindowBackendTest.kt b/window/window/src/androidTest/java/androidx/window/ExtensionWindowBackendTest.kt
index 51d5e6b..3b0b922 100644
--- a/window/window/src/androidTest/java/androidx/window/ExtensionWindowBackendTest.kt
+++ b/window/window/src/androidTest/java/androidx/window/ExtensionWindowBackendTest.kt
@@ -17,11 +17,12 @@
 
 import android.app.Activity
 import android.content.Context
-import android.graphics.Rect
 import androidx.core.util.Consumer
 import androidx.test.core.app.ApplicationProvider
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.LargeTest
+import androidx.window.FoldingFeature.State.Companion.FLAT
+import androidx.window.FoldingFeature.Type.Companion.HINGE
 import com.google.common.util.concurrent.MoreExecutors
 import com.nhaarman.mockitokotlin2.eq
 import com.nhaarman.mockitokotlin2.mock
@@ -198,14 +199,8 @@
             var builder = WindowLayoutInfo.Builder()
             val windowLayoutInfo = builder.build()
             assertTrue(windowLayoutInfo.displayFeatures.isEmpty())
-            val feature1: DisplayFeature = FoldingFeature(
-                Rect(0, 2, 3, 4),
-                FoldingFeature.TYPE_HINGE, FoldingFeature.STATE_FLAT
-            )
-            val feature2: DisplayFeature = FoldingFeature(
-                Rect(0, 1, 5, 1),
-                FoldingFeature.TYPE_HINGE, FoldingFeature.STATE_FLAT
-            )
+            val feature1: DisplayFeature = FoldingFeature(Bounds(0, 2, 3, 4), HINGE, FLAT)
+            val feature2: DisplayFeature = FoldingFeature(Bounds(0, 1, 5, 1), HINGE, FLAT)
             val displayFeatures = listOf(feature1, feature2)
             builder = WindowLayoutInfo.Builder()
             builder.setDisplayFeatures(displayFeatures)
diff --git a/window/window/src/androidTest/java/androidx/window/FoldingFeatureTest.kt b/window/window/src/androidTest/java/androidx/window/FoldingFeatureTest.kt
index 2515fec..95f589f 100644
--- a/window/window/src/androidTest/java/androidx/window/FoldingFeatureTest.kt
+++ b/window/window/src/androidTest/java/androidx/window/FoldingFeatureTest.kt
@@ -15,10 +15,14 @@
  */
 package androidx.window
 
-import android.graphics.Rect
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import androidx.window.FoldingFeature.OcclusionType
+import androidx.window.FoldingFeature.Orientation
+import androidx.window.FoldingFeature.State.Companion.FLAT
+import androidx.window.FoldingFeature.State.Companion.HALF_OPENED
+import androidx.window.FoldingFeature.Type.Companion.FOLD
+import androidx.window.FoldingFeature.Type.Companion.HINGE
 import androidx.window.TestFoldingFeatureUtil.allFoldStates
 import androidx.window.TestFoldingFeatureUtil.allFoldingFeatureTypeAndStates
 import org.junit.Assert.assertEquals
@@ -35,71 +39,45 @@
 
     @Test(expected = IllegalArgumentException::class)
     public fun tesEmptyRect() {
-        FoldingFeature(Rect(), FoldingFeature.TYPE_HINGE, FoldingFeature.STATE_HALF_OPENED)
+        FoldingFeature(Bounds(0, 0, 0, 0), HINGE, HALF_OPENED)
     }
 
     @Test(expected = IllegalArgumentException::class)
     public fun testHorizontalHingeWithNonZeroOrigin() {
-        FoldingFeature(
-            Rect(1, 10, 20, 10),
-            FoldingFeature.TYPE_HINGE,
-            FoldingFeature.STATE_HALF_OPENED
-        )
+        FoldingFeature(Bounds(1, 10, 20, 10), HINGE, HALF_OPENED)
     }
 
     @Test(expected = IllegalArgumentException::class)
     public fun testVerticalHingeWithNonZeroOrigin() {
-        FoldingFeature(
-            Rect(10, 1, 19, 29),
-            FoldingFeature.TYPE_HINGE,
-            FoldingFeature.STATE_HALF_OPENED
-        )
+        FoldingFeature(Bounds(10, 1, 19, 29), HINGE, HALF_OPENED)
     }
 
     @Test(expected = IllegalArgumentException::class)
     public fun testHorizontalFoldWithNonZeroOrigin() {
-        FoldingFeature(
-            Rect(1, 10, 20, 10),
-            FoldingFeature.TYPE_FOLD,
-            FoldingFeature.STATE_HALF_OPENED
-        )
+        FoldingFeature(Bounds(1, 10, 20, 10), FOLD, HALF_OPENED)
     }
 
     @Test(expected = IllegalArgumentException::class)
     public fun testVerticalFoldWithNonZeroOrigin() {
-        FoldingFeature(
-            Rect(10, 1, 10, 20),
-            FoldingFeature.TYPE_FOLD,
-            FoldingFeature.STATE_HALF_OPENED
-        )
-    }
-
-    @Test(expected = IllegalArgumentException::class)
-    public fun testInvalidType() {
-        FoldingFeature(Rect(0, 10, 30, 10), -1, FoldingFeature.STATE_HALF_OPENED)
-    }
-
-    @Test(expected = IllegalArgumentException::class)
-    public fun testInvalidState() {
-        FoldingFeature(Rect(0, 10, 30, 10), FoldingFeature.TYPE_FOLD, -1)
+        FoldingFeature(Bounds(10, 1, 10, 20), FOLD, HALF_OPENED)
     }
 
     @Test // TODO(b/173739071) remove when getType is package private
     public fun testSetBoundsAndType() {
-        val bounds = Rect(0, 10, 30, 10)
-        val type = FoldingFeature.TYPE_HINGE
-        val state = FoldingFeature.STATE_HALF_OPENED
+        val bounds = Bounds(0, 10, 30, 10)
+        val type = HINGE
+        val state = HALF_OPENED
         val feature = FoldingFeature(bounds, type, state)
-        assertEquals(bounds, feature.bounds)
-        assertEquals(type.toLong(), feature.type.toLong())
-        assertEquals(state.toLong(), feature.state.toLong())
+        assertEquals(bounds.toRect(), feature.bounds)
+        assertEquals(type, feature.type)
+        assertEquals(state, feature.state)
     }
 
     @Test
     public fun testEquals_sameAttributes() {
-        val bounds = Rect(1, 0, 1, 10)
-        val type = FoldingFeature.TYPE_FOLD
-        val state = FoldingFeature.STATE_FLAT
+        val bounds = Bounds(1, 0, 1, 10)
+        val type = FOLD
+        val state = FLAT
         val original = FoldingFeature(bounds, type, state)
         val copy = FoldingFeature(bounds, type, state)
         assertEquals(original, copy)
@@ -107,10 +85,10 @@
 
     @Test
     public fun testEquals_differentRect() {
-        val originalRect = Rect(1, 0, 1, 10)
-        val otherRect = Rect(2, 0, 2, 10)
-        val type = FoldingFeature.TYPE_FOLD
-        val state = FoldingFeature.STATE_FLAT
+        val originalRect = Bounds(1, 0, 1, 10)
+        val otherRect = Bounds(2, 0, 2, 10)
+        val type = FOLD
+        val state = FLAT
         val original = FoldingFeature(originalRect, type, state)
         val other = FoldingFeature(otherRect, type, state)
         assertNotEquals(original, other)
@@ -118,10 +96,10 @@
 
     @Test
     public fun testEquals_differentType() {
-        val rect = Rect(1, 0, 1, 10)
-        val originalType = FoldingFeature.TYPE_FOLD
-        val otherType = FoldingFeature.TYPE_HINGE
-        val state = FoldingFeature.STATE_FLAT
+        val rect = Bounds(1, 0, 1, 10)
+        val originalType = FOLD
+        val otherType = HINGE
+        val state = FLAT
         val original = FoldingFeature(rect, originalType, state)
         val other = FoldingFeature(rect, otherType, state)
         assertNotEquals(original, other)
@@ -129,10 +107,10 @@
 
     @Test
     public fun testEquals_differentState() {
-        val rect = Rect(1, 0, 1, 10)
-        val type = FoldingFeature.TYPE_FOLD
-        val originalState = FoldingFeature.STATE_FLAT
-        val otherState = FoldingFeature.STATE_HALF_OPENED
+        val rect = Bounds(1, 0, 1, 10)
+        val type = FOLD
+        val originalState = FLAT
+        val otherState = HALF_OPENED
         val original = FoldingFeature(rect, type, originalState)
         val other = FoldingFeature(rect, type, otherState)
         assertNotEquals(original, other)
@@ -140,10 +118,10 @@
 
     @Test
     public fun testHashCode_matchesIfEqual() {
-        val originalRect = Rect(1, 0, 1, 10)
-        val matchingRect = Rect(1, 0, 1, 10)
-        val type = FoldingFeature.TYPE_FOLD
-        val state = FoldingFeature.STATE_FLAT
+        val originalRect = Bounds(1, 0, 1, 10)
+        val matchingRect = Bounds(1, 0, 1, 10)
+        val type = FOLD
+        val state = FLAT
         val original = FoldingFeature(originalRect, type, state)
         val matching = FoldingFeature(matchingRect, type, state)
         assertEquals(original, matching)
@@ -152,132 +130,70 @@
 
     @Test
     public fun testIsSeparating_trueForHinge() {
-        val bounds = Rect(1, 0, 1, 10)
-        for (feature in allFoldStates(bounds, FoldingFeature.TYPE_HINGE)) {
-            assertTrue(separatingModeErrorMessage(true, feature), feature.isSeparating)
+        val bounds = Bounds(1, 0, 1, 10)
+        for (feature in allFoldStates(bounds, HINGE)) {
+            assertTrue(feature.isSeparating)
         }
     }
 
     @Test
     public fun testIsSeparating_falseForFlatFold() {
-        val bounds = Rect(1, 0, 1, 10)
-        val feature = FoldingFeature(bounds, FoldingFeature.TYPE_FOLD, FoldingFeature.STATE_FLAT)
-        assertFalse(separatingModeErrorMessage(false, feature), feature.isSeparating)
+        val bounds = Bounds(1, 0, 1, 10)
+        val feature = FoldingFeature(bounds, FOLD, FLAT)
+        assertFalse(feature.isSeparating)
     }
 
     @Test
     public fun testIsSeparating_trueForNotFlatFold() {
-        val bounds = Rect(1, 0, 1, 10)
+        val bounds = Bounds(1, 0, 1, 10)
         val nonFlatFeatures = mutableListOf<FoldingFeature>()
-        for (feature in allFoldStates(bounds, FoldingFeature.TYPE_FOLD)) {
-            if (feature.state != FoldingFeature.STATE_FLAT) {
+        for (feature in allFoldStates(bounds, FOLD)) {
+            if (feature.state != FLAT) {
                 nonFlatFeatures.add(feature)
             }
         }
         for (feature in nonFlatFeatures) {
-            assertTrue(separatingModeErrorMessage(true, feature), feature.isSeparating)
+            assertTrue(feature.isSeparating)
         }
     }
 
     @Test
     public fun testOcclusionTypeNone_emptyFeature() {
-        val bounds = Rect(0, 100, 100, 100)
+        val bounds = Bounds(0, 100, 100, 100)
         for (feature in allFoldingFeatureTypeAndStates(bounds)) {
-            assertEquals(
-                occlusionTypeErrorMessage(FoldingFeature.OCCLUSION_NONE, feature),
-                FoldingFeature.OCCLUSION_NONE.toLong(), feature.occlusionMode.toLong()
-            )
+            assertEquals(OcclusionType.NONE, feature.occlusionType)
         }
     }
 
     @Test
     public fun testOcclusionTypeFull_nonEmptyHingeFeature() {
-        val bounds = Rect(0, 100, 100, 101)
-        for (feature in allFoldStates(bounds, FoldingFeature.TYPE_HINGE)) {
-            assertEquals(
-                occlusionTypeErrorMessage(FoldingFeature.OCCLUSION_FULL, feature),
-                FoldingFeature.OCCLUSION_FULL.toLong(), feature.occlusionMode.toLong()
-            )
+        val bounds = Bounds(0, 100, 100, 101)
+        for (feature in allFoldStates(bounds, HINGE)) {
+            assertEquals(OcclusionType.FULL, feature.occlusionType)
         }
     }
 
     @Test
     public fun testGetFeatureOrientation_isHorizontalWhenWidthIsGreaterThanHeight() {
-        val bounds = Rect(0, 100, 200, 100)
+        val bounds = Bounds(0, 100, 200, 100)
         for (feature in allFoldingFeatureTypeAndStates(bounds)) {
-            assertEquals(
-                featureOrientationErrorMessage(FoldingFeature.ORIENTATION_HORIZONTAL, feature),
-                FoldingFeature.ORIENTATION_HORIZONTAL.toLong(), feature.orientation.toLong()
-            )
+            assertEquals(Orientation.HORIZONTAL, feature.orientation)
         }
     }
 
     @Test
     public fun testGetFeatureOrientation_isVerticalWhenHeightIsGreaterThanWidth() {
-        val bounds = Rect(100, 0, 100, 200)
+        val bounds = Bounds(100, 0, 100, 200)
         for (feature in allFoldingFeatureTypeAndStates(bounds)) {
-            assertEquals(
-                featureOrientationErrorMessage(FoldingFeature.ORIENTATION_VERTICAL, feature),
-                FoldingFeature.ORIENTATION_VERTICAL.toLong(), feature.orientation.toLong()
-            )
+            assertEquals(Orientation.VERTICAL, feature.orientation)
         }
     }
 
     @Test
     public fun testGetFeatureOrientation_isVerticalWhenHeightIsEqualToWidth() {
-        val bounds = Rect(0, 0, 100, 100)
+        val bounds = Bounds(0, 0, 100, 100)
         for (feature in allFoldingFeatureTypeAndStates(bounds)) {
-            assertEquals(
-                featureOrientationErrorMessage(FoldingFeature.ORIENTATION_VERTICAL, feature),
-                FoldingFeature.ORIENTATION_VERTICAL.toLong(), feature.orientation.toLong()
-            )
-        }
-    }
-
-    private fun separatingModeErrorMessage(expected: Boolean, feature: FoldingFeature): String {
-        return errorMessage(
-            FoldingFeature::class.java.simpleName,
-            "isSeparating",
-            expected.toString(),
-            feature.isSeparating.toString(),
-            feature
-        )
-    }
-
-    internal companion object {
-        private fun occlusionTypeErrorMessage(
-            @OcclusionType expected: Int,
-            feature: FoldingFeature
-        ): String {
-            return errorMessage(
-                FoldingFeature::class.java.simpleName, "getOcclusionMode",
-                FoldingFeature.occlusionTypeToString(expected),
-                FoldingFeature.occlusionTypeToString(feature.occlusionMode), feature
-            )
-        }
-
-        private fun featureOrientationErrorMessage(
-            @FoldingFeature.Orientation expected: Int,
-            feature: FoldingFeature
-        ): String {
-            return errorMessage(
-                FoldingFeature::class.java.simpleName, "getFeatureOrientation",
-                FoldingFeature.orientationToString(expected),
-                FoldingFeature.orientationToString(feature.orientation), feature
-            )
-        }
-
-        private fun errorMessage(
-            className: String,
-            methodName: String,
-            expected: String,
-            actual: String,
-            value: Any
-        ): String {
-            return String.format(
-                "%s#%s was expected to be %s but was %s. %s: %s", className,
-                methodName, expected, actual, className, value.toString()
-            )
+            assertEquals(Orientation.VERTICAL, feature.orientation)
         }
     }
 }
diff --git a/window/window/src/androidTest/java/androidx/window/SidecarAdapterTest.kt b/window/window/src/androidTest/java/androidx/window/SidecarAdapterTest.kt
index 69abf1d..55786fe 100644
--- a/window/window/src/androidTest/java/androidx/window/SidecarAdapterTest.kt
+++ b/window/window/src/androidTest/java/androidx/window/SidecarAdapterTest.kt
@@ -19,6 +19,8 @@
 package androidx.window
 
 import android.graphics.Rect
+import androidx.window.FoldingFeature.State.Companion.FLAT
+import androidx.window.FoldingFeature.Type.Companion.FOLD
 import androidx.window.sidecar.SidecarDeviceState
 import androidx.window.sidecar.SidecarDisplayFeature
 import androidx.window.sidecar.SidecarWindowLayoutInfo
@@ -54,12 +56,7 @@
         val sidecarDisplayFeatures = listOf(foldFeature)
         val windowLayoutInfo = sidecarWindowLayoutInfo(sidecarDisplayFeatures)
         val state = sidecarDeviceState(SidecarDeviceState.POSTURE_OPENED)
-        val expectedFeatures = listOf(
-            FoldingFeature(
-                foldFeature.rect, FoldingFeature.TYPE_FOLD,
-                FoldingFeature.STATE_FLAT
-            )
-        )
+        val expectedFeatures = listOf(FoldingFeature(Bounds(foldFeature.rect), FOLD, FLAT))
         val expected = WindowLayoutInfo(expectedFeatures)
         val sidecarAdapter = SidecarAdapter()
         val actual = sidecarAdapter.translate(windowLayoutInfo, state)
diff --git a/window/window/src/androidTest/java/androidx/window/SidecarCompatDeviceTest.kt b/window/window/src/androidTest/java/androidx/window/SidecarCompatDeviceTest.kt
index a3a0a0e..d7ba2e3 100644
--- a/window/window/src/androidTest/java/androidx/window/SidecarCompatDeviceTest.kt
+++ b/window/window/src/androidTest/java/androidx/window/SidecarCompatDeviceTest.kt
@@ -23,6 +23,9 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.LargeTest
 import androidx.window.ExtensionInterfaceCompat.ExtensionCallbackInterface
+import androidx.window.FoldingFeature.Type.Companion.FOLD
+import androidx.window.FoldingFeature.Type.Companion.HINGE
+import androidx.window.sidecar.SidecarDisplayFeature
 import androidx.window.sidecar.SidecarWindowLayoutInfo
 import com.nhaarman.mockitokotlin2.any
 import com.nhaarman.mockitokotlin2.argThat
@@ -86,7 +89,7 @@
                 // Sidecar only has folding features
                 val feature = windowLayoutInfo.displayFeatures[i] as FoldingFeature
                 val sidecarDisplayFeature = sidecarDisplayFeatures[i]
-                if (feature.type != sidecarDisplayFeature.type) {
+                if (!hasMatchingType(feature.type, sidecarDisplayFeature.type)) {
                     return false
                 }
                 if (feature.bounds != sidecarDisplayFeature.rect) {
@@ -95,5 +98,13 @@
             }
             return true
         }
+
+        private fun hasMatchingType(featureType: FoldingFeature.Type, sidecarType: Int): Boolean {
+            return when (featureType) {
+                FOLD -> sidecarType == SidecarDisplayFeature.TYPE_FOLD
+                HINGE -> sidecarType == SidecarDisplayFeature.TYPE_HINGE
+                else -> false
+            }
+        }
     }
 }
diff --git a/window/window/src/androidTest/java/androidx/window/SidecarCompatTest.kt b/window/window/src/androidTest/java/androidx/window/SidecarCompatTest.kt
index 71a1733..823d963 100644
--- a/window/window/src/androidTest/java/androidx/window/SidecarCompatTest.kt
+++ b/window/window/src/androidTest/java/androidx/window/SidecarCompatTest.kt
@@ -28,6 +28,8 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.LargeTest
 import androidx.window.ExtensionInterfaceCompat.ExtensionCallbackInterface
+import androidx.window.FoldingFeature.State.Companion.FLAT
+import androidx.window.FoldingFeature.State.Companion.HALF_OPENED
 import androidx.window.TestFoldingFeatureUtil.invalidFoldBounds
 import androidx.window.TestFoldingFeatureUtil.validFoldBound
 import androidx.window.sidecar.SidecarDeviceState
@@ -397,19 +399,13 @@
         verify(mockCallback).onWindowLayoutChanged(eq(activity), windowLayoutCaptor.capture())
         var capturedFoldingFeature = windowLayoutCaptor.firstValue
             .displayFeatures[0] as FoldingFeature
-        assertEquals(
-            FoldingFeature.STATE_FLAT.toLong(),
-            capturedFoldingFeature.state.toLong()
-        )
+        assertEquals(FLAT, capturedFoldingFeature.state)
         reset(mockCallback)
         fakeSidecarImp.triggerDeviceState(newDeviceState(SidecarDeviceState.POSTURE_HALF_OPENED))
         verify(mockCallback)
             .onWindowLayoutChanged(eq(activity), windowLayoutCaptor.capture())
         capturedFoldingFeature = windowLayoutCaptor.secondValue.displayFeatures[0] as FoldingFeature
-        assertEquals(
-            FoldingFeature.STATE_HALF_OPENED.toLong(),
-            capturedFoldingFeature.state.toLong()
-        )
+        assertEquals(HALF_OPENED, capturedFoldingFeature.state)
 
         // No display features must be reported in closed state or flipped state.
         reset(mockCallback)
diff --git a/window/window/src/androidTest/java/androidx/window/WindowBackendTest.kt b/window/window/src/androidTest/java/androidx/window/WindowBackendTest.kt
index fce69cd..6cad0b7 100644
--- a/window/window/src/androidTest/java/androidx/window/WindowBackendTest.kt
+++ b/window/window/src/androidTest/java/androidx/window/WindowBackendTest.kt
@@ -16,15 +16,16 @@
 package androidx.window
 
 import android.app.Activity
-import android.graphics.Rect
 import androidx.core.util.Consumer
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.LargeTest
+import androidx.window.FoldingFeature.State.Companion.FLAT
+import androidx.window.FoldingFeature.Type.Companion.HINGE
 import com.google.common.util.concurrent.MoreExecutors
+import com.nhaarman.mockitokotlin2.mock
+import com.nhaarman.mockitokotlin2.verify
 import org.junit.Test
 import org.junit.runner.RunWith
-import org.mockito.Mockito.mock
-import org.mockito.Mockito.verify
 import java.util.concurrent.Executor
 
 /** Tests for [WindowBackend] class.  */
@@ -42,24 +43,17 @@
         val windowBackend: WindowBackend = FakeWindowBackend(windowLayoutInfo)
         activityTestRule.scenario.onActivity { activity ->
             val wm = WindowManager(activity, windowBackend)
-            val layoutInfoConsumer: Consumer<WindowLayoutInfo> = mock(
-                WindowLayoutInfoConsumer::class.java
-            )
+            val layoutInfoConsumer = mock<Consumer<WindowLayoutInfo>>()
             wm.registerLayoutChangeCallback(MoreExecutors.directExecutor(), layoutInfoConsumer)
             verify(layoutInfoConsumer).accept(windowLayoutInfo)
         }
     }
 
     private fun newTestWindowLayout(): WindowLayoutInfo {
-        val displayFeature: DisplayFeature = FoldingFeature(
-            Rect(10, 0, 10, 100), FoldingFeature.TYPE_HINGE,
-            FoldingFeature.STATE_FLAT
-        )
+        val displayFeature = FoldingFeature(Bounds(10, 0, 10, 100), HINGE, FLAT)
         return WindowLayoutInfo(listOf(displayFeature))
     }
 
-    private interface WindowLayoutInfoConsumer : Consumer<WindowLayoutInfo>
-
     private class FakeWindowBackend(private val windowLayoutInfo: WindowLayoutInfo) :
         WindowBackend {
         override fun registerLayoutChangeCallback(
diff --git a/window/window/src/androidTest/java/androidx/window/WindowLayoutInfoTest.kt b/window/window/src/androidTest/java/androidx/window/WindowLayoutInfoTest.kt
index 24f7639..b0a4521 100644
--- a/window/window/src/androidTest/java/androidx/window/WindowLayoutInfoTest.kt
+++ b/window/window/src/androidTest/java/androidx/window/WindowLayoutInfoTest.kt
@@ -15,9 +15,11 @@
  */
 package androidx.window
 
-import android.graphics.Rect
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
+import androidx.window.FoldingFeature.State.Companion.FLAT
+import androidx.window.FoldingFeature.State.Companion.HALF_OPENED
+import androidx.window.FoldingFeature.Type.Companion.HINGE
 import com.google.common.truth.Truth.assertThat
 import org.junit.Assert.assertEquals
 import org.junit.Assert.assertNotEquals
@@ -38,14 +40,8 @@
 
     @Test
     public fun testBuilder_setDisplayFeatures() {
-        val feature1: DisplayFeature = FoldingFeature(
-            Rect(1, 0, 3, 4),
-            FoldingFeature.TYPE_HINGE, FoldingFeature.STATE_FLAT
-        )
-        val feature2: DisplayFeature = FoldingFeature(
-            Rect(1, 0, 1, 4),
-            FoldingFeature.STATE_FLAT, FoldingFeature.STATE_FLAT
-        )
+        val feature1: DisplayFeature = FoldingFeature(Bounds(1, 0, 3, 4), HINGE, FLAT)
+        val feature2: DisplayFeature = FoldingFeature(Bounds(1, 0, 1, 4), HINGE, HALF_OPENED)
         val displayFeatures = listOf(feature1, feature2)
         val builder = WindowLayoutInfo.Builder()
         builder.setDisplayFeatures(displayFeatures)
@@ -64,13 +60,8 @@
     @Test
     public fun testEquals_differentFeatures() {
         val originalFeatures = listOf<DisplayFeature>()
-        val rect = Rect(1, 0, 1, 10)
-        val differentFeatures = listOf(
-            FoldingFeature(
-                rect, FoldingFeature.TYPE_HINGE,
-                FoldingFeature.STATE_FLAT
-            )
-        )
+        val rect = Bounds(1, 0, 1, 10)
+        val differentFeatures = listOf(FoldingFeature(rect, HINGE, FLAT))
         val original = WindowLayoutInfo(originalFeatures)
         val different = WindowLayoutInfo(differentFeatures)
         assertNotEquals(original, different)
@@ -88,16 +79,8 @@
 
     @Test
     public fun testHashCode_matchesIfEqualFeatures() {
-        val originalFeature: DisplayFeature = FoldingFeature(
-            Rect(0, 0, 100, 0),
-            FoldingFeature.TYPE_HINGE,
-            FoldingFeature.STATE_FLAT
-        )
-        val matchingFeature: DisplayFeature = FoldingFeature(
-            Rect(0, 0, 100, 0),
-            FoldingFeature.TYPE_HINGE,
-            FoldingFeature.STATE_FLAT
-        )
+        val originalFeature: DisplayFeature = FoldingFeature(Bounds(0, 0, 100, 0), HINGE, FLAT)
+        val matchingFeature: DisplayFeature = FoldingFeature(Bounds(0, 0, 100, 0), HINGE, FLAT)
         val firstFeatures = listOf(originalFeature)
         val secondFeatures = listOf(matchingFeature)
         val first = WindowLayoutInfo(firstFeatures)
diff --git a/window/window/src/main/java/androidx/window/Bounds.kt b/window/window/src/main/java/androidx/window/Bounds.kt
index a6681a1..e7b5cd2 100644
--- a/window/window/src/main/java/androidx/window/Bounds.kt
+++ b/window/window/src/main/java/androidx/window/Bounds.kt
@@ -28,35 +28,34 @@
  * not contain any behavior or calculations.
  */
 internal class Bounds(
-    val left: Int,
-    val top: Int,
-    val right: Int,
-    val bottom: Int
+    public val left: Int,
+    public val top: Int,
+    public val right: Int,
+    public val bottom: Int
 ) {
-
-    constructor(rect: Rect) : this(rect.left, rect.top, rect.right, rect.bottom)
+    public constructor(rect: Rect) : this(rect.left, rect.top, rect.right, rect.bottom)
 
     /**
      * Return the [Rect] representation of the bounds
      */
-    fun toRect(): Rect = Rect(left, top, right, bottom)
+    public fun toRect(): Rect = Rect(left, top, right, bottom)
 
     /**
      * The width of the bounds, may be negative.
      */
-    val width: Int
+    public val width: Int
         get() = right - left
 
     /**
      * The height of the bounds, may be negative.
      */
-    val height: Int
+    public val height: Int
         get() = bottom - top
 
     /**
      * Determines if the bounds has empty area.
      */
-    val isEmpty: Boolean
+    public val isEmpty: Boolean
         get() = height == 0 || width == 0
 
     override fun toString(): String {
diff --git a/window/window/src/main/java/androidx/window/ExtensionAdapter.kt b/window/window/src/main/java/androidx/window/ExtensionAdapter.kt
index 9102d00..d36fd6f 100644
--- a/window/window/src/main/java/androidx/window/ExtensionAdapter.kt
+++ b/window/window/src/main/java/androidx/window/ExtensionAdapter.kt
@@ -62,8 +62,8 @@
                 return null
             }
             val type = when (feature.type) {
-                ExtensionFoldingFeature.TYPE_FOLD -> FoldingFeature.TYPE_FOLD
-                ExtensionFoldingFeature.TYPE_HINGE -> FoldingFeature.TYPE_HINGE
+                ExtensionFoldingFeature.TYPE_FOLD -> FoldingFeature.Type.FOLD
+                ExtensionFoldingFeature.TYPE_HINGE -> FoldingFeature.Type.HINGE
                 else -> {
                     if (ExtensionCompat.DEBUG) {
                         Log.d(TAG, "Unknown feature type: ${feature.type}, skipping feature.")
@@ -72,8 +72,8 @@
                 }
             }
             val state = when (feature.state) {
-                ExtensionFoldingFeature.STATE_FLAT -> FoldingFeature.STATE_FLAT
-                ExtensionFoldingFeature.STATE_HALF_OPENED -> FoldingFeature.STATE_HALF_OPENED
+                ExtensionFoldingFeature.STATE_FLAT -> FoldingFeature.State.FLAT
+                ExtensionFoldingFeature.STATE_HALF_OPENED -> FoldingFeature.State.HALF_OPENED
                 else -> {
                     if (ExtensionCompat.DEBUG) {
                         Log.d(TAG, "Unknown feature state: ${feature.state}, skipping feature.")
@@ -81,7 +81,7 @@
                     return null
                 }
             }
-            return FoldingFeature(feature.bounds, type, state)
+            return FoldingFeature(Bounds(feature.bounds), type, state)
         }
 
         private fun isValid(windowBounds: Rect, feature: ExtensionFoldingFeature): Boolean {
diff --git a/window/window/src/main/java/androidx/window/FoldingFeature.kt b/window/window/src/main/java/androidx/window/FoldingFeature.kt
index c3092bc..de69d1c 100644
--- a/window/window/src/main/java/androidx/window/FoldingFeature.kt
+++ b/window/window/src/main/java/androidx/window/FoldingFeature.kt
@@ -16,16 +16,14 @@
 package androidx.window
 
 import android.graphics.Rect
-import androidx.annotation.IntDef
-import androidx.window.FoldingFeature.Companion.ORIENTATION_VERTICAL as ORIENTATION_VERTICAL1
 
 /**
  * A feature that describes a fold in the flexible display
  * or a hinge between two physical display panels.
  *
- * @param [type] that is either [FoldingFeature.TYPE_FOLD] or [FoldingFeature.TYPE_HINGE]
- * @param [state] the physical state of the hinge that is either [FoldingFeature.STATE_FLAT] or
- * [FoldingFeature.STATE_HALF_OPENED]
+ * @param [type] that is either [FoldingFeature.Type.FOLD] or [FoldingFeature.Type.HINGE]
+ * @param [state] the physical state of the hinge that is either [FoldingFeature.State.FLAT] or
+ * [FoldingFeature.State.HALF_OPENED]
  */
 public class FoldingFeature internal constructor(
     /**
@@ -33,50 +31,153 @@
      * coordinate space.
      */
     private val featureBounds: Bounds,
-    @Type internal val type: Int,
-    @State public val state: Int
+    internal val type: Type,
+    public val state: State
 ) : DisplayFeature {
 
-    @Retention(AnnotationRetention.SOURCE)
-    @IntDef(TYPE_FOLD, TYPE_HINGE)
-    internal annotation class Type
+    /**
+     * Represents the type of hinge.
+     */
+    public class Type private constructor(private val description: String) {
 
-    @Retention(AnnotationRetention.SOURCE)
-    @IntDef(OCCLUSION_NONE, OCCLUSION_FULL)
-    internal annotation class OcclusionType
+        override fun toString(): String {
+            return description
+        }
 
-    @Retention(AnnotationRetention.SOURCE)
-    @IntDef(ORIENTATION_HORIZONTAL, ORIENTATION_VERTICAL1)
-    internal annotation class Orientation
+        public companion object {
+            /**
+             * Represent a continuous screen that folds.
+             */
+            @JvmField
+            public val FOLD: Type = Type("FOLD")
 
-    @Retention(AnnotationRetention.SOURCE)
-    @IntDef(STATE_HALF_OPENED, STATE_FLAT)
-    internal annotation class State
+            /**
+             * Represents a hinge connecting two separate display panels.
+             */
+            @JvmField
+            public val HINGE: Type = Type("HINGE")
+
+            internal fun from(value: Int): Type {
+                return when (value) {
+                    TYPE_FOLD -> FOLD
+                    TYPE_HINGE -> HINGE
+                    else -> throw IllegalArgumentException(
+                        "${FoldingFeature::class.java.simpleName} incorrect type value"
+                    )
+                }
+            }
+        }
+    }
+
+    /**
+     * Represents how the hinge might occlude content.
+     */
+    public class OcclusionType private constructor(private val description: String) {
+
+        override fun toString(): String {
+            return description
+        }
+
+        public companion object {
+            /**
+             * The [FoldingFeature] does not occlude the content in any way. One example is a flat
+             * continuous fold where content can stretch across the fold. Another example is a hinge
+             * that has width or height equal to 0. In this case the content is physically split
+             * across both displays, but fully visible.
+             */
+            @JvmField
+            public val NONE: OcclusionType = OcclusionType("NONE")
+
+            /**
+             * The [FoldingFeature] occludes all content. One example is a hinge that is considered
+             * to be part of the window, so that part of the UI is not visible to the user.
+             * Any content shown in the same area as the hinge may not be accessible in any way.
+             * Fully occluded areas should always be avoided when placing interactive UI elements
+             * and text.
+             */
+            @JvmField
+            public val FULL: OcclusionType = OcclusionType("FULL")
+        }
+    }
+
+    /**
+     * Represents the axis for which the [FoldingFeature] runs parallel to.
+     */
+    public class Orientation private constructor(private val description: String) {
+
+        override fun toString(): String {
+            return description
+        }
+
+        public companion object {
+
+            /**
+             * The height of the [FoldingFeature] is greater than or equal to the width.
+             */
+            @JvmField
+            public val VERTICAL: Orientation = Orientation("VERTICAL")
+
+            /**
+             * The width of the [FoldingFeature] is greater than the height.
+             */
+            @JvmField
+            public val HORIZONTAL: Orientation = Orientation("HORIZONTAL")
+        }
+    }
+
+    /**
+     * Represents the [State] of the [FoldingFeature].
+     */
+    public class State private constructor(private val description: String) {
+
+        override fun toString(): String {
+            return description
+        }
+
+        public companion object {
+            /**
+             * The foldable device is completely open, the screen space that is presented to the
+             * user is flat. See the
+             * [Posture](https://developer.android.com/guide/topics/ui/foldables#postures)
+             * section in the official documentation for visual samples and references.
+             */
+            @JvmField
+            public val FLAT: State = State("FLAT")
+
+            /**
+             * The foldable device's hinge is in an intermediate position between opened and closed
+             * state, there is a non-flat angle between parts of the flexible screen or between
+             * physical screen panels. See the
+             * [Posture](https://developer.android.com/guide/topics/ui/foldables#postures)
+             * section in the official documentation for visual samples and references.
+             */
+            @JvmField
+            public val HALF_OPENED: State = State("HALF_OPENED")
+        }
+    }
 
     override val bounds: Rect
         get() = featureBounds.toRect()
 
     init {
-        validateState(state)
-        validateType(type)
         validateFeatureBounds(featureBounds)
     }
 
     public constructor(
         bounds: Rect,
-        type: Int,
-        state: Int
+        type: Type,
+        state: State
     ) : this(Bounds(bounds), type, state)
 
     /**
      * Calculates if a [FoldingFeature] should be thought of as splitting the window into
      * multiple physical areas that can be seen by users as logically separate. Display panels
      * connected by a hinge are always separated. Folds on flexible screens should be treated as
-     * separating when they are not [FoldingFeature.STATE_FLAT].
+     * separating when they are not [FoldingFeature.State.FLAT].
      *
      * Apps may use this to determine if content should lay out around the [FoldingFeature].
      * Developers should consider the placement of interactive elements. Similar to the case of
-     * [FoldingFeature.OCCLUSION_FULL], when a feature is separating then consider laying
+     * [FoldingFeature.OcclusionType.FULL], when a feature is separating then consider laying
      * out the controls around the [FoldingFeature].
      *
      * An example use case is to determine if the UI should be split into two logical areas. A
@@ -89,8 +190,8 @@
      */
     public val isSeparating: Boolean
         get() = when {
-            type == TYPE_HINGE -> true
-            type == TYPE_FOLD && state == STATE_HALF_OPENED -> true
+            type == Type.HINGE -> true
+            type == Type.FOLD && state == State.HALF_OPENED -> true
             else -> false
         }
 
@@ -100,9 +201,9 @@
      * around so that the user can access them. For some devices occluded elements can not be
      * accessed by the user at all.
      *
-     * For occlusion type [FoldingFeature.OCCLUSION_NONE] the feature can be treated as a
+     * For occlusion type [FoldingFeature.OcclusionType.NONE] the feature can be treated as a
      * guideline. One example would be for a continuously folding screen. For occlusion type
-     * [FoldingFeature.OCCLUSION_FULL] the feature should be avoided completely since content
+     * [FoldingFeature.OcclusionType.FULL] the feature should be avoided completely since content
      * will not be visible or touchable, like a hinge device with two displays.
      *
      * The occlusion mode is useful to determine if the UI needs to adapt to the
@@ -110,35 +211,33 @@
      * the occluded region if it negatively affects the gameplay.  The user can not tap
      * on the occluded interactive UI elements nor can they see important information.
      *
-     * @return [FoldingFeature.OCCLUSION_NONE] if the [FoldingFeature] has empty
+     * @return [FoldingFeature.OcclusionType.NONE] if the [FoldingFeature] has empty
      * bounds.
      */
-    @get:OcclusionType
-    public val occlusionMode: Int
+    public val occlusionType: OcclusionType
         get() = if (featureBounds.width == 0 || featureBounds.height == 0) {
-            OCCLUSION_NONE
+            OcclusionType.NONE
         } else {
-            OCCLUSION_FULL
+            OcclusionType.FULL
         }
 
     /**
-     * Returns [FoldingFeature.ORIENTATION_HORIZONTAL] if the width is greater than the
-     * height, [FoldingFeature.ORIENTATION_VERTICAL] otherwise.
+     * Returns [FoldingFeature.Orientation.HORIZONTAL] if the width is greater than the
+     * height, [FoldingFeature.Orientation.VERTICAL] otherwise.
      */
-    @get:Orientation
-    public val orientation: Int
+    public val orientation: Orientation
         get() {
             return if (featureBounds.width > featureBounds.height) {
-                ORIENTATION_HORIZONTAL
+                Orientation.HORIZONTAL
             } else {
-                ORIENTATION_VERTICAL
+                Orientation.VERTICAL
             }
         }
 
     override fun toString(): String {
         return (
             "${FoldingFeature::class.java.simpleName} { $featureBounds, " +
-                "type=${typeToString(type)}, state=${stateToString(state)} }"
+                "type=$type, state=$state }"
             )
     }
 
@@ -157,8 +256,8 @@
 
     override fun hashCode(): Int {
         var result = featureBounds.hashCode()
-        result = 31 * result + type
-        result = 31 * result + state
+        result = 31 * result + type.hashCode()
+        result = 31 * result + state.hashCode()
         return result
     }
 
@@ -216,43 +315,6 @@
          */
         public const val ORIENTATION_HORIZONTAL: Int = 1
 
-        internal fun occlusionTypeToString(@OcclusionType type: Int): String {
-            return when (type) {
-                OCCLUSION_NONE -> "OCCLUSION_NONE"
-                OCCLUSION_FULL -> "OCCLUSION_FULL"
-                else -> "UNKNOWN"
-            }
-        }
-
-        internal fun orientationToString(@Orientation direction: Int): String {
-            return when (direction) {
-                ORIENTATION_HORIZONTAL -> "ORIENTATION_HORIZONTAL"
-                ORIENTATION_VERTICAL1 -> "ORIENTATION_VERTICAL"
-                else -> "UNKNOWN"
-            }
-        }
-
-        /**
-         * Verifies the state is [FoldingFeature.STATE_FLAT] or
-         * [FoldingFeature.STATE_HALF_OPENED].
-         */
-        internal fun validateState(state: Int) {
-            require(!(state != STATE_FLAT && state != STATE_HALF_OPENED)) {
-                "State must be either ${stateToString(STATE_FLAT)} or " +
-                    stateToString(STATE_HALF_OPENED)
-            }
-        }
-
-        /**
-         * Verifies the type is either [FoldingFeature.TYPE_HINGE] or
-         * [FoldingFeature.TYPE_FOLD]
-         */
-        internal fun validateType(type: Int) {
-            require(!(type != TYPE_FOLD && type != TYPE_HINGE)) {
-                "Type must be either ${typeToString(TYPE_FOLD)} or ${typeToString(TYPE_HINGE)}"
-            }
-        }
-
         /**
          * Verifies the bounds of the folding feature.
          */
@@ -262,21 +324,5 @@
                 "Bounding rectangle must start at the top or left window edge for folding features"
             }
         }
-
-        internal fun typeToString(type: Int): String {
-            return when (type) {
-                TYPE_FOLD -> "FOLD"
-                TYPE_HINGE -> "HINGE"
-                else -> "Unknown feature type ($type)"
-            }
-        }
-
-        internal fun stateToString(state: Int): String {
-            return when (state) {
-                STATE_FLAT -> "FLAT"
-                STATE_HALF_OPENED -> "HALF_OPENED"
-                else -> "Unknown feature state ($state)"
-            }
-        }
     }
 }
diff --git a/window/window/src/main/java/androidx/window/SidecarAdapter.kt b/window/window/src/main/java/androidx/window/SidecarAdapter.kt
index 5430c9b..6fab578 100644
--- a/window/window/src/main/java/androidx/window/SidecarAdapter.kt
+++ b/window/window/src/main/java/androidx/window/SidecarAdapter.kt
@@ -321,9 +321,9 @@
                     return null
                 }
             }
-            val type: Int = when (feature.type) {
-                SidecarDisplayFeature.TYPE_FOLD -> FoldingFeature.TYPE_FOLD
-                SidecarDisplayFeature.TYPE_HINGE -> FoldingFeature.TYPE_HINGE
+            val type = when (feature.type) {
+                SidecarDisplayFeature.TYPE_FOLD -> FoldingFeature.Type.FOLD
+                SidecarDisplayFeature.TYPE_HINGE -> FoldingFeature.Type.HINGE
                 else -> {
                     if (ExtensionCompat.DEBUG) {
                         Log.d(TAG, "Unknown feature type: ${feature.type}, skipping feature.")
@@ -331,15 +331,15 @@
                     return null
                 }
             }
-            val state: Int = when (getSidecarDevicePosture(deviceState)) {
+            val state = when (getSidecarDevicePosture(deviceState)) {
                 SidecarDeviceState.POSTURE_CLOSED,
                 SidecarDeviceState.POSTURE_UNKNOWN,
                 SidecarDeviceState.POSTURE_FLIPPED -> return null
-                SidecarDeviceState.POSTURE_HALF_OPENED -> FoldingFeature.STATE_HALF_OPENED
-                SidecarDeviceState.POSTURE_OPENED -> FoldingFeature.STATE_FLAT
-                else -> FoldingFeature.STATE_FLAT
+                SidecarDeviceState.POSTURE_HALF_OPENED -> FoldingFeature.State.HALF_OPENED
+                SidecarDeviceState.POSTURE_OPENED -> FoldingFeature.State.FLAT
+                else -> FoldingFeature.State.FLAT
             }
-            return FoldingFeature(feature.rect, type, state)
+            return FoldingFeature(Bounds(feature.rect), type, state)
         }
     }
 }
\ No newline at end of file
diff --git a/window/window/src/testUtil/java/androidx/window/SwitchOnUnregisterExtensionInterfaceCompat.kt b/window/window/src/testUtil/java/androidx/window/SwitchOnUnregisterExtensionInterfaceCompat.kt
index 899378d..56a9cde 100644
--- a/window/window/src/testUtil/java/androidx/window/SwitchOnUnregisterExtensionInterfaceCompat.kt
+++ b/window/window/src/testUtil/java/androidx/window/SwitchOnUnregisterExtensionInterfaceCompat.kt
@@ -19,6 +19,10 @@
 import android.graphics.Rect
 import androidx.annotation.GuardedBy
 import androidx.window.ExtensionInterfaceCompat.ExtensionCallbackInterface
+import androidx.window.FoldingFeature.State
+import androidx.window.FoldingFeature.State.Companion.FLAT
+import androidx.window.FoldingFeature.State.Companion.HALF_OPENED
+import androidx.window.FoldingFeature.Type.Companion.HINGE
 import java.util.concurrent.locks.Lock
 import java.util.concurrent.locks.ReentrantLock
 import kotlin.concurrent.withLock
@@ -34,7 +38,7 @@
     @GuardedBy("mLock")
     private var callback: ExtensionCallbackInterface = EmptyExtensionCallbackInterface()
     @GuardedBy("mLock")
-    private var state = FoldingFeature.STATE_FLAT
+    private var state = FLAT
 
     override fun validateExtensionInterface(): Boolean {
         return true
@@ -57,15 +61,15 @@
     }
 
     fun currentFoldingFeature(): FoldingFeature {
-        return FoldingFeature(foldBounds, FoldingFeature.TYPE_HINGE, state)
+        return FoldingFeature(foldBounds, HINGE, state)
     }
 
     internal companion object {
-        private fun toggleState(currentState: Int): Int {
-            return if (currentState == FoldingFeature.STATE_FLAT) {
-                FoldingFeature.STATE_HALF_OPENED
+        private fun toggleState(currentState: State): State {
+            return if (currentState == FLAT) {
+                HALF_OPENED
             } else {
-                FoldingFeature.STATE_FLAT
+                FLAT
             }
         }
     }
diff --git a/window/window/src/testUtil/java/androidx/window/TestFoldingFeatureUtil.kt b/window/window/src/testUtil/java/androidx/window/TestFoldingFeatureUtil.kt
index 78266e2..ad0acc2 100644
--- a/window/window/src/testUtil/java/androidx/window/TestFoldingFeatureUtil.kt
+++ b/window/window/src/testUtil/java/androidx/window/TestFoldingFeatureUtil.kt
@@ -16,6 +16,8 @@
 package androidx.window
 
 import android.graphics.Rect
+import androidx.window.FoldingFeature.State.Companion.FLAT
+import androidx.window.FoldingFeature.State.Companion.HALF_OPENED
 
 /**
  * A class containing static methods for creating different window bound types. Test methods are
@@ -75,10 +77,10 @@
      * given type.
      */
     @JvmStatic
-    fun allFoldStates(bounds: Rect, @FoldingFeature.Type type: Int): List<FoldingFeature> {
+    fun allFoldStates(bounds: Bounds, type: FoldingFeature.Type): List<FoldingFeature> {
         return listOf(
-            FoldingFeature(bounds, type, FoldingFeature.STATE_FLAT),
-            FoldingFeature(bounds, type, FoldingFeature.STATE_HALF_OPENED)
+            FoldingFeature(bounds, type, FLAT),
+            FoldingFeature(bounds, type, HALF_OPENED)
         )
     }
 
@@ -88,8 +90,8 @@
      * types.
      */
     @JvmStatic
-    fun allFoldingFeatureTypeAndStates(bounds: Rect): List<FoldingFeature> {
-        return allFoldStates(bounds, FoldingFeature.TYPE_HINGE) +
-            allFoldStates(bounds, FoldingFeature.TYPE_FOLD)
+    fun allFoldingFeatureTypeAndStates(bounds: Bounds): List<FoldingFeature> {
+        return allFoldStates(bounds, FoldingFeature.Type.HINGE) +
+            allFoldStates(bounds, FoldingFeature.Type.FOLD)
     }
 }