Quantcast
Jump to content


Recommended Posts

Posted

Watch faces are a special type of application that runs on the home screen of a Tizen wearable watch. Different watch faces have different purposes and can be interacted with in diverse ways. A watch face creates the first impression of the watch and holds value as a fashion accessory.

Anyone can make a watch face using Galaxy Watch Designer (GWD).[1] However, GWD limits how many different features you can add in a watch face. On watch faces, data is displayed to the user in the form of “complications,” which show individual data points such as steps or heart rate. While GWD gives you a set of complications you can add to designs, it does not allow you to add custom complications, as the numbers of complications are fixed inside the GWD tool. With Tizen Studio, you can create complications that pull in data from your own custom sources or perform custom actions, such as launching a separate application or opening a settings menu. With Tizen Studio, you have more options than the ones GWD gives you.

Using Tizen Web/Native/.NET APIs, developers can add a large number of functionalities on watch faces programmatically. In this article, we’ll start by developing a basic watch face using Tizen Web API.

Prerequisites

You need to define your app as a watch face application through an application category in the config.xml file. To achieve that, add wearable_clock under category.

<widget xmlns:tizen="http://tizen.org/ns/widgets" xmlns="http://www.w3.org/ns/widgets" id="http://yourdomain/WatchFace" version="1.0.0" viewmodes="maximized">
    <tizen:application id="msWLHN3Mpw.WatchFace" package="msWLHN3Mpw" required_version="2.3.1"/>
    <tizen:category name="http://tizen.org/category/wearable_clock"/>
    <content src="index.html"/>
    <feature name="http://tizen.org/feature/screen.shape.circle"/>
    <feature name="http://tizen.org/feature/screen.size.all"/>
    <icon src="icon.png"/>
    <name>WatchFace</name>
    <tizen:profile name="wearable"/>
</widget>

Resources

For an analog watch, we need three hands for second, minute, and hour. We also need a background image with a marked time index.

The following table shows resolutions for images in our example:

Image Width (pixels) Height (pixels)
Background 360 360
Hour hand 15 360
Minute hand 16 360
Second hand 16 360

Implementation

  1. We need to create a <div> element for each component, such as background, hour hand, minute hand, and second hand.
    <div id="container">
            <div id="background">
                <div id="components-main">
                    <div id="hand-main-hour"></div>
                    <div id="hand-main-minute"></div>
                    <div id="hand-main-second"></div>
                </div>
            </div>
        </div>
    
  2. We are using an image as the watch face background, so we need to set the background image by setting styles in the CSS file.

    Background Image: The clock time index is set on top of the background image. It could be a separate <div> element, but we assembled the clock index with the green background into one image (see Figure 1).

    2019-11-11-01-01.png

    Figure 1: Watch face background image

    CSS

    #background {
        width: 100%;
        height: 100%;
        background-image: url("../image/watch_bg.png");
    }
    
  3. We also need to set styles for watch face hands separately. The app image folder holds three images, one each for the hour hand, minute hand, and second hand. Then we’ll add some info to the CSS to adjust the position, size, and so on.
    The style set for the minute hand is shown below:
    #hand-main-minute {
        position: absolute;
        left: 172px;
        top: 0px;
        width: 16px;
        height: 360px;
        background-image: url("../image/watch_hand_minute.png");
        background-position: center top;
        background-size: contain;
    }
    
  4. We need to define a function that will rotate hands by a specific angle with its element ID.
     function rotateElement(elementID, angle) {
            var element = document.querySelector("#" + elementID);
            element.style.transform = "rotate(" + angle + "deg)";
        }
    
  5. We also need to have the hand update every second. To do that, we’ll set an interval to call the updateTime() function every second.
    // Update the watch hands every second
            setInterval(function() {
                updateTime();
            }, 1000);
    
  6. We are using the getCurrentDateTime() function of Tizen Time API[2] to get the current time object. From this time object, we can get the hour, minute, and second.
    var datetime = tizen.time.getCurrentDateTime(),
                hour = datetime.getHours(),
                minute = datetime.getMinutes(),
                second = datetime.getSeconds();
    
  7. Now we are going to call our defined function rotateElement() for the hour, minute, and second hands.
      // Rotate the hour/minute/second hands
        rotateElement("hand-main-hour", (hour + (minute / 60) + (second / 3600)) * 30);
        rotateElement("hand-main-minute", (minute + second / 60) * 6);
        rotateElement("hand-main-second", second * 6);
    
  8. We need to set an event listener for visibilitychange to update the screen when the display turns on from the off state.
    // Add an event listener to update the screen immediately when the device wakes up
         document.addEventListener("visibilitychange", function() {
             if (!document.hidden) {
                  updateTime();
             }
         });
    

    We also need to set an event and update the screen when the device’s time zone changes.

    // Add eventListener to update the screen when the time zone is changed
            tizen.time.setTimezoneChangeListener(function() {
                updateTime();
            });
    
  9. Additionally, we can set an event listener for ambient mode change. In this article, we added the listener and printed a console message when the ambient mode changed. It will not change anything on the watch during ambient mode, because we haven’t updated the sample watch face for ambient mode.
    window.addEventListener("ambientmodechanged", function(e) {
            if (e.detail.ambientMode === true) {
                 // Rendering ambient mode case
                 console.log("Ambient mode");
            } else {
                 // Rendering normal case
                 console.log("Normal mode");
            }
         });
    

