• Learn
    • Code Lab
    • Foldables and Large Screens
    • One UI Beta
    • Samsung Developers Podcasts
  • Develop
    • Mobile/Wearable
    • Galaxy GameDev
    • Galaxy Themes
    • Galaxy Watch
    • Health
    • Samsung Blockchain
    • Samsung DeX
    • Samsung IAP
    • Samsung Internet
    • Samsung Pay
    • Samsung Wallet
    • View All
      • Galaxy AR Emoji
      • Galaxy Accessory
      • Galaxy Edge
      • Galaxy Z
      • Galaxy Performance
      • Galaxy FM Radio
      • Galaxy S Pen Remote
      • Galaxy Sensor Extension
      • PENUP
      • Samsung Automation
      • Samsung Neural
      • Samsung TEEGRIS
      • Samsung eSE SDK
    • Visual Display
    • Smart TV
    • Smart Hospitality Display
    • Smart Signage
    • Digital Appliance
    • Family Hub
    • Platform
    • Bixby
    • Knox
    • SmartThings
    • Tizen.NET
  • Design
    • Design System
    • One UI
    • One UI Watch
    • Smart TV
  • Distribute
    • Galaxy Store
    • TV Seller Office
    • Galaxy Store Games
    • Samsung Podcasts
  • Support
    • Developer Support
    • Remote Test Lab
    • Issues and Bugs Channel
    • Samsung Android USB Driver
    • Galaxy Emulator Skin
  • Connect
    • Blog
    • News
    • Forums
    • Events
    • Samsung Developer Conference
    • SDC22
    • SDC21
    • SDC19 and Previous Events
  • Sign In
Top Global Search Form
Recommendation
  • Blog
  • Code Lab
  • Foldable and Large Screen Optimization
  • Forums
  • Galaxy Emulator Skin
  • Galaxy GameDev
  • Health
  • Remote Test Lab
  • Samsung Developer Conference
  • SDC22
  • Watch Face Studio
