Skip to content

HybridOS Foundation Class Library

Vincent Wei edited this page May 17, 2019 · 11 revisions

HybridOS Specification 01-C
Topic: HybridOS Foundation Class Library
Author: Vincent Wei
Category: App Framework
Date: November 2018
Status: Proposal

Copyright Notice

Copyright (C) 2018, 2019 FMSoft Technologies
All Rights Reserved.

Introduction

HFCL (HybridOS Foundation Class Library) is a C++ class library. It is derived from mGNGUX, a C++ library for MiniGUI. mGNGUX had been used as the foundation of two MMI (man-machine interface) solutions for feature phones.

mGNGUX introduced a new MMI framework for feature phone, and borrowed some concepts from other operating system (especially Android). mGNGUX also provided a new set of controls/widgets in C++ classes. These classes construct the view hierarchy of mGNGUX app framework.

The most important feature of mGNGUX is it introduced a new way to define the UI elements, including resource, views, and menus. And we can easily define the maps of views to C++ class member variables. Indeed, the UI definition files are C++ source files, but we wrote them in pre-defined C++ macros.

However, mGNGUX still uses the traditional widget-based programming mechanism, which does not provide a good solution for decoupling relationship among data, interaction, and rendering.

Therefore, as described in HybridOS Architecture, we use [HybrdOS View Markup Language] and hiWebKit to support HVML and render the activities.

HFCL implements the view types for HVML and help the developer to create and manage resource, activities, and services for HybrdiOS apps. The key features of HFCL are follow:

  • It acts as the framework for the C++ edition of your HybridOS app.

  • It manages the resource (images, fonts, l10n text, CSS definitions, and others assets) for your app. On device, these assets are loaded from disk or embedded directly into the program image. HFCL provides a universal way to manage the assets.

  • It manages the activites and the services of your app. You can launch an activity and pass an intent to it.

  • It provides a complete set of views which is conformed HVML specification.

  • It provides the standard DOM interfaces for your app to manipulate the DOM tree, including the nodes, the content, the style, and the attributes of them.

  • It is the foundation of Hybrid App Engine.

Resource Assets

We treat HVML files, CSS files, JavaScript files, images, and l10n text are all resource assets of a HybridOS apps.

Unlike web browser, for an app running in a device or client, the assets generally stored locally, either on the filesystem or embedded in the app program image.

HybridOS provides an easy and magic way for developer to define the assets and bind the assets with your C++ code.

Specifically, HFCL uses pre-defined C++ macros to define the resource assets. For our first sample, the main asset file will look like:

begin_app(firstSample)
    begin_assets()
        image(defAvatar, "file:///assets/image/def-avatar.png")
        css(default, "file:///assets/css/default.css"
        activity(userList, "file:///assets/hvml/userlist.hvml")
        activity(userInfo, "file:///assets/hvml/userInfo.hvml")
        l10n(en, "file:///assets/message/en.mo")
        l10n(zh_CN, "file:///assets/message/zh_CN.mo")
        l10n(zh_TW, "file:///assets/message/zh_TW.mo")
    end_assets
end_app(en, userList)

L10N of Text

For the L10N (localization) text, HFCL provides two ways:

  1. Using .mo files of GNU gettext.
  2. Using identifiers instead of text as GNU gettext does.

The interpreter hfclify can generate the C++ L10N translation source files for the app according to the L10N translation file specified in the assets section of the app.

The identifiers referred as STRID_TITLE or STRID_COPYING will be defined as C++ macros, and the l10n text table can be zipped by using zlib.

Assets Management

Not like HVML apps, the link of an asset (e.g., an image file) defined in a HFCL app is handled as a reference key first. We can integrate the assets data into the executable image of your app. We call them as in-core resource. If HFCL could not load a specific asset from the in-core resource, it will try to load if from the URL specified in the begin_assets section.

In this way, HFCL will provide a maximal flexibility for the app developers.

Activity and Intent

Customized View

Service

Components of HFCL

The components of HFCL are classified into the folllowing categories:

  1. Activity management

    • Resource management
    • Define customized HVML view types
    • Activity and intent
    • Animation and transition
  2. Service management

    • WebSocket responder
    • HTTP responder
    • MQTT service provider
    • ...
  3. System classes

    • hiBus event and task management
    • SQLite queries
    • JSON data
    • Async task management

The below words are deprecated...

For our user list activity, the asset code will look like:

begin_activity(userList, ActivityUserList)
    def_name(thePanel)
    def_name(theHeader)
    def_name(theList)
    def_name(theFooter)

    begin_view_template(UserItemView, ItemView, my_style_sheet(normalItem))
        begin_view(HiddenView, NULL))
            set(Name, "id")
        end_view
        begin_view(ImageView, my_style_sheet(userAvatar)))
            set(Name, "avatar")
        end_view
        begin_view(TextView, my_style_sheet(userName)))
            set(Name, "name")
        end_view
    end_view_template

    begin_view(PanelView, my_style_sheet(panel))
        map(my(thePanel))
        begin_view(TextView, my_style_sheet(panelHeader))
            map(my(theHeader))
            set(Content, STRID_TITLE)
        end_view
        begin_view(ListView, my_style_sheet(userList))
            map(my(theList))
            set(ItemTemplate, my_template(UserItemView))
            set(Name, "userItem")
        end_view
        begin_view(TextView, my_style_sheet(panelFooter))
            map(my(theFooter))
            set(Content, STRID_COPYING)
        end_view
    end_view
