FoldingFeature.kt

/*
 * 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.layout

/**
 * A feature that describes a fold in the flexible display
 * or a hinge between two physical display panels.
 *
 */
public interface FoldingFeature : DisplayFeature {

    /**
     * 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")
        }
    }

    /**
     * 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].
     *
     * 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.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
     * media app where there is some auxiliary content, such as comments or description of a video,
     * may need to adapt the layout. The media can be put on one side of the [FoldingFeature] and
     * the auxiliary content can be placed on the other side.
     *
     * @return `true` if the feature splits the display into two areas, `false`
     * otherwise.
     */
    public val isSeparating: Boolean

    /**
     * Calculates the occlusion mode to determine if a [FoldingFeature] occludes a part of
     * the window. This flag is useful for determining if UI elements need to be moved
     * 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.OcclusionType.NONE] the feature can be treated as a
     * guideline. One example would be for a continuously folding screen. For occlusion type
     * [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
     * [FoldingFeature]. For example, full screen games should consider avoiding anything in
     * 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.OcclusionType.NONE] if the [FoldingFeature] has empty
     * bounds.
     */
    public val occlusionType: OcclusionType

    /**
     * Returns [FoldingFeature.Orientation.HORIZONTAL] if the width is greater than the
     * height, [FoldingFeature.Orientation.VERTICAL] otherwise.
     */
    public val orientation: Orientation

    /**
     * Returns the [FoldingFeature.State] for the [FoldingFeature]
     */
    public val state: FoldingFeature.State
}