surface-duo-compose-sdk/WindowState
Kristen Halper 6802487a05
Update WindowState dependencies (#57)
* Update WindowState gradle and dependencies

* Update readme

* Update JDK version for workflow
2023-05-04 11:01:53 -07:00
..
gradle/wrapper Update WindowState dependencies (#57) 2023-05-04 11:01:53 -07:00
library Use JWM WindowSizeClass in WindowState (#51) 2022-11-22 09:33:48 -08:00
sample Use JWM WindowSizeClass in WindowState (#51) 2022-11-22 09:33:48 -08:00
screenshots Use height window size class in window mode calculations (#47) 2022-10-27 08:32:15 -07:00
.gitignore Introducing Windowstate as a new SDK (#9) 2022-01-07 10:32:06 -08:00
README.md Update WindowState dependencies (#57) 2023-05-04 11:01:53 -07:00
build.gradle Introducing Windowstate as a new SDK (#9) 2022-01-07 10:32:06 -08:00
dependencies.gradle Update WindowState dependencies (#57) 2023-05-04 11:01:53 -07:00
gradle.properties Update WindowState dependencies (#57) 2023-05-04 11:01:53 -07:00
gradlew Introducing Windowstate as a new SDK (#9) 2022-01-07 10:32:06 -08:00
gradlew.bat Introducing Windowstate as a new SDK (#9) 2022-01-07 10:32:06 -08:00
ktlint.gradle Update WindowState API (#10) 2022-01-31 19:01:12 -05:00
publishing.gradle Update WindowState to Compose 1.2.0 and update sample (#40) 2022-08-09 11:36:37 -07:00
settings.gradle Introducing Windowstate as a new SDK (#9) 2022-01-07 10:32:06 -08:00

README.md

WindowState - Surface Duo Compose SDK

WindowState is a component for Jetpack Compose that helps you easily get details about the window state of the dual-screen, foldable and large screen devices, using the Google Jetpack WindowManager library.

The component provides the current window information as a Compose state, including folding position, orientation and window size classes. For dual-screen and foldable devices, combining different folding positions and orientations, we introduce four display postures to take advantage of these new form factors: Dual Portrait, Dual Landscape, Single Portrait, Single Landscape.

postures

And the window size classes are measured based on Google's Window size classes to help you support different screen sizes of devices, including large screen and regular single screen devices.

Add to your project

  1. Make sure you have mavenCentral() repository in your top level build.gradle file:

    allprojects {
        repositories {
            google()
            mavenCentral()
         }
    }
    
  2. Add dependencies to the module-level build.gradle file (current version may be different from what's shown here).

    implementation "com.microsoft.device.dualscreen:windowstate:1.0.0-alpha09"
    
  3. Also ensure the compileSdkVersion is set to API 33 and the targetSdkVersion is set to API 32 or newer in the module-level build.gradle file.

    android { 
        compileSdkVersion 33
    
        defaultConfig { 
            targetSdkVersion 32
        } 
        ... 
    }
    
  4. Access the info about the window state from WindowState to build or adjust your UI. Please refer to the sample for more details.

API reference

@Composable
fun Activity.rememberWindowState(): WindowState

An interface to provide all the relevant info about the device window.

Large screen and foldable properties

val foldSizeDp: Dp

Returns a dp value of the thickness of the hinge of dual-screen device or the folding line of foldable device when the device is in dual-screen mode. If the device is in single screen mode, or the device is a regular single screen device, the return value will be 0.

Must be set before calling pane1SizeDp or pane2SizeDp for the correct value to be applied.

var largeScreenPane1Weight: Float = 0.5f

Proportion of the window that pane 1 should occupy on a large screen. Used when calculating pane size for the pane1SizeDp and pane2SizeDp properties.

Default value is 0.5 to create equal panes - any new values must be between 0 and 1 or an IllegalArgumentException will be thrown.

val pane1SizeDp: DpSize

Returns the dp size of the primary pane of any device, including dual-screen, foldable, and large screen devices. This is the recommended value to use when creating dualscreen layouts.

The primary pane is either the top pane or the left/right pane, depending on device orientation and local language layout direction.

If the device is in single screen mode, or the device is a regular single screen device, the return value will be 0.

If the device is a large screen, then the largeScreenPane1Weight property will be used to calculate how much space each pane takes up. The property must be set before calling this method for the correct value to be applied.

val pane2SizeDp: DpSize

Returns the dp size of the primary pane of any device, including dual-screen, foldable, and large screen devices. This is the recommended value to use when creating dualscreen layouts.

The secondary pane is either the bottom pane or the left/right pane, depending on device orientation and local language layout direction.

If the device is in single screen mode, or the device is a regular single screen device, the return value will be 0.

If the device is a large screen, then the largeScreenPane1Weight property will be used to calculate how much space each pane takes up. The property must be set before calling this method for the correct value to be applied.

val foldablePane1SizeDp: DpSize

Returns the dp size of the primary pane of the dual-screen or foldable device when the device is in dual-screen mode - note that this does NOT include large screen devices.

The primary pane is either the top pane or the left/right pane, depending on device orientation and local language layout direction.

If the device is in single screen mode, or the device is a regular single screen device, the return value will be 0.

val foldablePane2SizeDp: DpSize

Returns the dp size of the secondary pane of the dual-screen or foldable device when the device is in dual-screen mode - note that this does NOT include large screen devices.

The secondary pane is either the bottom pane or the left/right pane, depending on device orientation and local language layout direction.

If the device is in single screen mode, or the device is a regular single screen device, the return value will be 0.

Window mode properties

val windowMode: WindowMode

Returns the display posture of the window mode: SINGLE_PORTRAIT, SINGLE_LANDSCAPE, DUAL_PORTRAIT, DUAL_LANDSCAPE.

@Composable
fun isDualScreen(): Boolean

Check if the device window is in the dual screen mode, we called it spanned for the dual-screen device or unfolded for the foldable device.

@Composable
fun isDualPortrait(): Boolean

Check if the device window is in the dual portrait posture, with which the hinge or folding line is vertical.

@Composable
fun isDualLandscape(): Boolean

Check if the device window is in the dual portrait posture, with which the hinge or folding line is horizontal.

@Composable
fun isSinglePortrait(): Boolean

Check if the device window is in the single portrait posture, with which the device is in the single screen mode or the device is a single screen device with the portrait orientation.

@Composable
fun isSingleLandscape(): Boolean

Check if the device window is in the single landscape posture, with which the device is in the single screen mode or the device is a single screen device with the landscape orientation.

Window size properties

@Composable
fun widthSizeClass(): WindowWidthSizeClass

Returns the width window size class: Compact, Medium, Expanded, based on the width of the window.

@Composable
fun heightSizeClass(): WindowHeightSizeClass

Returns the height window size class: Compact, Medium, Expanded, based on the height of the window.

Other properties

val hasFold: Boolean = false

Returns true if a FoldingFeature is detected, otherwise returns false.

val foldIsHorizontal: Boolean = false

Returns true if a FoldingFeature is present and in the horizontal orientation, otherwise returns false when a fold is vertical. If no fold is detected, the return value will be false.

Based on the orientation field in FoldingFeature.

val foldBoundsDp: DpRect = DpRect(0.dp, 0.dp, 0.dp, 0.dp)

Returns the bounding rectangle of a fold in units of Dp. If no fold is present, the returned rectangle will contain all zeroes.

Based on the bounds field in DisplayFeature.

val foldState: FoldState = FoldState.FLAT

Returns the state of a fold: FLAT or HALF_OPENED. If no fold is present, the returned state is flat.

Based on the state field in FoldingFeature.

val foldIsSeparating: Boolean = false

Returns whether a fold should be thought of as separating the window into distinct sections.

Based on the isSeparating field in FoldingFeature.

val foldIsOccluding: Boolean = false

Returns whether a fold occludes content in the window.

Based on the occlusionType field in FoldingFeature.

val windowWidthDp: Dp = 1.dp

Returns the window width in Dp.

val windowHeightDp: Dp = 1.dp

Returns the window height in Dp.

Sample behavior

The table below shows screenshots from the sample running on different large screen and foldable emulators.

Emulator Sample screenshot
Surface Duo 2 (unspanned) Sample running on the Surface Duo 2 emulator, unspanned
Surface Duo 2 (unspanned) Sample running on the Surface Duo 2 emulator, unspanned
Surface Duo 2 (spanned) Sample running on the Surface Duo 2 emulator, spanned
6.7 fold-in Sample running on the 6.7 fold-in emulator
7.6 fold-in Sample running on the 7.6 fold-in emulator
8 fold-out Sample running on the 8 fold-out emulator
Pixel C Sample running on the Pixel C emulator

Contributing

This project welcomes contributions and suggestions. Most contributions require you to agree to a Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com.

When you submit a pull request, a CLA bot will automatically determine whether you need to provide a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions provided by the bot. You will only need to do this once across all repos using our CLA.

This project has adopted the Microsoft Open Source Code of Conduct. For more information see the Code of Conduct FAQ or contact opencode@microsoft.com with any additional questions or comments.

License

Copyright (c) Microsoft Corporation.

MIT License

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.