{"id":2398,"date":"2022-04-14T15:04:14","date_gmt":"2022-04-14T22:04:14","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/surface-duo\/?p=2398"},"modified":"2022-04-14T15:04:14","modified_gmt":"2022-04-14T22:04:14","slug":"isseparating-foldable-jetpack-window-manager","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/surface-duo\/isseparating-foldable-jetpack-window-manager\/","title":{"rendered":"isSeparating: the field that unites all foldables"},"content":{"rendered":"<p>\n  Hello Android developers,\n<\/p>\n<p>\n  Today we are going to talk about a very useful field that is part of <a href=\"https:\/\/developer.android.com\/jetpack\/androidx\/releases\/window\">Jetpack Window Manager<\/a> library. This field is called <a href=\"https:\/\/developer.android.com\/reference\/androidx\/window\/layout\/FoldingFeature#isSeparating()\"><em>isSeparating<\/em><\/a>, and will help you to understand when there is content separated by a <a href=\"https:\/\/developer.android.com\/reference\/androidx\/window\/layout\/FoldingFeature\">FoldingFeature<\/a> on a foldable device.\n<\/p>\n<p>\n  The value of <em>isSeparating<\/em> will be <code>false<\/code> if there is no content that is separated by a hinge or a fold.\n<\/p>\n<p>\n  The value of <em>isSeparating<\/em> will be <code>true<\/code> if there is content that is separated by a hinge or a fold.\n<\/p>\n<p>\n  Is this field and the value it holds valid for all kinds of foldable devices, no matter how many physical displays or types of hinges they have? Yes, this field has you covered no matter what the foldable device is. One field to rule them all! \ud83d\ude0a\n<\/p>\n<p>\n  Wait, wait! too fast Cesar! Ok, ok, let\u2019s take a step back. \n<\/p>\n<h2>Understanding the different foldable scenarios that we have<\/h2>\n<p>\n  Until very recently, we had just one kind of device: single-screen. A single-screen device could be a phone with a small display, a tablet with a large one, or a TV with an even larger one. No matter the size, it was a continuous display without anything that could occlude its content and without the possibility to change its posture; it was just flat.\n<\/p>\n<p>\n  Now, foldable devices have entered the game. Foldable devices, as you may know, currently have one display that can be folded or two independent displays that can be folded through a physical hinge. Foldable devices can also have different postures &#8211; not just different orientations (portrait and landscape), but different postures &#8211; such as mirroring a tabletop, a book, a tent, etc. A foldable device can take these different postures because of its FoldingFeature, which is where the device folds. As briefly mentioned above, we currently have two kinds of FoldingFeatures:\n<\/p>\n<ul>\n<li>\n    <b>Hinge<\/b> &#8211; joins two physical and independent displays. Surface Duo is a device that has a hinge.\n  <\/li>\n<li>\n    <b>Fold<\/b> &#8211; the area where a foldable device with just one physical display can be folded.\n  <\/li>\n<\/ul>\n<p>\n  In this new scenario, where devices can have multiple displays and\/or displays that can be folded, we should provide UIs that handle these new scenarios and configurations, especially those that take advantage of the more available display area to provide a fantastic user experience.\n<\/p>\n<p>\n  <img decoding=\"async\" width=\"1484\" height=\"481\" src=\"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-content\/uploads\/sites\/53\/2022\/04\/shape-description-automatically-generated-2.png\" class=\"wp-image-2399\" alt=\"Three different examples of device posture - book-like, laptop-like, and tented which is folded over 240 degrees\" srcset=\"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-content\/uploads\/sites\/53\/2022\/04\/shape-description-automatically-generated-2.png 1484w, https:\/\/devblogs.microsoft.com\/surface-duo\/wp-content\/uploads\/sites\/53\/2022\/04\/shape-description-automatically-generated-2-300x97.png 300w, https:\/\/devblogs.microsoft.com\/surface-duo\/wp-content\/uploads\/sites\/53\/2022\/04\/shape-description-automatically-generated-2-1024x332.png 1024w, https:\/\/devblogs.microsoft.com\/surface-duo\/wp-content\/uploads\/sites\/53\/2022\/04\/shape-description-automatically-generated-2-768x249.png 768w\" sizes=\"(max-width: 1484px) 100vw, 1484px\" \/>\n<\/p>\n<p><em>Figure 1. Some of the postures that a foldable device can take.<\/em>\n<\/p>\n<p>\n  Let\u2019s think about a foldable that is folded 90 degrees and that takes a tabletop posture. In this posture, content that is located in the folded area is pretty much unusable, and users won\u2019t be able to see the content there correctly nor able to interact with its UI. The same happens when the foldable device takes a different posture, such as book, where now the FoldingFeature is vertical, and the content located there is not accessible nor visible correctly.\n<\/p>\n<p>\n  And what about Surface Duo that has two physical displays separated by a physical hinge? In the case of this device, the FoldingFeature is always separating the content when the app is spanned across displays and uses the whole display area. The device can also take the same postures that we have mentioned above, such as tabletop and book (and even more!), and in these postures there is also content that is not accessible nor visible.\n<\/p>\n<p>\n  Here is where isSeparating from Jetpack Window Manager will help you!\n<\/p>\n<h2>isSeparating<\/h2>\n<p>\n  As we have mentioned briefly in the introduction, <em>isSeparating <\/em>is part of Jetpack Window Manager. This field will help us to understand when a FoldingFeature is separating the content. \n<\/p>\n<p>\n  When is the content separated in a foldable device?\n<\/p>\n<ul>\n<li>\n    In a foldable device with a continuous display with a fold area: when the device is in a posture where the content is difficult to access or to visualize, postures like tabletop and book, where the device is in a half-opened posture.\n  <\/li>\n<li>\n    In a foldable device with two independent displays separated by a hinge: the content, when the app is using the whole display area (both displays) will be always separated by the hinge, no matter the posture that takes.\n  <\/li>\n<\/ul>\n<p>\n  The value of <em>isSeparating<\/em> will be <em>true <\/em>or <em>false<\/em> depending on whether the content is separated or not.\n<\/p>\n<p>\n  Do you want to see the internals of that field? Let\u2019s see:\n<\/p>\n<pre>override val isSeparating: Boolean\r\n   get() = when {\r\n       type == Type.HINGE -&gt; true\r\n       type == Type.FOLD &amp;&amp; state == FoldingFeature.State.HALF_OPENED -&gt; true\r\n       else -&gt; false\r\n   }<\/pre>\n<p><em>Figure 2. isSeparating field (<\/em><a href=\"https:\/\/cs.android.com\/androidx\/platform\/frameworks\/support\/+\/androidx-main:window\/window\/src\/main\/java\/androidx\/window\/layout\/HardwareFoldingFeature.kt\"><em>find the source code in the AndroidX repository<\/em><\/a><em>)<\/em>\n<\/p>\n<p>\n  As you can see the code is simple but very powerful! \n<\/p>\n<h2>How can we use isSeparating in our apps?<\/h2>\n<p>\n  If you have been following us, you may know how Jetpack Window Manager works and how to get its <a href=\"https:\/\/developer.android.com\/reference\/androidx\/window\/layout\/WindowLayoutInfo\">WindowLayoutInfo<\/a>, but once again, first thing we have to do is to register for changes:\n<\/p>\n<pre>lifecycleScope.launch(Dispatchers.Main) {\r\n   lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED {\r\n      WindowInfoTracker.getOrCreate(this@MainActivity)\r\n         .windowLayoutInfo(this@MainActivity)\r\n         .collect {newLayoutInfo -&gt;\r\n            updateCurrentLayout(newLayoutInfo)\r\n         }\r\n   }\r\n}<\/pre>\n<p><em>Figure 3. Initializing Window Manager<\/em>\n<\/p>\n<p>\n  As you can see, once we get new WindowLayoutInfo (inside <em>collect<\/em>), we will handle the UI and apply the changes we want depending on if the content is separated by the FoldingFeature or not.\n<\/p>\n<p>\n  In the function <em>updateCurrentLayout<\/em>:\n<\/p>\n<pre>private fun updateCurrentLayout(newLayoutInfo: WindowLayoutInfo) {\r\n   for (displayFeature in newLayoutInfo.displayFeatures) {\r\n      val foldFeature = displayFeature as? FoldingFeature\r\n      foldFeature?.let {\r\n         if (it.isSeparating) {\r\n  \t\t\/\/The content is separated by the FoldingFeature.\r\n  \t\t\/\/Here is where you should adapt your UI.\r\n         }  \r\n         else {\r\n  \t\t\/\/The content is not separated.\r\n  \t\t\/\/Users can see and interact with your UI properly.\r\n         }\r\n      }\r\n   }\r\n}<\/pre>\n<p><em>Figure 4. Using isSeparating to know whether the content is separated or not<\/em>\n<\/p>\n<p>\n  Easy, right? As you can see, we just get the foldFeature value and see the value <em>isSeparating<\/em> has, and with that we then know whether the content is being separated or not so we can decide whether or not to make changes in our UI.\n<\/p>\n<p>\n  Remember that <strong><em>isSeparating<\/em> works for all foldable devices<\/strong>! No matter the hinge, the display, the posture the device has, etc. <em>isSeparating<\/em> will tell you whether the content is being separated or not.\n<\/p>\n<h2>isSeparating-sample app<\/h2>\n<p>\n  Do you want to see in action how isSeparating works, and how we can enhance the UI to provide a better user experience in all scenarios?\n<\/p>\n<p>\n  We have created <a href=\"https:\/\/github.com\/CesarValiente\/isseparating-sample\">a very simple application<\/a> where we change the UI depending on whether the content is being separated or not. To make the app we have relied heavily on a couple of components: <a href=\"https:\/\/developer.android.com\/reference\/androidx\/constraintlayout\/motion\/widget\/MotionLayout\">MotionLayout<\/a> and <a href=\"https:\/\/developer.android.com\/reference\/androidx\/constraintlayout\/widget\/ReactiveGuide\">ReactiveGuide<\/a>. These components will help us to build a dynamic UI that can be adapted whenever there is a FoldingFeature that separates the content and adds a bit of motion, making it easier to see the applied changes.\n<\/p>\n<p>\n  The app basically shows text when its content is not separated, and when it is, the UI is adapted to show new text on the other side of the FoldingFeature that indicates if the FoldingFeature is in a horizontal or vertical orientation.\n<\/p>\n<p>\n  Let\u2019s see the app in action in a couple of animations:\n<\/p>\n<p>\n  <img decoding=\"async\" width=\"778\" height=\"662\" src=\"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-content\/uploads\/sites\/53\/2022\/04\/word-image.gif\" class=\"wp-image-2400\" \/>\n<\/p>\n<p><em>Figure 5. Sample app running in a foldable device<\/em>\n<\/p>\n<p>\n  As you see above, when we run the app in a foldable device, when the FoldingFeature is not separating the content (the device is in a flat posture), we see just one text (\u201cisSeparating?\u201d).\n<\/p>\n<p>\n  But when we change its posture to half-open, so the device is folded 90 degrees adopting a tabletop posture, <em>isSeparating<\/em> value will be <em>true<\/em> and we will adjust the UI accordingly showing a different one.\n<\/p>\n<p>\n  Let\u2019s see now the same app running on Surface Duo, a dual-screen device:\n<\/p>\n<p>\n  <img decoding=\"async\" width=\"966\" height=\"662\" src=\"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-content\/uploads\/sites\/53\/2022\/04\/word-image-1.gif\" class=\"wp-image-2401\" alt=\"Animation of a foldable device showing when isSeparating becomes true or false based on the fold angle\" \/>\n<\/p>\n<p><em>Figure 6. Sample app running in a dual-screen device.<\/em>\n<\/p>\n<p>\n  In dual-screen devices, when the app runs in single-screen mode, there is no interaction with the FoldingFeature, hence the content is not separated, so we show just the initial text; but when the app is spanned across displays, as we have mentioned before, since the device has two physical displays separated by a physical hinge, its content is always separated, and we show the different UI.\n<\/p>\n<h2>More samples and docs?<\/h2>\n<p>\n  Google has started to use <em>isSeparating<\/em> as well in the apps that are getting enhanced with foldable support. <a href=\"https:\/\/github.com\/android\/compose-samples\/tree\/main\/Jetcaster\">Jetcaster<\/a> is a sample podcast app built with <a href=\"https:\/\/developer.android.com\/jetpack\/compose\">Jetpack Compose<\/a> that uses Jetpack Window Manager to make its UI foldable aware. <a href=\"https:\/\/github.com\/android\/compose-samples\/pull\/751\">They recently updated the app to use isSeparating<\/a> to create a UI that is enhanced whenever the FoldingFeature separates the content, so now Jetcaster works well on all kinds of foldable devices.\n<\/p>\n<p>\n  Google has also very recently <a href=\"https:\/\/developer.android.com\/guide\/topics\/large-screens\/make-apps-fold-aware#folding_features\">updated their fantastic foldable docs<\/a> covering also <em>isSeparating<\/em> functionality and the values that can get depending on the different scenarios (that we also have seen in this blog post).\n<\/p>\n<p>\n  We also provide a lot of other different samples where we use Jetpack Window Manager and <em>isSeparating<\/em> to enhance dynamically the apps\u2019 UI, and in fact, most of them are more complex and more-real scenarios than the basic sample we have seen here. Many of them are in our <a href=\"https:\/\/github.com\/microsoft\/surface-duo-window-manager-samples\">WindowManager samples repo<\/a>, and also our <a href=\"https:\/\/github.com\/microsoft\/surface-duo-compose-sdk\">Jetpack Compose libraries repo<\/a> make use of the field.\n<\/p>\n<p>\n  We also have you covered in terms of docs. We have a <a href=\"https:\/\/docs.microsoft.com\/dual-screen\/android\/jetpack\/window-manager\/\">complete section<\/a> where we cover Jetpack Window Manager (including <em>isSeparating<\/em>) and libraries around it such as <a href=\"https:\/\/docs.microsoft.com\/dual-screen\/android\/jetpack\/window-manager\/slidingpanelayout\">SlidingPaneLayout<\/a>.\n<\/p>\n<h2>Resources and feedback<\/h2>\n<p>\n  The code for the <a href=\"https:\/\/github.com\/CesarValiente\/isseparating-sample\">isSeparating-sample<\/a> is available 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 <a href=\"https:\/\/twitter.com\/surfaceduodev\">Twitter @surfaceduodev<\/a>.\n<\/p>\n<p>\n  Finally, please join us for our <a href=\"https:\/\/www.twitch.tv\/surfaceduodev\">dual-screen developer livestream<\/a> at 11am (Pacific time) each Friday \u2013 mark it in your calendar and check out the <a href=\"https:\/\/www.youtube.com\/channel\/UClGu9QLtPNz8OdddBfhZXPA\">archives on YouTube<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Hello Android developers, Today we are going to talk about a very useful field that is part of Jetpack Window Manager library. This field is called isSeparating, and will help you to understand when there is content separated by a FoldingFeature on a foldable device. The value of isSeparating will be false if there is [&hellip;]<\/p>\n","protected":false},"author":30297,"featured_media":2402,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[31,706,473,46],"class_list":["post-2398","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-surface-duo-sdk","tag-dual-screen-development","tag-jetpack-window-manager","tag-kotlin","tag-surface-duo"],"acf":[],"blog_post_summary":"<p>Hello Android developers, Today we are going to talk about a very useful field that is part of Jetpack Window Manager library. This field is called isSeparating, and will help you to understand when there is content separated by a FoldingFeature on a foldable device. The value of isSeparating will be false if there is [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-json\/wp\/v2\/posts\/2398","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\/30297"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-json\/wp\/v2\/comments?post=2398"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-json\/wp\/v2\/posts\/2398\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-json\/wp\/v2\/media\/2402"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-json\/wp\/v2\/media?parent=2398"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-json\/wp\/v2\/categories?post=2398"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-json\/wp\/v2\/tags?post=2398"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}