{"id":272320,"date":"2025-03-13T05:48:51","date_gmt":"2025-03-13T05:48:51","guid":{"rendered":"https:\/\/michigandigitalnews.com\/index.php\/2025\/03\/13\/jetpack-windowmanager-1-4-is-stable\/"},"modified":"2025-06-25T17:09:10","modified_gmt":"2025-06-25T17:09:10","slug":"jetpack-windowmanager-1-4-is-stable","status":"publish","type":"post","link":"https:\/\/michigandigitalnews.com\/index.php\/2025\/03\/13\/jetpack-windowmanager-1-4-is-stable\/","title":{"rendered":"Jetpack WindowManager 1.4 is stable"},"content":{"rendered":"<p> [ad_1]<br \/>\n<\/p>\n<div>\n<meta content=\"https:\/\/blogger.googleusercontent.com\/img\/b\/R29vZ2xl\/AVvXsEhvmObDTm_UvKKZP8bDM_YVpknfPh2MBo1pZun6Vc_0CTOsoxvFAq0O_tIa33owHNckOXqKEGGf35C7PccmUFU9gA9VX7djih13zWISVNwdqAHY7waJ7tcWoZJUSuCwSnrLCmhQzNCr21e61IJ_8PLUzj6eKApPrxmK-cwMHrYp-iCbQ6XPyiLxIKvRZPU\/s1600\/Jetpack%20Adaptive%20Compose%20Metadata.png\" name=\"twitter:image\"\/><br \/>\n<img decoding=\"async\" src=\"https:\/\/blogger.googleusercontent.com\/img\/b\/R29vZ2xl\/AVvXsEhvmObDTm_UvKKZP8bDM_YVpknfPh2MBo1pZun6Vc_0CTOsoxvFAq0O_tIa33owHNckOXqKEGGf35C7PccmUFU9gA9VX7djih13zWISVNwdqAHY7waJ7tcWoZJUSuCwSnrLCmhQzNCr21e61IJ_8PLUzj6eKApPrxmK-cwMHrYp-iCbQ6XPyiLxIKvRZPU\/s1600\/Jetpack%20Adaptive%20Compose%20Metadata.png\" style=\"display: none;\"\/><\/p>\n<p><em>Posted by  Xiaodao Wu &#8211; Developer Relations Engineer<\/em><\/p>\n<p><a href=\"https:\/\/blogger.googleusercontent.com\/img\/b\/R29vZ2xl\/AVvXsEiq-xjyTG_ks5AfowEaHg8NFwpTVt0EqH59N_7RExbYOHp8WESDEmFbRFPB7kc3_tP0B7XGARTbDvX6woNwZgRtwX2xH8xJI0uq4w7T3b2JFOjzB3qfU6EZC-MpYSZ537orOmLoI5VY69Fc-h9XMiJ3MRe7rk66yTMcEdDxSWlrOY71cQ04-kxG-kFalms\/s1600\/Jetpack%20Adaptive%20Compose%20%281%29.png\"><img decoding=\"async\" border=\"0\" data-original-height=\"800\" data-original-width=\"100%\" src=\"https:\/\/blogger.googleusercontent.com\/img\/b\/R29vZ2xl\/AVvXsEiq-xjyTG_ks5AfowEaHg8NFwpTVt0EqH59N_7RExbYOHp8WESDEmFbRFPB7kc3_tP0B7XGARTbDvX6woNwZgRtwX2xH8xJI0uq4w7T3b2JFOjzB3qfU6EZC-MpYSZ537orOmLoI5VY69Fc-h9XMiJ3MRe7rk66yTMcEdDxSWlrOY71cQ04-kxG-kFalms\/s1600\/Jetpack%20Adaptive%20Compose%20%281%29.png\"\/><\/a><\/p>\n<p>Jetpack WindowManager keeps getting better. WindowManager gives you tools to build adaptive apps that work seamlessly across all kinds of large screen devices. Version 1.4, which is stable now, introduces new features that make multi-window experiences even more powerful and flexible. While Jetpack Compose is still the best way to create app layouts for different screen sizes, 1.4 makes some big improvements to activity embedding, including activity stack spinning, pane expansion, and dialog full-screen dim. Multi-activity apps can easily take advantage of all these great features.<\/p>\n<p>WindowManager 1.4 introduces a range of enhancements. Here are some of the highlights.<\/p>\n<h2><span style=\"font-size: x-large;\">WindowSizeClass<\/span><\/h2>\n<p>We\u2019ve updated the <span style=\"font-family: courier;\"><a href=\"https:\/\/developer.android.com\/reference\/kotlin\/androidx\/compose\/material3\/windowsizeclass\/WindowSizeClass\" target=\"_blank\" rel=\"noopener\">WindowSizeClass<\/a><\/span> API to support custom values. We changed the API shape to make it easy and extensible to support custom values and add new values in the future. The high level changes are as follows:<\/p>\n<ul>\n<ul>\n<li>Opened the constructor to take in <span style=\"color: #0d904f; font-family: courier;\">minWidthDp<\/span> and <span style=\"color: #0d904f; font-family: courier;\">minHeightDp<\/span> parameters so you can create your own window size classes<\/li>\n<\/ul>\n<ul>\n<li>Added convenience methods for checking breakpoint validity<\/li>\n<\/ul>\n<ul>\n<li>Deprecated <span style=\"color: #0d904f; font-family: courier;\">WindowWidthSizeClass<\/span> and <span style=\"color: #0d904f; font-family: courier;\">WindowHeightSizeClass<\/span> in favor of <span style=\"color: #0d904f; font-family: courier;\">WindowSizeClass#isWidthAtLeastBreakpoint()<\/span> and <span style=\"color: #0d904f; font-family: courier;\">WindowSizeClass#isHeightAtLeastBreakpoint()<\/span> respectively<\/li>\n<\/ul>\n<\/ul>\n<p>Here\u2019s a migration example:<\/p>\n<p><!--Kotlin--><\/p>\n<div style=\"background: rgb(248, 248, 248); border: 0px; overflow: auto; width: auto;\">\n<pre style=\"line-height: 125%; margin: 0px;\"><span style=\"color: #408080; font-style: italic;\">\/\/ old <\/span>\n\n<span style=\"color: green; font-weight: bold;\">val<\/span> sizeClass = WindowSizeClass.compute(widthDp, heightDp)\n<span style=\"color: green; font-weight: bold;\">when<\/span> (sizeClass.widthSizeClass) {\n  COMPACT -&gt; doCompact()\n  MEDIUM -&gt; doMedium()\n  EXPANDED -&gt; doExpanded()\n  <span style=\"color: green; font-weight: bold;\">else<\/span> -&gt; doDefault()\n}\n\n<span style=\"color: #408080; font-style: italic;\">\/\/ new<\/span>\n<span style=\"color: green; font-weight: bold;\">val<\/span> sizeClass = WindowSizeClass.BREAKPOINTS_V1\n                               .computeWindowSizeClass(widthDp, heightDp)\n\n<span style=\"color: green; font-weight: bold;\">when<\/span> {\n  sizeClass.isWidthAtLeastBreakpoint(WIDTH_DP_EXPANDED_LOWER_BOUND) -&gt; {\n    doExpanded()\n  }\n  sizeClass.isWidthAtLeastBreakpoint(WIDTH_DP_MEDIUM_LOWER_BOUND) -&gt; {\n    doMedium()\n  }\n  <span style=\"color: green; font-weight: bold;\">else<\/span> -&gt; {\n    doCompact()\n  }\n}\n<\/pre>\n<\/div>\n<p>Some things to note in the new API:<\/p>\n<ul>\n<ul>\n<li>The order of the <span style=\"color: #0d904f; font-family: courier;\">when<\/span> branches should go from largest to smallest to support custom values from developers or new values in the future<\/li>\n<li>The default branch should be treated as the smallest window size class<\/li>\n<\/ul>\n<\/ul>\n<h2><span style=\"font-size: x-large;\">Activity embedding<\/span><\/h2>\n<h3><span style=\"font-size: large;\"><b>Activity stack pinning<\/b><\/span><\/h3>\n<p><b>Activity stack pinning<\/b> provides a way to keep an activity stack always on screen, no matter what else is happening in your app. This new feature lets you pin an activity stack to a specific window, so the top activity stays visible even when the user navigates to other parts of the app in a different window. This is perfect for things like live chats or video players that you want to keep on screen while users explore other content.<\/p>\n<p><!--Kotlin--><\/p>\n<div style=\"background: rgb(248, 248, 248); border: 0px; overflow: auto; width: auto;\">\n<pre style=\"line-height: 125%; margin: 0px;\"><span style=\"color: green; font-weight: bold;\">private<\/span> <span style=\"color: green; font-weight: bold;\">fun<\/span> <span style=\"color: blue;\">pinActivityStackExample<\/span>(taskId: Int) {\n <span style=\"color: green; font-weight: bold;\">val<\/span> splitAttributes: SplitAttributes = SplitAttributes.Builder()\n   .setSplitType(SplitAttributes.SplitType.ratio(<span style=\"color: #666666;\">0.66f<\/span>))\n   .setLayoutDirection(SplitAttributes.LayoutDirection.LEFT_TO_RIGHT)\n   .build()\n\n <span style=\"color: green; font-weight: bold;\">val<\/span> pinSplitRule = SplitPinRule.Builder()\n   .setDefaultSplitAttributes(splitAttributes)\n   .build()\n\n SplitController.getInstance(applicationContext).pinTopActivityStack(taskId, pinSplitRule)\n}\n<\/pre>\n<\/div>\n<h3><span style=\"font-size: large;\"><b>Pane expansion<\/b><\/span><\/h3>\n<p>The new <b><a href=\"https:\/\/m3.material.io\/foundations\/layout\/applying-layout\/pane-layouts#d3ef6c37-d8a5-4029-99d1-033ec6db39a6\" target=\"_blank\" rel=\"noopener\">pane expansion<\/a><\/b> feature, also known as <b>interactive divider<\/b>, lets you create a visual separation between two activities in split-screen mode. You can make the pane divider draggable so users can resize the panes \u2013 and the activities in the panes \u2013 on the fly. This gives users control over how they want to view the app\u2019s content.<\/p>\n<p><!--Kotlin--><\/p>\n<div style=\"background: rgb(248, 248, 248); border: 0px; overflow: auto; width: auto;\">\n<pre style=\"line-height: 125%; margin: 0px;\"><span style=\"color: green; font-weight: bold;\">val<\/span> splitAttributesBuilder: SplitAttributes.Builder = SplitAttributes.Builder()\n   .setSplitType(SplitAttributes.SplitType.ratio(<span style=\"color: #666666;\">0.33f<\/span>))\n   .setLayoutDirection(SplitAttributes.LayoutDirection.LEFT_TO_RIGHT)\n\n<span style=\"color: green; font-weight: bold;\">if<\/span> (WindowSdkExtensions.getInstance().extensionVersion &gt;= <span style=\"color: #666666;\">6<\/span>) {\n   splitAttributesBuilder.setDividerAttributes(\n       DividerAttributes.DraggableDividerAttributes.Builder()\n           .setColor(getColor(context, R.color.divider_color))\n           .setWidthDp(<span style=\"color: #666666;\">4<\/span>)\n           .setDragRange(\n               DividerAttributes.DragRange.DRAG_RANGE_SYSTEM_DEFAULT)\n           .build()\n   )\n}\n<span style=\"color: green; font-weight: bold;\">val<\/span> splitAttributes: SplitAttributes = splitAttributesBuilder.build()\n<\/pre>\n<\/div>\n<h3><span style=\"font-size: large;\"><b>Dialog full-screen dim<\/b><\/span><\/h3>\n<p>WindowManager 1.4 gives you more control over how dialogs dim the background. With <b>dialog full-screen dim<\/b>, you can choose to dim just the container where the dialog appears or the entire task window for a unified UI experience. The entire app window dims by default when a dialog opens (see <span style=\"color: #0d904f; font-family: courier;\"><a href=\"https:\/\/developer.android.com\/reference\/androidx\/window\/embedding\/EmbeddingConfiguration.DimAreaBehavior#ON_TASK%28%29\" target=\"_blank\" rel=\"noopener\">EmbeddingConfiguration.DimAreaBehavior.ON_TASK<\/a><\/span>).To dim only the container of the activity that opened the dialog, use <span style=\"color: #0d904f; font-family: courier;\"><a href=\"https:\/\/developer.android.com\/reference\/androidx\/window\/embedding\/EmbeddingConfiguration.DimAreaBehavior#ON_ACTIVITY_STACK%28%29\" target=\"_blank\" rel=\"noopener\">EmbeddingConfiguration.DimAreaBehavior.ON_ACTIVITY_STACK<\/a><\/span>. This gives you more flexibility in designing dialogs and makes for a smoother, more coherent user experience. Temu is among the first developers to integrate this feature, <b>the full-screen dialog dim has reduced screen invalid touches by about 5%<\/b>.<\/p>\n<p><image><\/p>\n<div style=\"text-align: center;\"><img decoding=\"async\" alt=\"Customised shopping cart reminder with dialog full-screen dim in the Temu app\" border=\"0\" id=\"imgCaption\" src=\"https:\/\/blogger.googleusercontent.com\/img\/b\/R29vZ2xl\/AVvXsEhLiE6tczDdr2zyqCLvzFCMWwOev6PfUDyotLJBA2tmdjeiNM7179ZbUXKo7S4aZk0cB2vi4hIeK9PmRSRw5q_CHsJgIEE8tIEKdTKQdbV5FwsmZLRHeRG7uxzSmqk2cNy2ox5luCaz2YvK9G4MBw_7TpKUiwhPouvoaVG_3XHnQFbGPHoxjDbqMi-I2vU\/s1600\/image1.png\" width=\"640\"\/><\/div>\n<p><imgcaption><center><em>Customised shopping cart reminder with dialog full-screen dim in Temu.<\/em><\/center><\/imgcaption><\/image><\/p>\n<h2><span style=\"font-size: x-large;\">Enhanced posture support<\/span><\/h2>\n<p>WindowManager 1.4 makes building apps that work flawlessly on foldables straightforward by providing more information about the physical capabilities of the device. The new <span style=\"font-family: courier;\"><a href=\"https:\/\/developer.android.com\/reference\/kotlin\/androidx\/window\/layout\/WindowInfoTracker#supportedPostures%28%29\" target=\"_blank\" rel=\"noopener\">WindowInfoTracker#supportedPostures<\/a><\/span> API lets you know if a device supports tabletop mode, so you can optimize your app&#8217;s layout and features accordingly.<\/p>\n<p><!--Kotlin--><\/p>\n<div style=\"background: rgb(248, 248, 248); border: 0px; overflow: auto; width: auto;\">\n<pre style=\"line-height: 125%; margin: 0px;\"><span style=\"color: green; font-weight: bold;\">val<\/span> currentSdkVersion = WindowSdkExtensions.getInstance().extensionVersion\n<span style=\"color: green; font-weight: bold;\">val<\/span> message =\n<span style=\"color: green; font-weight: bold;\">if<\/span> (currentSdkVersion &gt;= <span style=\"color: #666666;\">6<\/span>) {\n  <span style=\"color: green; font-weight: bold;\">val<\/span> supportedPostures = WindowInfoTracker.getOrCreate(LocalContext.current).supportedPostures\n  buildString {\n    append(supportedPostures.isNotEmpty())\n    <span style=\"color: green; font-weight: bold;\">if<\/span> (supportedPostures.isNotEmpty()) {\n      append(<span style=\"color: #ba2121;\">\" \"<\/span>)\n      append(\n      supportedPostures.joinToString(\n      separator = <span style=\"color: #ba2121;\">\",\"<\/span>, prefix = <span style=\"color: #ba2121;\">\"(\"<\/span>, postfix = <span style=\"color: #ba2121;\">\")\"<\/span>))\n    }\n  }\n} <span style=\"color: green; font-weight: bold;\">else<\/span> {\n  <span style=\"color: #ba2121;\">\"N\/A (WindowSDK version 6 is needed, current version is $currentSdkVersion)\"<\/span>\n}\n<\/pre>\n<\/div>\n<h2><span style=\"font-size: x-large;\">Other API changes<\/span><\/h2>\n<p>WindowManager 1.4 includes several API changes and additions to support the new features. Notable changes include:<\/p>\n<ul style=\"text-align: left;\">\n<ul>\n<li>Stable and no longer experimental APIs:<\/li>\n<\/ul>\n<ul>\n<ul>\n<li><span style=\"color: #0d904f; font-family: courier;\">ActivityEmbeddingController#invalidateVisibleActivityStacks<\/span><\/li>\n<\/ul>\n<ul>\n<li><span style=\"color: #0d904f; font-family: courier;\">ActivityEmbeddingController#getActivityStack<\/span><\/li>\n<\/ul>\n<ul>\n<li><span style=\"color: #0d904f; font-family: courier;\">SplitController#updateSplitAttributes<\/span><\/li>\n<\/ul>\n<\/ul>\n<\/ul>\n<ul style=\"text-align: left;\">\n<ul>\n<li>API added to set activity embedding animation background:<\/li>\n<ul>\n<li><span style=\"color: #0d904f; font-family: courier;\">SplitAttributes.Builder#setAnimationParams<\/span><\/li>\n<\/ul>\n<\/ul>\n<\/ul>\n<ul style=\"text-align: left;\">\n<ul>\n<li>API to get updated WindowMetrics information:<\/li>\n<ul>\n<li><span style=\"color: #0d904f; font-family: courier;\">ActivityEmbeddingController#embeddedActivityWindowInfo<\/span><\/li>\n<\/ul>\n<\/ul>\n<\/ul>\n<ul style=\"text-align: left;\">\n<ul>\n<li>API to finish all activities in an activity stack:<\/li>\n<ul>\n<li><span style=\"color: #0d904f; font-family: courier;\">ActivityEmbeddingController#finishActivityStack<\/span><\/li>\n<\/ul>\n<\/ul>\n<\/ul>\n<h2><span style=\"font-size: x-large;\">How to get started<\/span><\/h2>\n<p>To start using Jetpack WindowManager 1.4 in your Android projects, update your app dependencies in build.gradle.kts to the latest stable version:<\/p>\n<p><!--Kotlin--><\/p>\n<div style=\"background: rgb(248, 248, 248); border: 0px; overflow: auto; width: auto;\">\n<pre style=\"line-height: 125%; margin: 0px;\">dependencies {\n    implementation(<span style=\"color: #ba2121;\">\"androidx.window:window:1.4.0\"<\/span>) \n    <span style=\"color: #408080; font-style: italic;\">\/\/ or, if you're using the WindowManager testing library:<\/span>\n    testImplementation(<span style=\"color: #ba2121;\">\"androidx.window:window-testing:1.4.0\"<\/span>)\n}\n<\/pre>\n<\/div>\n<p>Happy coding!<\/p>\n<\/div>\n<p>[ad_2]<br \/>\n<br \/><a href=\"http:\/\/android-developers.googleblog.com\/2025\/03\/jetpack-windowmanager-14-is-stable.html\">Source link <\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>[ad_1] Posted by Xiaodao Wu &#8211; Developer Relations Engineer Jetpack WindowManager keeps getting better. WindowManager gives you tools to build adaptive apps that work seamlessly<\/p>\n","protected":false},"author":1,"featured_media":272321,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"_uf_show_specific_survey":0,"_uf_disable_surveys":false,"footnotes":""},"categories":[146],"tags":[],"_links":{"self":[{"href":"https:\/\/michigandigitalnews.com\/index.php\/wp-json\/wp\/v2\/posts\/272320"}],"collection":[{"href":"https:\/\/michigandigitalnews.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/michigandigitalnews.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/michigandigitalnews.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/michigandigitalnews.com\/index.php\/wp-json\/wp\/v2\/comments?post=272320"}],"version-history":[{"count":0,"href":"https:\/\/michigandigitalnews.com\/index.php\/wp-json\/wp\/v2\/posts\/272320\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/michigandigitalnews.com\/index.php\/wp-json\/wp\/v2\/media\/272321"}],"wp:attachment":[{"href":"https:\/\/michigandigitalnews.com\/index.php\/wp-json\/wp\/v2\/media?parent=272320"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/michigandigitalnews.com\/index.php\/wp-json\/wp\/v2\/categories?post=272320"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/michigandigitalnews.com\/index.php\/wp-json\/wp\/v2\/tags?post=272320"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}