{"id":209,"date":"2020-04-02T14:11:36","date_gmt":"2020-04-02T21:11:36","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/surface-duo\/?p=209"},"modified":"2022-06-17T10:44:53","modified_gmt":"2022-06-17T17:44:53","slug":"orientation-spanning-and-insets","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/surface-duo\/orientation-spanning-and-insets\/","title":{"rendered":"Orientation, Spanning and Insets"},"content":{"rendered":"<p>Hello Microsoft Surface Duo Developers!<\/p>\n<p>Until recently, mobile devices all had one thing in common: a single screen. While applications had to support multiple screen sizes, recently manufacturers got creative and introduced new foldable, dual-screen devices, Google added support for <a href=\"https:\/\/developer.android.com\/guide\/topics\/ui\/multi-window\">multi-windowing on Android<\/a>.\nNow applications need to dynamically handle size changes and various screen sizes.<\/p>\n<p>In today\u2019s blog post, I\u2019ll discuss how your Android application will behave on the Surface Duo, by answering the following questions:<\/p>\n<ol>\n<li>Is the activity spanned or running in a single screen?<\/li>\n<li>If a single screen, is it on the right or left portrait or top or bottom landscape<\/li>\n<li>Is there an inset from the keyboard?<\/li>\n<li>How to launch an external activity while spanned, without it taking the whole display<\/li>\n<\/ol>\n<p>We also published a new sample called <a href=\"https:\/\/github.com\/microsoft\/surface-duo-sdk-samples\">Orientation And Spanning<\/a> in our GitHub repository.<\/p>\n<h2>Spanning and Screen Location (questions 1 and 2)<\/h2>\n<p>To best support dual-screen devices, activities should support resizing and react to configuration changes, to do that, add these lines to the activity manifest:<\/p>\n<pre class=\"prettyprint\">android:resizeableActivity=\"true\"\r\nandroid:configChanges=\"screenSize|smallestScreenSize|screenLayout|orientation\"\r\n<\/pre>\n<p>This also means that the <a href=\"https:\/\/developer.android.com\/guide\/topics\/ui\/multi-window#config\">activity will not restart every time its size changes.<\/a><\/p>\n<p>On Surface Duo the following actions will fire configuration change:<\/p>\n<ul>\n<li>Orientation change \u2013 the aspect ratio of the app changes<\/li>\n<li>Span or un-span \u2013 when the user drags the app to span both displays horizontally or vertically<\/li>\n<\/ul>\n<p>Next, override the <a href=\"https:\/\/developer.android.com\/reference\/android\/app\/Activity#onConfigurationChanged(android.content.res.Configuration)\">onConfigurationChanged<\/a> method in the activity,<\/p>\n<p>In it, gather the information we need:<\/p>\n<ul>\n<li>From the orientation field, find out if the activity is in Landscape or portrait,<\/li>\n<li>Detect if the user spanned the activity by using the <a href=\"https:\/\/docs.microsoft.com\/en-us\/dual-screen\/android\/sample-code\/is-app-spanned?tabs=java\">ScreenHelper.isDualMode<\/a> helper method<\/li>\n<li>Then use the <a href=\"https:\/\/developer.android.com\/reference\/android\/view\/View#getLocationOnScreen(int%5B%5D)\">getLocationOnScreen<\/a> to find out the absolute coordinates of our window.<\/li>\n<\/ul>\n<pre class=\"prettyprint\">@Override\r\npublic void onConfigurationChanged (Configuration newConfig){\r\n \tsuper.onConfigurationChanged(newConfig);\r\nboolean isSpanned = ScreenHelper.isDualMode(MainActivity.this);\r\n\r\n\tint screenPosition[] = new int [2];\r\n\tgetWindow().getDecorView().getLocationOnScreen(screenPosition);\r\n}\r\n<\/pre>\n<p>Using this information, I can answer question 1 and 2:<\/p>\n<table cellspacing=\"10\" align=\"center\">\n<tbody>\n<tr>\n<th><\/th>\n<th style=\"text-align: center;\">Spanned<\/th>\n<th style=\"text-align: center;\">Not Spanned<\/th>\n<\/tr>\n<tr>\n<th style=\"text-align: center;\">Landscape<\/th>\n<td><img decoding=\"async\" class=\"aligncenter size-large wp-image-222\" src=\"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-content\/uploads\/sites\/53\/2020\/04\/Screenshot_1585759755-1024x662.png\" alt=\"Application spanned across 2 screens\" width=\"320\" height=\"212\" \/><\/td>\n<td>\n<table>\n<tbody>\n<tr>\n<td><img decoding=\"async\" class=\"aligncenter size-large wp-image-226\" src=\"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-content\/uploads\/sites\/53\/2020\/04\/Screenshot_1585759827-662x1024.png\" alt=\"Application in landscape mode on the top screen\" width=\"160\" height=\"212\" \/><\/td>\n<td><img decoding=\"async\" class=\"aligncenter size-large wp-image-227\" src=\"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-content\/uploads\/sites\/53\/2020\/04\/Screenshot_1585759833-662x1024.png\" alt=\"Application in landscape mode on the bottom screen\" width=\"160\" height=\"212\" \/><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/td>\n<\/tr>\n<tr>\n<th style=\"text-align: center;\">Portrait<\/th>\n<td><img decoding=\"async\" class=\"aligncenter size-large wp-image-224\" src=\"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-content\/uploads\/sites\/53\/2020\/04\/Screenshot_1585759841-662x1024.png\" alt=\"Application spanned in portrarit mode\" width=\"320\" height=\"424\" \/><\/td>\n<td>\n<table>\n<tbody>\n<tr>\n<td><img decoding=\"async\" class=\"aligncenter size-large wp-image-230\" src=\"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-content\/uploads\/sites\/53\/2020\/04\/Screenshot_1585759730-1024x662.png\" alt=\"Application in portrait mode on the left screen\" width=\"320\" height=\"212\" \/><\/td>\n<\/tr>\n<tr>\n<td><img decoding=\"async\" class=\"aligncenter size-large wp-image-231\" src=\"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-content\/uploads\/sites\/53\/2020\/04\/Screenshot_1585759747-1024x662.png\" alt=\"Application in portrait mode on the right screen\" width=\"320\" height=\"212\" \/><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p style=\"text-align: center;\"><strong>Table: 6 different configuration an activity can be<\/strong><\/p>\n<p>When run on the emulator, you\u2019ll notice the sample uses animations to re-arrange the user interface when configuration changes are detected.<\/p>\n<p><div class=\"alert alert-primary\"><p class=\"alert-divider\"><i class=\"fabric-icon fabric-icon--Info\"><\/i><strong>Screen position cannot be determined<\/strong><\/p>This blog was written with pre-release implementations for some methods including <code>getLocationOnScreen<\/code> &#8211; some changes were made prior to shipping and the screen position can no longer be determined from this API alone.<\/div><\/p>\n<h2>Detecting when the activity is moved from screen to screen<\/h2>\n<p>The <a href=\"https:\/\/developer.android.com\/reference\/android\/app\/Activity#onConfigurationChanged(android.content.res.Configuration)\">onConfigurationChanged<\/a> method will let us know on size changes on our activity, but it will not notify if the user moves the activity from the side to side or top to bottom screens.<\/p>\n<p>Detecting that is a little bit more work:<\/p>\n<ol>\n<li>First, find the root view for our activity like this:<\/li>\n<\/ol>\n<pre class=\"prettyprint\">View rootView = getWindow().getDecorView().getRootView();<\/pre>\n<ol start=\"2\">\n<li>Add a layout listener using the <a href=\"https:\/\/developer.android.com\/reference\/android\/view\/View#addOnLayoutChangeListener(android.view.View.OnLayoutChangeListener)\">addOnLayoutChangeListener<\/a>\nThe listener will fire whenever the user moves the activity.<\/li>\n<\/ol>\n<h2>Keyboard inset<\/h2>\n<p>To detect the keyboard inset, you first add <a href=\"https:\/\/developer.android.com\/training\/keyboard-input\/visibility\">android:windowSoftInputMode<\/a> to your activity manifest:<\/p>\n<pre class=\"prettyprint\">android:windowSoftInputMode=\"stateAlwaysHidden|adjustResize\"<\/pre>\n<p>(the adjustResize part is the relevant one)\nThen set a listener with the setOnApplyWindowInsetsListener method on the root view of the activity.\nAndroid will call the listener whenever the keyboard appears and the systemWindowInsets.bottom will have the pixel amount taken by the keyboard even if the keyboard is floating.\n<img decoding=\"async\" class=\"aligncenter size-large wp-image-220\" src=\"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-content\/uploads\/sites\/53\/2020\/04\/Screenshot_1585759864-1024x662.png\" alt=\"Emulator with keyboard open\" width=\"640\" height=\"414\" srcset=\"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-content\/uploads\/sites\/53\/2020\/04\/Screenshot_1585759864-1024x662.png 1024w, https:\/\/devblogs.microsoft.com\/surface-duo\/wp-content\/uploads\/sites\/53\/2020\/04\/Screenshot_1585759864-300x194.png 300w, https:\/\/devblogs.microsoft.com\/surface-duo\/wp-content\/uploads\/sites\/53\/2020\/04\/Screenshot_1585759864-768x497.png 768w, https:\/\/devblogs.microsoft.com\/surface-duo\/wp-content\/uploads\/sites\/53\/2020\/04\/Screenshot_1585759864-1536x993.png 1536w, https:\/\/devblogs.microsoft.com\/surface-duo\/wp-content\/uploads\/sites\/53\/2020\/04\/Screenshot_1585759864-2048x1324.png 2048w\" sizes=\"(max-width: 640px) 100vw, 640px\" \/><\/p>\n<p style=\"text-align: center;\"><strong>Figure: keyboard inset 702 pixels<\/strong><\/p>\n<h2>Launching external activity while spanned,\nwithout it taking the whole display<\/h2>\n<p>Whenever an activity launched another activity within the same Task, the operating system will configure the activity to open on the same configuration of the original one as those activities will occupy the same window. Meaning if our activity is spanned and we will open another, the activity will be spanned as well.<\/p>\n<p>This might work well for some scenarios but on others we might want that our activity and the new one will appear side by side.<\/p>\n<p>To achieve this, we can use the same mechanism of launching the activity in a new task like we did in the sample and explained in the <a href=\"https:\/\/devblogs.microsoft.com\/surface-duo\/bring-your-app-to-surface-duo-step-2\/\">Bring your app to Surface Duo \u2013 Step 2<\/a> blog post.<\/p>\n<pre class=\"prettyprint\">intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK| Intent.FLAG_ACTIVITY_NEW_TASK);<\/pre>\n<p>Use the Intent.<a href=\"https:\/\/developer.android.com\/reference\/android\/content\/Intent#FLAG_ACTIVITY_MULTIPLE_TASK\"><em>FLAG_ACTIVITY_MULTIPLE_TASK<\/em><\/a> | Intent.<a href=\"https:\/\/developer.android.com\/reference\/android\/content\/Intent#FLAG_ACTIVITY_NEW_TASK\"><em>FLAG_ACTIVITY_NEW_TASK<\/em><\/a> flags when launching the activity.<\/p>\n<p>This will cause the spanned activity to un-span and the current activity to be on the adjacent screen.<\/p>\n<p>Try out the <a href=\"https:\/\/github.com\/microsoft\/surface-duo-sdk-samples\/tree\/master\/OrientationAndSpanning\">Orientation And Spanning<\/a> sample on GitHub on the Surface Duo emulator, and start applying these ideas to your own Android apps! We look forward to seeing you on the Surface Duo.<\/p>\n<h2>Feedback<\/h2>\n<p>We would LOVE to hear from you about your experiences using the SDK, emulator, and your first thoughts on how you can use these in YOUR app.<\/p>\n<p>Please reach out using the <a href=\"http:\/\/aka.ms\/SurfaceDuoSDK-Feedback\">feedback forum<\/a> or direct message me on <a href=\"https:\/\/twitter.com\/tggmbi\">Twitter<\/a> .<\/p>\n<p>And if you have not seen those already, we started a <a href=\"https:\/\/www.youtube.com\/playlist?reload=9&amp;list=PLlrxD0HtieHg0F4sBsc4c29ReSHQqpsqs\">series of 1 minute videos<\/a> to answer the most frequent questions<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Hello Microsoft Surface Duo Developers! Until recently, mobile devices all had one thing in common: a single screen. While applications had to support multiple screen sizes, recently manufacturers got creative and introduced new foldable, dual-screen devices, Google added support for multi-windowing on Android. Now applications need to dynamically handle size changes and various screen sizes. [&hellip;]<\/p>\n","protected":false},"author":23662,"featured_media":222,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"image","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[294,292,293],"class_list":["post-209","post","type-post","status-publish","format-image","has-post-thumbnail","hentry","category-surface-duo-sdk","tag-inset","tag-orientation","tag-span","post_format-post-format-image"],"acf":[],"blog_post_summary":"<p>Hello Microsoft Surface Duo Developers! Until recently, mobile devices all had one thing in common: a single screen. While applications had to support multiple screen sizes, recently manufacturers got creative and introduced new foldable, dual-screen devices, Google added support for multi-windowing on Android. Now applications need to dynamically handle size changes and various screen sizes. [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-json\/wp\/v2\/posts\/209","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\/23662"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-json\/wp\/v2\/comments?post=209"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-json\/wp\/v2\/posts\/209\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-json\/wp\/v2\/media\/222"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-json\/wp\/v2\/media?parent=209"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-json\/wp\/v2\/categories?post=209"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-json\/wp\/v2\/tags?post=209"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}