top

Upgrading Legacy platform to Tizen

This guide covers how to upgrading application from Legacy platform to Tizen.

Overview

Importing Legacy platform application

When you import the application for Tizen, remove “config.xml” and “widget.info” files first.
There are 2 ways to import Legacy platform application.

  • Creating a new Tizen web project
  • Importing exist legacy platform application to Tizen web project

For more details, please refer Creating TV Application.

Create a new Empty Tizen web application by using Installation of TV SDK.
Select “File > New > Tizen Project > Template > TV > Web Application > Empty”.

After that, copy or move all contents in previous project into new project you made for Tizen.

2. Importing exist legacy platform application

Import existing application to Tizen web project.
Select “File > Import > Existing Projects into Workspace”.

After that, It is required to add new “config.xml” for Tizen in your project.

Important

Please note that legacy platform “config.xml” and Tizen “config.xml” contain different format each other.

Changed Feature

Common

1. Object Tag and Plugin APIs

Remove Plugin(through include object tag) and also all APIs which are related to the plugin.

  • index.html
<!-- <object id="pluginPlayer" border="0" classid="clsid:SAMSUNG-INFOLINK-PLAYER" style="position:absolute; z-index:50;left:0px;top:0px;width:1280px;height:720px;display:none;"></object> -->

2. Common API

Common APIs(through include Widget.js, TVKeyValue.js and Plugin.js) are not supported. These should be removed and replaced to the HTML5 standard.

  • Remove Common APIs
<!--
 <script type="text/javascript" language="javascript" src="$MANAGER_WIDGET/Common/API/Widget.js"></script>
 <script type="text/javascript" language="javascript" src="$MANAGER_WIDGET/Common/API/TVKeyValue.js"></script>
 <script type="text/javascript" language="javascript" src="$MANAGER_WIDGET/Common/API/PlugIn.js"></script>
-->
  • Widget.js
Table 1. Replacing to the HTML5 Standard
Previous Tizen
widgetAPI.putInnerHTML(pdiv,pContents) pdiv.innerHTML = pContents
widgetAPI.blockNavigation event.preventDefault()
widgetAPI.sendReadyEvent() Removed
widgetAPI.sendExitEvent() tizen.application.getCurrentApplication().exit()
widgetAPI.sendReturnEvent() tizen.application.getCurrentApplication().hide()
  • TVKeyValue.js
    Since Key value is changed, so the previous value with TVKeyValue.js can not be used. If you use attached TizenTVKeyValue.js, you can use same way of keyValue API(enum) as before. Please refer below sample code.
    tizentvkeyvalue.zip
<script src="Common/API/TizenTVKeyValue.js"></script>
// TizenTVKeyValue.js wrapped Tizen key code to TVKeyValue.js for legacy platform.
// You can only need to use like that such as legacy platform.
var tvKey = new Common.API.TVKeyValue();

3. Curwidget

  • Remove Curwidget related APIs
Table 2. Removing Curwidget related APIs
Previous Tizen
Curwidget.sendReadyEvent() Removed
Curwidget.id tizen.application.getCurrentApplication().appInfo.id

For more details, please refer Application API

4. Alert

alert() method is not supported any more for printing log. For printing log, please use console.log().
You can still use alert() for displaying popup window.

5. Viewport

If you want to display application with fullscreen, content size should be set by viewport at index.html like below. Width value is App’s own width.

<meta name="viewport" content="width=960" />

For more details, please refer Application Resolution

6. Network Policy

You should set a network policy in “config.xml”. Tizen applies WARP security rule of W3C. You should add your server domain in “Policy” tab.

Figure 1. Adding Network Policy

Figure 1. Adding Network Policy


Select “Policy” tab and click “Add” button. Write your server address in “Network URI”, and click “Allow” subdomain to make its value true.

7. Anchor Tag