end_activity

begin_activity(userInfo)
    begin_view(PanelView, ...)
        ...
    end_view
end_activity

This file (assume named `firstsample.res.inc") will be pre-compiled by your C++ compiler in a magic way:

  • In a C++ header file, include the resource file in the following way to generate the identifiers and names of the resource:

      #include <hfcl/resource/resdefines.head.h>
      #include "firstsample.res.inc"
      #include <hfcl/resource/resundefines.h>
    
      #include <hfcl/resource/resdefines.name.h>
      #include "firstsample.res.inc"
      #include <hfcl/resource/resundefines.h>
    
  • In a C++ source file, include the resource file in the following way to generate the source code and the initialization code:

      #include <hfcl/resource/resdefines.source.h>
      #include "firstsample.res.inc"
      #include <hfcl/resource/resundefines.h>
    
      #include <hfcl/resource/resdefines.init.h>
      #include "firstsample.res.inc"
      #include <hfcl/resource/resundefines.h>
    

By using the method described above, we do not need a utility tool to interpret the resource file and generate the souce code, the C++ compiler will do this for us.

The another advantage is that we seperate the resource data with the app logical code in a good way.

The last advantage is that the resource file can be generated from the HVML tags. Thus, if you have to use C++ to write your device app because the poor hardware performance, you can easily keep up your C++ code with the JavaScript code.

If you have some expirience with HTML and CSS, you will easily get the the define the style sheet of views with the same manner of CSS. For example, the style sheet of the user name corresponds to the following CSS definition:

.userAvatar {
    display: inline-block;
    position: relative;
    margin: 0px 0px 0px 0px;
    padding: 0px 0px 0px 0px;
    height: 20px;
    width: 20px;
    border-radius: 5px 5px 5px 5px;
}

For performance reason, we do not use the direct literal CSS definition in HFCL. We use the macros to define every style element in C++ way instead:

begin_css(userAvatar, ".avatar")
    style(Display,      PV_INLINE_BLOCK)
    style(Position,     PV_RELATIVE)
    style(Margin,       PV_LENGTH_PX,   0)
    style(Padding,      PV_LENGTH_PX,   0)
    style(Height,       PV_LENGTH_PX,   20.0f)
    style(Width,        PV_PERCENTAGE,  100.0f)
    style(BorderRadius, PV_LENGTH_PX,   5.0f)
end_css

In the definition of a view which uses a style sheet, we passed the class of the way:

begin_view_ex(hvimage, "avatar", ...))
    ...
end_view

Translate HTML/HVML and CSS into C++ Code

It will be a trouble if we write the style sheets and views by hand in the way above. So we introduce a interpreting tool which can translate the HVML tags and CSS into the HFCL resource source files.

This tool is called hfclify, and it will be written in Python.

If you want to change the style sheet of one view on the fly, you can call one of the following APIs of HFCL:

view->addStyleSheet (HFCL_STYLE_SET_NAME (firstSample, activeItem));
view->useStyleSheet (HFCL_STYLE_SET_NAME (firstSample, focusItem));
view->setStyleProperty (HCFL_STYLE_COLOR, Color::WHITE);

Note that the resource source file can not reflect all details in your HVML tags. You need to write the interaction code in your C++ source file. For example, in HVML tags, you can define the iteration of an item from a template view by using the property hbd-iterate-by, but in HFCL, we can not do this for you. You need to initialize the list view in your implementation classes manually.

When you re-generate the resource source file from HVML tags, because the real implemenations are seperated from the resource source files, the translator will not override your own code.

In HFCL, a view template is defined as a derived class of one standard view, as shown in the sample:

begin_view_template(UserItemView, ItemView, my_style_sheet(normalItem))
    ...
end_view_template

The UserItemView will be defined by the macro as a new view class in the resource header file, just a simply subclass of ItemView:

class UserItemView : public ItemView {
    public:
        UserItemView (View* parent) : ItemView (parent) { }
        UserItemView (View* parent, StyleSheet* style_sheet) : ItemView (parent, style_sheet) { }
        virtual ~UserItemView () {};
}

The UserItemView will be defined by the macro as an interface class in the resource header file. You should define the implemetation class by yourself (in separated files):

class UserItemViewIf : public ItemView {
    public:
        UserItemViewIf (View* parent) : ItemView (parent) { }
        UserItemViewIf (View* parent, StyleSheet* ss) : ItemView (parent, ss) { }

        virtual View* getChildByName (const char* name) = 0;
        virtual ~UserItemViewIf () {};
}

class UserItemViewIm : public UserItemViewIf {
    public:
        UserItemViewIm (View* parent);
        UserItemViewIm (View* parent, StyleSheet* ss);
        virtual View* getChildByName (const char* name);
        ...

    private:
        ...
}

...The above words are deprecated.