This topic describes how to convert applications from Samsung Legacy Platform to Tizen.
To migrate an application from Samsung Legacy Platform to Tizen, you must import the project to the Tizen Studio, and make the necessary changes in the code.
To import a Samsung Legacy Platform application to Tizen:
Remove the existing "config.xml" and "widget.info" files from the application.
Create the project in the Tizen Studio. You can do this in 2 different ways:
For more information, see Creating Web Applications.
Create a new "config.xml" file for your project. For more information, see Configuring Web Applications.
To conform to HTML5 standards, modules from the Samsung Legacy Platform Common Modules API, such as the "Widget.js" and "PlugIn.js" libraries, are no longer supported. In Tizen, the Application Manager functionalities are handled using the Application API.
"Widget.js" library Replace the "Widget.js" library methods with their HTML5 equivalents in Tizen.
widgetAPI.putInnerHTML(pdiv,pContents)
pdiv.innerHTML = pContents
widgetAPI.blockNavigation()
event.preventDefault()
widgetAPI.sendReadyEvent()
widgetAPI.sendExitEvent()
tizen.application.getCurrentApplication().exit()
widgetAPI.sendReturnEvent()
tizen.application.getCurrentApplication().hide()
Table 1. Tizen equivalents to Samsung Legacy Platform "Widget.js" methods
curWidget object The curWidget object is not used in Tizen:
curWidget
curWidget.id
tizen.application.getCurrentApplication().appInfo.id
Log messages In Tizen, the alert() method is used to display popup windows. Use the console.log() method to print log messages.
alert()
console.log()
Viewport configuration To display an application in fullscreen, set the application width as the viewport width in the "index.html" file:
<meta name="viewport" content="width=960" />
For more information, see Managing Screen Resolution.
You must set the content security policy in the "config.xml" file. Tizen supports the W3C standard WARP security rules. To set the content security policy for the application:
Tizen handles user interaction differently from Samsung Legacy Platform:
Anchor elements In Samsung Legacy Platform, when mouse devices were not supported, applications registered the keydown event for clicks on an anchor element. In Tizen, use the click event for mouse and remote control clicks. To migrate key handling on anchor elements to Tizen:
keydown
click
body
IME Tizen provides the IME by default. When an input element is focused, the IME appears automatically. You do not need to create the IME using the IMEShell() method. For more information on implementing the IME in Tizen, see Keyboard/IME.
input
IMEShell()
Key values The key values in the Samsung Legacy Platform "TVKeyValue.js" library have changed in Tizen. If you want to continue using the same keyValue enumeration as before, include the TizenTVKeyValue.js file (direct download).
keyValue
TizenTVKeyValue.js
<script src="Common/API/TizenTVKeyValue.js"></script>
// TizenTVKeyValue.js maps Tizen keyCode values to Legacy Platform' js // You can use the same "KeyValue" values from the Legacy Platform: var tvKey = new Common.API.TVKeyValue();
Play/Pause key The basic remote control was distributed with Samsung TVs until 2014. Since 2015, Samsung Smart TVs are distributed with a Samsung Smart Remote. The Samsung Smart Remote has a "Play/Pause" key, and you must make sure your Tizen application handles its key clicks correctly. During media playback, clicking the "Play/Pause" key must pause playback, and clicking it while playback is paused must resume playback.
Multitasking is supported by default on Samsung TVs using Tizen. Unlike in Samsung Legacy Platform, you do not need to configure multitasking in the "config.xml" file. However, you must register an event handler for visibility changes.
The sendReturnEvent(), onPause(), and onResume() methods are not used in Tizen:
sendReturnEvent()
onPause()
onResume()
Before:
window.onPause = function() { // pause } window.onResume = function() { // resume }
After:
document.addEventListener("visibilitychange", function() { if (document.hidden) { // Something you want to do when application is paused console.log("lifecycle [pause]"); // This code handles playing media when application is hidden // webapis.avplay.suspend(); } else { // Something you want to do when application is resumed console.log("lifecycle [resume]"); // This code handles playing media when application is visible // webapis.avplay.restore(); } } );
In Samsung Legacy Platform, the application controlled the screensaver using the setOnScreenSaver() and setOffScreenSaver() methods. The screensaver functionality is handled by the Samsung Product API in Tizen:
setOnScreenSaver()
setOffScreenSaver()
var nnaviPlugin = document.getElementById("pluginObjectNNavi"); // ScreenSaver ON var screenStateON = 3; nnaviPlugin.SendEventToDevice(screenStateON, 1); // ScreenSaver OFF // var screenStateOFF = 4; //ScreenSaver OFF // nnaviPlugin.SendEventToDevice(screenStateOFF, 1);
function onsuccess(data) { console.log("setScreensavervalue = " + data); } function onerror(error) { console.log("error code : " + error.code); } try { // ScreenSaver ON var screenState = webapis.appcommon.AppCommonScreenSaverState.SCREEN_SAVER_ON; // ScreenSaver OFF var screenState = webapis.appcommon.AppCommonScreenSaverState.SCREEN_SAVER_OFF; var value = webapis.appcommon.setScreenSaver(screenState, onsuccess, onerror); } catch (error) { console.log(" error code = " + error.code); }
For more information, see Setting Screensaver.
In Samsung Legacy Platform, media playback was implemented using a plugin object and the Player API. These are not supported in Tizen.
plugin
In Tizen, you can implement media playback in 2 different ways:
video
audio
To implement media playback with a video element:
Player implementation:
// getElement var videoElem = document.getElementById("pluginPlayer"); // setDisplayArea videoElem.SetDisplayArea(left, top, width, height); // set any value // init videoElem.InitPlayer(url); // set your url // After InitPlayer is called. Seek play to sec. videoElem.StartPlayback(sec); // set any value // play videoElem.Play(url); // set your url // pause videoElem.Pause(); // resume videoElem.Resume(); // stop videoElem.Stop(); // Rewind / Fast forward videoElem.JumpForward(sec); videoElem.JumpBackward(sec); // get Duration var duration = videoElem.GetDuration(); // get mute status var muteStatus = videoElem.GetUserMute(); // set mute videoElem.SetUserMute(true); // videoElem.SetUserMute(false); // set volume videoElem.SetVolumeWithKey(0); // get volume var volume = videoElem.GetVolume();
// getElement var videoElem = document.createElement("video"); videoElem.style.backgroundColor = "#000"; document.body.appendChild(videoElem); // setDisplayArea videoElem.style.left = left + "px"; // set any value videoElem.style.top = top + "px"; // set any value videoElem.style.width = width + "px"; // set any value videoElem.style.height = height + "px"; // set any value // init videoElem.src = url; // set your url videoElem.load(); // Seek play to sec. if (sec > 0) { var jumper = function () { this.currentTime = sec; this.removeEventListener('loadedmetadata', jumper); }; videoElem.addEventListener('loadedmetadata', jumper); } videoElem.play(); // play videoElem.src = url; // set your url videoElem.play(); // pause videoElem.pause() // resume videoElem.play(); // stop if (videoElem.readyState > 0) { videoElem.src = ''; } // Rewind / Fast forward videoElem.currentTime += sec; videoElem.currentTime -= sec; // get Duration var duration = videoElem.duration * 1000; // get mute status var muteStatus = videoElem.muted; // set mute videoElem.muted = true; // videoElem.muted = false; // set volume (deprecated) // get volume var volume = videoElem.volume;
Event handler implementation:
// load metadata VideoElem.OnStreamInfoReady // time update VideoElem.OnCurrentPlayTime = "Player.OnCurrentPlayTime"; // ended VideoElem.OnRenderingComplete; // buffering event VideoElem.OnBufferingStart = "Player.OnBufferingStart"; VideoElem.OnBufferingComplete = "Player.OnBufferingComplete"; // error VideoElem.OnRenderError = "Player.OnRenderError"; VideoElem.OnStreamNotFound = "Player.OnStreamNotFound"; VideoElem.OnConnectionFailed = "Player.OnConnectionFailed"; VideoElem.OnNetworkDisconnected = "Player.OnNetworkDisconnected";
// load metadata VideoElem.addEventListener('loadedmetadata', function(){}, false); // time update VideoElem.addEventListener('timeupdate',function() { Player.OnCurrentPlayTime(this.currentTime * 1000); }, false); // ended VideoElem.addEventListener('ended', function(){}, false); // buffering event var bBuffering = false; VideoElem.addEventListener("stalled", function(e) { console.log("stalled"); !bBuffering && Player.OnBufferingStart(); bBuffering = true; }, false); VideoElem.addEventListener("waiting", function(e) { console.log("waiting"); !bBuffering && Player.OnBufferingStart(); bBuffering = true; }, false); VideoElem.addEventListener("timeupdate", function(e) { bBuffering && Player.OnBufferingComplete(); bBuffering = false; }); // error VideoElem.addEventListener("error", function(e) { if (this.getAttribute("src") === "" && this.error.code === MediaError.MEDIA_ERR_SRC_NOT_SUPPORTED) { // MEDIA_ERR_SRC_NOT_SUPPORTED occurs // when changing or initializing source during playback // Do not treat this as an error // this.src is not null string but baseURI ("index.html" path) // Use the getAttribute() method to get the current source } else if (this.error && typeof this.error.code === "number") { switch (this.error.code) { case MediaError.MEDIA_ERR_ABORTED: Player.OnConnectionFailed.call(PlayerEvtListener, e); break; case MediaError.MEDIA_ERR_ENCRYPTED: case MediaError.MEDIA_ERR_DECODE: case MediaError.MEDIA_ERR_SRC_NOT_SUPPORTED: Player.OnRenderError.call(Player, e); break; case MediaError.MEDIA_ERR_NETWORK: Player.OnNetworkDisconnected.call(Player, e); break; default: PlayerEvtListener.OnRenderError.call(Player, e); } } });
Samsung Legacy Platform provided 2 file system APIs:
FileSystem()
If you use the asynchronous Filesystem API, you do not need to make changes to the application logic. In Tizen, however, the Filesystem API is no longer part of the WebAPI module but a Tizen API:
webapis.filesystem.resolve()
tizen.filesystem.resolve()
Tizen does not provide a synchronous file system API. If you used the FileSystem() method, you must change your application implementation in one of the following ways:
Adapt the application logic to use the file system asynchronously and use the Filesystem API:
var filesystemObj = new FileSystem(); var fileObj = fileSystem.obj.openCommonFile(curWidget.id + "sample.data", "w"); fileObj.writeAll("Something to write."); var str = fileObj.readAll(); filesystemObj.closeCommonFile(fileObj); filesystemObj.deleteCommonFile(curwidget.id + "sample.data");
var str; tizen.filesystem.resolve("wgt-private", function(dir ){ dir.createFile("sample.data"); dir.resolve("wgt-private/sample.data").openStream("rw", function(stream) { stream.write("Something to write."); str = stream.read(100); stream.close(); tizen.filesystem.resolve("wgt-private", function(dir2) { dir2.deleteFile("wgt-private/sample.data"); }); }); });
If it is difficult to adapt the synchronous logic to asynchronous logic, you can use the Web standard Web Storage API. For more information, see Using Web Storage.
localStorage
// write data var fileSystemObj = new FileSystem(); var fileObj = fileSystemObj.openCommonFile(curWidget.id + '/testFile.data', 'w'); fileObj.writeAll('something to write.'); fileSystemObj.closeCommonFile(fileObj); // read data var fileObj = fileSystemObj.openCommonFile(curWidget.id + '/testFile.data', 'r'); var strResult = fileObj.readAll(); // delete file var bResult = fileSystemObj.deleteCommonFile(curWidget.id + '/testFile.data'); // validation check var bValid = fileSystemObj.isValidCommonPath(curWidget.id);
// write data localStorage.setItem('testFile', 'something to write.'); // read data var strResult = localStorage.getItem('testFile'); // delete file localStorage.removeItem('testFile'); // validation check // always true