{"id":2864,"date":"2022-11-03T13:02:06","date_gmt":"2022-11-03T20:02:06","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/surface-duo\/?p=2864"},"modified":"2022-11-03T13:33:42","modified_gmt":"2022-11-03T20:33:42","slug":"activity-embedding-preview-for-large-screens-and-foldables","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/surface-duo\/activity-embedding-preview-for-large-screens-and-foldables\/","title":{"rendered":"Activity Embedding preview for large screens and foldables"},"content":{"rendered":"<p>\n  Hello Android developers,\n<\/p>\n<p>\nThe <a href=\"https:\/\/developer.android.com\/jetpack\/androidx\/releases\/window\">Jetpack Window Manager<\/a> (JWM) library helps you build adaptive UIs that work well on any device form factor (i.e. single screen, dual screen, foldable, and large screen devices). Jetpack Window Manager provides you with the information that you need to adapt your app\u2019s UI, so it works well on any device. For example, you can know where a folding feature is located, the posture that the device is using according to the folding feature and its orientation, etc.<\/p>\n<h2>Activity Embedding<\/h2>\n<p><a href=\"https:\/\/developer.android.com\/guide\/topics\/large-screens\/activity-embedding\">Activity Embedding<\/a> is part of Jetpack Window Manager version 1.1 alpha and contains APIs that help you to optimize apps on large screen devices by splitting an application\u2019s task window between two activities or two instances of the same activity.\n<\/p>\n<p>\n  <img decoding=\"async\" width=\"924\" height=\"924\" src=\"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-content\/uploads\/sites\/53\/2022\/11\/graphical-user-interface-text-application-descr.png\" class=\"wp-image-2865\" alt=\"Example of activity embedding - the Android settings app - on a foldable device\" srcset=\"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-content\/uploads\/sites\/53\/2022\/11\/graphical-user-interface-text-application-descr.png 924w, https:\/\/devblogs.microsoft.com\/surface-duo\/wp-content\/uploads\/sites\/53\/2022\/11\/graphical-user-interface-text-application-descr-300x300.png 300w, https:\/\/devblogs.microsoft.com\/surface-duo\/wp-content\/uploads\/sites\/53\/2022\/11\/graphical-user-interface-text-application-descr-150x150.png 150w, https:\/\/devblogs.microsoft.com\/surface-duo\/wp-content\/uploads\/sites\/53\/2022\/11\/graphical-user-interface-text-application-descr-768x768.png 768w, https:\/\/devblogs.microsoft.com\/surface-duo\/wp-content\/uploads\/sites\/53\/2022\/11\/graphical-user-interface-text-application-descr-24x24.png 24w, https:\/\/devblogs.microsoft.com\/surface-duo\/wp-content\/uploads\/sites\/53\/2022\/11\/graphical-user-interface-text-application-descr-48x48.png 48w, https:\/\/devblogs.microsoft.com\/surface-duo\/wp-content\/uploads\/sites\/53\/2022\/11\/graphical-user-interface-text-application-descr-96x96.png 96w\" sizes=\"(max-width: 924px) 100vw, 924px\" \/>\n  <br \/><em>Figure 1. Settings app with activities side by side. (<\/em><a href=\"https:\/\/developer.android.com\/guide\/topics\/large-screens\/activity-embedding\"><em>source<\/em><\/a><em>)<\/em>\n<\/p>\n<p>\n  Activity Embedding helps with legacy codebases that are based on Activities (e.g., every screen is an Activity, or it has several Activities with Fragments inside of them, etc.) that want to get enhanced and build adaptive UIs that work well on different form factor devices. With Activity Embedding, we can define specific <strong>rules that define how we want to show the activities<\/strong> in our app when satisfying them.\n<\/p>\n<p>\n  For example, we could define a rule that whenever there is a specific enough width available, we show two activities side-by-side, or otherwise, stacked one on top of the other:\n<\/p>\n<p>\n  <img decoding=\"async\" width=\"846\" height=\"322\" src=\"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-content\/uploads\/sites\/53\/2022\/11\/word-image-2864-2.png\" class=\"wp-image-2866\" alt=\"Two Surface Duos showing activity embedding samples with one or two activities showing\" srcset=\"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-content\/uploads\/sites\/53\/2022\/11\/word-image-2864-2.png 846w, https:\/\/devblogs.microsoft.com\/surface-duo\/wp-content\/uploads\/sites\/53\/2022\/11\/word-image-2864-2-300x114.png 300w, https:\/\/devblogs.microsoft.com\/surface-duo\/wp-content\/uploads\/sites\/53\/2022\/11\/word-image-2864-2-768x292.png 768w\" sizes=\"(max-width: 846px) 100vw, 846px\" \/><\/p>\n<p><em>Figure 2. Activity Embedding will show one activity by default and will show two activities side-by-side when the rules match.<\/em>\n<\/p>\n<p>\n  If your codebase is based on single-activity architecture, you may take a look to other components built for these use cases such as <a href=\"https:\/\/developer.android.com\/reference\/androidx\/slidingpanelayout\/widget\/SlidingPaneLayout\">SlidingPaneLayout<\/a> or the <a href=\"https:\/\/learn.microsoft.com\/dual-screen\/android\/jetpack\/compose\/\">Jetpack Compose components we have created<\/a>.\n<\/p>\n<p>\n  Activity Embedding is an experimental API that may change. It\u2019s available for devices that run Android 12L (API v32) or higher.\n<\/p>\n<p>\n  There are many more features and aspects you should consider that we don\u2019t cover here and that are explained in the <a href=\"https:\/\/developer.android.com\/guide\/topics\/large-screens\/activity-embedding\">official docs<\/a>.\n<\/p>\n<h2>Get started<\/h2>\n<p>\n  To use Activity Embedding, you will have to add Jetpack Window Manager to your <b>build.gradle<\/b> file. Most recent update is <code>1.1.0-alpha03<\/code>.\n<\/p>\n<p>\n  Activity Embedding usage is based on an XML configuration file and Window Manager API calls. You will have to place an xml file in the xml folder with the split rules you want to use and where you define which activities should be split.\n<\/p>\n<h2>Activity Embedding sample<\/h2>\n<p>\n  This <a href=\"https:\/\/github.com\/CesarValiente\/activity-embedding-sample\">sample app<\/a> helps explain how to take use Activity Embedding for a scenario where multiple Activities are used in an app, and where we want to build an adaptive UI that works well on foldable and large-screen devices.\n<\/p>\n<p>\n  The sample app is based on four activities which starts with Activity A (as defined in the manifest), and then each activity opens the following one, in this order: <strong>A -&gt; B -&gt; C -&gt; D<\/strong>. \n<\/p>\n<p>\n  If you open the app on Surface Duo 2 in single screen mode, you will see each activity occupy the entire screen as you navigate from one to the next. The activities are stacked one on top of the other.\n<\/p>\n<p>\n  In dual-screen mode on Surface Duo 2, or on a large screen device (or any device whose window size meets the rules we are going to use), it will show activities side-by-side according to the rules we have set.\n<\/p>\n<p>\n  The sample highlights these three features:\n<\/p>\n<ol>\n<li><strong>Adding an activity as placeholder in a two-pane scenario<\/strong>. This is useful when you need to show two activities side-by-side (e.g., a list with options on the left and the content at the right), but the content is not ready, to help handle that, we can show an activity as a placeholder.\n<\/li>\n<li><strong>Show two activities side-by-side according to a split rule<\/strong>. This split action will be explicitly triggered from the source activity.\n<\/li>\n<li>\n  Detecting <strong>whether an activity is running embedded or not<\/strong>.\n<\/li>\n<\/ol>\n<p>\n  Let\u2019s look at them one by one, but first is important to mention that we have to inform the library about the <a href=\"https:\/\/github.com\/CesarValiente\/activity-embedding-sample\/blob\/main\/app\/src\/main\/res\/xml\/main_split_config.xml\">rule definitions<\/a> we have. For that, we are going to use the <a href=\"https:\/\/developer.android.com\/jetpack\/androidx\/releases\/startup\">Jetpack Startup<\/a> library to perform an initialization before other components of the app load and activity start. We have to add an <a href=\"https:\/\/github.com\/CesarValiente\/activity-embedding-sample\/blob\/7f542b0fe346b452c737adf3fc3d785b52d1f892\/app\/src\/main\/AndroidManifest.xml#L34\">entry in the manifest<\/a> were we setup the startup library and link to our <a href=\"https:\/\/github.com\/CesarValiente\/activity-embedding-sample\/blob\/main\/app\/src\/main\/java\/com\/cesavaliente\/embedding\/ExampleWindowInitializer.kt\">Activity Embedding initializer<\/a>  where we indicate the rules file xml that we are going to use. In our case, the one located at <a href=\"https:\/\/github.com\/CesarValiente\/activity-embedding-sample\/blob\/main\/app\/src\/main\/res\/xml\/main_split_config.xml\"><strong>\/res\/xml\/main_split_config.xml<\/strong><\/a>.\n<\/p>\n<p>\n  Now, let\u2019s see finally the three different features we want to cover:\n<\/p>\n<h3>Show two Activities side-by-side defining a split placeholder rule<\/h3>\n<p>\n  As mentioned <a href=\"https:\/\/developer.android.com\/guide\/topics\/large-screens\/activity-embedding#split_by_default\">in the docs<\/a>, sometimes is useful to have a default state, so when we need to open two activities side-by-side but the activity with the content is not ready we can show a <strong>placeholder<\/strong>. How can we define and use one?\n<\/p>\n<p>\n  As you can see in the app <a href=\"https:\/\/github.com\/CesarValiente\/activity-embedding-sample\/blob\/main\/app\/src\/main\/res\/xml\/main_split_config.xml\"><strong>\/res\/xml\/main_split_config.xml<\/strong><\/a>:\n<\/p>\n<pre>&lt;SplitPlaceholderRule\r\n    window:placeholderActivityName=\"com.cesavaliente.embedding.ActivityB\"\r\n    window:splitMinWidth=\"537dp\"\r\n    window:splitRatio=\"0.5\"&gt;\r\n    &lt;ActivityFilter \r\n          window:activityName=\"com.cesavaliente.embedding.ActivityA\" \/&gt;\r\n  &lt;\/SplitPlaceholderRule&gt;<\/pre>\n<p><em>Figure 3. <\/em><a href=\"https:\/\/github.com\/CesarValiente\/activity-embedding-sample\/blob\/7f542b0fe346b452c737adf3fc3d785b52d1f892\/app\/src\/main\/res\/xml\/main_split_config.xml#L10\"><em>SplitPlaceholderRule<\/em><\/a><em> with the ActivityFilter where we define with activity will trigger this split and the placeholderActivityName where we define the activity that will act as placeholder.<\/em>\n<\/p>\n<p>\n  Here, inside <strong>SplitPlaceholderRule<\/strong> we are saying that when we have at least 537dp width window size (<strong>splitMinWidth<\/strong>), and we are in the Activity A (<strong>ActivityFilter<\/strong>) then we will show the <strong>placeholder<\/strong> (Activity B) side-by-side with the Activity A in a 0.5 screen <strong>splitRatio<\/strong>. If we don\u2019t satisfy the rule, then we will just show activity A.\n<\/p>\n<p>\n  If you are wondering about why we are using that specific value (537dp) in <em>splitMinWidth<\/em>, that\u2019s because in this sample, we want to have the side-by-side activity scenario just when the app is spanned across displays on Surface Duo 2, <a href=\"https:\/\/learn.microsoft.com\/dual-screen\/android\/surface-duo-dimensions#screen-elements-double-portrait\">and each display on this device, has a 537dp width<\/a>.\n<\/p>\n<p>\n  For <em>splitRatio<\/em> set to 0.5, that\u2019s because we want that each activity, when running them side-by-side, take a whole display, so each one takes exactly 50% of the whole display area available.\n<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-content\/uploads\/sites\/53\/2022\/11\/figure-3-anim-white.gif\" alt=\"animation of activity embedding\" width=\"1074\" height=\"844\" class=\"alignnone size-full wp-image-2886\" \/><\/p>\n<p><em>Figure 3. Activity A and B are shown in single screen mode (on top of the other) and later as placeholder in dual screen mode (side-by-side).<\/em>\n<\/p>\n<p>\n  Is important to mention that Activity Embedding is not fold aware, that means that depending on the rules we define, the content may be or not separated and\/or occluded by a FoldingFeature. Since the library doesn\u2019t handle FoldingFeature automatically, placing the content around it, we must do it by ourselves, hence the importance of defining attributes that work for most devices or scenarios (or creating different rules).\n<\/p>\n<h3>Show two Activities side-by-side defining a split pair rule<\/h3>\n<p>\n  We can define as well that whenever we launch a specific activity, if the split-rules are satisfied, the activity can be launched side-by-side with its parent.\n<\/p>\n<p>\n  If we go to the <a href=\"https:\/\/github.com\/CesarValiente\/activity-embedding-sample\/blob\/main\/app\/src\/main\/res\/xml\/main_split_config.xml\">xml file<\/a> where we have the rules defined, we can see now:\n<\/p>\n<pre>&lt;SplitPairRule\r\n    window:finishPrimaryWithSecondary=\"adjacent\"\r\n    window:finishSecondaryWithPrimary=\"adjacent\"\r\n    window:splitLayoutDirection=\"rtl\"\r\n    window:splitMinWidth=\"537dp\"\r\n    window:splitRatio=\"0.5\"&gt;\r\n    &lt;SplitPairFilter\r\n        window:primaryActivityName=\"com.cesavaliente.embedding.ActivityC\"\r\n        window:secondaryActivityName=\"com.cesavaliente.embedding.ActivityD\" \/&gt;\r\n&lt;\/SplitPairRule&gt;<\/pre>\n<p><em>Figure 4. <a href=\"https:\/\/github.com\/CesarValiente\/activity-embedding-sample\/blob\/7f542b0fe346b452c737adf3fc3d785b52d1f892\/app\/src\/main\/res\/xml\/main_split_config.xml#L22\">SplitPairRule<\/a> and the rule to show two activities side-by-side if the rule is satisfied.<\/em>\n<\/p>\n<p>\n  In this node, <strong>SplitPairRule<\/strong>, the most important part is the <strong>SplitPairFilter<\/strong> node, here we are defining which one will be the primary activity (or parent) and which one the secondary activity (or child).\n<\/p>\n<p>\n  Then with attributes such as what we saw before <strong>splitMinWidth<\/strong> and <strong>splitRatio<\/strong> we can define the window configuration we have to have to show them side-by-side. Otherwise, they will be launched one on top of the other (as usual).\n<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-content\/uploads\/sites\/53\/2022\/11\/figure-5-anim-white.gif\" alt=\"animation of activity embedding\" width=\"1074\" height=\"844\" class=\"alignnone size-full wp-image-2885\" \/><\/p>\n<p><em>Figure 5. All activities are shown on top of each other in single screen mode and activity D is launched side-by-side later (from activity C) when in dual-screen mode (when split rule is satisfied).<\/em>\n<\/p>\n<h3>Check whether an activity is embedded or not<\/h3>\n<p>\n  The last thing we want to show you is to check if an activity that is being shown embedded or not. To know that we must use this API through code; using the <strong>SplitController<\/strong> instance and call the specific <strong>isActivityEmbedded<\/strong> function:\n<\/p>\n<pre>val isActivityEmbedded = SplitController.getInstance().isActivityEmbedded(this)<\/pre>\n<p><em>Figure 6. Knowing whether an activity is embedded or not using the SplitController instance.<\/em>\n<\/p>\n<p>\n  In the below figure, we can see the result of <a href=\"https:\/\/github.com\/CesarValiente\/activity-embedding-sample\/blob\/7f542b0fe346b452c737adf3fc3d785b52d1f892\/app\/src\/main\/java\/com\/cesavaliente\/embedding\/ActivityD.kt#L18\">calling this function<\/a> on both scenarios. We can see how a toast shows that the activity is not embedded (false) when running the app in single screen mode, and that the activity is embedded (true) when running in dual-screen mode with two activities side-by-side:\n<\/p>\n<p>\n  <img decoding=\"async\" width=\"897\" height=\"499\" src=\"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-content\/uploads\/sites\/53\/2022\/11\/word-image-2864-7.png\" class=\"wp-image-2871\" alt=\"Pixel tablet emulator showing activity embedding sample with two activities side by side in landscape mode\" srcset=\"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-content\/uploads\/sites\/53\/2022\/11\/word-image-2864-7.png 897w, https:\/\/devblogs.microsoft.com\/surface-duo\/wp-content\/uploads\/sites\/53\/2022\/11\/word-image-2864-7-300x167.png 300w, https:\/\/devblogs.microsoft.com\/surface-duo\/wp-content\/uploads\/sites\/53\/2022\/11\/word-image-2864-7-768x427.png 768w\" sizes=\"(max-width: 897px) 100vw, 897px\" \/>\n<\/p>\n<p><em>Figure 7. A toast shows that the activity D is not embedded in single screen mode (left) and that it is, in dual-screen mode (right).<\/em>\n<\/p>\n<p>\n  Note: the above figure has been created using a Pixel C emulator. If you want to reproduce the same scenario in the sample app, you will have to change <em>splitMinWidth<\/em> to 1100dp and <em>splitRatio<\/em> to 0.2 in both rules (SplitPlaceHolder and SplitPairRule) in the xml rules file.\n  \n<\/p>\n<h2>Resources and feedback<\/h2>\n<p>\n  If you have questions about foldable Android app development or want to share your work, please reach out to us on\u00a0<a href=\"https:\/\/techcommunity.microsoft.com\/t5\/surface-duo-sdk\/bd-p\/SurfaceDuoSDK\">Tech Community<\/a> or find us on\u00a0<a href=\"https:\/\/twitter.com\/surfaceduodev\">Twitter @surfaceduodev<\/a>.\n<\/p>\n<p>\n  You can also live chat with us on\u00a0<a href=\"https:\/\/twitch.tv\/surfaceduodev\">Twitch\u00a0<\/a>this Friday at 13h CET and later at 11am PST!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Hello Android developers, The Jetpack Window Manager (JWM) library helps you build adaptive UIs that work well on any device form factor (i.e. single screen, dual screen, foldable, and large screen devices). Jetpack Window Manager provides you with the information that you need to adapt your app\u2019s UI, so it works well on any device. [&hellip;]<\/p>\n","protected":false},"author":30297,"featured_media":2880,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[717,706,473],"class_list":["post-2864","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-surface-duo-sdk","tag-foldable","tag-jetpack-window-manager","tag-kotlin"],"acf":[],"blog_post_summary":"<p>Hello Android developers, The Jetpack Window Manager (JWM) library helps you build adaptive UIs that work well on any device form factor (i.e. single screen, dual screen, foldable, and large screen devices). Jetpack Window Manager provides you with the information that you need to adapt your app\u2019s UI, so it works well on any device. [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-json\/wp\/v2\/posts\/2864","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=2864"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-json\/wp\/v2\/posts\/2864\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-json\/wp\/v2\/media\/2880"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-json\/wp\/v2\/media?parent=2864"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-json\/wp\/v2\/categories?post=2864"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-json\/wp\/v2\/tags?post=2864"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}