Demo

A sample watch face app can be downloaded here, and the final watch face is shown in Figure 2.

2019-11-11-01-02.png

Figure 2: Demo watch face developed using Tizen Web

Conclusion

This article demonstrates how to start developing watch face apps with Tizen web API using Tizen Studio. We can now add more functionalities and change the watch into more than just a device that shows time.

References

  1. https://developer.samsung.com/galaxy-watch/design/watch-face/complications
  2. https://developer.tizen.org/development/guides/web-application/device-settings-and-systems/time-and-date-management

View the full blog at its source



  • Replies 0
  • Created
  • Last Reply

Top Posters In This Topic

Popular Days

Top Posters In This Topic

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Similar Topics

    • By Samsung Newsroom
      Samsung In-App Purchase (IAP) offers developers a robust solution for handling digital transactions within mobile applications available on Galaxy Store. Whether it is selling digital goods, handling subscriptions, or managing refunds, Samsung IAP is designed to offer a smooth, secure experience. The Samsung IAP Orders API expands the scope of these benefits. You can fetch all the payments and refunds history according to specified dates. This content guides you through the essential components for implementing both the Samsung IAP and Samsung IAP Orders APIs.
      Figure 1: Sample Application UI In this tutorial, we provide a sample application called Book Spot, which offers users the option to subscribe to their favorite books and consumable items, such as text fonts, for purchase. After purchase, users can consume the item. Finally, developers can view all their payment and refund history on specific dates by calling the Samsung IAP Orders API from the back-end server.
      Prerequisites
      Before implementing in-app purchases in your app, do the following to enable a smooth and effective execution of the process while developing your own application:
      Integrate the Samsung IAP SDK into your application. For more information about the IAP SDK integration, you can follow the Integration of Samsung IAP Services in Android Apps article. Upload the application for Beta testing on Samsung Galaxy Store. A step-by-step guide with screenshots has been provided in the documentation. For more details, see the section “Production Closed Beta Test” on the Test Guide. Finally, create items on the Seller Portal so that users can purchase or subscribe to them while using the application. For more details about the available items that the Seller Portal supports, see the Programming Guide. For the sample application, we have already completed these steps. Some example items were already created in Seller Portal, such as books and fonts so that you can consume and subscribe to them while using this sample application.
      Implementation of Item Purchase
      Now that the application and items are ready, you can implement the purchase functionality in your application like in the sample below:
      When clicking "Buy," the startPayment() method is called, specifying parameters for item ID and the OnPaymentListener interface, which handles the results of the payment transaction. The onPayment() callback returns whether the purchase has succeeded or failed. The purchaseVo object is instantiated and in case it is not null, it holds the purchase results. If the purchase is successful, then it validates the purchase showing its ID. If the purchase is not successful, a purchaseError message is shown. For more information, check the Purchase an in-app item section. iapHelper.startPayment(itemId, String.valueOf(1), new OnPaymentListener() { @Override public void onPayment(@NonNull ErrorVo errorVo, @Nullable PurchaseVo purchaseVo) { if (purchaseVo != null) { // Purchase Successful Log.d("purchaseId" , purchaseVo.getPurchaseId().toString()); Toast.makeText(getApplicationContext() ,"Purchase Successfully", Toast.LENGTH_SHORT).show(); } else { Log.d("purchaseError" , errorVo.toString()); Toast.makeText(getApplicationContext() ,"Purchase Failed", Toast.LENGTH_SHORT).show(); } } }); Implementation of Item Consumption
      After successfully purchasing an item, the user can then consume it. In the sample code below, when "Consumed" is selected, the consumePurchaseItems() triggers the consume functionality. This is necessary as items must be marked as consumed so they can be purchased again:
      The consumePurchaseItems() method is called specifying the parameters for purchaseId and the OnConsumePurchasedItemsListener() interface, which handles the item data and results. This code also checks if consuming the purchased items succeeded or failed: If the errorVo parameter is not null and there is no error with the purchase, which can be verified with the IAP_ERROR_NONE response code, then the “Purchase Acknowledged” message is displayed. However, if there is an error, the errorVo parameter returns an error description with the getErrorString() getter, along with the “Acknowledgment Failed” message. iapHelper.consumePurchasedItems(purchaseId, new OnConsumePurchasedItemsListener() { @Override public void onConsumePurchasedItems(@NonNull ErrorVo errorVo, @NonNull ArrayList<ConsumeVo>arrayList) { if (errorVo != null && errorVo.getErrorCode() == iapHelper.IAP_ERROR_NONE) { Toast.makeText(getApplicationContext() ,"Purchase Acknowledged", Toast.LENGTH_SHORT).show(); } else { Toast.makeText(getApplicationContext(), "Acknowledgment Failed: " + errorVo.getErrorString(), Toast.LENGTH_SHORT).show(); } } }); Implementation of Item Subscription
      Besides purchasing and consuming items, you can also subscribe to them in your applications. Similar to the validation done for the consumable item purchase, you validate the subscription with a purchase ID if the purchase is successful. Use the same code snippet specified for “Item Purchase.” For more information, check the Implementation of Item Purchase section.
      Implementation of the Samsung IAP Orders API
      The Samsung IAP Orders API is used to view all payments and refunds on a specific date. It does this by fetching the payments and refunds history within the date you specified. Let’s implement the Samsung IAP Orders API and create a server to listen to its notifications. Through server-to-server communication, the API returns all orders data for the application.
      Configuring the Server
      You can develop a Spring Boot server for this purpose. Here are the guidelines on how to set up this server:
      Set up a Spring Boot Project. For more information, follow the steps on Developing Your First Spring Boot Application. Set up your server endpoint: Create a controller for the Samsung IAP Orders API in an integrated development environment (IDE) after importing the Spring Boot project you created. This helps managing all in-app order-related activities and processing them within your application.
      The controller receives POST requests sent from Samsung’s IAP orders service ensuring the communication with your application.
      Get Payment and Refund History
      To view all payments and refunds:
      You must make a POST request to the Samsung IAP Orders API endpoint with the required headers specified below. If you specify a date, all the payment history for this date is returned. Otherwise, it only returns all the data from the day before the current date. API Endpoint: https://devapi.samsungapps.com/iap/seller/orders
      Method: POST
      Headers:
      Add the following fields to the request header. For more information, see the Create an Access Token page, which helps you understand how to create the access token in detail. The token is used for authorization. You can also get the Service Account ID by clicking the Assistance > API Service tabs on Seller Portal. For more details, read the section Create a service account and visit Seller Portal.
      Header Name
      Description
      Required/Optional
      Values
      Content-Type
      Format of the request body
      Required
      application/json
      Authorization
      Authorization security header
      Required
      Bearer: access_token
      Service Account ID
      This ID can be created in Seller Portal and is used to generate the JSON Web Token (JWT)
      Required
      service-account-id
      Parameters:
      The following parameters can be used to build your POST request.
      Name
      Type
      Required/Optional
      Description
      sellerSeq
      String
      Required
      Your seller deeplink, which is found in your profile in Seller Portal and consists of a 12-digit number.
      packageName
      String
      Optional
      Used to view payment and refund data. You can provide the application package name. When a package name is not specified, the data for all applications is shown.
      requestDate
      String
      Optional
      Specify a date from which to view the payment and refund data. If the date is not specified, the data from a day before your current date is returned.
      continuationToken
      String
      Optional
      Use this if you want to check if there is a continuation for the data on the next page. If there is no more data, the response is null.
      To implement REST API support, add the following OkHttp library dependencies to your application's build.gradle file:
      implementation 'com.squareup.okhttp3:okhttp: version' implementation 'com.google.code.gson:gson: version' A detailed description of the request items can be found in the Request section of the Samsung IAP Orders API documentation. For more information on the server communication, see Samsung IAP Server API. Here is a brief summary of the code below:
      A POST request is mapped to the /orders URL, which logs the request. The previously described parameters containing the data you specified are formatted in a JSON body using the String.format() method. The outgoing request is logged in a JSON body format. A RequestBody is instantiated containing the JSON data, formatted for an HTTP request to be sent to the server with the specified token and Service Account ID. This code also handles multiple results your request can return: The onFailure() method is called when the network request fails for some reason, providing any error details using the IOException exception. If the request succeeds, the onResponse() method returns the response body or any response exception found. @RestController @RequestMapping(value = "/iap", method = RequestMethod.POST) public class OrdersController { private final OkHttpClient client = new OkHttpClient(); @GetMapping("/orders") public void sendToServer() { System.out.println("POST request received"); // Log the request // Define parameters values, use according to your requirement // String packageName = "com.example.app_name "; // String requestDate = "20240615"; // String continuationToken = "XXXXXXXXXXX…….XXXXXX"; String sellerSeq = "0000000XXXXX"; // Create the JSON body, use packageName, requestDate, continuationToken according to your requirement String jsonBody = String.format( "{\"sellerSeq\":\"%s\"}", sellerSeq ); // Create the request body RequestBody body = RequestBody.create(jsonBody, MediaType.parse("application/json; charset=utf-8")); // Access token String token = "0DjT9yzrYUKDoGbVUlXXXXXX"; // Build the request Request request = new Request.Builder() .url("https://devapi.samsungapps.com/iap/seller/orders") .post(body) .addHeader("Authorization","Bearer " + token) .addHeader("service-account-id", "85412253-21b2-4d84-8ff5-XXXXXXXXXXXX") .addHeader("content-type", "application/json") .build(); client.newCall(request).enqueue(new Callback() { @Override public void onFailure(@NotNull Call call, @NotNull IOException e) { System.err.println("Request failed: " + e.getMessage()); } @Override public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException { if (response.isSuccessful()) { String responseBody = response.body().string(); System.out.println("Response: " + responseBody); } else { System.err.println("Unexpected response code: " + response.code()); System.err.println("Response body: " + response.body().string()); } response.close(); // Close the response body } }); } } Congratulations! You have just built the Spring Boot server to handle API POST requests using the OkHttpClient to manage HTTP requests and responses for your sample application.
      Example Response
      As previously mentioned, a JSON-formatted response is returned to your request. For detailed descriptions of each response body element, see the “Response” section of the Samsung IAP Orders API documentation. The following output format is a sample in which only some of the response-body data is presented.
      In this case, the continuationToken parameter key returns null because there is no continuation for the data on the next page. The orderItemList parameter key lists all the orders with specific details, such as orderId, countryId, packageName, among others. { "continuationToken": null, "orderItemList": [ { "orderId": "S20230210KR019XXXXX", "purchaseId": "a778b928b32ed0871958e8bcfb757e54f0bc894fa8df7dd8dbb553cxxxxxxxx", "contentId": "000005059XXX", "countryId": "USA", "packageName": "com.abc.xyz" }, { "orderId": "S20230210KR019XXXXX", "purchaseId": "90a5df78f7815623eb34f567eb0413fb0209bb04dad1367d7877edxxxxxxxx", "contentId": "000005059XXX", "countryId": "USA", "packageName": "com.abc.xyz" }, ] } Usually, the responses contain all the relevant information about user purchases, such as the in-app item title, price, and payment status. Therefore, you can use the information and create views for an easier order management.
      NoteIf the IAP operating mode is configured to test mode, the API response is empty. This is because the API is configured to operate and return a response only in production mode. Conclusion
      You have learned how to implement item purchase, consumption, and registration, as well as how to integrate the Samsung IAP Orders API and configure a server to fetch all the payment and refund history within specific dates.
      Integrating the Samsung IAP Orders API functionality into your server is an essential step in managing your application payments history to ensure a seamless experience to users. Now, you can implement the Samsung IAP Orders API into your application to track all payments, refunds and make your business more manageable.
      Related Resources
      For additional information on this topic, see the resources below:
      Download the Android Sample Application Source Code Add Samsung In-App Purchase service to your app Samsung IAP Orders API Integration of Samsung IAP Services in Android Apps View the full blog at its source
    • By Samsung Newsroom
      View the full blog at its source





×
×
  • Create New...