All Search Form
Recommendation
    Suggestion
      All Search Form
      Filter
      Filter
      Filter
      • ALL (85)
      • DOCS
      • SDK
      • API REFERENCE
      • CODE LAB
      • BLOG
      • NEWS/EVENTS
      • OTHERS
        api reference code lab blog news/events
      1. Learn
      2. Code Lab

      codelab

      Implement Flex Mode on an Unreal Engine Game

      implement flex mode on an unreal engine game objective learn how to implement flex mode on an unreal engine game using android jetpack windowmanager and raw java native interface (jni). overview the flexible hinge and glass display on galaxy foldable devices, such as the galaxy z fold4 and galaxy z flip4, let the phone remains propped open while you use apps. when the phone is partially folded, it will go into flex mode. apps will reorient to fit the screen, letting you watch videos or play games without holding the phone. for example, you can set the device on a flat surface, like on a table, and use the bottom half of the screen to navigate. unfold the phone to use the apps in full screen mode, and partially fold it again to return to flex mode. to provide users with a convenient and versatile foldable experience, developers need to optimize their apps to meet the flex mode standard. set up your environment you will need the following: epic games launcher with unreal engine 4 or later visual studio or any source code editor samsung galaxy foldable device: galaxy z fold2, z fold3, or newer galaxy z flip, z flip3, or newer remote test lab (if physical device is not available) requirements: samsung account java runtime environment (jre) 7 or later with java web start internet environment where port 2600 is available create and set up your project after launching unreal engine from the epic games launcher, follow the steps below to start your project: in the select or create new project window, choose games as a new project category and click next. select third person as template, then click next to proceed. noteyou can implement flex mode on any template or existing projects and use this code lab activity as a reference. in the project settings window, set the following: type of project: c++ target platform: mobile / tablet performance characteristics: scalable 3d or 2d real-time raytracing: raytracing disabled include an additional content pack: no starter content project name: tutorial_project click create project. wait for the engine to finish loading and open the unreal editor. once the project is loaded, go to edit > project settings > platforms > android. click the configure now button if the project is not yet configured for the android platform. then, proceed with the following apk packaging and build settings: a. apk packaging set target sdk version to 30. set orientation to full sensor. change the maximum supported aspect ratio to 2.8 (aspect ratio of galaxy z fold3 in decimal) to prevent black bars from appearing on the cover display. leave it if your game does not need to use the cover display. enable use display cutout region?, to prevents black bars at the edge of the main screen. otherwise, leave it unchecked. b. build disable support opengl es3.1 and enable support vulkan. notecurrently, there is a problem with opengl es and the split-screen system being investigated. the only option right now is to turn off opengl es and use vulkan instead. enable native resize event the resize event of a game when switching between displays is disabled in the engine by default. however, this behavior can be easily enabled by setting android.enablenativeresizeevent=1 in the deviceprofile. currently, the only way to create a profile for foldable devices is by creating a specific rule for each device. to save time in this code lab, enable the native resize event for all android devices instead. locate and open the tutorial_project > config folder in file explorer. inside the config folder, create a new folder named android. create a new file called androiddeviceprofiles.ini and open this file in a text editor, such as visual studio. copy below deviceprofile code to the newly created androiddeviceprofiles.ini file. [deviceprofiles] +deviceprofilenameandtypes=android,android [android deviceprofile] devicetype=android baseprofilename= +cvars=r.mobilecontentscalefactor=1.0 +cvars=slate.absoluteindices=1 +cvars=r.vulkan.delayacquirebackbuffer=2 +cvars=r.vulkan.robustbufferaccess=1 +cvars=r.vulkan.descriptorsetlayoutmode=2 ; don't enable vulkan by default. specific device profiles can set this cvar to 0 to enable vulkan. +cvars=r.android.disablevulkansupport=1 +cvars=r.android.disablevulkansm5support=1 ; pf_b8g8r8a8 +cvars=r.defaultbackbufferpixelformat=0 +cvars=android.enablenativeresizeevent=1 ; previewallowlistcvars and previewdenylistcvars are arrays of cvars that are included or excluded from being applied in mobile preview. ; if any previewallowlistcvars is set, cvars are denied by default. previewallowlistcvars=none this is a copy of the default android deviceprofile from the existing basedeviceprofiles.ini file but with the enabled nativeresizeevent console variable (cvars). notethis step is not required when you only want to implement flex mode. yet, it's recommended, to allow applications to run seamlessly from main to cover display without stretching and squashing the game, by enabling the nativeresizeevent. create a new plugin and import the foldablehelper foldablehelper is a java file that you can use in different projects. it provides an interface to the android jetpack windowmanager library, enabling application developers to support new device form factors and multi-window environments. before proceeding, read how to use jetpack windowmanager in android game dev and learn the details of how foldablehelper uses windowmanager library to retrieve information about the folded state of the device (flat for normal mode and half-opened for flex mode), window size, and orientation of the fold on the screen. download the foldablehelper.java file here: foldablehelper.java (5.64 kb) to import the foldablehelper.java file to the project, follow the steps below: go to edit > plugins in the unreal editor. click the new plugin button and select blank to create a blank plugin. in the name field, type foldables_tutorial and click the create plugin button. in file explorer, locate and open tutorial_project > plugins folder. go to plugins > foldables_tutorial > source> foldables_tutorial > private and create a new folder called java. copy the foldablehelper.java file into java folder. open the tutorial_project.sln file in visual studio. in the same private folder path, add a new filter called java. right-click on the java filter and click add > existing item. locate the foldablehelper.java file, then click add to include this java file in the build. modify java activity to use foldablehelper unreal plugin language (upl) is a simple xml-based language created by epic games for manipulating xml and returning strings. using upl, you can utilize the foldablehelper.java file by modifying the java activity and related gradle files as follows: in visual studio, right-click on source > foldables_tutorial folder, then click add > new item > web > xml file (.xml). create an xml file called foldables_tutorial_upl.xml. ensure that the file location is correct before clicking add. in the newly created xml file, include the foldablehelper.java file in the build by copying the java folder to the build directory. <root xmlns:android="http://schemas.android.com/apk/res/android"> <prebuildcopies> <copydir src="$s(plugindir)/private/java" dst="$s(builddir)/src/com/samsung/android/gamedev/foldable" /> </prebuildcopies> set up the gradle dependencies in the build.gradle file by adding the following in the xml file: <buildgradleadditions> <insert> dependencies { implementation filetree(dir: 'libs', include: ['*.jar']) implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.6.0" implementation "androidx.core:core:1.7.0" implementation "androidx.core:core-ktx:1.7.0" implementation "androidx.appcompat:appcompat:1.4.0" implementation "androidx.window:window:1.0.0" implementation "androidx.window:window-java:1.0.0" } android{ compileoptions{ sourcecompatibility javaversion.version_1_8 targetcompatibility javaversion.version_1_8 } } </insert> </buildgradleadditions> next, modify the gameactivity: <gameactivityimportadditions> <insert> <!-- package name of foldablehelper --> import com.samsung.android.gamedev.foldable.foldablehelper; </insert> </gameactivityimportadditions> <gameactivityoncreateadditions> <insert> foldablehelper.init(this); </insert> </gameactivityoncreateadditions> <gameactivityonstartadditions> <insert> foldablehelper.start(this); </insert> </gameactivityonstartadditions> <gameactivityonstopadditions> <insert> foldablehelper.stop(); </insert> </gameactivityonstopadditions> </root> gameactivityimportadditions adds the com.samsung.android.gamedev.foldable.foldablehelper into the gameactivity with the existing imports. gameactivityoncreateadditions adds the code to the oncreate() method inside the gameactivity. gameactivityonstartadditions adds the code to the onstart() method inside the gameactivity. gameactivityonstopadditions adds the code to the onstop() method inside the gameactivity. save the xml file. then, ensure that the engine uses the upl file by modifying the foldables_tutorial.build.cs script, located in the same folder as the foldables_tutorial_upl.xml file. after the dynamicallyloadedmodulenames.addrange call, add the following: if (target.platform == unrealtargetplatform.android) { additionalpropertiesforreceipt.add("androidplugin", moduledirectory + "\\foldables_tutorial_upl.xml"); } this means that the game engine will use the upl file if the platform is android. otherwise, the foldablehelper won’t work. implement a storage struct the next thing to implement is a struct, the native version of java’s foldablelayoutinfo class. to store the data retrieved from the java code using a struct, do the following: in content browser of unreal editor, right-click on c++ classes > add/import content. then, click new c++ class. select none for the parent class and click next. name the new class as foldablelayoutinfo. assign it to the foldables_tutorial plugin. then, click create class. delete the created foldablelayoutinfo.cpp file and only keep its header file. in the header file called foldablelayoutinfo.h, set up a struct to store all needed data from the windowmanager. #pragma once #include "core.h" enum efoldstate { undefined_state, flat, half_opened }; enum efoldorientation { undefined_orientation, horizontal, vertical }; enum efoldocclusiontype { undefined_occlusion, none, full }; struct ffoldablelayoutinfo { efoldstate state; efoldorientation orientation; efoldocclusiontype occlusiontype; fvector4 foldbounds; fvector4 currentmetrics; fvector4 maxmetrics; bool isseparating; ffoldablelayoutinfo() : state(efoldstate::undefined_state), orientation(efoldorientation::undefined_orientation), occlusiontype(efoldocclusiontype::undefined_occlusion), foldbounds(-1, -1, -1, -1), currentmetrics(-1, -1, -1, -1), maxmetrics(-1, -1, -1, -1), isseparating(false) { } }; implement jni code to implement jni, create a new c++ class with no parent and name it foldables_helper. assign the class to the same plugin, then modify the c++ header and source files as follows: in the created header file (foldables_helper.h), include foldablelayoutinfo.h. #include "foldablelayoutinfo.h" then, declare a multicast_delegate to serve as a listener for passing the data from the java implementation to the rest of the engine. declare_multicast_delegate_oneparam(fonlayoutchangeddelegate, ffoldablelayoutinfo); lastly, set up the methods and member variables. class foldables_tutorial_api ffoldables_helper { public: static void init(); static bool haslistener; static fonlayoutchangeddelegate onlayoutchanged; }; moving to the source file (foldables_helper.cpp), set up the definitions for the methods and member variables created in the header file. bool ffoldables_helper::haslistener = false; fonlayoutchangeddelegate ffoldables_helper::onlayoutchanged; void ffoldables_helper::init() { haslistener = true; } now, in the same source file, create the native version of the onlayoutchanged() function created in the foldablehelper.java file. since the java onlayoutchanged() function only works on android, surround the function with an #if directive to ensure that it compiles only on android. #if platform_android #endif within this directive, copy the code below to use the jni definition of the java onlayoutchanged() function. extern "c" jniexport void jnicall java_com_samsung_android_gamedev_foldable_foldablehelper_onlayoutchanged(jnienv * env, jclass clazz, jobject jfoldablelayoutinfo) { create the ffoldablelayoutinfo to store the data retrieved from java. ffoldablelayoutinfo result; retrieve the field ids of the foldablelayoutinfo and rect objects created in the java file. //java foldablelayoutinfo field ids jclass jfoldablelayoutinfocls = env->getobjectclass(jfoldablelayoutinfo); jfieldid currentmetricsid = env->getfieldid(jfoldablelayoutinfocls, "currentmetrics", "landroid/graphics/rect;"); jfieldid maxmetricsid = env->getfieldid(jfoldablelayoutinfocls, "maxmetrics", "landroid/graphics/rect;"); jfieldid hingeorientationid = env->getfieldid(jfoldablelayoutinfocls, "hingeorientation", "i"); jfieldid stateid = env->getfieldid(jfoldablelayoutinfocls, "state", "i"); jfieldid occlusiontypeid = env->getfieldid(jfoldablelayoutinfocls, "occlusiontype", "i"); jfieldid isseparatingid = env->getfieldid(jfoldablelayoutinfocls, "isseparating", "z"); jfieldid boundsid = env->getfieldid(jfoldablelayoutinfocls, "bounds", "landroid/graphics/rect;"); jobject currentmetricsrect = env->getobjectfield(jfoldablelayoutinfo, currentmetricsid); //java rect object field ids jclass rectcls = env->getobjectclass(currentmetricsrect); jfieldid leftid = env->getfieldid(rectcls, "left", "i"); jfieldid topid = env->getfieldid(rectcls, "top", "i"); jfieldid rightid = env->getfieldid(rectcls, "right", "i"); jfieldid bottomid = env->getfieldid(rectcls, "bottom", "i"); retrieve the current windowmetrics and store it in the ffoldablelayoutinfo as an fintvector4. // currentmetrics int left = env->getintfield(currentmetricsrect, leftid); int top = env->getintfield(currentmetricsrect, topid); int right = env->getintfield(currentmetricsrect, rightid); int bottom = env->getintfield(currentmetricsrect, bottomid); // store currentmetrics rect to fvector4 result.currentmetrics = fintvector4{ left, top, right, bottom }; do the same for the other variables in the java foldablelayoutinfo. // maxmetrics jobject maxmetricsrect = env->getobjectfield(jfoldablelayoutinfo, maxmetricsid); left = env->getintfield(maxmetricsrect, leftid); top = env->getintfield(maxmetricsrect, topid); right = env->getintfield(maxmetricsrect, rightid); bottom = env->getintfield(maxmetricsrect, bottomid); //store maxmetrics rect to fvector4 result.maxmetrics = fintvector4{ left, top, right, bottom }; int hingeorientation = env->getintfield(jfoldablelayoutinfo, hingeorientationid); int state = env->getintfield(jfoldablelayoutinfo, stateid); int occlusiontype = env->getintfield(jfoldablelayoutinfo, occlusiontypeid); bool isseparating = env->getbooleanfield(jfoldablelayoutinfo, isseparatingid); // store the values to an object for unreal result.orientation = tenumasbyte<efoldorientation>(hingeorientation + 1); result.state = tenumasbyte<efoldstate>(state + 1); result.occlusiontype = tenumasbyte<efoldocclusiontype>(occlusiontype + 1); result.isseparating = isseparating; // boundsrect jobject boundsrect = env->getobjectfield(jfoldablelayoutinfo, boundsid); left = env->getintfield(boundsrect, leftid); top = env->getintfield(boundsrect, topid); right = env->getintfield(boundsrect, rightid); bottom = env->getintfield(boundsrect, bottomid); // store maxmetrics rect to fvector4 result.foldbounds = fintvector4{ left, top, right, bottom }; broadcast the result via the onlayoutchanged delegate for use in the engine. if (ffoldables_helper::haslistener) { ue_log(logtemp, warning, text("broadcast")); ffoldables_helper::onlayoutchanged.broadcast(result); } } create a player controller and two ui states this section focuses on adding a player controller and creating two user interface (ui) states for flat and flex modes. these objects are needed for the flex mode logic implementation. following are the steps to add a player controller and create two ui states : add a new player controller blueprint. in content browser, go to content > thirdpersoncpp and right-click on blueprints > add/import content > blueprint class. pick player controller as its parent class. rename it as flexplayercontroller. notethe flexplayercontroller added is generic and can be replaced by your custom player controller in an actual project. add a new c++ class with actor component as its parent class. name it as foldables_manager and assign it to the foldables_tutorial plugin. click the create class button. open the flexplayercontroller blueprint by double-clicking it. click open full blueprint editor. attach the actor component to the flexplayercontroller. in the left pane, click add component, then find and select the foldables_manager. next, create a pair of userwidget classes for the ui layouts needed: flat mode ui for the full screen or normal mode; and flex mode ui for split-screen. in add c++ class window, select the show all classes checkbox. find and pick userwidget as the parent class. then, click next. name the new user widget as flatui and attach it to the plugin. click next. repeat the process but name the new user widget as flexui. you might get an error when trying to compile stating that the userwidget is an undeclared symbol. to fix this, open the foldables_tutorial.build.cs file, and in the publicdependencymodulenames.addrange call, add "inputcore" and "umg" to the list. create a pair of blueprints made from subclasses of these two user widgets. right-click on content and create a new folder called foldui. inside the newly created folder, right-click to add a new blueprint class. in all classes, choose flatui and click the select button. rename the blueprint as bp_flatui. in the same folder, repeat the process but choose the flexui class and rename the blueprint as bp_flexui. double-click on bp_flatui and bp_flexui, then design your two uis like below to visualize switching between flat and flex mode: flat ui flex ui notethis code lab activity does not cover the steps on how to create or design ui. if you want to learn about how to create your own game design in unreal engine 4, refer to unreal motion graphics ui designer guide. implement the flex mode logic after creating the flexplayercontroller and the two ui states (bp_flatui and bp_flexui), you can now implement flex mode logic in the foldables_manager. open the foldables_manager.h and include the necessary c++ header files: #pragma once #include "coreminimal.h" #include "components/actorcomponent.h" #include "engine.h" #include "flatui.h" #include "flexui.h" #include "foldables_helper.h" #include "foldables_manager.generated.h" remove the line below to save a little bit of performance as this component doesn't need to tick. public: // called every frame virtual void tickcomponent(float deltatime, eleveltick ticktype, factorcomponenttickfunction* thistickfunction) override; set up the functions needed in foldables_manager: the constructor, a function to create the ui widgets the implementation of onlayoutchanged delegate public: // sets default values for this component's properties ufoldables_manager(); void createwidgets(); protected: // called when the game starts virtual void beginplay() override; protected: void onlayoutchanged(ffoldablelayoutinfo foldablelayoutinfo); then, set up the variables needed: references to the flat and flex ui classes references to the flat and flex ui objects mark the pointers as uproperty to ensure that garbage collection does not delete the objects they point to. tsubclassof<uuserwidget> flatuiclass; tsubclassof<uuserwidget> flexuiclass; uproperty() class uflatui* flatui; uproperty() class uflexui* flexui; finally, define a new private function restoreflatmode(), to disable flex mode and return to normal mode. private: void restoreflatmode(); moving over to foldables_manager.cpp, implement the constructor. using the constructorhelpers, find the ui classes and set the variables to store these classes. also, set the bcanevertick to false to prevent the component from ticking and remove the code block of tickcomponent() function. // sets default values for this component's properties ufoldables_manager::ufoldables_manager() { primarycomponenttick.bcanevertick = false; static constructorhelpers::fclassfinder<uflatui> flatuibpclass(text("/game/foldui/bp_flatui")); static constructorhelpers::fclassfinder<uflexui> flexuibpclass(text("/game/foldui/bp_flexui")); if (flatuibpclass.succeeded()) { flatuiclass = flatuibpclass.class; } if (flexuibpclass.succeeded()) { flexuiclass = flexuibpclass.class; } } next, set up the beginplay() function to link the delegate to the onlayoutchanged() function, to initialize the foldables_helper, and to create the widgets ready for use in the first frame. // called when the game starts void ufoldables_manager::beginplay() { super::beginplay(); ffoldables_helper::onlayoutchanged.adduobject(this, &ufoldables_manager::onlayoutchanged); ffoldables_helper::init(); createwidgets(); } set up the createwidgets() function to create the widgets using the ui classes acquired in the constructor. add the flatui widget to the viewport, assuming the app opens in normal mode until it receives the foldablelayoutinfo. void ufoldables_manager::createwidgets() { flatui = createwidget<uflatui>((aplayercontroller*)getowner(), flatuiclass, fname(text("flatui"))); flexui = createwidget<uflexui>((aplayercontroller*)getowner(), flexuiclass, fname(text("flexui"))); flatui->addtoviewport(); } afterward, create the onlayoutchanged() function, which will be called via a delegate. inside this function, check whether the device’s folded state is half_opened. if so, check whether the orientation of the fold is horizontal. void ufoldables_manager::onlayoutchanged(ffoldablelayoutinfo foldablelayoutinfo) { //if state is now flex if (foldablelayoutinfo.state == efoldstate::half_opened) { if (foldablelayoutinfo.orientation == efoldorientation::horizontal) { notefor this third person template, splitting the screen vertically isn’t ideal from a user experience (ux) point of view. for this code lab activity, split the screen only on the horizontal fold (top and bottom screen). if you want it vertically, you need to use the same principle in the next step but for the x-axis instead of the y-axis. you must also ensure that you have a flex ui object for the vertical layout. if the device is both on flex mode and horizontal fold, change the viewport to only render on the top screen using the normalized position of the folding feature. then in an asynctask on the game thread, disable the flatui and enable the flexui. however, if the device is on normal mode, then return to flat ui using restoreflatmode() function. //horizontal split float foldratio = (float)foldablelayoutinfo.foldbounds.y / (foldablelayoutinfo.currentmetrics.w - foldablelayoutinfo.currentmetrics.y); gengine->gameviewport->splitscreeninfo[0].playerdata[0].sizex = 1.0f; gengine->gameviewport->splitscreeninfo[0].playerdata[0].sizey = foldratio; asynctask(enamedthreads::gamethread, [=]() { if (flatui->isinviewport()) { flatui->removefromparent(); } if (!flexui->isinviewport()) { flexui->addtoviewport(0); } }); } else { restoreflatmode(); } } else { restoreflatmode(); } } reverse the flex mode implementation logic to create the restoreflatmode() function by setting the viewport to fill the screen, then disable the flexui and enable the flatui. void ufoldables_manager::restoreflatmode() { gengine->gameviewport->splitscreeninfo[0].playerdata[0].sizex = 1.0f; gengine->gameviewport->splitscreeninfo[0].playerdata[0].sizey = 1.0f; asynctask(enamedthreads::gamethread, [=]() { if (!flatui->isinviewport()) { flatui->addtoviewport(0); } if (flexui->isinviewport()) { flexui->removefromparent(); } }); } set up a game mode and attach the flexplayercontroller the game mode defines the game rules, scoring, and any game-specific behavior. set up the game mode in unreal editor by creating a blueprint class in the content > thirdpersoncpp > blueprints folder. pick game mode base as the parent class and rename it as flexgamemode. double-click on flexgamemode. in the drop-down menu next to player controller class, choose the flexplayercontroller. lastly, go to edit > project settings > project > maps & modes and select flexgamemode as the default gamemode. build and run the app go to edit > package project > android to build the apk. ensure that the android development environment for unreal is already set up to your computer. noteif the build failed due to corrupted build tools, consider downgrading the version to 30 or lower using the sdk manager. or, simply rename d8.bat to the name of the missing file (dx.bat) in (sdk path) > build-tools > (version number) directory and, in lib folder of the same directory, rename d8.jar to dx.jar. after packaging your android project, run the game app on a foldable galaxy device and see how the ui switches from normal to flex mode. if you don’t have any physical device, you can also test it on a remote test lab device. tipwatch this tutorial video and know how to easily test your app via remote test lab. you're done! congratulations! you have successfully achieved the goal of this code lab. now, you can implement flex mode in your unreal engine game app by yourself! if you're having trouble, you may download this file: flex mode on unreal complete code (20.16 mb) to learn more, visit: www.developer.samsung.com/galaxy-z www.developer.samsung.com/galaxy-gamedev

      https://developer.samsung.com/codelab/gamedev/flex-mode-unreal.html
      1. Learn
      2. Code Lab

      codelab

      Measure Blood Oxygen Level and Heart Rate on Galaxy Watch

      measure blood oxygen level and heart rate on galaxy watch objective create a health app for galaxy watches powered by wear os, utilizing the new samsung privileged health sdk to trigger and obtain results of simultaneous blood oxygen level (spo2) and heart rate measurements. partnership request in this code lab, you will use a specially prepared mock library. it has limited functionality and uses dummy data instead of real-time data. to get real values, you will need the full version of the samsung privileged health sdk library, which is available to samsung partners. apply as a partner by checking out the partner app program to get exclusive access to the samsung privileged health sdk. overview samsung privileged health sdk provides means of accessing and tracking health information contained in the health data storage. its tracking service gives raw and processed sensor data such as accelerometer and body composition data sent by the samsung bioactive sensor. the latest bioactive sensor of galaxy watch runs powerful health sensors such as photoplethysmogram (ppg), electrocardiogram (ecg), bioelectrical impedance analysis (bia), sweat loss, and spo2. see samsung privileged health sdk descriptions for detailed information. set up your environment you will need the following: galaxy watch4 or newer android studio (latest version recommended) java se development kit (jdk) 11 or later sample code here is a sample code for you to start coding in this code lab. download it and start your learning experience! measuring blood oxygen level and heart rate sample code (128.16 kb) turn on developer mode and adjust its settings on your watch, go to settings > about watch > software and tap on software version 5 times. upon successful activation of developer mode, a toast message will display as on the image below. afterwards, developer options will be visible under settings. tap developer options and enable the following options: adb debugging debug over wi-fi turn off automatic wi-fi connect your galaxy watch to wi-fi go to settings > connection > wi-fi and make sure that wi-fi is enabled. from the list of available wi-fi networks, choose and connect to the same one as your pc. when successfully connected, tap a wi-fi network name, swipe down, and note the ip address. you will need this to connect your watch over adb from your pc. connect your galaxy watch to android studio in android studio, go to terminal and type: adb connect <ip address as mentioned in previous step> when prompted, tap always allow from this computer to allow debugging. upon successful connection, you will see the following message in android studio’s terminal: connected to <ip address of your watch> now, you can run the app directly on your watch. start your project after downloading the sample code containing the project files, in android studio click open to open existing project. locate the downloaded android project (advanced) from the directory and click ok. establish service connection and check capabilities for the device to track data with the samsung privileged health sdk, it must connect to the service by healthtrackingservice api. after establishing a connection, verify if the required tracker type is available. to check this, get the list of available tracker types and verify that the tracker is on the list. in this code lab, you will utilize blood oxygen level and heart rate trackers. the healthtrackingservice api usage is in the table below. healthtrackingservicehealthtrackingservice initiates a connection to samsung's health tracking service and provides a healthtracker instance to track a healthtrackertype. public void connectservice() establish a connection with samsung's health tracking service. public void disconnectservice() release a connection for samsung's health tracking service. public healthtrackercapability gettrackingcapability() provide a healthtrackercapability instance to get a supporting health tracker type list. initialize multiple trackers before the measurement starts, initialize the spo2 tracker by obtaining the proper health tracker object. in the connectionmanager.java file, navigate to initspo2(), create an oxygen saturation healthtracker instance, and pass it to the spo2listener instance. get the healthtracker object using the healthtrackingservice api. use the healthtrackertype.spo2 type as parameter. healthtrackingservicehealthtrackingservice initiates a connection to samsung's health tracking service and provides a healthtracker instance to track a healthtrackertype. public healthtracker gethealthtracker(healthtrackertype healthtrackertype) provide a healthtracker instance for the given healthtrackertype. pass the healthtracker object to the spo2listener instance object. spo2listener public void sethealthtracker(healthtracker tracker) set healthtracker instance for the given tracker. /******************************************************************************************* * [practice 1] create blood oxygen level health tracker object * - get health tracker object * - pass it to spo2listener ------------------------------------------------------------------------------------------- * - (hint) replace todo 1 with parts of code * (1) get healthtracker object using healthtrackingservice.gethealthtracker() * use healthtrackertype.spo2 type as parameter * (2) pass it to spo2listener using sethealthtracker function ******************************************************************************************/ public void initspo2(spo2listener spo2listener) { //"todo 1 (1)" //"todo 1 (2)" sethandlerforbaselistener(spo2listener); } next, in the connectionmanager.java file, in the initheartrate() function, create a heart rate healthtracker instance, and pass it to the heartratelistener instance. get the healthtracker object using the healthtrackingservice api. use the healthtrackertype.heart_rate type as parameter. pass the healthtracker object to the heartratelistener instance object. heartratelistener public void sethealthtracker(healthtracker tracker) set healthtracker instance for the given tracker. /******************************************************************************************* * [practice 2] create heart rate health tracker object * - get health tracker object * - pass it to heartratelistener ------------------------------------------------------------------------------------------- * - (hint) replace todo 2 with parts of code * (1) get healthtracker object using healthtrackingservice.gethealthtracker() * use healthtrackertype.heart_rate type as parameter * (2) pass it to heartratelistener using sethealthtracker function ******************************************************************************************/ public void initheartrate(heartratelistener heartratelistener) { //"todo 2 (1)" //"todo 2 (2)" sethandlerforbaselistener(heartratelistener); } start and stop trackers for the client app to start obtaining the data through the sdk, set a listener method on healthtracker. this method will be called every time there is new data. after the measurement completes, the listener has to be disconnected. to start measurement in the baselistener.java file, navigate to starttracker() function, and set trackereventlistener as listener healthtracker object. set an event listener on healthtracker object using healthtracking api. use the healthtracker.trackereventlistener object instance as parameter. healthtrackerhealthtracker enables an application to set an event listener and get tracking data for a specific healthtrackertype. public void seteventlistener(healthtracker.trackereventlistener listener) set an event listener to this healthtracker instance. /******************************************************************************************* * [practice 3] start health tracker by setting event listener * - set event listener on health tracker ------------------------------------------------------------------------------------------- * - (hint) replace todo 3 with parts of code * set event listener on healthtracker object using healthtracker.seteventlistener() * use trackereventlistener object as parameter ******************************************************************************************/ public void starttracker() { log.i(app_tag, "starttracker called "); log.d(app_tag, "healthtracker: " + healthtracker.tostring()); log.d(app_tag, "trackereventlistener: " + trackereventlistener.tostring()); if (!ishandlerrunning) { handler.post(() -> { //"todo 3" sethandlerrunning(true); }); } } to stop measurement, unset the trackereventlistener from the healthtracker object in the stoptracker() function. unset the event listener on healthtracker object using healthtracking api. healthtrackerhealthtracker enables an application to set an event listener and get tracking data for a specific healthtrackertype. public void unseteventlistener() stop the registered event listener to this healthtracker instance. /******************************************************************************************* * [practice 4] stop health tracker by removing event listener * - unset event listener on health tracker ------------------------------------------------------------------------------------------- * - (hint) replace todo 4 with parts of code * unset event listener on healthtracker object using healthtracker.unseteventlistener() ******************************************************************************************/ public void stoptracker() { log.i(app_tag, "stoptracker called "); log.d(app_tag, "healthtracker: " + healthtracker.tostring()); log.d(app_tag, "trackereventlistener: " + trackereventlistener.tostring()); if (ishandlerrunning) { //"todo 4" sethandlerrunning(false); handler.removecallbacksandmessages(null); } } process obtained and batching data the response from the platform will be asynchronous with the results you want to obtain. follow the steps below to get blood oxygen level and heart rate data. in the spo2listener.java file, navigate to updatespo2() function, and read spo2 data from datapoint: get the oxygen saturation status using the datapoint api (key: valuekey.spo2set.status). get the oxygen saturation value using the datapoint api (key: valuekey.spo2set.spo2). datapointdatapoint provides a map of valuekey and value with a timestamp. public <t>t getvalue(valuekey<t> type) get data value for the given key. /******************************************************************************************* * [practice 5] read values from datapoint object * - get blood oxygen level status * - get blood oxygen level value ------------------------------------------------------------------------------------------- * - (hint) replace todo 5 with parts of code * (1) remove spo2status.calculating and * set status from 'datapoint' object using datapoint.getvalue(valuekey.spo2set.status) * (2) set spo2value from 'datapoint' object using datapoint.getvalue(valuekey.spo2set.spo2) * if status is 'spo2status.measurement_completed' ******************************************************************************************/ public void updatespo2(datapoint datapoint) { int status = spo2status.calculating; //"todo 5 (1)" int spo2value = 0; //"todo 5 (2)" trackerdatanotifier.getinstance().notifyspo2trackerobservers(status, spo2value); log.d(app_tag, datapoint.tostring()); } in the heartratelistener.java file, navigate to readvaluesfromdatapoint() function, and read the heart rate data from datapoint: get the heart rate status using the datapoint api (key: valuekey.heartrateset. status). get the heart rate value using the datapoint api (key: valuekey.heartrateset.heart_rate). get the heart rate inter-beat interval (ibi) value using the datapoint api (key: valuekey.heartrateset. heart_rate_ibi). calculate the ibi quality using the first bit from the heart rate ibi value. calculate the ibi value using the remaining 15 bits from the heart rate ibi value. /******************************************************************************************* * [practice 6] read values from datapoint object * - get heart rate status * - get heart rate value * - get heart rate ibi value * - check retrieved heart rate’s ibi and ibi quality values ------------------------------------------------------------------------------------------- * - (hint) replace todo 6 with parts of code * (1) set hrdata.status from 'datapoint' object using datapoint.getvalue(valuekey.heartrateset.status) * (2) set hrdata.hr from 'datapoint' object using datapoint.getvalue(valuekey.heartrateset.heart_rate) * (3) set local variable 'final int hribi' using datapoint.getvalue(valuekey.heartrateset.heart_rate_ibi) * (4) set hrdata.qibi with the first of 16 bits of 'hribi' value * (use heartratedata.ibi_quality_shift 15 bits shift and heartratedata.ibi_mask 1 bit mask) * (5) set hrdata.ibi with the rest of the 15 bits of 'hribi' value * (use heartratedata.ibi_quality_mask 15 bit mask) ******************************************************************************************/ public void readvaluesfromdatapoint(datapoint datapoint) { heartratedata hrdata = new heartratedata(); //"todo 6 (1)" //"todo 6 (2)" //"todo 6 (3)" //"todo 6 (4)" //"todo 6 (5)" trackerdatanotifier.getinstance().notifyheartratetrackerobservers(hrdata); log.d(app_tag, datapoint.tostring()); } run unit tests for your convenience, you will find an additional unit tests package. this will let you verify your code changes even without using a physical watch. see instructions below on how to run the unit tests: right click on com.samsung.sdc22.health.advanced (test) and execute run 'tests in 'com.samsung.sdc22.health.advanced'' command. if you completed all the tasks correctly, you will see all the unit tests passed successfully. run the app after building the apk, you can run the application on a connected device to see blood oxygen level and heart rate values. right after the app is started, it will request user permission. allow the app to receive data from the body sensors. afterwards, it will show the application's main screen and automatically display the heart rate. to get the blood oxygen level (spo2) value, tap on the measure button. to stop the measurement, tap on the stop button. tap on the details label to see more heart rate data. you're done! congratulations! you have successfully achieved the goal of this code lab. now, you can create a health app that measures blood oxygen level and heart rate by yourself! if you're having trouble, you may download this file: measuring blood oxygen level and heart rate complete code (120.06 kb) to learn more about samsung health, visit: developer.samsung.com/health

      https://developer.samsung.com/codelab/health/blood-oxygen-heart-rate.html
      1. Develop
      2. Health

      doc

      Health

      samsung privileged health sdk the galaxy watch5 is equipped with samsung’s unique bioactive sensor that drives the next era of digital health monitoring. first introduced on the galaxy watch4 series, the bioactive sensor uses a single unique chip that combines three powerful health sensors — optical heart rate, electrical heart signal, and bioelectrical impedance analysis — to deliver extensive readings that include heart rate and blood oxygen level. what is samsung privileged health sdk the samsung privileged health sdk is specialized for galaxy watch4 devices or later. it provides both raw sensor signal data from the samsung bioactive sensor and processed data with our differentiated features. the sdk supports an improved health tracking capability to allow your applications to track the user's health data accurately with the accelerometer, raw ecg (electrocardiogram), ppg (photoplethysmogram), and heart rate including inter-beat interval. in addition, it provides more advanced health features such as the body composition measurement, to enable compelling use cases for health and fitness applications. the blood oxygen level and sweat loss after a running workout are also useful data to check a user's health status. what you can do a watch application using the samsung privileged health sdk runs on a galaxy watch with wear os powered by samsung. it will help users to monitor their overall health data and to provide an advanced healthy life. the sdk can be utilized in various fields such as fitness, remote patient monitoring, senior care, digital therapy, fatigue risk management, and corporate wellness. what are the advantages let's review more advantages of the samsung privileged health sdk. low watch battery consumption the samsung privileged health sdk's accelerometer data, ppg green data, and heart rate data are all received as a batching event. the sdk's batching operation gathers sensor data in an application processor without waking up the cpu and sends an event at specific periods to a watch application. this minimizes the watch's battery consumption and enables a watch application to track the user's status for the entire day. receiving raw sensor data the accelerometer, ecg, and ppg green data are provided as raw data by the samsung privileged health sdk. this is very useful to conduct various analyses and more in-depth research with your own algorithm. using galaxy watch specific features measuring the user's body composition, blood oxygen level, heart rate including the inter-beat interval, and sweat loss after a running workout is a feature specific to the galaxy watch. using the privileged health sdk, your watch application can easily measure these data. what data is provided the following data types are supported by the samsung privileged health sdk: data type details accelerometer raw x, y, and z axis data. provided as a batching event. ecg raw electrocardiogram data. provided as an on-demand event. ppg green raw data from ppg green led. provided as a batching event. ppg red raw data from ppg red led. provided as an on-demand event. ppg ir raw data from ppg infrared led. provided as an on-demand event. heart rate heart rate data, including inter-beat interval. provided as a batching event. bia body composition data. provided as an on-demand event. spo2 blood oxygen level. provided as an on-demand event. sweat loss lost water amount after a running workout. provided as an on-demand event. experience samsung privileged health sdk you can practice using the samsung privileged health sdk with our code labs. visit code lab to get started. partner app program our partner app program is an exclusive service for the samsung privileged health sdk that allows users to discover engaging health and fitness applications. the samsung privileged health sdk is now available for selected partners and we are reviewing all applications to join. apply for partner app program restrictions the samsung privileged health sdk only works on galaxy watch4 devices or later with wear os powered by samsung. testing the samsung privileged health sdk features is not possible in an emulator.

      https://developer.samsung.com/health/platform/overview.html
      1. Learn
      2. Code Lab

      codelab

      Develop a Secure Blockchain App

      develop a secure blockchain app objective learn how to create your own decentralized applications (dapp) using samsung blockchain keystore sdk. overview integrating with new technology like blockchain is a burden to most developers. for this reason, we offer a way to interwork with samsung blockchain keystore sdk with less effort. developers can easily become a dapp developer with our samsung blockchain keystore sdk. decentralized applications (dapps) run and store data on the blockchain network instead of a central server. dapps offer increased security and reliability compared to centralized applications. moreover, it provides a simple method for in-app payments using cryptocurrency. samsung blockchain keystore sdk is used to obtain account information and sign a transaction to transfer cryptocurrency or execute smart contract execution. in this code lab, you can learn how to integrate samsung blockchain keystore sdk into your app and how to implement blockchain basic concepts such as account information and signing transactions. set up your environment you will need the following: java se development kit 8 or later android studio (latest version recommended) mobile phone which supports samsung blockchain sample code here is a sample code for you to start coding in this code lab. download it and start your learning experience! keystore sdk sample code (897.12 kb) enable developer mode the developer mode helps developers test the samsung blockchain keystore. in developer mode, app id verification is bypassed, so samsung blockchain keystore apis will be enabled. to activate developer mode on your mobile device, follow the steps below: navigate through settings > biometrics and security > samsung blockchain keystore and click about blockchain keystore. tap the samsung blockchain keystore app name quickly, ten times or more. if succeeded, (developer mode) will show. noteonly a limited number of devices can be activated for one test app. open project file after downloading the sample code, open the given android application project. this project is a simple comments dapp based on ethereum ropsten test network. it retrieves comments data from smart contract, displays them on the screen, and makes a transaction to execute smart contract function to post user’s comment. in the next steps, you can get an account address and execute dapp service with blockchain keystore and you can see the result of successful dapp execution. set the app id here, you don’t need to set the application id to use samsung blockchain keystore sdk. instead, you must enable developer mode as described previously. for the release version of your android app, in your android manifest file, add a metadata with a name as scw_app_id and a value as the app id issued by samsung blockchain keystore team. samsung blockchain keystore aar file will read this value when your android app is initialized and help your android app connect to samsung blockchain keystore: <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.samsung.android.sdk.coldwallet.test" android:versioncode="1" android:versionname="1.0"> <application> <meta-data android:name="scw_app_id" android:value= <!-- put your app id here --> /> </application> </manifest> import samsung blockchain keystore sdk library into the project the sdk library is located at aar/keystoresdk_v1.5.1.aar of the project file. to import the library go to gradle scripts > build.gradle and enter the following dependencies: dependencies { repositories { flatdir{ dirs 'aar' } } implementation 'com.samsung.android.sdk.coldwallet:keystoresdk_v1.5.1@aar' } check the status of samsung blockchain keystore the first thing to do is to check the status of samsung blockchain keystore. in the sample application, it is implemented at initializekeystore() in presenter intropresenter.java. you can find the following steps to check the status of keystore. in your android app, call scwservice.getinstance(). if the returned value is an instance and not null, then it means samsung blockchain keystore is supported on the device. however, if null is returned, the user must use a different keystore. in the sample code, toast a message to notify that the device doesn’t support the keystore. // check samsung blockchain keystore is supported or not. if (scwservice.getinstance() == null) { mcontract.toastmessage("samsung blockchain keystore is not supported on your device."); } call getkeystoreapilevel api to see if the current samsung blockchain keystore being used, properly supports the features that your android app is currently aiming for. if the required api level is higher than the current samsung blockchain keystore level, users are directed to samsung blockchain keystore app page in galaxy store through the provided deeplink to update. // check installed api level else if (scwservice.getinstance().getkeystoreapilevel() < 1) { // if api level is lower, jump to galaxy apps to update keystore app. mcontract.showdialog("" , "ok" , "the api level is too low. jump to galaxy store" , () -> mcontract.launchdeeplink(scwdeeplink.galaxy_store)); } check if a user has set up the samsung blockchain keystore and is ready to use it by calling getseedhash api. if the seed hash value in string is zero-length, this means the user has not set up samsung blockchain keystore yet. hence, your app will need to guide the user to jump to samsung blockchain keystore via deeplink to either create or import a wallet. // check seed hash exist. else if (scwservice.getinstance().getseedhash().length() == 0) { // if seed hash is empty, // jump to blockchain keystore to create or import wallet mcontract.showdialog("" , "ok" , "the seed hash is empty." + "jump to blockchain keystore to create/import wallet." , () -> mcontract.launchdeeplink(scwdeeplink.main)); } if the getseedhash api returned value is not zero-length, it means that the user has successfully set up samsung blockchain keystore. if there is a previously saved or cached seed hash value, compare the two seed hash values. if those two values are not equal, nor if there is no such saved cached seed hash value, then the address has to be checked again. if the seed hash value has been changed, it means the master seed has been changed as well, meaning the address that your android app was linked to may no longer be the same address. // check seed hash cached else if (!textutils.equals(cachedseedhash, scwservice.getinstance().getseedhash())) { // if the seed hash is different from cached, update seed hash and address // go to next activity final string ethereumhdpath = "m/44'/60'/0'/0/0"; getethereumaddress(ethereumhdpath , (success, errorcode, address, seedhash) -> { if (success) { updateaddress(address); updateseedhash(seedhash); mcontract.showtimelineactivity(true); } else { mcontract.toastmessage("cannot get address. error code :" + errorcode); } mcontract.setloading(false); }); return false; } if those two values are equal, it means checking the keystore status was successful, and you can move on to the next step. // success else { // set address from cached value // go to next activity string address = prefshelper.getinstance().getcachedaddress(); updateseedhash(cachedseedhash); updateaddress(address); mcontract.showtimelineactivity(false); } get the ethereum address in the blockchain network, the address can be used like a user’s account as the balance and the transaction history can be checked using the address. in this sample project, get the address from keystore and display the address and account balance in the bottom sheet of the screen. keystore is a hierarchical deterministic (hd) wallet, a standard tree structure represented by derivation paths. for the ethereum address, use “m/44'/60'/0'/0/0” follow bip44. it is implemented at getethereumaddress(string hdpath, getethereumaddresscallback callback) in presenter/intropresenter.java: arraylist<string> path = new arraylist<>(); path.add(hdpath); scwservice.getinstance().getaddresslist(new scwservice.scwgetaddresslistcallback() { @override public void onsuccess(list<string> list) { string seedhash = scwservice.getinstance().getseedhash(); string address = list.get(0); callback.onaddressreceived(true, 0, address, seedhash); } @override public void onfailure(int errorcode, string errormessage) { callback.onaddressreceived(false, errorcode, "", ""); } }, path); sign a transaction ether value transfer or smart contract execution is executed by transactions that users create and sign. signing a transaction is the process of generating a signature on it using the private key of the transaction sender. samsung blockchain keystore can be utilized to sign a cryptocurrency transaction, such as ethereum by implementing the following steps: creates an unsigned transaction, and requests samsung blockchain keystore to sign the transaction via apis like signethtransaction. then the user will see a transaction confirmation page on a secure screen called, trusted user interface (tui) executed in trusted execution environment (tee) by samsung blockchain keystore. once the user confirms the transaction with pin or biometrics authentication, like fingerprint, samsung blockchain keystore will sign a transaction with the private key derived from the given hd path. when samsung blockchain keystore returns the signed transaction, your app can submit or send the signed transaction to the blockchain network. in this sample project, create an unsigned transaction to execute posting a comment smart contract. in addition, sign the transaction with keystore and send the transaction. it is implemented at signtransaction() in presenter/writefeedpresenter.java: // sign the transaction with samsung blockchain keystore // use hdpath m/44'/60'/0'/0/0 final string hdpath = "m/44'/60'/0'/0/0"; scwservice.getinstance().signethtransaction( new scwservice.scwsignethtransactioncallback() { @override public void onsuccess(byte[] signedtransaction) { boolean result = sendsignedtransaction(signedtransaction); listener.transactiondidfinish(result, ""); } @override public void onfailure(int errorcode, string errormessage) { listener.transactiondidfinish(false, "error code : " + errorcode); } }, unsignedtx, hdpath, null); run the app and try it out. the app screen should look like below. you're done! congratulations! you have successfully achieved the goal of this code lab. now, you can create a decentralized app by yourself! if you're having trouble, you may download this file: keystore sdk complete code (897.07 kb)

      https://developer.samsung.com/codelab/blockchain/keystore-sdk.html
      1. Develop
      2. GameDev

      web

      Galaxy GameDev | Samsung Developers

      galaxy gamedev galaxy gamedev provides various technical support options to assist game developers. get the gamedev newsletter get the gamedev newsletter related materials get support via our technical documents and online resources. galaxy gamedev learn about joining galaxy gamedev and best practices for game developers best practices find useful tips, know-hows and gamedev's stories in our technical blogs adaptive performance adaptive performance provides that way to manage both the thermals and performance of a game on a mobile device gpuwatch gpuwatch is a tool for observing gpu activity in your apps. you can find out how to use it and which devices support it here resources articles, white papers, and interesting code samples for game developers event archive videos and slides of key technical presentations from a variety of developer events what is galaxy gamedev and what do we do? through this program, we collaborate with many key partners in the gaming industry to support game developers with early engagement of new technologies for better gaming experiences read more adaptive performance the adaptive performance package provides an api to get feedback about the thermal and power state of mobile devices, enabling applications to make performance-relevant adaptions at runtime. read more code lab looking for a community? meet other developers. ask questions. find answers. read more

      https://developer.samsung.com/galaxy-gamedev/
      1. tutorials | game, mobile

      blog

      How to Use Jetpack WindowManager in Android Game Dev

      with the increasing popularity of foldable phones such as the galaxy z fold3 and galaxy z flip3, apps on these devices are adopting its foldable features. in this blog, you can get started on how to utilize these foldable features on android game apps. we focus on creating a java file containing an implementation of the android jetpack windowmanager library that can be imported into game engines like unity or unreal engine. this creates an interface allowing developers to retrieve information about the folding feature on the device. at the end of this blog, you can go deeper in learning by going to code lab. android jetpack windowmanager android jetpack, in their own words, is "a suite of libraries to help developers follow best practices, reduce boilerplate code, and write code that works consistently across android versions and devices so that developers can focus on the code they care about." windowmanager is one of these libraries, and is intended to help application developers support new device form factors and multi-window environments. the library had its 1.0.0 release in january 2022 for targeted foldable devices. according to its documentation, future versions will be extended to more display types and window features. creating the android jetpack windowmanager setup as previously mentioned, we are creating a java file that can be imported into either unity or unreal engine 4, to create an interface for retrieving information on the folding feature and pass it over to the native or engine side of your applications. set up the foldablehelper class and data storage class create a file called foldablehelper.java in visual studio or any source code editor. let's start off by giving it a package name of package com.samsung.android.gamedev.foldable; next, let's import all the necessary libraries and classes in this file: //android imports import android.app.activity; import android.graphics.rect; import android.os.handler; import android.os.looper; import android.util.log; //android jetpack windowmanager imports import androidx.annotation.nonnull; import androidx.core.util.consumer; import androidx.window.java.layout.windowinfotrackercallbackadapter; import androidx.window.layout.displayfeature; import androidx.window.layout.foldingfeature; import androidx.window.layout.windowinfotracker; import androidx.window.layout.windowlayoutinfo; import androidx.window.layout.windowmetrics; import androidx.window.layout.windowmetricscalculator; //java imports import java.util.list; import java.util.concurrent.executor; start by creating a class, foldablehelper, that is going to contain all of our helper functions. let's then create variables to store a callback object as well as windowinfotrackercallbackadapter and windowmetricscalculator. let's also create a temporary declaration of the native function to pass the data from java to the native side of application once we start working in the game engines. public class foldablehelper { private static layoutstatechangecallback layoutstatechangecallback; private static windowinfotrackercallbackadapter wit; private static windowmetricscalculator wmc; public static native void onlayoutchanged(foldablelayoutinfo resultinfo); } let's create a storage class to hold the data received from the windowmanager library. an instance of this class will also be passed to the native code to transfer the data. public static class foldablelayoutinfo { public static int undefined = -1; // hinge orientation public static int hinge_orientation_horizontal = 0; public static int hinge_orientation_vertical = 1; // state public static int state_flat = 0; public static int state_half_opened = 1; // occlusion type public static int occlusion_type_none = 0; public static int occlusion_type_full = 1; rect currentmetrics = new rect(); rect maxmetrics = new rect(); int hingeorientation = undefined; int state = undefined; int occlusiontype = undefined; boolean isseparating = false; rect bounds = new rect(); } initialize the windowinfotracker since we are working in java and the windowmanager library is written in kotlin, we have to use the windowinfotrackercallbackadapter. this is an interface provided by android to enable the use of the windowinfotracker from java. the window info tracker is how we receive information about any foldable features inside the window's bounds. next is to create windowmetricscalculator, which lets us retrieve the window metrics of an activity. window metrics consists of the windows' current and maximum bounds. we also create a new layoutstatechangecallback object. this object is passed into the window info tracker as a listener object and is called every time the layout of the device changes (for our purposes this is when the foldable state changes). public static void init(activity activity) { //create window info tracker wit = new windowinfotrackercallbackadapter(windowinfotracker.companion.getorcreate(activity)); //create window metrics calculator wmc = windowmetricscalculator.companion.getorcreate(); //create callback object layoutstatechangecallback = new layoutstatechangecallback(activity); } set up and attach the callback listener in this step, let's attach the layoutstatechangecallback to the windowinfotrackercallbackadapter as a listener. the addwindowlayoutinfolistener function takes three parameters: the activity to attach the listener to, an executor, and a consumer of windowlayoutinfo. we will set up the executor and consumer in a moment. the adding of the listener is kept separate from the initialization, since the first windowlayoutinfo is not emitted until activity.onstart has been called. as such, we'll likely not be needing to attach the listener until during or after onstart, but we can still set up the windowinfotracker and windowmetricscalculator ahead of time. public static void start(activity activity) { wit.addwindowlayoutinfolistener(activity, runonuithreadexecutor(), layoutstatechangecallback); } now, let's create the executor for the listener. this executor is straightforward and simply runs the command on the mainlooper of our activity. it is possible to set this up to run on a custom thread, however this is not going to be covered in this blog. for more information, we recommend checking the official documentation for the jetpack windowmanager. static executor runonuithreadexecutor() { return new myexecutor(); } static class myexecutor implements executor { handler handler = new handler(looper.getmainlooper()); @override public void execute(runnable command) { handler.post(command); } } we're going to create the basic layout of our layoutstatechangecallback. this consumes windowlayoutinfo and implements consumer<windowlayoutinfo>. for now, let's simply lay out the class and give it some functionality a little bit later. static class layoutstatechangecallback implements consumer<windowlayoutinfo> { private final activity activity; public layoutstatechangecallback(activity activity) { this.activity = activity; } } if the use of the listener is no longer needed, we want a way to remove it and the windowinfotrackercallbackadapter contains a function to do just that. public static void stop() { wit.removewindowlayoutinfolistener(layoutstatechangecallback); } this just tidies things up for us and ensures that the listener is cleaned up when we no longer need it. next, we're going to add some functionality to the layoutstatechangecallback class. we are going to process windowlayoutinfo into foldablelayoutinfo we created previously. using java native interface (jni), we are going to send that information over to the native side using the function onlayoutchanged. note: this doesn't actually do anything yet, but we cover how to set this up in unreal engine and in unity through code lab tutorials. static class layoutstatechangecallback implements consumer<windowlayoutinfo> { @override public void accept(windowlayoutinfo windowlayoutinfo) { foldablelayoutinfo resultinfo = updatelayout(windowlayoutinfo, activity); onlayoutchanged(resultinfo); } } let's implement the updatelayout function to process windowlayoutinfo and return a foldablelayoutinfo. firstly, create a foldablelayoutinfo that contains the processed information. follow this up by getting the window metrics, both maximum metrics and current metrics. private static foldablelayoutinfo updatelayout(windowlayoutinfo windowlayoutinfo, activity activity) { foldablelayoutinfo retlayoutinfo = new foldablelayoutinfo(); windowmetrics wm = wmc.computecurrentwindowmetrics(activity); retlayoutinfo.currentmetrics = wm.getbounds(); wm = wmc.computemaximumwindowmetrics(activity); retlayoutinfo.maxmetrics = wm.getbounds(); } get the displayfeatures present in the current window bounds using windowlayoutinfo.getdisplayfeatures. currently, the api only has one type of displayfeature: foldingfeatures, however in the future there will likely be more as screen types evolve. at this point, let's use a for loop to iterate through the resulting list until it finds a foldingfeature. once it detects a folding feature, it starts processing its data: orientation, state, seperation type, and its bounds. then, store these data in foldablelayoutinfo we've created at the start of the function call. you can learn more about these data by going to the jetpack windowmanager documentation. private static foldablelayoutinfo updatelayout(windowlayoutinfo windowlayoutinfo, activity activity) { foldablelayoutinfo retlayoutinfo = new foldablelayoutinfo(); windowmetrics wm = wmc.computecurrentwindowmetrics(activity); retlayoutinfo.currentmetrics = wm.getbounds(); wm = wmc.computemaximumwindowmetrics(activity); retlayoutinfo.maxmetrics = wm.getbounds(); list<displayfeature> displayfeatures = windowlayoutinfo.getdisplayfeatures(); if (!displayfeatures.isempty()) { for (displayfeature displayfeature : displayfeatures) { foldingfeature foldingfeature = (foldingfeature) displayfeature; if (foldingfeature != null) { if (foldingfeature.getorientation() == foldingfeature.orientation.horizontal) { retlayoutinfo.hingeorientation = foldablelayoutinfo.hinge_orientation_horizontal; } else { retlayoutinfo.hingeorientation = foldablelayoutinfo.hinge_orientation_vertical; } if (foldingfeature.getstate() == foldingfeature.state.flat) { retlayoutinfo.state = foldablelayoutinfo.state_flat; } else { retlayoutinfo.state = foldablelayoutinfo.state_half_opened; } if (foldingfeature.getocclusiontype() == foldingfeature.occlusiontype.none) { retlayoutinfo.occlusiontype = foldablelayoutinfo.occlusion_type_none; } else { retlayoutinfo.occlusiontype = foldablelayoutinfo.occlusion_type_full; } retlayoutinfo.isseparating = foldingfeature.isseparating(); retlayoutinfo.bounds = foldingfeature.getbounds(); return retlayoutinfo; } } } return retlayoutinfo; } if there's no folding feature detected, it simply returns the foldablelayoutinfo without setting its data leaving it with undefined (-1) values. conclusion the java file you have now created should be usable in new or existing unity and unreal engine projects, to provide access to the information on the folding feature. continue learning about it by going to the code lab tutorials showing how to use the file created here, to implement flex mode detection and usage in game applications. additional resources on the samsung developers site the samsung developers site has many resources for developers looking to build for and integrate with samsung devices and services. stay in touch with the latest news by creating a free account and subscribing to our monthly newsletter. visit the marketing resources page for information on promoting and distributing your apps. finally, our developer forum is an excellent way to stay up-to-date on all things related to the galaxy ecosystem.

      Lochlann Henry Ramsay-Edwards

      https://developer.samsung.com/galaxy-gamedev/blog/en-us/2022/07/20/how-to-use-jetpack-window-manager-in-android-game-dev
      1. Learn
      2. Code Lab

      codelab

      Control a Smart Bulb

      control a smart bulb objective control a smart light bulb and change its color using bixby home studio. overview bixby home studio (bhs) provides a simple and optimized way for accessing and controlling devices connected to your smartthings account. you can quickly create complex diagrams and condition-based flows with bhs's user-friendly graphical user interface (gui). any device compatible with smartthings can be adjusted, controlled, and updated through bixby home studio. for more information, visit getting started with bixby home studio. set up your environment you will need the following: samsung and smartthings account (same email address) smart rgb light bulb added to smartthings account virtual switch from smartthings labs (if a smart rgb light bulb is not available) a. go to smartthings app. b. in the menu, select labs. c. choose virtual switch and click + to add a virtual switch. d. enter the name of virtual switch, location, and room. notewhen you use a virtual switch, you can only create metadata and test the turning on and off functionality. however, a physical smart rgb light bulb is necessary for testing other functions of this code lab activity, such as changing the light bulb color to red. smartthings labs feature is available only on android app in us, canada, uk, india, and south korea. start your project go to bhs.bixbydevelopers.com and sign in using your samsung account. create a new project. select your smartthings location and smart rgb light bulb or virtual switch for the device. click create metadata from scratch. then, click next. choose powerswitch under bixby voice category. select the powerswitch-turnoff and powerswitch-turnon voice intents. click next. input a project name and click done. use a sample graph to switch on the bulb sample graphs are various example action flows that you can explore to learn more about the different voice intents, nodes, and smartthings capabilities. you can use these sample graphs as starter points for your own devices. each sample graph generically handles specific capabilities covered under various user utterances through the different voice intents. for example, the turn on device sample graph works for any device. it covers a variety of user utterances such as "turn on air conditioner.", "turn on fan.", "turn on speaker.”, and so on. follow the steps below to use the turn on device sample graph to switch on the device: go to voice intents > powerswitch-turnon > graph. click the sample graphs icon on the left sidebar menu to show all the available sample graphs. scroll down to see the turn on device sample graph or find it using the search bar. drag and drop the sample graph into your powerswitch-turnon graph editor. click try it to turn on your light bulb. noteif you're using a virtual switch, it will turn on, but you won't be able to see the switch itself. however, you can see the state of the virtual switch change from off to on in the smartthings app. turn off the light bulb and add an alternative response the turn on device sample graph functions to switch on the device when the start node triggers the command node. this graph can be modified to reverse its function, to do that: copy the nodes from the powerswitch-turnon graph to the powerswitch-turnoff graph editor. click the command node to open the node configuration pane and change the command from on to off. right-click on the command node and change its comment to turn off device. click try it to turn off the device. after the command is performed, the response is either success or execution failed. to make the light bulb more responsive, design the graph to provide different responses depending on whether the light bulb is already off or currently on. a. click the raw button and delete the existing code in the raw graph. b. copy and paste the following json into it and click add. [{"nodeid":"5b648da1-a2c3-4912-baff-a559b968070e","nodever":"1.0","nodetype":"capabilityattribute","isstateful":true,"group":null,"inputports":{"device":{"nodes":[],"portinfo":null}},"triggerports":{"success":{"nodes":["ccf1cbb8-c99b-439f-8246-bc9e7b7abfbf"],"portinfo":null},"failure":{"nodes":[],"portinfo":null}},"valueports":{},"triggerinports":{},"configurations":{"attribute":{"datatype":"datatype.schema.afcapabilityattribute","datavalue":{"component":"main","capability":"switch","attribute":"switch","property":{"name":"value","datatype":"datatype.primitive.afstring"}}},"required":{"datatype":"datatype.primitive.afboolean","datavalue":true}},"styles":{"x":415,"y":360}},{"nodeid":"ccf1cbb8-c99b-439f-8246-bc9e7b7abfbf","nodever":"1.0","nodetype":"equalcomparison","isstateful":true,"group":null,"inputports":{"leftvalue":{"nodes":["5b648da1-a2c3-4912-baff-a559b968070e"],"portinfo":null},"rightvalue":{"nodes":["8d9bf8ec-7cb1-4ffe-b4c0-b0424d394027"],"portinfo":null}},"triggerports":{"true":{"nodes":["593250c4-9c19-4155-8f90-1318f9484aab"],"portinfo":null},"false":{"nodes":["a9c4d152-eb0d-45d2-a2bd-20217de6fee6"],"portinfo":null}},"valueports":{},"triggerinports":{},"configurations":{"operator":{"datatype":"datatype.operator.equalcomparisonoperator","datavalue":"equalto"}},"styles":{"x":585,"y":332}},{"nodeid":"8d9bf8ec-7cb1-4ffe-b4c0-b0424d394027","nodever":"1.0","nodetype":"constant","isstateful":true,"group":null,"inputports":{},"triggerports":{},"valueports":{},"triggerinports":{},"configurations":{"value":{"datatype":"datatype.primitive.afstring","datavalue":"on"}},"styles":{"x":415,"y":500}},{"nodeid":"a9c4d152-eb0d-45d2-a2bd-20217de6fee6","nodever":"1.0","nodetype":"responsefeaturealreadyset","isstateful":true,"group":null,"inputports":{},"triggerports":{},"valueports":{},"triggerinports":{},"configurations":{},"styles":{"x":635,"y":480}}] c. four nodes were added to the graph. an attribute node that receives and passes an on or off value; a constant node with on as its value; an equal comparison node that compares if the attribute value is equal to the constant value; and a response: already set node d. rewire the graph to make it work properly by clicking the line coming from the start node and pressing the delete key. e. create a new line from the start node and connect it to the attribute node's trigger port. f. connect the equal comparison node's true port to the command node's trigger port. g. click the align button a couple of times to automatically organize the graph. h. then, click try it while the device is already off or already on, to observe the different responses. change the light bulb's color based on time the command node has two capabilities that can adjust the color of light bulb, such as colorcontrol and colortemperature. in this step, use these command node capabilities together with the get current datetime node and get datetime attributes node to set the light bulb's color to red or warm, if the current date time is 8:00 pm or later. otherwise, the light bulb's color remains blue. add the following json into the powerswitch-turnon graph. [{"nodeid":"a31659e2-68fc-42b6-8076-01c2cb9fec23","nodever":"1.0","nodetype":"getcurrentdatetime","isstateful":true,"group":null,"inputports":{"__zoneid":{"nodes":[],"portinfo":null}},"triggerports":{"main":{"nodes":["ea58c225-7d40-45b9-85d6-d8d941de9b2e"],"portinfo":null}},"valueports":{},"triggerinports":{},"configurations":{},"styles":{"x":715,"y":280}},{"nodeid":"ea58c225-7d40-45b9-85d6-d8d941de9b2e","nodever":"1.0","nodetype":"getdatetimeattributes","isstateful":true,"group":null,"inputports":{"input":{"nodes":["a31659e2-68fc-42b6-8076-01c2cb9fec23"],"portinfo":null}},"triggerports":{"main":{"nodes":["880416f6-d288-4b97-b763-2abd46bf2737"],"portinfo":null}},"valueports":{"seconds":{"name":"seconds"},"month":{"name":"month"},"hour":{"name":"hour"},"year":{"name":"year"},"minutes":{"name":"minutes"},"timestampinseconds":{"name":"timestampinseconds"},"day":{"name":"day"}},"triggerinports":{},"configurations":{},"styles":{"x":815,"y":280}},{"nodeid":"880416f6-d288-4b97-b763-2abd46bf2737","nodever":"1.0","nodetype":"comparablecomparison","isstateful":true,"group":null,"inputports":{"leftvalue":{"nodes":["gr://node/ea58c225-7d40-45b9-85d6-d8d941de9b2e/value/hour"],"portinfo":null},"rightvalue":{"nodes":["606796bc-d8ea-4421-942d-91544271615d"],"portinfo":null}},"triggerports":{"true":{"nodes":["b2ba65ab-5e3e-4615-8d3a-79015a03d7bc"],"portinfo":null},"false":{"nodes":[],"portinfo":null}},"valueports":{},"triggerinports":{},"configurations":{"operator":{"datatype":"datatype.operator.comparablecomparisonoperator","datavalue":"greaterthanorequalto"}},"styles":{"x":975,"y":320}},{"nodeid":"606796bc-d8ea-4421-942d-91544271615d","nodever":"1.0","nodetype":"constant","isstateful":true,"group":null,"inputports":{},"triggerports":{},"valueports":{},"triggerinports":{},"configurations":{"value":{"datatype":"datatype.primitive.afinteger","datavalue":20}},"styles":{"x":815,"y":420}},{"nodeid":"2b22b1a1-b9cb-4881-a861-3bf74ccd7847","nodever":"1.0","nodetype":"capabilitycommand","isstateful":true,"group":null,"inputports":{"device":{"nodes":[],"portinfo":null},"1:color":{"nodes":["2389baa9-db45-4eb3-a40c-1166bf1e620f"],"portinfo":{"datatypes":["undefined"],"minitems":1,"maxitems":1,"iscustomport":true}}},"triggerports":{"success":{"nodes":["a31659e2-68fc-42b6-8076-01c2cb9fec23"],"portinfo":null},"failure":{"nodes":[],"portinfo":null}},"valueports":{},"triggerinports":{},"configurations":{"commands":{"datatype":"datatype.util.aflist","datavalue":[{"datatype":"datatype.schema.afcapabilitycommand","datavalue":{"component":"main","capability":"colorcontrol","command":"setcolor","arguments":[{"datatype":"datatype.schema.afcommandargument","datavalue":{"name":"color","optional":false,"datatype":"datatype.primitive.afjsonobject"}}]}}]}},"styles":{"x":590,"y":274}},{"nodeid":"2389baa9-db45-4eb3-a40c-1166bf1e620f","nodever":"1.0","nodetype":"constant","isstateful":true,"group":null,"inputports":{},"triggerports":{},"valueports":{},"triggerinports":{},"configurations":{"value":{"datatype":"datatype.primitive.afjsonobject","datavalue":{"hue":55,"saturation":55}}},"styles":{"x":675,"y":440}},{"nodeid":"b2ba65ab-5e3e-4615-8d3a-79015a03d7bc","nodever":"1.0","nodetype":"capabilitycommand","isstateful":true,"group":null,"inputports":{"device":{"nodes":[],"portinfo":null},"1:temperature":{"nodes":["4d02fcda-df99-4c75-8b0a-73bb67933acd"],"portinfo":{"datatypes":["undefined"],"minitems":1,"maxitems":1,"iscustomport":true}}},"triggerports":{"success":{"nodes":[],"portinfo":null},"failure":{"nodes":[],"portinfo":null}},"valueports":{},"triggerinports":{},"configurations":{"commands":{"datatype":"datatype.util.aflist","datavalue":[{"datatype":"datatype.schema.afcapabilitycommand","datavalue":{"component":"main","capability":"colortemperature","command":"setcolortemperature","arguments":[{"datatype":"datatype.schema.afcommandargument","datavalue":{"name":"temperature","optional":false,"datatype":"datatype.primitive.afinteger"}}]}}]}},"styles":{"x":1115,"y":380}},{"nodeid":"4d02fcda-df99-4c75-8b0a-73bb67933acd","nodever":"1.0","nodetype":"constant","isstateful":true,"group":null,"inputports":{},"triggerports":{},"valueports":{},"triggerinports":{},"configurations":{"value":{"datatype":"datatype.primitive.afinteger","datavalue":500}},"styles":{"x":975,"y":478}}] rewire the graph as follows: a. delete the wire that connects command (switch) node's success port and response: success node's trigger port. b. connect the command (switch) node's success port to the command (colorcontrol) node's trigger port. c. connect the command (colortemperature) node's success port to the response: success node's trigger port. d. connect the numerical comparison node's false port to the response: success node's trigger port. noteadd a constant node with time zone, for example america/new_york, as string value if you want to test this section based on your local time. click align. then, click try it to see how the light bulb color change based on time. you're done! congratulations! you have successfully achieved the goal of this code lab. now, you can control a smart light bulb using bixby home studio. if you face any trouble, you may download this file: control bulb complete code (25.72 kb) notewatch this short clip to quickly know how to navigate your way in this code lab and to see how easy it is to use bixby home studio. to learn more about bixby, visit: developer.samsung.com/bixby

      https://developer.samsung.com/codelab/bixby/smart-bulb.html
      1. Learn
      2. Code Lab

      codelab

      Create a Daily Step Counter on Galaxy Watch

      create a daily step counter on galaxy watch objective create a native app for galaxy watch, operating on wear os powered by samsung, using health platform to read your daily steps. overview health platform provides a unified and straightforward way for accessing a wide range of health and wellness related data. with health platform api, you may easily read and write data stored in health platform on android and wear os powered by samsung. applications can have access to these secured data only with explicit user consent. additionally, users may disable access to the data at any point in time. see health platform descriptions for detailed information. set up your environment you will need the following: galaxy watch4 or newer android studio (latest version recommended) java se development kit (jdk) 11 or later sample code here is a sample code for you to start coding in this code lab. download it and start your learning experience! health step count sample code (119.87 kb) turn on developer mode and adjust its settings on your watch, go to settings > about watch > software and tap on software version 5 times. upon successful activation of developer mode, a toast message will display as on the image below. afterwards, developer options will be visible under settings. tap developer options and enable the following options: adb debugging debug over wi-fi turn off automatic wi-fi connect your galaxy watch to wi-fi go to settings > connection > wi-fi and make sure that wi-fi is enabled. from the list of available wi-fi networks, choose and connect to the same one as your pc. when successfully connected, tap a wi-fi network name, swipe down, and note the ip address. you will need this to connect your watch over adb from your pc. connect your galaxy watch to android studio in android studio, go to terminal and type: adb connect <ip address as mentioned in previous step> when prompted, tap always allow from this computer to allow debugging. upon successful connection, you will see the following message in android studio’s terminal: connected to <ip address of your watch> now, you can run the app directly on your watch. start your project after downloading the sample code containing the project files, in android studio click open to open existing project. locate the downloaded android project (stepcount) from the directory and click ok. check dependency and app manifest in the dependencies section of stepcount/app/build.gradle file, see the appropriate dependency for health platform. dependencies { implementation com.google.android.libraries.healthdata:health-data-api:1.0.0-alpha01' // ... } notelibrary might update from time to time. if necessary, choose the version suggested by android studio. request for data permissions before accessing any data through health platform, the client app must obtain necessary permissions from the user. in permissions.java, create a permission instance to trigger relevant permission screen and obtain required consent from end user. data type name: intervaldatatypes.steps read access: accesstype.read /******************************************************************************************* * [practice 1] build permission object grand permissions for read today's steps * - set interval data type of steps * - set read access type ------------------------------------------------------------------------------------------- * - (hint) uncomment lines below and fill todos with * (1) for interval data type: intervaldatatypes.steps * (2) for read access: accesstype.read ******************************************************************************************/ permission stepsreadpermission = permission.builder() //.setdatatype("todo 1 (1)") //.setaccesstype("todo 1 (2)") .build(); make a query to aggregate today’s steps create read request with all necessary information to read data through health platform api. the answer from the platform will be asynchronous with the result from which you can get all the data you are interested in. follow the steps below to get today's steps count: in stepsreader.java, create a readaggregateddatarequest with cumulativeaggregationspec instance: data type name: intervaldatatypes.steps /******************************************************************************************* * [practice 2] build read aggregated data request object for read today's steps * - set interval data type of steps ------------------------------------------------------------------------------------------- * - (hint) uncomment line below and fill todo 2 with * (1) for interval data type: intervaldatatypes.steps ******************************************************************************************/ readaggregateddatarequest readaggregateddatarequest = readaggregateddatarequest.builder() .settimespec( timespec.builder() .setstartlocaldatetime(localdatetime.now().with(localtime.midnight)) .build()) //.addcumulativeaggregationspec(cumulativeaggregationspec.builder("todo 2 (1)").build()) .build(); read cumulative steps count from cumulativedata: set variable steps value to 0l. it is the count of daily steps. get aggregatedvalue object using cumulativedata api. cumulativedataaggregateddata representing total of intervaldata over a period of time (e.g. total steps in a day). public aggregatedvalue gettotal () check the result. if it is not null, get aggregated value using aggregatedvalue api: aggregatedvaluevalue fields aggregated over a period of time. only numeric fields (longfield, doublefield) can be included in aggregation. public long getlongvalue () returns all longfields and their values that are already set. add value to the daily steps result counter. /******************************************************************************************* * [practice 3] read aggregated value from cumulative data and add them to the result * - get aggregatedvalue from cumulativedata object * - get steps count from aggregatedvalue object ------------------------------------------------------------------------------------------- * - (hint) uncomment lines below and replace todo 3 with parts of code * (1) get aggregatedvalue object 'obj' using cumulativedata.gettotal() * (2) get value using obj.getlongvalue() and add to the result ******************************************************************************************/ long steps = 0l; if(result != null) { list<cumulativedata> cumulativedatalist = result.getcumulativedatalist(); if (!cumulativedatalist.isempty()) { for(cumulativedata cumulativedata : cumulativedatalist) { //"todo 3 (1)" //"todo 3 (2)" } } } return steps; run unit tests for your convenience, you will find an additional unit tests package. this will let you verify your code changes even without using a physical watch. see instruction below on how to run unit tests: right click on com.samsung.sdc21.stepcount (test) and execute run 'tests in 'com.samsung.sdc21.stepcount'' command. if you completed all the tasks correctly, you will see all the unit tests passed successfully. run the app after building the apk, you can run the application on a connected device to see real-life aggregated steps count measured by a smartwatch. right after the app is started, it will request for the user permission. allow the app to receive data of the activity. afterwards, the application main screen will be shown. it will automatically display today’s step count. tap on refresh button to read current steps count from health platform. you're done! congratulations! you have successfully achieved the goal of this code lab. now, you can create a daily step counter app by yourself! if you're having trouble, you may download this file: health step count complete code (119.79 kb) learn more by going to health platform.

      https://developer.samsung.com/codelab/health/daily-step-counter.html
      1. Learn
      2. Code Lab

      codelab

      Track Deadlift Exercise on Galaxy Watch

      track deadlift exercise on galaxy watch objective create a native app for galaxy watch, operating on wear os powered by samsung, using health services to track deadlift exercise. this app measures repetition count, calories burned, and time spent during the exercise. overview health services provides a simple and unified way for accessing a wide range of health and wellness related data. with health services api, you will no longer need to develop your own algorithms processing sensors data in order to compute metrics like heart rate, steps counts, distance, calories burned, and other more. these are now accessible through health services embedded on wearables operating on wear os powered by samsung. see health platform descriptions for detailed information. set up your environment you will need the following: galaxy watch4 or newer android studio (latest version recommended) java se development kit (jdk) 11 or later sample code here is a sample code for you to start coding in this code lab. download it and start your learning experience! health track deadlift sample code (122.22 kb) turn on developer mode and adjust its settings on your watch, go to settings > about watch > software and tap on software version 5 times. upon successful activation of developer mode, a toast message will display as on the image below. afterwards, developer options will be visible under settings. tap developer options and enable the following options: adb debugging debug over wi-fi turn off automatic wi-fi connect your galaxy watch to wi-fi go to settings > connection > wi-fi and make sure that wi-fi is enabled. from the list of available wi-fi networks, choose and connect to the same one as your pc. when successfully connected, tap a wi-fi network name, swipe down, and note the ip address. you will need this to connect your watch over adb from your pc. connect your galaxy watch to android studio in android studio, go to terminal and type: adb connect <ip address as mentioned in previous step> when prompted, tap always allow from this computer to allow debugging. upon successful connection, you will see the following message in android studio’s terminal: connected to <ip address of your watch> now, you can run the app directly on your watch. start your project after downloading the sample code containing the project files, click open to open existing project in android studio. locate the downloaded android project (deadlift) from the directory and click ok. check dependency and app manifest in the dependencies section of deadlift/app/build.gradle file, see the appropriate dependency for health services. dependencies { implementation 'androidx.health:health-services-client:1.0.0-alpha03' // ... } notesince the library might update from time to time, it is recommended to choose the version suggested by android studio. in androidmanifest.xml file, note the following: <queries> element <queries> <package android:name="com.google.android.wearable.healthservices" /> </queries> section with requests for necessary permissions <uses-permission android:name="android.permission.body_sensors" /> <uses-permission android:name="android.permission.activity_recognition" /> check capabilities to check what can be measured during exercise, you need to check its capabilities. follow these steps to obtain them: open deadlift.java and navigate to checkcapabilities function. prepare a listenablefuture<exercisecapabilities> instance that will query for deadlift capabilities. getcapabilities() checks exercise capabilities in exerciseclient object. public void checkcapabilities() { listenablefuture<exercisecapabilities> capabilitieslistenablefuture = null; /****************************************************************************************** * [practice 1] create listenablefuture object that will get a callback with exercise * capabilities. choose correct function from exerciseclient *-------------------------------------------------------------------------------------- * uncomment line below and fill todo 1 * (1) for checking capabilities use getcapabilities() ****************************************************************************************/ //capabilitieslistenablefuture = exerciseclient.todo 1; futures.addcallback(capabilitieslistenablefuture, new futurecallback<exercisecapabilities>() { @override public void onsuccess(@nullable exercisecapabilities result) { log.i(tag,"got exercise capabilities"); try { exercisecapabilitiesset = deadliftreader.getexercisecapabilities(result); } next, go to deadliftreader.java and navigate to getexercisecapabilities function. getsupporteddatatypes() gets measurable data types in exercisetypecapabilities. public set<datatype> getexercisecapabilities(exercisecapabilities result) throws deadliftexception { if(result == null) throw new deadliftexception("exercisecapabilities is null"); exercisetypecapabilities exercisetypecapabilities = result.getexercisetypecapabilities(exercisetype); set<datatype> datatypeset = null; /**************************************************************************************** * [practice 1] read set of deadlift capabilities. choose correct function from exercise * type capabilities. * -------------------------------------------------------------------------------------- * uncomment line below and fill todo 2 * - for checking deadlift capabilities use getsupporteddatatypes() */ //datatypeset = exercisetypecapabilities.todo 2; return datatypeset; } register an event for deadlift state update in deadlift.java, navigate to startexerciseupdatelistener() function. to get exercise updates, you need to set a listener using setupdatelistener(exerciseupdatelisener). public void startexerciseupdatelistener() throws deadliftexception { if(exerciseclient == null) throw new deadliftexception("exercise client is null"); /**************************************************************************************** * [practice 2] create listenablefuture object that will get a callback with exercise * capabilities. choose correct function from exerciseclient *-------------------------------------------------------------------------------------- * uncomment line below and fill todo 3 * for setting update listener use setupdatelistener(exerciseupdatelistener) */ listenablefuture<void> updatelistenablefuture = null; //updatelistenablefuture = exerciseclient.todo 3; if(updatelistenablefuture == null) throw new deadliftexception("update is null"); futures.addcallback(updatelistenablefuture, new futurecallback<void>() { @override public void onsuccess(@nullabledecl void result) { log.i(tag, "successfully set update listener"); ismeasurementrunning = true; butstart.settext("stop"); } check the updated event to work with the data provided by an exercise, you need to get the latest reading metrics. in deadlift.java, navigate to updaterepcount() function. getlatestmetrics() gets the latest readings from an exercise update. public void updaterepcount(exerciseupdate update) throws deadliftexception { /*************************************************************************************** * [practice 3] create map object that will get readings from the update * choose correct function from exerciseupdate class * ------------------------------------------------------------------------------------- * uncomment line below and fill todo 4 * for reading latest values from update use getlatestmetrics() */ map<datatype, list<datapoint>> map = null; if (update == null) throw new deadliftexception("exercise update is null"); //map = update.todo 4; if (map.isempty()) return; run unit tests for your convenience, you will find an additional unit tests package. this will let you verify your code changes even without using a physical watch. see instruction below on how to run unit tests: right click on com.samsung.sdc21.deadlift (test) > deadliftunittest and execute run 'deadliftunittest' command. if you completed all the tasks correctly, you will see all the unit tests passed successfully. run the app after building the apk, you can run the application on a connected device to measure actual deadlift parameters. right after the app is started, it will request for the user permission. allow the app to receive data of the activity. afterwards, the application main screen will be shown. before doing deadlifts, press the start button to track your exercise. when done, tap on the stop button. you're done! congratulations! you have successfully achieved the goal of this code lab. now, you can create a deadlift exercise tracker app by yourself! if you're having trouble, you may download this file: health track deadlift complete code (122.24 kb) learn more by going to health platform.

      https://developer.samsung.com/codelab/health/deadlift-tracker.html
      1. Learn
      2. Code Lab

      codelab

      Optimize Unity Game Performance

      optimize unity game performance objective learn how to optimize the performance of a demo game using the adaptive performance package from within unity. the adaptive performance package provides you with tools, including relevant information from the mobile device. the tools allow you to edit different features in the game with useful scalers that give you the ability to improve the overall game performance. overview galaxy gamesdk delivers an interface between game application and device which helps developers optimize their games. integrating unity adaptive performance with galaxy gamesdk allows unity developers to use this feature on unity editor within unity package manager and also customize their game contents by c# scripting. game performance and quality settings can be adjusted in real-time by identifying device performance status and heat trends. moreover, using a set of simple ui controls, you can scale the quality of the game to match the device platform. samsung galaxy s10 / note10 devices and onwards support adaptive performance. thermal throttling mobile devices don’t have an active cooling system, so temperature continues to rise and it will limit the cpu / gpu clock to control heat and consequently degrading the performance. the ideal goal is to make performance stable with low temperature. adaptive performance, primarily for performance and quality balance management, can help achieve this. thermal warning the warning system implemented in gamesdk can trigger the throttling system to adjust the cpu/gpu clock. adjust quality it also provides you with the option to adjust the quality of the game to maintain stable performance at different warning levels. dynamic quality setting you can scale the quality of your game in real-time to meet the desired performance. this includes changes in network, animation, physics, level of detail, and visual effects. scalers with the latest addition to the adaptive performance tool v2.0, available in the 2020 version of unity, here’s a list of features that can be managed within the adaptive performance scalers in the project settings: frame rate resolution batching level of detail (lod) look up texture (lut) multisample anti-aliasing (msaa) shadow cascade shadow distance shadow map resolution shadow quality sorting transparency view distance there are other available features in the adaptive performance settings menu that can be edited similarly with different scale ranges. variable refresh rate another latest addition provided in v2.0 is the variable refresh rate (vrr). this will increase frame rate for devices that support refresh rates above 60. simulator the newest and useful feature that allows you to facilitate mobile development would be the device simulator. this allows developers to display the game as it would be presented on a device. megacity demo game you will use a demo game, named megacity, and optimize its performance using adaptive performance tools. megacity contains the following: 8 million triangles 6 million entities 2000 cars 100 audio source (heavy for mobile in general case) unity 2019.1 visual studio 2017 android sdk + ndk 16b profiling: gpu watch gpuwatch gpuwatch is a profiling tool for observing gpu activity in your app. the following gpu related information are measured by the gpuwatch: fps counters current average cpu / gpu load cpu load gpu load gpu frequency frame info render pass stats vertex / fragment shader load set up your environment you will need the following: visual studio 2017 android sdk (latest) ndk r16b or later java se development kit (jdk) 8 or later unity 2019.1.14f1 or later https://unity3d.com/get-unity/download/archive run unity hub and add megacity project sample code here is a sample code for you to start coding in this code lab. download it and start your learning experience! adaptive performance sample code (1.93 kb) enable gpuwatch how to enable gpuwatch: test out the base sample app the base sample is written with classic simple approach: check cpu / gpu bottleneck trigger when thermal status is changed adjust cpu / gpu clock level adjust quality setting by setting lod adjust target fps all of these can be controlled in real-time. install adapative performance package go to editor > windows > package manager > install adaptive performance package. modify c# script go to editor > window > package manager > import adaptive performance package. double click adaptiveperformancecontroller.cs script file to edit. modify script as intended. build and launch apk select file > build settings. check that the device is connected and check the development build / scripts only build option. then, click patch and the installed apk on your device will be updated. measure performance to check current application performance, check the fps and cpu / gpu load counters. as you can see, the performance is not very good. the next step is to check current status where you will try to: check performance status to know if there is any bottleneck iadaptiveperformance.performancestatus.performancemetrics.performancebottleneck cpu: frame rate is limited by cpu processing gpu: frame rate is limited by gpu processing targetframerate: can’t reach target frame rate frame rate is limited by application.targetframerate. in this case, the application should consider lowering performance requirements. check thermal status register event handler to trigger thermal status and set handler into: ithermalstatus.thermalstatus.thermalevent check thermalmetrics information in event handler: warninglevel temperaturelevel (0.0 ~ 1.0) current normalized temperature level in the range of [0, 1]. a value of 0 means standard operation temperature and the device is not in a throttling state. a value of 1 means that the maximum temperature of the device is reached and the device is going into or is already in throttling state. temperaturetrend (-1.0 ~ 1.0) current normalized temperature trend in the range of [-1, 1]. a value of 1 describes a rapid increase in temperature. a value of 0 describes a constant temperature. a value of -1 describes a rapid decrease in temperature. please note that it takes at least 10s until the temperature trend may reflect any changes. adjust target frame rate change target frame rate when thermal status is changed. for example: change the quality setting change the quality setting by adjusting lod in real-time. adjust cpu/gpu clock change cpu / gpu clock level by ideviceperformancecontrol. ideviceperformancecontrol automaticperformancecontrol when set to true (default) cpulevel and gpulevel are set automatically by adaptive performance. maxcpuperformancelevel the maximum valid cpu performance level you use with cpulevel. the minimum value returned is mincpuperformancelevel. this value does not change after startup is complete. maxgpuperformancelevel the maximum valid gpu performance level you use with gpulevel. the minimum value returned is mingpuperformancelevel. this value does not change after startup is complete. cpulevel the requested cpu performance level. higher levels typically allow cpu cores to run at higher clock speeds. the consequence is that thermal warnings and throttling may happen sooner when the device cannot sustain high clock speeds. changes are applied once per frame. it is recommended to set the cpulevel as low as possible to save power. the valid value range is [mincpuperformancelevel, maxcpuperformancelevel]. gpulevel the requested gpu performance level. higher levels typically allow the gpu to run at higher clock speeds. the consequence is that thermal warnings and throttling may happen sooner when the device cannot sustain high clock speeds. changes are applied once per frame. it is recommended to set the gpulevel as low as possible to save power. the valid value range is [mingpuperformancelevel, maxgpuperformancelevel]. summary check the current status by: thermalmetrics.warninglevel (nowarning/ throttlingimminent/ throtting) performancebottleneck (cpu / gpu / targetframerate) control the performance by adjusting: lod bias cpu / gpu clock level target frame rate if possible, gfx load (triangles, memory, draw calls..) performance results frame rate now displays a stable fps with adaptive performance. you're done! congratulations! you have successfully achieved the goal of this code lab. now, you can improve the frame rate using adaptive performance by yourself! if you're having trouble, you may download this file: adaptive performance complete code (2.25 kb) to learn more about adaptive performance, gpuwatch, and galaxy gamedev, visit: www.developer.samsung.com/galaxy-gamedev

      https://developer.samsung.com/codelab/gamedev/adaptive-performance.html
      No Search Results
      No Search results. Try using another keyword.
      • <<
      • <
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • >
      • >>
      Samsung Developers
      Samsung Developers
      Quick Link
      • Android USB Driver
      • Code Lab
      • Galaxy Emulator Skin
      • Foldables and Large Screens
      • One UI Beta
      • Remote Test Lab
      • Samsung Developers Podcast
      Family Site
      • Bixby
      • Knox
      • Samsung Pay
      • SmartThings
      • Tizen
      • Samsung Research
      • Samsung Open Source
      • Samsung Dev Spain
      • Samsung Dev Brazil
      Legal
      • Terms
      • Privacy
      • Open Source License
      • Cookie Policy
      Social Communications
      • Facebook
      • Instagram
      • Twitter
      • YouTube
      • Buzzsprout
      • Rss
      • Linkedin
      • System Status
      • Site Map
      • System Status
      • Site Map
      • facebook
      • instagram
      • twitter
      • youtube
      • buzzsprout
      • rss
      • linkedin

      Copyright © 2023 SAMSUNG. All rights reserved.