{"id":2138,"date":"2022-01-20T12:13:30","date_gmt":"2022-01-20T20:13:30","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/surface-duo\/?p=2138"},"modified":"2022-01-20T12:13:30","modified_gmt":"2022-01-20T20:13:30","slug":"jetpack-compose-windowstate-preview","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/surface-duo\/jetpack-compose-windowstate-preview\/","title":{"rendered":"Jetpack Compose WindowState preview"},"content":{"rendered":"<p>\n  Hello Jetpack Compose developers!\n<\/p>\n<p>\n  This week, we\u2019d like to announce the release of <a href=\"https:\/\/github.com\/microsoft\/surface-duo-compose-sdk\/tree\/main\/WindowState\">WindowState<\/a>, a new utility library that\u2019s part of our <a href=\"https:\/\/github.com\/microsoft\/surface-duo-compose-sdk\">Compose SDK<\/a>. Our goal was to provide easy access to all the window information provided by the <a href=\"https:\/\/developer.android.com\/reference\/androidx\/window\/layout\/package-summary\">Jetpack Window Manager library<\/a> and to simplify the logic required to enhance your apps for large screens and foldables.  \n<\/p>\n<h2>Library overview<\/h2>\n<p>\n  The main features of the library are the WindowState data class, which contains three categories of information, and the <code>rememberWindowState()<\/code> helper function.\n<\/p>\n<pre>data class WindowState(\r\n   val hasFold: Boolean = false,\r\n   val isFoldHorizontal: Boolean = false,\r\n   val foldBounds: Rect = Rect(),\r\n   val foldState: FoldState = FoldState.FLAT,\r\n   val foldSeparates: Boolean = false,\r\n   val foldOccludes: Boolean = false,\r\n   val windowWidth: Dp = 0.dp,\r\n   val windowHeight: Dp = 0.dp,\r\n)\r\n@Composable\r\nfun Activity.rememberWindowState(): WindowState<\/pre>\n<p><em>Figure 1. Constructor for the WindowState data class and function signature for rememberWindowState().<\/em>\n<\/p>\n<h3>Fold properties<\/h3>\n<p>\n  The WindowState class encapsulates all of the fold data that can be extracted from Jetpack Window Manager\u2019s <a href=\"https:\/\/developer.android.com\/reference\/androidx\/window\/layout\/WindowLayoutInfo\">WindowLayoutInfo<\/a> and <a href=\"https:\/\/developer.android.com\/reference\/androidx\/window\/layout\/FoldingFeature\">FoldingFeature<\/a> classes. As shown above, the properties passed into the WindowState constructor are all publicly accessible values, and we also added a few other properties that might be helpful in your app\u2019s logic:\n<\/p>\n<pre>val foldablePaneWidth: Int<\/pre>\n<p>\n  The <code>foldablePaneWidth<\/code> property returns the width (in pixels) of a single pane of a dual-screen or 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. (Note: the return value is based on the assumption that the developer wants two panes of equal width)\n<\/p>\n<pre>val foldSize: Int<\/pre>\n<p>\n  The <code>foldSize<\/code> property returns the width (in pixels) 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.\n<\/p>\n<h3>Window size<\/h3>\n<p>\n  The WindowState class also contains properties related to large screens. As you can see in constructor, the class accepts the height and width of the current window, then uses this information to calculate the corresponding <code>WindowSizeClass<\/code> for both window dimensions. Our implementation follows the <a href=\"https:\/\/developer.android.com\/guide\/topics\/large-screens\/support-different-screen-sizes#window_size_classes\">official Android guidance<\/a> for how to partition windows into the three size classes.\n<\/p>\n<p>\n  The window dimensions passed into the constructor are public, so these can be accessed at any time. In addition, the calculated size classes for the window can be accessed via the following getters:\n<\/p>\n<pre>fun widthSizeClass(): WindowSizeClass\r\nfun heightSizeClass(): WindowSizeClass<\/pre>\n<p><em>Figure 2. Getter methods for window width and height size classes<\/em>\n<\/p>\n<h3>Window mode<\/h3>\n<p>\n  Lastly, WindowState makes it simple to calculate the current window mode, which is helpful when making decisions about your app\u2019s layout. We\u2019ve provided several properties and getters that help you determine which of the <a href=\"https:\/\/docs.microsoft.com\/dual-screen\/introduction#dual-screen-overview\">four window modes<\/a> is currently in use:\n<\/p>\n<pre>val windowMode: WindowMode\r\nfun isDualScreen(): Boolean\r\nfun isDualPortrait(): Boolean\r\nfun isDualLandscape(): Boolean\r\nfun isSinglePortrait(): Boolean\r\nfun isSingleLandscape(): Boolean<\/pre>\n<p><em>Figure 3. Public properties and getter methods for window mode information<\/em>\n<\/p>\n<p>\n  To make the library as flexible as possible, we\u2019ve given you the option to access the <code>windowMode<\/code> directly, which is useful for choosing between different layouts in a <code>when<\/code> block, or to simply ask whether the current window is in a specific mode, which is useful as a state to pass to composables.\n<\/p>\n<h2>Get started<\/h2>\n<h3>Add to your project<\/h3>\n<p>\n  To start using the WindowState library, follow these steps:\n<\/p>\n<ol>\n<li>\n  Add the following dependency to your <b>build.gradle<\/b> file:<\/p>\n<pre>implementation \"com.microsoft.device.dualscreen:windowstate:1.0.0-alpha1\"<\/pre>\n<\/li>\n<li>\n  Call the <code>rememberWindowState()<\/code> function from your MainActivity and pass the result into your top-level composable<\/p>\n<pre>class MainActivity : ComponentActivity() {\r\n    override fun onCreate(savedInstanceState: Bundle?) {\r\n        super.onCreate(savedInstanceState)\r\n        \r\n        setContent {\r\n            ExampleAppTheme {\r\n                ExampleApp(rememberWindowState())\r\n            }\r\n        }\r\n    }\r\n}<\/pre>\n<\/li>\n<li>\n  Access the WindowState properties within your composables and use them to make layout decisions<\/p>\n<pre>\r\nfun ExampleApp(windowState: WindowState) {\r\n    if (windowState.isDualScreen())\r\n        DualScreenAppContent(windowState.foldSize)\r\n    else\r\n        SingleScreenAppContent()\r\n}<\/pre>\n<\/li>\n<\/ol>\n<p>\n  For more detailed instructions and API reference information, please refer to the <a href=\"https:\/\/github.com\/microsoft\/surface-duo-compose-sdk\/tree\/main\/WindowState\/\">WindowState README<\/a>.\n<\/p>\n<h3>Example usage<\/h3>\n<p>\n  To see some of examples of how to use the library, you can check out a few different samples. \n<\/p>\n<p>\n  In the SDK repo, we created a <a href=\"https:\/\/github.com\/microsoft\/surface-duo-compose-sdk\/tree\/main\/WindowState\/sample\">small sample<\/a> to showcase all of the properties that can be accessed via WindowState.\n<\/p>\n<p>\n  <img decoding=\"async\" width=\"1194\" height=\"957\" src=\"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-content\/uploads\/sites\/53\/2022\/01\/word-image.png\" class=\"wp-image-2139\" srcset=\"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-content\/uploads\/sites\/53\/2022\/01\/word-image.png 1194w, https:\/\/devblogs.microsoft.com\/surface-duo\/wp-content\/uploads\/sites\/53\/2022\/01\/word-image-300x240.png 300w, https:\/\/devblogs.microsoft.com\/surface-duo\/wp-content\/uploads\/sites\/53\/2022\/01\/word-image-1024x821.png 1024w, https:\/\/devblogs.microsoft.com\/surface-duo\/wp-content\/uploads\/sites\/53\/2022\/01\/word-image-768x616.png 768w\" sizes=\"(max-width: 1194px) 100vw, 1194px\" \/>\n  <img decoding=\"async\" width=\"957\" height=\"1194\" src=\"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-content\/uploads\/sites\/53\/2022\/01\/word-image-1.png\" class=\"wp-image-2140\" srcset=\"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-content\/uploads\/sites\/53\/2022\/01\/word-image-1.png 957w, https:\/\/devblogs.microsoft.com\/surface-duo\/wp-content\/uploads\/sites\/53\/2022\/01\/word-image-1-240x300.png 240w, https:\/\/devblogs.microsoft.com\/surface-duo\/wp-content\/uploads\/sites\/53\/2022\/01\/word-image-1-821x1024.png 821w, https:\/\/devblogs.microsoft.com\/surface-duo\/wp-content\/uploads\/sites\/53\/2022\/01\/word-image-1-768x958.png 768w\" sizes=\"(max-width: 957px) 100vw, 957px\" \/>\n<\/p>\n<p><em>Figure 4. Screenshots of the library sample in single portrait mode and dual landscape mode on the Surface Duo emulator.<\/em>\n<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-content\/uploads\/sites\/53\/2022\/01\/windowstate-devices.png\"><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-content\/uploads\/sites\/53\/2022\/01\/windowstate-devices.png\" alt=\"WindowState sample output on three different sized device emulators\" width=\"1168\" height=\"1836\" class=\"alignnone size-full wp-image-2150\" srcset=\"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-content\/uploads\/sites\/53\/2022\/01\/windowstate-devices.png 1168w, https:\/\/devblogs.microsoft.com\/surface-duo\/wp-content\/uploads\/sites\/53\/2022\/01\/windowstate-devices-191x300.png 191w, https:\/\/devblogs.microsoft.com\/surface-duo\/wp-content\/uploads\/sites\/53\/2022\/01\/windowstate-devices-651x1024.png 651w, https:\/\/devblogs.microsoft.com\/surface-duo\/wp-content\/uploads\/sites\/53\/2022\/01\/windowstate-devices-768x1207.png 768w, https:\/\/devblogs.microsoft.com\/surface-duo\/wp-content\/uploads\/sites\/53\/2022\/01\/windowstate-devices-977x1536.png 977w\" sizes=\"(max-width: 1168px) 100vw, 1168px\" \/><\/a><\/p>\n<p><em>Figure 5. Screenshots of the library sample on other large screen and foldable emulators (clockwise from the top: 6.7 Horizontal Fold-in, 7.6 Fold-in with outer display, Pixel C).<\/em>\n<\/p>\n<p>\n  We\u2019ve also updated each of our <a href=\"https:\/\/github.com\/microsoft\/surface-duo-compose-samples\/\">Compose samples<\/a> to use WindowState. For an example of how foldable properties can be used, check out the updated <a href=\"https:\/\/github.com\/microsoft\/surface-duo-compose-samples\/blob\/main\/TwoPage\/src\/main\/java\/com\/microsoft\/device\/display\/samples\/twopage\/ui\/view\/HomePage.kt\">TwoPage sample<\/a>. To see how you can use <code>windowMode<\/code> inside a <code>when<\/code> block, check out the updated <a href=\"https:\/\/github.com\/microsoft\/surface-duo-compose-samples\/blob\/main\/CompanionPane\/src\/main\/java\/com\/microsoft\/device\/display\/samples\/companionpane\/HomePage.kt\">CompanionPane sample<\/a>. If you would prefer to check whether the window is in a specific mode, you can refer to the <a href=\"https:\/\/github.com\/microsoft\/surface-duo-compose-samples\/blob\/main\/ListDetail\/src\/main\/java\/com\/microsoft\/device\/display\/samples\/listdetail\/ui\/view\/MainPage.kt\">ListDetail sample<\/a> to see how <code>isDualPortrait()<\/code> is used.\n<\/p>\n<p>\n  In our samples, we definitely noticed that using WindowState helped simplify our app logic, and we hope it does the same for you! Since this is the first version of the library, please don\u2019t hesitate to send us feedback on how you think future versions could be improved \ud83d\ude0a\n<\/p>\n<h2>Resources and Feedback<\/h2>\n<p>\n  Check out the <a href=\"https:\/\/docs.microsoft.com\/dual-screen\/android\/jetpack\/compose\">Surface Duo Jetpack Compose developer documentation<\/a> and <a href=\"https:\/\/devblogs.microsoft.com\/surface-duo\/\">past blog posts<\/a> for links and details on all our samples. You can find our <a href=\"https:\/\/github.com\/microsoft\/surface-duo-compose-samples\">Jetpack Compose samples<\/a> on GitHub.\n<\/p>\n<p>\n  If you have any questions, or would like to tell us about your apps, use the <a href=\"http:\/\/aka.ms\/SurfaceDuoSDK-Feedback\">feedback forum<\/a> or message us on Twitter <a href=\"https:\/\/twitter.com\/surfaceduodev\">@surfaceduodev<\/a>.\n<\/p>\n<p>\n  Finally, join us <a href=\"https:\/\/twitch.tv\/surfaceduodev\">live on Twitch<\/a> at 11am PST to discuss the WindowState library, Jetpack Window Manager, and any other Surface Duo developer questions you might have.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Hello Jetpack Compose developers! This week, we\u2019d like to announce the release of WindowState, a new utility library that\u2019s part of our Compose SDK. Our goal was to provide easy access to all the window information provided by the Jetpack Window Manager library and to simplify the logic required to enhance your apps for large [&hellip;]<\/p>\n","protected":false},"author":72597,"featured_media":2139,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[692,706,46],"class_list":["post-2138","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-surface-duo-sdk","tag-jetpack-compose","tag-jetpack-window-manager","tag-surface-duo"],"acf":[],"blog_post_summary":"<p>Hello Jetpack Compose developers! This week, we\u2019d like to announce the release of WindowState, a new utility library that\u2019s part of our Compose SDK. Our goal was to provide easy access to all the window information provided by the Jetpack Window Manager library and to simplify the logic required to enhance your apps for large [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-json\/wp\/v2\/posts\/2138","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-json\/wp\/v2\/users\/72597"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-json\/wp\/v2\/comments?post=2138"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-json\/wp\/v2\/posts\/2138\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-json\/wp\/v2\/media\/2139"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-json\/wp\/v2\/media?parent=2138"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-json\/wp\/v2\/categories?post=2138"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-json\/wp\/v2\/tags?post=2138"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}