{"id":5074,"date":"2024-08-02T15:31:51","date_gmt":"2024-08-02T15:31:51","guid":{"rendered":"https:\/\/castle-engine.io\/wp\/?p=5074"},"modified":"2024-08-02T15:31:51","modified_gmt":"2024-08-02T15:31:51","slug":"mobile-android-improvements-safe-borders-new-ui-scaling-accounting-for-auto-rotation-nicer-better-gestures-with-tcastleexaminenavigation-modern-android-photo-services-improved-docs","status":"publish","type":"post","link":"https:\/\/castle-engine.io\/wp\/2024\/08\/02\/mobile-android-improvements-safe-borders-new-ui-scaling-accounting-for-auto-rotation-nicer-better-gestures-with-tcastleexaminenavigation-modern-android-photo-services-improved-docs\/","title":{"rendered":"Mobile \/ Android improvements: safe borders, new UI scaling accounting for auto-rotation nicer, better gestures with TCastleExamineNavigation, modern Android photo services, improved docs"},"content":{"rendered":"<table class=\"thumbnails thumbnails-align-right\"><tr><td>\n          <a href=\"https:\/\/castle-engine.io\/wp\/wp-content\/uploads\/2024\/08\/Screenshot_1722611917.png\"\n             class=\"screenshot\"\n             title=\"Android inspector with safe borders\"><img loading=\"lazy\" decoding=\"async\"\n            style=\"float: right\"\n            src=\"https:\/\/castle-engine.io\/wp\/wp-content\/uploads\/2024\/08\/Screenshot_1722611917-200x113.png\"\n             width=\"200\" height=\"113\" \n            alt=\"Android inspector with safe borders\"\n          ><\/a><\/td><\/tr><tr><td>\n          <a href=\"https:\/\/castle-engine.io\/wp\/wp-content\/uploads\/2024\/08\/Screenshot_1722611973.png\"\n             class=\"screenshot\"\n             title=\"Android inspector with safe borders\"><img loading=\"lazy\" decoding=\"async\"\n            style=\"float: right\"\n            src=\"https:\/\/castle-engine.io\/wp\/wp-content\/uploads\/2024\/08\/Screenshot_1722611973-200x113.png\"\n             width=\"200\" height=\"113\" \n            alt=\"Android inspector with safe borders\"\n          ><\/a><\/td><\/tr><tr><td>\n          <a href=\"https:\/\/castle-engine.io\/wp\/wp-content\/uploads\/2024\/08\/Screenshot_1722612090.png\"\n             class=\"screenshot\"\n             title=\"Android with safe borders\"><img loading=\"lazy\" decoding=\"async\"\n            style=\"float: right\"\n            src=\"https:\/\/castle-engine.io\/wp\/wp-content\/uploads\/2024\/08\/Screenshot_1722612090-200x113.png\"\n             width=\"200\" height=\"113\" \n            alt=\"Android with safe borders\"\n          ><\/a><\/td><\/tr><\/table>\n<p>Hi all! Today we announce a number of improvements for mobile (<a href=\"https:\/\/castle-engine.io\/android\">Android<\/a>, <a href=\"https:\/\/castle-engine.io\/ios\">iOS<\/a>) development. They&#8217;ve been done while testing:<\/p>\n<ul>\n<li>\n    <a href=\"https:\/\/castle-engine.io\/castle-model-viewer-mobile\">Recently announced Castle Model Viewer on Android<\/a>, see <a href=\"https:\/\/castle-engine.io\/wp\/2024\/07\/27\/castle-model-viewer-reimagined-for-mobile-available-for-android-now\/\">news<\/a>.<\/p>\n<li>\n<p>Updated <a href=\"https:\/\/play.google.com\/store\/apps\/details?id=io.castleengine.mobile.game.services\">Game Services Demo<\/a> on <i>Google Play<\/i>.<\/p>\n<li>\n<p>Updated <a href=\"https:\/\/castle-engine.io\/darkest_before_dawn.php\">Darkest Before the Dawn<\/a>. A really old game developed using <em>Castle Game Engine<\/em>. Updated &#8211; no ads, use latest engine, released again on Google Play! Historically, this is the first game made for Android using Castle Game Engine, in 2013.\n<\/ul>\n<p>( Missed anything? See <a href=\"https:\/\/play.google.com\/store\/apps\/dev?id=8315026166336791468\">all Castle Game Engine applications on Google Play<\/a>. )<\/p>\n<p>Onward to engine improvements around the mobile:<\/p>\n<ol>\n<li>\n    <code><a href=\"https:\/\/castle-engine.io\/apidoc\/html\/CastleUIControls.TCastleContainer.html#SafeBorder\">TCastleContainer.SafeBorder<\/a><\/code> &#8212; new property, working on both iOS and Android, exposing the safe area on screen edges where you should not draw anything important\/clickable, because the system itself may draw important\/clickable stuff on top of your application there. <\/p>\n<p>For example the system clock\/battery\/network state take space on top. The software home\/back buttons may be on the bottom. <i>Notch<\/i> are present on some phones which obscure some part of some edge. See <a href=\"https:\/\/developer.android.com\/develop\/ui\/views\/layout\/display-cutout\">Android docs for display cutouts<\/a>, <a href=\"https:\/\/android-developers.googleblog.com\/2018\/07\/supporting-display-cutouts-on-edge-to.html\">and here<\/a> how these displays look like. There are a few terms more-or-less interchangeable for this: <em>safe area<\/em>, <em>insets<\/em>, <em>display cutouts<\/em> on Android, <em>status bar\/bottom bar<\/em> on iOS.<\/p>\n<p>Usually these are non-zero at top and bottom, but <code><a href=\"https:\/\/castle-engine.io\/apidoc\/html\/CastleUIControls.TCastleContainer.html#SafeBorder\">TCastleContainer.SafeBorder<\/a><\/code> allows us to expose safe areas on potentially any screen side. Underlying API on Android actually gets all 4 sides. (Current code on iOS only queries for top safe area now, but we can improve it.)<\/p>\n<p>We also exposed <code><a href=\"https:\/\/castle-engine.io\/apidoc\/html\/CastleUIControls.TCastleContainer.html#OnSafeBorderChanged\">TCastleContainer.OnSafeBorderChanged<\/a><\/code> to notify about safe area changes. This is important, as applications dynamically switch orientation and\/or enter\/exit immersive fullscreen modes. So to support <code><a href=\"https:\/\/castle-engine.io\/apidoc\/html\/CastleUIControls.TCastleContainer.html#SafeBorder\">TCastleContainer.SafeBorder<\/a><\/code> perfectly, make sure to react to <code><a href=\"https:\/\/castle-engine.io\/apidoc\/html\/CastleUIControls.TCastleContainer.html#OnSafeBorderChanged\">TCastleContainer.OnSafeBorderChanged<\/a><\/code> events.<\/p>\n<p>Our inspector (F8 on desktop, hold 3 fingers for 1 second on mobile) also shows them, as red bars.<\/p>\n<p>They behave OK with switchable orientations (portrait, landscape), phones and tablets and all supported Android versions, and it doesn&#8217;t break our behavior on <a href=\"https:\/\/castle-engine.io\/project_manifest#_basic_project_information\">fullscreen_immersive<\/a>. This was some work to test \ud83d\ude42<\/p>\n<p>How to actually support them &#8212; you need to move \/ enlarge your UI, to leave an extra space at the respective screen edges. You can move your UI (<code><a href=\"https:\/\/castle-engine.io\/apidoc\/html\/CastleUIControls.TCastleUserInterface.html#Translation\">TCastleUserInterface.Translation<\/a><\/code>), you can enlarge it (<code><a href=\"https:\/\/castle-engine.io\/apidoc\/html\/CastleUIControls.TCastleUserInterface.html#Height\">TCastleUserInterface.Height<\/a><\/code>), you can use UI borders (<code><a href=\"https:\/\/castle-engine.io\/apidoc\/html\/CastleUIControls.TCastleUserInterface.html#Border\">TCastleUserInterface.Border<\/a><\/code>), you can use padding available on some controls, you can also just add a solid-colored rectangle just for the sake of these insets. There&#8217;s no &#8220;automatic&#8221; answer, as you see &#8212; what to do depends on what UI you display. You can take a look <a href=\"https:\/\/github.com\/castle-engine\/castle-model-viewer-mobile\/blob\/master\/code\/gameviewdisplayscene.pas\">what Castle Model Viewer for mobile<\/a> does. <\/p>\n<li>\n<p>We have a new UI scaling method <code><a href=\"https:\/\/castle-engine.io\/apidoc\/html\/CastleUIControls.html#usEncloseReferenceSizeAutoOrientation\">usEncloseReferenceSizeAutoOrientation<\/a><\/code>. It is very similar to <code><a href=\"https:\/\/castle-engine.io\/apidoc\/html\/CastleUIControls.html#usEncloseReferenceSize\">usEncloseReferenceSize<\/a><\/code>, but automatically &#8220;flips&#8221; the reference width\/height based on whether the current window sizes indicate portrait or landscape orientation. This means that UI controls have the same physical (real) size as your application orientation changes at runtime (e.g. because you support both portrait and landscape, and user just rotated the device).<\/p>\n<p>Designing for it is a bit more work. You have to account for both modes, portrait and landscape, as they result in different reference sizes. Your UI must fit sensibly in both cases.<\/p>\n<p>It is used by <a href=\"https:\/\/castle-engine.io\/castle-model-viewer-mobile\">Castle Model Viewer for mobile<\/a> so you can test it out and see how it works.<\/p>\n<li>\n<p>Gestures done with 2 fingers (on mobile) to zoom (pinch) and move (pan) with <code><a href=\"https:\/\/castle-engine.io\/apidoc\/html\/CastleCameras.TCastleExamineNavigation.html\">TCastleExamineNavigation<\/a><\/code> have been quite improved. The code was simplified, the gestures now &#8220;kick in&#8221; instantly and they switch between pinch \/ pan dynamically, so you can effectively do both pinch and pan without releasing your fingers. This results in UX that feels much better to user.<\/p>\n<p>Again <a href=\"https:\/\/castle-engine.io\/castle-model-viewer-mobile\">Castle Model Viewer for mobile<\/a> is an example how it works. Run it and use 2 fingers e.g. on sample cat model to zoom\/move it.<\/p>\n<li>\n<p><a href=\"https:\/\/github.com\/castle-engine\/castle-engine\/blob\/master\/tools\/build-tool\/data\/android\/integrated-services\/photo_service\/README.adoc\">photo_service<\/a> on Android was reimplemented to use modern approach on new Android devices and place the images reliably such that they appear in default <i>&#8220;Photos&#8221;<\/i> application.<\/p>\n<p>Using it is really trivial, just call <code>TPhotoService.StoreImage<\/code>. The full code (from <a href=\"https:\/\/github.com\/castle-engine\/castle-model-viewer-mobile\/blob\/master\/code\/gameviewdisplayscene.pas#L405\">castle-model-viewer-mobile<\/a>) is:<\/p>\n<pre lang=\"pascal\">\nprocedure TViewDisplayScene.ClickScreenshot(Sender: TObject);\nvar\n  Image: TRGBImage;\n  ImageUrl: String;\nbegin\n  ..\n  Image := Container.SaveScreen;\n  try\n    ImageUrl := FileNameAutoInc(ApplicationConfig('screenshots\/'), 'screenshot_%d.png');\n    SaveImage(Image, ImageUrl);\n    TPhotoService.StoreImage(ImageUrl);\n  finally FreeAndNil(Image) end;\n  ...\nend;\n<\/pre>\n<li>\n<p>We fixed saving files, when the subdirectory of the target file doesn&#8217;t exist. Our <a href=\"https:\/\/github.com\/castle-engine\/castle-engine\/commit\/c281e332c544bd109e475440f1ece4dfe64a6b3e\">handler for saving to <code>file:\/<\/code> protocol now creates directory automatically<\/a>. <\/p>\n<p>This makes sense for our engine, because we don&#8217;t want you to care about need for <code>ForceDirectories<\/code> and similar calls, because we don&#8217;t want you to usually care whether the protocol you use is <code>file:\/<\/code> or something else. We also don&#8217;t want you to depend on whether <code><a href=\"https:\/\/castle-engine.io\/apidoc\/html\/CastleFilesUtils.html#ApplicationConfig-string-\">ApplicationConfig<\/a><\/code> returns URL with <code>file:\/<\/code> protocol or something else (like future planned <code>castle-config:\/...<\/code>). We also want constructions like <code>SaveImage(..., ApplicationConfig('some_subdirectory\/') + 'yet_another_subdirectory\/foo.png');<\/code> to work automatically.<\/p>\n<p>A sample application is <a href=\"https:\/\/github.com\/michaliskambi\/test_config_subdir\">test_config_subdir<\/a>.<\/p>\n<li>\n<p>We improved our <a href=\"https:\/\/castle-engine.io\/android\">Android documentation page<\/a> (again &#8212; this seems to be most often updated documentation page of our website in 2024, maybe aside from <a href=\"https:\/\/castle-engine.io\/roadmap\">roadmap<\/a> \ud83d\ude42 ). Simplified, and clearly recommends <a href=\"https:\/\/developer.android.com\/studio\">Android Studio<\/a>. We work hard to make the Android process very simple and documented. At this point, installing <em>Android Studio<\/em> (not only Android command-line tools) is the best approach, IMHO &#8212; it has Java version that always works, has GUI-friendly access to emulators, mirroring, accepting licenses&#8230;<\/p>\n<li>\n<p>We improved our <a href=\"https:\/\/castle-engine.io\/android_faq#emulator\">Android FAQ about emulator usage<\/a>.<\/p>\n<li>\n<p>We improved our <a href=\"https:\/\/castle-engine.io\/android_services\">Android services list, to list all services and clearly specify which services are usually added automatically to the project<\/a>.\n<\/ol>\n<p>That&#8217;s all, for this news announcement! We have a ton of new stuff, brace yourselves for more news \ud83d\ude42 If you like this, we appreciate your <a href=\"https:\/\/www.patreon.com\/castleengine\">support on Patreon<\/a>, or <a href=\"https:\/\/castle-engine.io\/donate_other.php\">other financial support<\/a> , or <a href=\"https:\/\/castle-engine.io\/helping.php\">other contributions<\/a>. Reposting \/ resharing the news about our engine to interested people \/ places is in particular always appreciated!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Hi all! Today we announce a number of improvements for mobile (Android, iOS) development. They&#8217;ve been done while testing: Recently announced Castle Model Viewer on Android, see news. Updated Game Services Demo on Google Play. Updated Darkest Before the Dawn. A really old game developed using Castle Game Engine. Updated &#8211; no ads, use latest &hellip; <\/p>\n<p class=\"link-more\"><a href=\"https:\/\/castle-engine.io\/wp\/2024\/08\/02\/mobile-android-improvements-safe-borders-new-ui-scaling-accounting-for-auto-rotation-nicer-better-gestures-with-tcastleexaminenavigation-modern-android-photo-services-improved-docs\/\" class=\"more-link\">Continue reading  \u27a4<span class=\"screen-reader-text\"> &#8220;Mobile \/ Android improvements: safe borders, new UI scaling accounting for auto-rotation nicer, better gestures with TCastleExamineNavigation, modern Android photo services, improved docs&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":5092,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"publish_to_discourse":"1","publish_post_category":"9","wpdc_auto_publish_overridden":"","wpdc_topic_tags":"","wpdc_pin_topic":"","wpdc_pin_until":"","discourse_post_id":"4999","discourse_permalink":"https:\/\/forum.castle-engine.io\/t\/mobile-android-improvements-safe-borders-new-ui-scaling-accounting-for-auto-rotation-nicer-better-gestures-with-tcastleexaminenavigation-modern-android-photo-services-improved-docs\/1293","wpdc_publishing_response":"","wpdc_publishing_error":"","jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[1],"tags":[],"class_list":["post-5074","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"https:\/\/castle-engine.io\/wp\/wp-content\/uploads\/2024\/08\/Screenshot_1722611917.png","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/p9IgYW-1jQ","jetpack_likes_enabled":false,"_links":{"self":[{"href":"https:\/\/castle-engine.io\/wp\/wp-json\/wp\/v2\/posts\/5074","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/castle-engine.io\/wp\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/castle-engine.io\/wp\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/castle-engine.io\/wp\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/castle-engine.io\/wp\/wp-json\/wp\/v2\/comments?post=5074"}],"version-history":[{"count":17,"href":"https:\/\/castle-engine.io\/wp\/wp-json\/wp\/v2\/posts\/5074\/revisions"}],"predecessor-version":[{"id":5094,"href":"https:\/\/castle-engine.io\/wp\/wp-json\/wp\/v2\/posts\/5074\/revisions\/5094"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/castle-engine.io\/wp\/wp-json\/wp\/v2\/media\/5092"}],"wp:attachment":[{"href":"https:\/\/castle-engine.io\/wp\/wp-json\/wp\/v2\/media?parent=5074"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/castle-engine.io\/wp\/wp-json\/wp\/v2\/categories?post=5074"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/castle-engine.io\/wp\/wp-json\/wp\/v2\/tags?post=5074"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}