Previously, when the mouse is not supported, App managed KeyHandler by using keydown event on anchor tag. But on Tizen, this way is not recommended.
We strongly recommend that using click event for pointing devices(ex. Mouse, Smart Remot control, etc). Further, on side of customer satisfaction, this way is much better. Until 14’ normal remote control is not distributed, only Smart Remote Control is distributed.

  • One Anchor Tag
    Register KeyHandler at anchor tag to keydown event at body tag.
  • More than one Anchor Tag
    KeyHandler function is needed for managing multiple anchor tag. In case of this, there is no specific solution. Modification should be applied differently for each case.

8. IME

Samsung Smart TV for Tizen provides IME. You don’t need to call IMEShell anymore. If you focus on input tag, IME appears automatically.
Remove old IME related codes. For more details, refer Keyboard / IME.

9. PlayPause Key

Tizen Smart Remote Controller has “PlayPause” Key which is new supported key. If user presses the “PlayPause” key for playback status, application has to respond to “PlayPause” key. So we strongly recommend to use “PlayPause” smart remote controller key for playback status.

  • If the video is playing when the “PlayPause” key is pressed, the video will be paused.
  • If the video is paused when the “PlayPause” key is pressed, the video will be played.

10. Multitasking

Samsung Smart TV for Tizen supports multitasking basically. You don’t need to set multiapp-support as y in “config.xml”, and you should add multitasking handler in your application.
The multitasking of Tizen is handled differently with Samsung Smart TV for Legacy Platform. Remove sendReturnEvent, onPause and onResume methods.

  • 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 in hide status.
            // 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 in show status.
            // webapis.avplay.restore();
        }
    }
);

11. Screen Saver

Previously, app can control the screensaver by using some APIs(setOnScreenSaver(), setOffScreenSaver()) for Video play. Screen Saver is also supported at Tizen Platform as product API.

  • Before
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);
  • After
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 details, please refer Setting Screen Saver.

APIs

1. Video/Audio

You have two options for multimedia player in Tizen application.

  • Using HTML5 video element
    It doesn’t support DRMs and streaming engines like DASH, HAS, HLS and SmoothStreaming.
    If your application has simple functionalities and plays multimedia without DRM and streaming engine, using HTML5 video element may be convenience.
  • Using AVPlay API or Samsung Smart TV product API
    It supports DRMs and streaming engines like DASH, HAS, HLS and Smooth Streaming.
    If your application uses DRM or streaming engine, we recommend using AVPlay API.
  • APIs

    • Before
    // 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 / Fastforward
    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();
    
    • After
    // 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 / Fastforward
    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

    • Before
    // 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";
    
    • After
    // 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 is occured when switching src during playback to change or initialize the source.
        // We don't treat this as not a error.
        // at this time, the this.src is not null string but baseURI(index.html's path). So we use 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);
            }
        }
    });
    

2. FileSystem

Samsung Legacy Platform provides two filesystem APIs.

  • FileSystem called by new FileSystem() (as known as Browser API).
  • Filesystem called by webapis.filesystem (as known as WebAPI).
    They have different characteristics and methods for migrations.

1) FileSystem (Browser API)

Main characteristic of FileSystem of Browser API is synchronous API. Unfortunately, Tizen provides only asynchronous filesystem API.

You can select one of belows.
- Make application’s flow is suitable to asynchronous API and use Filesystem API
- Use W3C WebStorage API, refer here

  • before
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");
  • after
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");
        });
    });
});

2) FileSystem (WebAPI)

  • Before
var str;
webapis.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();
        webapis.filesystem.resolve("wgt-private", function(dir2){
            dir2.deleteFile("wgt-private/sample.data");
        });
    });
});
  • After
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");
        });
    });
});

3. Web Storage

If it is hard to change synchronous logic into asynchronous logic, you can use Web Storage of W3C API.

Important

Data in localStorage is weak in security. The other apps can reach the data which is made by your application. So we recommend below guideline.

1) You should use unique key value.

  • Before
// 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);
  • After
// write data
localStorage.setItem('testFile', 'something to write.');

// read data
var strResult = localStorage.getItem('testFile');

// delete file
localStorage.removeItem('testFile');

// validation check
// always true