Skip navigation

RhoMobile Blogs

12 Posts authored by: Darryn Campbell

Angular JS is an immensely popular JavaScript framework for creating dynamic, responsive web pages with built in support for MVC.  Angular can be used for desktop, tablet or mobile applications and is the engine behind Ionic which there was a recent previous blog about.  Any framework that renders the application’s view in an HTML5 compatible browser can build their applications in Angular and Rho is no exception.  Other recent blogs have gone into more detail on Angular specifics but I wanted to share my experience on using Angular and Rho together.

 

If you’re new to Angular I highly recommend following their standard tutorial that runs you through the basics of creating an Angular apps and some of the fundamental concepts, there are countably infinite tutorials on Angular JS already on the web so for the rest of this blog I’ll assume at least a basic working knowledge of Angular.

To get started I’ve uploaded a RhoElements application that uses Angular to github, https://github.com/darryncampbell/ng-rho-demo.  You may notice more than a passing resemblance to the official Angular tutorial. Please go ahead and clone the demo to your local disk.

 

Pre-Requisites:

You’ll need NodeJS installed on your machine and accessible from a command prompt in order to get going as well as RhoMobile Suite.  I've developed this example with RhoMobile Suite 5.1 so I recommend you use that but previous versions should also work.

Since it’s easier to develop web applications on the desktop it makes sense to start there.  Navigate to the public directory of ng-rho-demo and install the node dependencies:

 

/ng-rho-demo/public>npm install





 

This will install the dependencies of the application including angular and a local http server we can use to test our application.  Start the server with the following command

 

ng-rho-demo/public>npm start





 

Now launch your favourite web browser and navigate to http://localhost:8000 to see the application.

 

To see the application running without any of the above steps then head over to http://darryncampbell.github.io/ng-rho-demo/public/index.html

 

Since the application UI is designed for mobile devices you’ll see it does not render properly on the desktop in the detail view.  Chrome has a “device mode” to simulate viewing the page on a device,

https://developer.chrome.com/devtools/docs/device-mode that makes the page render well.

 

device view.png

 

What is happening?

At this stage we have no dependencies on Rho, we are just viewing the Angular application in our web browser.  Since Angular relies on a lot of dynamic JavaScript, the browser will prevent it running from the local file system so we need to run a local server.  I recommend having a look through the code at /ng-rho-demo/public and noticing that this is just a standard Angular application:

  • Bower_components: The dependencies installed by bower including Angular itself
  • Css: The application’s CSS.  I’m not a graphic artist.
  • Img: The images of Zebra devices which will be shown in our application
  • Js: JavaScript files:
    • App.js: Angular bootstrapping and routing
    • Controllers.js: Controllers for our device list and device detail view.  Notice how the detail controller makes use of the Rho barcode API to enable the barcode scanner
    • Directives.js: empty
    • Filters.js: An example filter that prepends the barcode data with an arbitrary string depending on the scanned data.
    • Rhoapi-modules.js: This is the Rho API as you’ll find in any Rho application
    • Services.js: Empty.  this blog describes how you can expose the Barcode API through an Angular service should you choose to do so but in this example we take the more simple route.
  • Node_modules: The dependencies installed by npm.  Take care to delete this folder prior to building your Rho application as it will be quite large.
  • Partials: The views associated with both the list and detail pages
  • Devices: Information on the Zebra devices

 

Compiling for Rho

 

So far, everything we have done has been in the web browser with no Rho dependencies but now we want to use Rho for two things in this example:

  1. Produce a native package so we can install it as an application on our mobile device
  2. Take advantage of native device features through JavaScript

 

Firstly, add in JavaScript capabilities by uncommenting the rhoapi-modules.js script include in the following file: ng-rho-demo/public/index.html

 

  <script src="js/rhoapi-modules.js"></script>




 

Important: Before compiling make sure you delete the following folder: \ng-rho-demo\public\node_modules as this contains node dependencies and is far too large to be included in the native app

/ng-rho-demo/public>rmdir /S node_modules
/ng-rho-demo/public>cd ..
/ng-rho-demo>rake device:android:production




 

The application is now building for Android provided you have RhoMobile Suite installed and have configured it appropriately to point to your Android build chain.

 

Whilst the application is compiling, open up the following file: ng-rho-demo/public/js/controllers.js and observe the DeviceDetailCtrl controller:

 

if (typeof Rho !== 'undefined')
  {
    Rho.Barcode.enable({}, function(scan)
      {
        $scope.barcodes.push(scan);
        $scope.$apply();
        window.scrollTo(0,document.body.scrollHeight);
      })
  }




 

Here we test for the existence of the Rho namespace which will be present after we included the rhoapi-modules.js file.  This is just a quick (and dirty) way to allow us to develop our application view and business logic on the desktop before moving to the device.

 

The Barcode API is being called just like it is in a standard Rho application, this particular example is adding the scanned data to the model scope which gets displayed in the 'device-detail' view after running through an Angular filter.  You can run this example on any supported Zebra Android device to see the scanner beam but on some of our older models you will also need to ensure that datawedge is manually disabled prior to scanning in Rho.

 

IMG_20150812_104222.jpg

 

Note: If you do not have a RhoElements license you won’t be able to build the application.  You can still use Angular in any Rhodes application, just modify the example to remove “app_type: rhoelements” from ng-rho-demo/build.yml and remove the JavaScript scanning logic from controllers.js.

rhobundle:
  exclude_items:
  - thumb.db
#app_type: rhoelements
capabilities: []




Head over to the download link (Windows, Mac) to download the latest minor release of RhoMobile Suite.

New Features Added

  • iOS apps can now be built with 64-bit support. This complies with Apple's change to their terms and conditions stating that from February 1st 2015, all new submissions must be built with the iOS8 SDK and include support for 64-bit architecture, Support article.

Issues Resolved

  • Critical Windows Phone 8 build issue identified with 5.0 service pack 1 which prevented WP8 applications from being built.

Tips, tricks and techniques to make your native RhoElements Apps faster, more responsive and more efficient.

 

From our last two developer forums in Bangkok and Birmingham our engineers have delivered an informative presentation on improving your native application performance, concentrating on both code optimization and database access.  Whilst the slides from this presentation are available (https://launchpad.motorolasolutions.com/appforum/apac/1330-1430%20AppForumAPACNativeOptimisation.pdf)  I wanted to walk through some of the tips covered for those unable to attend the forums.

 

Introduction

 

Untitled.png

Here is a block diagram of a typical native RhoElements application.  A native application is such that it follows the MVC pattern of development, with your business logic stored as models on the device accessing data resident either on or off the device.  This blog will concentrate on those parts of the diagram coloured red and will assume your business logic is coded in Ruby.

 

Code Optimization

 

Any application developed for mobile devices must take the hardware constraints into account, this is true of any development framework and every mobile device.  Some of the key constraints are:

  • Device battery life
  • Available Memory


Power Consumption

 

The power consumption of your application will be affected by a number of factors but one of the most easily avoidable drains is polling. When writing your application you avoid polling for values from hardware where possible, instead you should register for callbacks to be notified when values change.  The RhoElements API is written almost exclusively to not require polling.

 

We can take callbacks a step further when we require the status of a server.  Polling a server to determine if our local copy of the database is up to date can be a very expensive, in terms of both Network load and battery life.  Network push notifications are an ideal work around to server polling and there are lots of platform specific push systems out there like iOS push or Google cloud messaging.  From RhoElements 2.2 onwards we ship with RhoConnect push, a new cross platform technology allowing you to do push without the need for a complex, managed solution involving Google or Apple.  You can check out the Webinar on the new RhoConnect push technology at https://developer.motorolasolutions.com/docs/DOC-1721

 

To further reduce your application's power consumption it can de-register callbacks and stop any other processing when it is sent into the background, this is acheived through the on_active_app and on_deactiveate_app overrides:

 

class AppApplication < Rho::RhoApplication
  def on_activate_app
    # restore all callbacks and js timers
  end
  def on_deactivate_app
    # remove all unnecessary callbacks and js timers
  end
end

 

For more information on the activate and deactivate callbacks see the documentation at http://docs.rhomobile.com/rhodes/application#appapplication-class

 

Memory

 

The following tips will ensure your application doesn't use excessive memory unnecessarily:

 

  • Don't use big global or class variables, all global and class variables will remain in memory until you nil them.  If you wish to maintain large persistent objects then they should be kept in a database and accessed through the database API, http://docs.rhomobile.com/rhodesapi/database-api/

 

  • Only load Ruby classes on demand as once loaded they remain in memory forever.  This will also decrease your application startup time.
def controller_action
require 'some_library'
#business logic
end

 

  • To improve application performance and stability the Ruby Garbage collector is disabled before each controller action and re-enabled after the controller action exits.  If you allocate / deallocate a lot of ruby objects in your controller action you should call it as follows:
def my_objects_generatorGC.enable
#Do some heavy operations
end



 

 

Performance Metrics

 

In order to analyse your application performance RhoElements offers metrics to detect inefficiencies and identify where you could speed up your code.

 

Logging

 

When written to the log file, logs will contain time information.  Using this time information you can get a quick and dirty idea of where your application performance is slow.

 

You can enable logging in your configuration file as follows:

MinSeverity = 1 #0 – trace, 1 – info, 3 - errors only
LogCategories = * # category1, category2
MaxLogFileSize=50000 # in kilobytes
LogMemPeriod=5000 #milliseconds

 

And in your application you can log with the following calls:

puts “Hello!” # will log with APP category
RhoLog.error("Some Category", "Some error message") 
RhoLog.info("Some Category", "Some info message")

 

Profiler

 

To better control and quantify your application's performance it is recommended to use the RhoProfiler, http://docs.rhomobile.com/rhodesapi/rhoprofiler-api

 

Say you had two functions whose performance you wanted to measure, you would use the RhoProfiler as follows:

RhoProfiler.create_counter('Counter1') RhoProfiler.start_counter('Counter1') 
function1() 
RhoProfiler.stop_counter('Counter1') 
#do something 
RhoProfiler.start_counter('Counter1') 
function2() 
RhoProfiler.stop_counter('Counter1') RhoProfiler.destroy_counter('Counter1')
# destroy_counter will log summary of function1 and function2 execution time

 

And that will write the resulting log as follows:

I 09/18/2012 23:27:20:311 00002ffc PROFILER| Counter1 (0:03:104) : STOP

 

 

 

Data Optimization

 

There are multiple ways of storing and manipulating data with RhoElements

  • PropertyBag (generated by default)
  • Data Schema
  • RhoConnect (to connect with data at the back end)

 

Data storage techniques are discussed in more detail at the documentation page for rhom, http://docs.rhomobile.com/rhodes/rhom.  Rhom is a mini database object mapper for RhoElements, providing high level interfaces to use a local database.

 

You may choose to use a PropertyBag or Fixed Schema for data storage

 

Property Bag

 

Simple to use, it doesn't require specifying attributes in the model definition file.

Data migrations are not necessary

Attributes can be added ore removed without modifying the database schema

For some applications, the database size may be significantly larger than for fixed schema.  This is because each attribute is indexed for fast lookup.

 

Fixed Schema

 

Smaller database size, indexes can be specified only on specific attributes.

You may use direct SQL queries if and when required.

Schema changes must be handled with data migrations

Database performance may be slower unless you specify proper indices

 

Tips

 

Pre-populating the database

 

If your application requires seeding of initial data then you can use RhoUtils.load_offline_data.

For example, in the rhodes/spec/framework_spec, we use load_offline_data to seed the device database for each test: 

Rho::RhoUtils.load_offline_data(
  ['client_info','object_values'], 'spec'
)

 

In this example, there is a ‘spec/fixtures’ directory which contains a client_info.txt and object_values.txt pipe-delimited files. For more information on this please see the online documentation at http://docs.rhomobile.com/rhodes/rhom#seeding-the-database

 

You might also consider creating the local database file beforehand, then including the .db file in your application at deployment.  You can use the emulator to achieve this and there is documentation online at http://docs.rhomobile.com/faq#how-to-pre-populate-client-database

 

Pagination

 

Often you'll be dealing with long lists of data that the user has to scroll through.  It is very inefficient (and slow) to try and load this entire list all at once, the recommended solution is to use pagination to display say 20 records at a time.  The rhom API offers a syntax identical to rails' syntax and is documented at http://docs.rhomobile.com/rhodes/rhom#rhom-paginate-example

Account.paginate(:page => 0) 
  #=> returns first 10 records
Account.paginate(:page => 1, :per_page => 20) 
  #=> returns records 21-40
Account.paginate(
  :page => 5, 
  :conditions => {'industry' => 'Technology'}, 
  :order => 'name'
) #=> you can have :conditions and :order as well

 

 

Tips for using the Property Bag model

 

Do not use SQL conditions in Model.find, use Advanced queries instead (http://docs.rhomobile.com/rhodes/rhom#advanced-queries):

 

#Let’s say we have the following SQL fragment condition:
Product.find( :all, :conditions => [ "LOWER(description) like ? or LOWER(title) like ?", query, query ], 
:select => ['title','description'] ) 

#Using advanced :conditions, this becomes:
Product.find( :all, :conditions => { 
  { :func => 'LOWER', :name => 'description', :op => 'LIKE' } => query, 
  { :func => 'LOWER', :name => 'title', :op => 'LIKE' } => query }, 
  :op => 'OR', 
  :select => ['title','description'] ) 

 

To modify an object in the database, prepare the data first and call update_attributes once.  Do not use save

props = {"name" => "ABC Inc.", “brand" => “Comp2"}
@product.update_attributes( props )

 

To insert or update multiple objects or models use a database transaction

 

db = ::Rho::RHO.get_src_db('Model') 
GC.enable()
db.start_transaction() 
begin 
  items.each do |item| 
    # create hash of attribute/value pairs 
    data = { :field1  => item['value1'], :field2 => item['value2'] } 
    # Creates a new Model object and saves it    
    new_item = Model.create(data) 
  end 
    db.commit() 
rescue 
    db.rollback() 
end

 

RhoConnect

 

For more information on RhoConnect then please see the user documentation at http://docs.rhomobile.com/rhoconnect/introduction, it's a large topic which I would not be able to adequately cover in this blog.

 

If your application solution uses RhoConnect to sync its data with the backend database you might consider using bulk sync, http://docs.rhomobile.com/rhoconnect/bulk-sync

 

Enabling bulk sync either in your configuration file or at runtime will cause the next synchronization with the back end to first be zipped up before being sent to the device. 

 

To enable bulk sync in your configuration add:

bulksync_state = 0

 

To enable bulk sync at runtime call:

Rho::RhoConfig.bulksync_state = '0‘

 

The following actions are performed for a bulk sync:

  • The RhoConnect server prepares the sqlite database, zipps it and sends it to the client, running on your mobile device.
  • The RhoConnect client receives the database, unzips it and replaces the database on the device, without the overhead of SQL inserts.

 

 

 

 

 


Configuration Settings and other Tips introduced in 2.2 to make your RhoElements Application Run Faster

 

An overview of the RhoElements performance improvement drive

 

The great thing about an open developer community is the ability to interact and work at a group and individual level with many of the developers out there. It really allows us to prioritize product feature sets and focus on the things that the greater community feels are a priority. It also allows us to get real-time feedback on the product and address any concerns that may arise in a more agile process. The RhoMobile Suite team really prides itself on being agile and producing a product that not only meets the needs of those developing enterprise cross-platform applications, but also does so with the utmost level of quality and performance.

 

Introduction

 

To coincide with the release of RhoMobile Suite 2.2 I wanted to share some of the new ways we have improved performance for users of RhoElements on Motorola Devices running Windows Mobile (Embedded Handheld), CE and Android.  This blog builds on my earlier blog offering configuration settings to improve performance (https://developer.motorolasolutions.com/community/rhomobile-suite/docs/developer-reference/blog/2012/10/08/rhoelements-performance-improvements-2) and you'll find we've improved the out of the box experience compared to 2.1.

 

New Configuration Options

 

Although all the new configuration options are documented online at http://docs.rhomobile.com/rhoelements/ConfigurationSettings I wanted to highlight the new ones and explain exactly how they can improve performance.  Details of where to find the configuration file are given in my previous blog at https://developer.motorolasolutions.com/community/rhomobile-suite/docs/developer-reference/blog/2012/10/08/rhoelements-performance-improvements-2.

 

UseRegularExpressions

Default Value '0' meaning "Do not use Regular Expressions".  Only applies to Windows Embedded Handheld (WM) and Windows CE.

 

<General>
   <Name value="Menu"/>
   <StartPage value="http://www.mysite.com" name="Menu"/>
   <UseRegularExpressions value="0"/>
</General>

 

Regular Expressions are a way for RhoElements applications to recognise EMML 1.0 syntax, http://docs.rhomobile.com/rhoelements/EMMLOverview which means applications written to target Motorola PocketBrowser will work unmodified in RhoElements.  Applying all the regular expressions which ship with RhoElements for each meta tag, Javascript and Ruby call listed in the Mobile API reference at http://docs.rhomobile.com can cause slower navigation.

 

In my earlier blog I explained how applying regular expressions can be expensive in 2.1 and offered work arounds for improving performance.  In 2.2 the out of the box experience has been improved to not use any Regular Expressions by default, this means that applications written for PocketBrowser will not necessarily run in RhoElements 2.2.  In order to enable regular expressions just set the 'UseRegularExpressions' configuration setting to '1' but you will take a performance hit in doing so.

 

If you wish to be more intelligent about applying Regular Expressions I have written a separate blog on porting PocketBrowser applications to RhoElements (https://developer.motorolasolutions.com/community/rhomobile-suite/docs/developer-reference/blog/2012/10/17/porting-your-pocketbrowser-application-to-rhoelements); this also goes into more detail of what exactly the Regular Expressions are doing.

 

DisableScannerDuringNavigation

Default value '1' meaning "Disable the scanner during navigation".  Applies to both Windows and Android applications running RhoElements on Motorola devices.

 

<Scanner>
   <DisableScannerDuringNavigation  value="0"/>
</Scanner>

 

By default if you are on a page which is using the Scanner and you navigate away from that page the Scanner will be automatically disabled, meaning if you press the trigger button or initiate a soft start no laser will be emitted.  Because disabling the scanner is done at the hardware level it can take as much as half a second for the operation to complete, meaning if an application wants to use the scanner on multiple pages the navigation will be slowed down unnecessarily. 

 

Consider a navigation between two pages, both of which have the following in their header:

<meta http-equiv="Scanner" Content="Enable"/>

Navigating between these two pages will first disable the Scanner and then re-enable it once the second page is loaded.  The reason for disabling the Scanner is to ensure a default Scanner state however to improve navigation performance in this scenario you can set "DisableScannerDuringNavigation" to '1'; doing so will mean the scanner remains enabled during the navigation to the second page, remembering all previously set decoder properties and scanning settings.  For a further performance improvement all scanner control logic can now be removed from the second page as it will still be remembered after being set on the first page.

 

Cache

Default value '5MB' meaning "Cache 5MB worth of browser content into RAM (scripts / images / pages)".  Applies to both Windows and Android applications running RhoElements on Motorola devices in 2.2.

 

<Navigation>
   <Cache      VALUE="5MB"/>
</Navigation>

 

RhoElements 2.1 and earlier had no form of browser caching and this has been corrected in 2.2, by default RhoElements will cache 5MB of scripts, images and pages into RAM.  This is browser cache, not to be confused by Application Cache or Cookies.  The maximum amount of cache available will depend on the device on which RhoElements is being run.

 

Cache is stored in memory and not written out to the device file system or SD Card.  The RhoElements refresh button (http://docs.rhomobile.com/rhoelements/reloadbutton) will request a reload from the server rather than the cache.

 

Other Tips

 

Here are some additional tips which didn't make it into my previous performance blog on configuration settings.

 

Default Meta Tags

 

In my previous performance blog I advised not to use default meta tags wherever possible as processing them can take a while.  In RhoElements 2.2 I retract this advice, there have been a number of improvements around the handling of Default Meta Tags which means they can now be used:

  • Internally we have improved the effeciency of how we process default meta tags, previously they were being re-parsed on each page load but they are now cached.
  • Regular Expressions were being applied to each meta tag on each page load.  Given we now disable regular expression parsing by default (as explained above) there is a further performance improvement.
  • Enabling the scanner in a default meta tag is a common user scenario.  With the introduction of the DisableScannerDuringNavigation configuration setting you can now enable the scanner in a default meta tag without worry of a performance hit, just be sure to set DisableScannerDuringNavigation to '0'.  Also be aware that doing this will cause a log to be written on each navigate telling you you tried to enable the scanner whilst it was already enabled, obviously this is to be expected.
<Scanner>
   <DisableScannerDuringNavigation  value="0"/>
</Scanner>

 

 

RhoElements JavaScript objects

 

In RhoElements on Motorola Devices we currently use NPAPI to inject JavaScript objects onto the page, this gives you the capability to write functions like:

function enableScanner()
{
     scanner.enable();
}

without getting a Javascript syntax error.

 

Some people have asked me if they can improve their performance by not loading these NPAPI objects if they don't need them:

<NPAPI>
   <NPAPIDirectory value="file://%INSTALLDIR%\NPAPI\"/>
   <Preloads>
      <PreloadLegacyGeneric value="0"/>
      <PreloadLegacyODAX    value="0"/>
      <PreloadLegacyNoSIP   value="0"/>
      <PreloadLegacyAirBeam value="0"/>
      <PreloadLegacyAPD     value="0"/>
      <PreloadJSObjects     value="0"/>
   </Preloads>
</NPAPI>

 

The RhoElements JavaScript APIs (Scanner, CardReader, Imager etc) are injected onto the page by the PreloadJSObjects setting.  The other 'Legacy' objects refer to http://docs.rhomobile.com/rhoelements/generic, http://docs.rhomobile.com/rhoelements/odax, http://docs.rhomobile.com/rhoelements/nosip, http://docs.rhomobile.com/rhoelements/airbeam

and http://docs.rhomobile.com/rhoelements/apd respectively.

 

Testing on an MC75a running WEH 6.5 I only see a maximum navigation improvement of 23ms when everything is removed, I would recommend keeping the default values and pre-loading all of these objects.

 

Preloading Modules

 

Preloading modules is not the same as preloading Javascript objects, discussed above.  Preloading modules tells RhoElements that you intend to use specific functionality such as the card reader in your application, this means that the functionality can be loaded when RhoElements is first initialised.  If for example you had an application that used the card reader half way through the application flow, if you had not pre-loaded the card reader it will be done at runtime when the functionality is first used and could impact the user experience.

 

It is recommended you pre-load all modules which you intend to use in your application.  This topic is also explained in greater detail at http://docs.rhomobile.com/rhoelements/ConfigurationSettings#optimizing-the-runtime

 

By default a number of commonly used modules are already preloaded:

<Preloads>
   <Preload value="Scanner"/>  <!--  Most Applications on Motorola Devices will use the Scanner so it makes sense to preload it -->
   <Preload value="Hourglass"/>  <!--  Gives visual feedback during navigation -->
   <Preload value="KeyCapture"/> <!--  Allows Function Keys to be captured and the Operating System to be locked out -->
   <Preload value="SIP"/>  
   <Preload value="ScreenOrientation"/> <!--  Allows RhoElements to be screen rotation aware -->
</Preloads>

 

Because loading modules is such a small part of RhoElements' initialisation you will find removing the default pre-loads does not have a significant impact on RhoElements' start up time.

 

ResizeOnSIP Config option

 

In previous incarnations of RhoElements and PocketBrowser the ResizeOnSIP parameter resized the browser Window to ensure the SIP did not occlude any of your site.  There are a number of difficulties with this such as incompatibilities with some variants of CE, and not being able to move the SIP.  Several versions ago RhoElements introduced work arounds for this specifically the SIP will no longer obscure your webpage's text fields.

 

By default ResizeOnSIP is disabled (set to '0').  It is not recommended to change this default setting.

 

RhoElements_Icon_TB.jpg

This blog describes how you would go about porting an existing PocketBrowser application into RhoElements for Motorola devices and how to do so in a high performing fashion.

 

What is PocketBrowser?

PocketBrowser

Motorola PocketBrowser is the precursor to RhoElements and RhoMobile Suite within Motorola.  It allows developers to write HTML based applications across a range of Motorola Solutions' devices to access the device capabilities of that device such as Scanning and Magnetic Stripe Card reading.  Introduced 10 years ago the software continues to be supported in its current form on Motorola's latest Windows devices.

 

In order to access the device capabilities using PocketBrowser developers use <Meta /> Tags on their HTML pages which expose the underlying hardware.  The syntax provided to these meta tags is known as EMML 1.0 (http://docs.rhomobile.com/rhoelements/EMMLOverview#emml-in-its-original-form-emml-10) and it was primarily designed as a declarative rather than an interactive user experience.

 

Whilst EMML 1.1 was introduced in PocketBrowser 3.0 this blog will assume that all PocketBrowser code is written in EMML1.0 syntax, code already written in EMML1.1 does not require conversion.

 

The underlying rendering engine of PocketBrowser is Internet Explorer, as shipped on the device and therefore the functionality of the rendering engine (eg. support for CSS) is dependant on the device running your application.  In order to access the EMML tags and device capabilities from JavaScript a number of ActiveX objects can be instantiated, the most common of which is 'Generic' and the code below shows how you would enable the scanner using the ActiveX object:

 

var myObj = new ActiveXObject("PocketBrowser.Generic");
myObj.invokeMETAFunction('Scanner','enable');

 

 

 

Why would I want to port to RhoElements?

 

RhoElements can be viewed as the latest incarnation of PocketBrowser; whilst PocketBrowser will continue to be maintained for our Enterprise customers in their current device deployments customers are advised to move to RhoElements to take advantage of the additional features on offer.

  • Support for the latest Motorola devices.  RhoElements will always be ahead of the curve in supporting the latest Motorola Windows products as they enter the market, we are already working on supporting devices which have yet to enter the market.
  • There are no plans to support PocketBrowser on any current or future Motorola Android devices, such as the ET1.
  • PocketBrowser will not run on the full suite of consumer devices supported by RhoElements, such as iPhone, BlackBerry, consumer Android and Windows
  • PocketBrowser only allows for the creation of 'Hybrid' applications, that is applications written in HTML / JavaScript and take advantage of device capabilities.  RhoElements offers a plethora of additional development opportunities e.g. support for the MVC pattern, native application development, an Eclipse based IDE, a device simulator, full integration with 'RhoConect' providing seemless syncing with the backend and so on.
  • RhoElements has more functional APIs for scanning, image capture and more
  • RhoElements has APIs to hardware not exposed through PocketBrowser such as device sensors and NFC.
  • RhoElements offers an HTML5 compliant rendering engine allowing you to create beautiful applications, in stark contrast with the Internet Explorer based rendering engine in PocketBrowser.

 

 

Native Applications vs. the Shared Runtime

 

With all this talk of native applications, backend databases, synchronization and IDEs it's difficult to understand how PocketBrowser and RhoElements can be considered similar.  To make the transition easier for both existing MPB customers and customers who just want a 'hybrid' application solution we have provided the 'Shared Runtime'.  The Shared Runtime can be considered a shell, a cab file (or apk) which can be installed on Windows Mobile / CE / Android devices including the full range of supported Motorola Solutions' devices.  Pointing the shared runtime at your HTML start page will launch your application in the HTML5 rendering engine, then you can write your application using a combination of meta tags and Javascript.  As you can see if you're familiar with how PocketBrowser works you are already familiar with how the shared runtime works.

 

I have previously written a blog on obtaining the shared runtime from the RhoMobile Suite download, you can see it at https://developer.motorolasolutions.com/community/rhomobile-suite/docs/developer-reference/blog/2012/06/29/accessing-the-shared-runtime

 

If you are interested in porting your Web Application directly to a native Application using RhoMobile Suite you can see a good video on our presentation at our Americas Application Forum here https://developer.motorolasolutions.com/docs/DOC-1636

 

Porting an application in RhoElements 1.x, RhoElements 2.0 or RhoElements 2.1

 

RhoElements was designed from day one to be completely backwardly compatible with applications written for PocketBrowser, if you are running RhoElements 1.x, RhoElements 2.0 or RhoElements 2.1 you should be able to point your RhoMobile Suite shared runtime at your existing PocketBrowser application and it should run without modification, though because a different rendering engine is being used underneath you may need to modify your user interface slightly to accommodate.

 

Backwards compatibility is accomplished in 2 ways:

  • PocketBrowser syntax Meta tags and Javascript calls are converted to RhoElements syntax by the use of regular expressions, eg

 

<meta http-equiv="battery" content="x=50"/>

 

is converted to

 

<meta http-equiv="battery" content="left:50"/> 

 

using the Regular expression:

 

<Expression patternEx="^(x)=(-?[0-9]+)" replaceEx="left:\2" />

 

All of the regular expression patterns used by RhoElements can be found in your Shared runtime installation at \Program Files\RhoElements\Config\regex.xml (by default) with separate regular expressions being provided for the HTTP-Equiv components and Content components of the meta tags.  This is all done internally meaning RhoElements will see syntax it recognises even though it has been declared in PocketBrowser.

 

This syntax conversion also applies to calls made through JavaScript.

 

  • ActiveX has been replaced by NPAPI.  Remember the PocketBrowser syntax for enabling the Scanner:
var myObj = new ActiveXObject("PocketBrowser.Generic");
myObj.invokeMETAFunction('Scanner','enable');

 

The WebKit engine (HTML5 rendering engine) used by RhoElements does not understand what an 'ActiveX' object is by default, this this is a Microsoft technology; for this reason the functionality is simulated within RhoElements using an NPAPI object.  For more information on NPAPI as well as writing your own I have written a blog post at https://developer.motorolasolutions.com/community/rhomobile-suite/docs/developer-reference/blog/2012/04/10/creating-an-npapi-for-rhoelements.  One word of advice though: custom NPAPI creation is only supported on Windows Mobile devices and will continue to be moving forward but with the introduction of consumer device support in RhoElements we are not able to offer NPAPI support across our full range of devices.

 

There are several configuration options which are appropriate to mention here:

 

The NPAPI Preloads section of the config.xml file specifies which of the PocketBrowser ActiveX objects should be preloaded on the page, by default they are all preloaded.  The NPAPI Directory option specifies which directory the NPAPI objects can be found in, by default on Windows this will point to a sub directory off of where you installed the shared runtime.

<NPAPI>
<NPAPIDirectory         VALUE="file://\Program Files\RhoElements\NPAPI\"/>
          <Preloads>
                    <PreloadLegacyGeneric value="1"/>
                    <PreloadLegacyODAX value="1"/>
                    <PreloadLegacyNoSIP value="1"/>
                    <PreloadLegacyAirBeam value="1"/>
                    <PreloadLegacyAPD value="1"/>
          </Preloads>
</NPAPI>

 

 

Porting an application in RhoElements 2.2

 

Applying a series of regular expressions to every EMML tag parsed introduces a performance hit whenever a device capability is accessed, if you are using <meta /> tags or JavaScript functions in your body onLoad() handler the navigation performance of RhoElements will suffer.  In RhoElements version 2.2 the decision was made to disable regular expressions by default, this means that if you install the RhoElements 2.2 shared runtime and point it at your existing PocketBrowser application it will not work out of the box.  There is a configuration option you can modify to turn regular expressions back on again, unsurprisingly named:

 

<UseRegularExpressions value="1"/>

 

However doing this is inefficient as you will be applying ALL conversions.  Towards the end of my second performance blog (https://developer.motorolasolutions.com/community/rhomobile-suite/docs/developer-reference/blog/2012/10/08/rhoelements-performance-improvements-2) I spoke about how the regular expressions applied to EMML tags were stored in an XML file as part of the shared runtime installation, what we want to do is to reduce the default RegEx.xml file containing about 330 conversions in total to only contain the conversions used by your application.

 

For example, to take the earlier example of an application which used

 

<meta http-equiv="battery" content="x=50"/>

 

with no other functionality, though somewhat of a contrived example we could reduce the RegEx.xml file to:

 

<?xml version = "1.0"?>  
<RegularEx>  
  <Equivs>  
  </Equivs>  
  <Contents>  
    <Expression patternEx="^(x)=(-?[0-9]+)" replaceEx="left:\2" />
  </Contents>   
</RegularEx> 

 

which means we would only be processing one regular expression per EMML tag which is far more efficient.

 

Of course it's not immediately obvious which PocketBrowser specific EMML calls you are using, your application could have hundreds of calls out to the device capabilities and it may not be obvious which entries in RegEx.xml are being applied.  To make reducing your RegEx.xml file easier in RhoElements 2.2 a log entry will be written with severity:Info whenever a regular expression conversion is applied, for example if the example above is found in an application the log will output:

 

A Regular Expression has been applied to the Module method or parameter (x=50 => left:50)  
   RegEx.xml entry is "<Expression patternEx="^(x)=(-?[0-9]+)" replaceEx="left:\2" />"

 

By running your PocketBrowser application in RhoElements 2.2 shared runtime with <UseRegularExpressions value="1"/> and <LogInfo value="1"/> you can analyse the logs your application produces to determine what your RegEx.xml file must contain.

 

Rewriting your application for RhoElements 2.2

 

So let us suppose you are updating your PocketBrowser application as you move to RhoElements, there are a number of reasons you might want to do this:

  • You want to improve your user interface to take advantage of the HTML5 compliant rendering engine.
  • You want to access device APIs not available in PocketBrowser
  • You wish to transition to a new framework which, detecting the existence of ActiveXObjects on the page, mistakenly serves you up pages configured for Internet Explorer.

 

It is recommended you follow the following steps:

 

  1. Locate every instance of 'ActiveX' in your code and replace it with the corresponding Javascript interface, For example the earlier code snippet
var myObj = new ActiveXObject("PocketBrowser.Generic");
myObj.invokeMETAFunction('Scanner','enable');

 

becomes

scanner.enable();

 

and

var myPrinter = new ActiveXObject("PocketBrowser.NarrowBand");
myPrinter.PSExternalEx(257, 'Hello World');

 

becomes

apd.PSExternalEx(257, 'Hello World');

 

2. Modify your NPAPI preloads section as follows to stop loading any pseudo-ActiveX objects on the page:

<Preloads>
          <PreloadLegacyGeneric value="0"/>
          <PreloadLegacyODAX    value="0"/>
          <PreloadLegacyNoSIP   value="0"/>
          <PreloadLegacyAirBeam value="0"/>
          <PreloadLegacyAPD     value="0"/>
          <PreloadJSObjects     value="1"/>
</Preloads>

 

3. Convert all your EMML1.0 syntax to EMML1.1.  You can use the technique described in the previous section to determine which of your calls are using EMML 1.0 syntax and the log file will also tell you the corresponding EMML 1.1 syntax.

 

For example

<meta http-equiv="battery" content="x=50"/>

 

wrote the following to the log file:

A Regular Expression has been applied to the Module method or parameter (x=50 => left:50)  
   RegEx.xml entry is "<Expression patternEx="^(x)=(-?[0-9]+)" replaceEx="left:\2" />"

 

and so it should be converted to

<meta http-equiv="battery" content="left:50"/>

 

Your upgrade from PocketBrowser to RhoElements is now complete.

Customising your Native Applications' View for Motorola WebKit

 

An overview of the RhoElements performance improvement drive

 

The great thing about an open developer community is the ability to interact and work at a group and individual level with many of the developers out there. It really allows us to prioritize product feature sets and focus on the things that the greater community feels are a priority. It also allows us to get real-time feedback on the product and address any concerns that may arise in a more agile process. The RhoMobile Suite team really prides itself on being agile and producing a product that not only meets the needs of those developing enterprise cross-platform applications, but also does so with the utmost level of quality and performance.  Recently there have been concerns that HTML5 cannot deliver a performant application but with the right techniques it can be done.

 

Introduction

In the third of a series of blog posts we will start to tackle Native Applications on Motorola devices, by that I mean applications developed in RhoMobile Suite using the Model View controller paradigm making use of the built in JQueryMobile library and CSS which ship with the product.  I'm not going to take a 'deep dive' here, this blog is designed to improve the out of the box experience with RhoMobile Suite 2.x all the way to the upcoming 2.2 & I'll highlight a few gotchas and tips to deliver an immediate performance perception improvement.  This blog has been designed to address performance concerns I've been hearing from customers using Motorola WebKit running on Windows Mobile / Windows CE but can apply equally to any supported device or platform.

 

This is just an overview and first step, over the coming weeks and releases we'll be making further improvements to the performance and developer experience.

 

Modifying your CSS

 

There are two ways you can improve the out of the box experience and the first of these is by modifying the default CSS. 

 

You will find your application's css file in its \public\css directory and if your application uses Motorola WebKit the framework will select the 're_webkit.css' styles.  The problem with 're_webkit.css' is it is based heavily on the android.css and relies on lots of 'hover' styles, unnecessary in mobile applications.  The first suggestion is to customize the default CSS file to match your company's style and making all hover styles equivalent to the up style, doing so will ensure a smoother scrolling performance.

 

The videos below show a native application with the default styling on the left and some customized styling on the right:

 

 

Default Styling 'out of the box'       
Modified Styling

A native application built without modification to the default style
The same native application built with modified styling to remove hover parameters.  Notice the improved scrolling performance.  Also notice that I'm an engineer and not a designer!

 

You can download the css file used in the video on the right at the bottom of this blog post (re_webkit.css), bear in mind that I am not a designer and this CSS was created solely to show the performance difference, it is left to the far more talented and creative reader to improve on this design.

 

Modifying the default JQueryMobile settings

 

It is possible to modify the behaviour of JQueryMobile to improve the performance on Motorola Windows Mobile / CE devices and also to improve user perception.

 

The JQueryMobile settings which can be configured are listed at http://jquerymobile.com/demos/1.2.0/docs/api/globalconfig.html; that API is actually specific to JQM 1.2.0 but will be largely identical to the version used in RhoMobile Suite (currently 1.0.1).

 

Native applications written in RMS provide a really convenient hook to configuring JQM; in your application's layout.erb file you'll see:

 

        <script type="text/javascript">
            $(document).bind("mobileinit", function() {

 

In the mobileinit function you can configure the settings as follows:

 

$.mobile.[configuration item]= [configuration setting];

 

In fact, depending on which version you are running you may already see the following options commented out:

 

// Uncomment these options in case of performance problem in pages transition
//$.mobile.defaultPageTransition = 'none';
//$.mobile.defaultDialogTransition = 'none';
//$.mobile.ajaxEnabled = false;
//$.mobile.pushStateEnabled = false;
//$.mobile.loadingMessageDelay = 50; // in ms

 

The following table shows what effect each JQM setting will have with the Motorola WebKit Browser on Windows Mobile / Windows CE:

 

SettingDescription from JQM documentationDefault Value
Recommended Value with Motorola WebKit
Experience
defaultPageTransitionSet the default transition for page changes that use Ajax. Note: default changed from 'slide' to 'fade' in 1.1. Set to 'none' for no transitions.SlideNoneSetting this value to None eliminates the choppy page transitions and reduces the time for each navigation.
defaultDialogTransition Set the default transition for dialog changes that use Ajax. Set to 'none' for no transitions.PopNoneIn order to keep the experience consistent this should be set to none.
ajaxEnabled jQuery Mobile will automatically handle link clicks and form submissions through Ajax, when possible. If false, URL hash listening will be disabled as well, and URLs will load as ordinary HTTP requests.TrueKeep TrueChanging this setting changes the fundamental behaviour of navigation, because the entire JQM library is being reloaded on each navigation the performance was degraded if this value was disabled.
pushStateEnabled

Enhancement to use history.replaceState in supported browsers, to convert the hash-based Ajax URL into the full document path. Note that we recommend disabling this feature if Ajax is disabled or if external links are used extensively.

TrueKeep TrueIn keeping with JQM recommendations this setting should be kept the same as ajaxEnabled.
loadingMessage Set the text that appears when a page is loading. If set to false, the message will not appear at all.False"Loading..."You should specify a custom message here to let your user know the device is doing something, 'Loading...' seems fairly innofensive.
loadingMessageDelayNot documented505Although 50ms seems perfectly adequate, just to be sure I reduced this to 5ms to ensure the loading message was always displayed.

 

But you might not want to have the same settings for your iPhone or Android applications; In your layout.erb file there are two ways to detect the presence of Motorola WebKit, the first is to use the JavaScript call:

 

navigator.userAgent.match(new RegExp('MotorolaWebKit'))

 

This will return true if the browser's user agent contains 'Motorola WebKit', as is the case by default.

 

The second technique is to use some inline Ruby:

 

<% if System::get_property('webview_framework') =~ /^WEBKIT/ %>

 

Calling get_property('webview_framework') will return "WEBKIT/MOTOROLA" if you are running on a Motorola device running Windows Mobile / Windows CE.

 

You may wish to differentiate between whether you are running on a Windows Motorola device or an Android Motorola device (such as the ET1 or MC40), in which case you can use the Ruby callget_property('os_version').

 

The videos below show a comparison of user interaction in an application using JQueryMobile settings 'out of the box' against an application customised for Motorola WebKit on Windows Mobile / Windows CE.  You can download the layout.erb I used in my modified version at the bottom of this blog post.

 

Default Performance 'out of the Box'    
Performance after JQueryMobile Customization

Interacting with a native application using the default JQueryMobile settings on an MC75a
Interacting with the same native application on an MC75a using the modified JQueryMobile settings as described in this blog post.

 

 

Limitations of the Device & Other Considerations

 

It's pretty obvious from the above videos that we haven't achieved a miracle but we have at least improved the performance of our application from a user perception point of view and will continue to improve performance in this area. These ruggedised devices are a couple of years old now and as such do not have an on board GPU or GHz processors so can not be directly compared with an iPad or Galaxy S smart phone.  As Motorola Solutions continues to innovate we will bring the true consumer experience to the ruggedised market, targeted for Enterprise.

 

I've heard a lot of suggestions from customers and even internally that we should enable the JIT in our WebKit engine, this is Just In Time compilation for JavaScript, enabling faster processing of JS.  There's been a lot written over the past few years on JIT optimizations in both Safari and Chrome and watch out for more information on JIT being enabled on our Windows devices in upcoming releases (it is already enabled on Motorola Android devices).  I did do a comparison in this case against the as yet unreleased JIT engine and did not see any noteworthy improvement, in reality the application I created for the videos above did not make sufficient use of JavaScript to benefit from JIT compilation, even though it made use of JQueryMobile.

 

Another suggestion I've heard frequently is to update to the latest version of JQueryMobile, whilst this can certainly be done the version of JQM which ships with RhoMobile Suite is the version with which the product was validated, so you may see some unexpected behaviour.  I've also not heard any reports that updating to the latest JQM will improve performance.

 

Links to other relevant Material

 

Here's some links which dive deeper into some of the topics touched on in this blog:

 

 

RhoElements_Icon_TB.jpg

Configuration Settings & Other Tips to make your RhoElements application Run Faster

 

An overview of the RhoElements performance improvement drive

 

The great thing about an open developer community is the ability to interact and work at a group and individual level with many of the developers out there. It really allows us to prioritize product feature sets and focus on the things that the greater community feels are a priority. It also allows us to get real-time feedback on the product and address any concerns that may arise in a more agile process. The RhoMobile Suite team really prides itself on being agile and producing a product that not only meets the needs of those developing enterprise cross-platform applications, but also does so with the utmost level of quality and performance. Recently there have been concerns that HTML5 cannot deliver a performant application, and with the latest announcements around Facebook and their application it has even more people wondering.

 

 

Introduction

 

In the second of a series of blog posts I will discuss the configuration settings present in RhoElements 2.1 which you can tweak to make your applications run faster.  If you missed my first blog post a couple of weeks ago you can find it at https://developer.motorolasolutions.com/community/rhomobile-suite/docs/developer-reference/blog/2012/09/24/rhoelements-performance-improvements-1, that's where I shared our latest Motorola WebKit browser for Windows Mobile (Embedded Handheld) / CE.  The tips in this blog post are aimed at Windows Mobile / CE users.


Configuration Settings

 

What is the configuration file and where is it?

 

The configuration file is an xml document which is used to define the behaviour of your RhoElements application, you can find a detailed description of it at http://docs.rhomobile.com/rhoelements/ConfigurationSettings along with an explanation of what all the configuration parameters do.  If you are using the shared runtime you will find the config file at

 \Program Files\RhoElements\Config\Config.xml

 

If you are using a native RhoElements application you will find your configuration file at

\Program Files\<Your Application Name>\Config\Config.xml

 

The tips below involve modifying the configuration file used by your application.

 

Configuring the Hourglass / Wait cursor

 

By default whenever you navigate from page to page you will see a wait cursor animation appear as a spinning coloured disc.  In some circumstances users may see this as visually distracting, especially if navigation times are very low and application users may perceive a performance increase by disabling the wait cursor.  For historical reasons the configuration file uses the term 'hourglass' for the wait cursor.

 

The wait cursor is configured with the following settings:

<GUI>
  <HourglassEnabled   VALUE="1" />  <!-- Set this value to "0" to not display the hourglass -->
  <HourglassLeft      VALUE="" />
  <HourglassTop       VALUE="" />
</GUI>

 

To stop the wait cursor displaying you can set the 'HourglassEnabled' parameter to '0'.

 

Alternatively you can prevent the hourglass module from being preloaded to have the same effect, see http://docs.rhomobile.com/rhoelements/ConfigurationSettings#optimizing-the-runtime.

 

It is possible to hide or show the hourglass manually from within your code if your application wants to give some feedback to the user, for example you may be uploading a file to an FTP site or logging in to a server.  Because the wait cursor is written in native code it will have less performance impact than doing the same in HTML.  To hide or show the wait cursor from Javascript use the following code snippet:

 

<SCRIPT LANGUAGE="JavaScript">
    function showHourglass()
    {
        hourglass.visibility = 'visible';
    }

    function hideHourglass()
    {
        hourglass.visibility = 'hidden';
    }
  </SCRIPT>

 

For more information see the API at http://docs.rhomobile.com/rhoelements/hourglass

 

Default Meta Tags

 

Default meta tags are EMML tags which are applied to every page, following a navigation:

 

<DefaultMetaTags>
        <MetaTag VALUE="SignatureCapture~left:30;top:130;height:100;bgcolor:#663300;width:200;border:visible;visibility:visible;" />
        <MetaTag VALUE="Signal~left:10;top:200;color:#663300;"/>      
</DefaultMetaTags>

 

In the above example after a page load the Signature Capture box will be shown at position (30,130) with size (200x100) with a border; the signal indicator will also be shown.

 

In RhoMobile Suite 2.1 default meta tags are expensive and should be avoided if necessary, for example 2 simple tags can add as much as half a second to each page navigation, increasing with the more that are used.  Version 2.2 will introduce performance improvements for default meta tags but in 2.1.  As an example of a way to avoid default meta tags, the signal module visibility is persistent, it is not necessary to re-specify the colour and location for each page load so in this particular case the tag can be replaced with Javascript on the application home page.

 

The Scanner is disabled during page navigation, whilst this cannot be configured in version 2.1 it will be configurable in 2.2.  Enabling the scanner in a default meta tag will cause the scanner to first be disabled when the navigation starts and then re-enabled after the navigation has finished; this can add as much as half a second to the page load and it is recommended to only enable the scanner on pages where it will be used rather than on every page via a default tag.

 

Logging

 

Having logging turned on will have only a minor impact on application performance, this is because the logging functionality runs at lower priority to the rest of the application.  Nevertheless in order to squeeze every last bit of performance out of your application you can turn logging off using the following configuration settings:

 

<Logger>
    <LogProtocol  VALUE="FILE"/>
    <LogPort      VALUE="80"/>
    <LogURI       VALUE="file://\Program Files\RhoElements\Log.txt"/>
    <LogError     VALUE="0"/>  <!--  Set this to "1" to output error logs -->
    <LogWarning   VALUE="0"/>
    <LogInfo      VALUE="0"/>
    <LogUser      VALUE="0"/>
    <LogMemory    VALUE="0"/>
    <LogMemPeriod VALUE="5000"/>
    <LogMaxSize   VALUE="100"/>
</Logger>

 

It is however recommended that error logs are still turned on just in case anything critical does go wrong (e.g. incorrect installation), you will have a means to find out why.

 

"Debug" Controls

 

The "Debug" Controls are by design only provided for the application developer to debug their application, they are not necessarily visually appealing and can allow the user to disrupt your designed program flow.  In RhoElements 2.1 their use can impact performance by upwards of 100 milliseconds when compared to performing the same behaviour in Javascript or Ruby.

 

The debug controls are:

AddressBar http://docs.rhomobile.com/rhoelements/addressbar

BackButton http://docs.rhomobile.com/rhoelements/backbutton

ForwardButton http://docs.rhomobile.com/rhoelements/forwardbutton

ReloadButton http://docs.rhomobile.com/rhoelements/reloadbutton

StopButton http://docs.rhomobile.com/rhoelements/stopbutton

GoButton http://docs.rhomobile.com/rhoelements/gobutton

QuitButton http://docs.rhomobile.com/rhoelements/quitbutton

MinimizeButton http://docs.rhomobile.com/rhoelements/minimizebutton

HomeButton http://docs.rhomobile.com/rhoelements/HomeButton

SipButton http://docs.rhomobile.com/rhoelements/sipbutton

ZoomTextButton http://docs.rhomobile.com/rhoelements/zoomTextButton

 

Other Tips

 

Disabling Regular Expressions

 

Regular Expressions are a way for RhoElements applications to recognise EMML 1.0 syntax, http://docs.rhomobile.com/rhoelements/EMMLOverview which means applications written to target Motorola PocketBrowser will work unmodified in RhoElements.

 

Applying all the regular expressions which ship by default in RhoElements for each meta tag, Javascript and Ruby call listed in the Mobile API reference at http://docs.rhomobile.com can be very expensive.  If you do not require your installation to be backwardly compatible with applications written for PocketBrowser you can modify your RegEx.xml file as follows:

 

<?xml version = "1.0"?>
<RegularEx>
  <Equivs>
  </Equivs>
  <Contents>
  </Contents> 
</RegularEx>

 

If you are using the shared runtime you can find your RegEx.xml file at:

 \Program Files\RhoElements\Config\RegEx.xml

 

If you are using a native RhoElements application you will find your RegEx file at

\Program Files\<Your Application Name>\Config\RegEx.xml

 

Removing all regular expressions can increase your Mobile API parsing speed by as much as 10 times.  In RhoElements 2.2 there will be a configuration option to disable regular expression parsing by default so there will be no need to modify your RegEx.xml file.

 

Use of remote viewers

 

And finally... In the course of performance analysis one issue crops up continuously, the use of remote viewers such as those developed by http://www.soti.net/.  Remote viewers are invaluable for mobile application development but by their very nature can impact your device's performance, in order to achieve consistent results it is recommended to disable your remote viewer to get a true picture of your application's performance, also ensuring you have no other CPU intensive tasks running in the background.

 

 

RhoElements_Icon_TB.jpg

How to improve your HTML5 rendering and application performance.

 

An overview of the RhoElements performance improvement drive

 

The great thing about an open developer community is the ability to interact and work at a group and individual level with many of the developers out there. It really allows us to prioritize product feature sets and focus on the things that the greater community feels are a priority. It also allows us to get real-time feedback on the product and address any concerns that may arise in a more agile process. The RhoMobile Suite team really prides itself on being agile and producing a product that not only meets the needs of those developing enterprise cross-platform applications, but also does so with the utmost level of quality and performance. Recently there have been concerns that HTML5 cannot deliver a performant application, and with the latest announcements around Facebook and their application it has even more people wondering.

 

In all reality there are many performant HTML5 applications that have been very successful while following key best practices. As a result we really listened to the community, got the team focused and are excited to present a blog series on how to do just that. Over the coming weeks we will be sharing with you a series of best practices, test suites and configuration settings that allow you to make intelligent decisions on how to best design, architect and develop your cross-platform application.

 

The first step: Improving Motorola WebKit performance

 

Our first step is very simple. As a result of our focus on performance and this blog series, we also worked with a number of developers in the community on a series of edge cases. This allowed us to drive further optimization into the HTM5 Webkit rendering engine that is provided with RhoElements for devices with a lower powered CPU and less available memory than your modern day consumer smartphones. And the great news is that it had a general impact as well on overall performance of the solution.

 

This hotfix has been developed to deliver performance improvements in the Motorola WebKit engine for both Windows Mobile and Windows CE devices.  It is recommended that anybody developing applications for Motorola devices running Windows operating systems upgrade to this latest release to see a noticeable decrease in rendering time.

 

Contents of the Patch and Installation

Prerequisites

 

In order to install this hotfix you must first download and install Motorola RhoMobile Suite 2.1, available from

http://www.motorola.com/Business/US-EN/RhoMobile%20Suite/Downloads

 

Note: This fix is already included in RhoMobile Suite 2.2.

 

Installation and Deployment Instructions

 

This patch consists of four Windows DLLs which need to be copied to your Windows Mobile / Windows Embedded Handheld or Windows CE device.  It is necessary to copy the DLLs manually to your device as you may have multiple RhoElements applications installed.

 

This patch is attached to this blog post as a zip file, MotorolaWebKit_r9406.zip.  Download this zip file and extract it to a temporary directory on your computer, the contents should be as follows:

  • eklibrary.dll
  • openssl.dll
  • PBEngine_WK.dll
  • webkit.dll

 

To install this patch please follow the steps below:

 

  1. Shutdown any instances of RhoElements running on your device.
  2. Connect your device to your PC using ActiveSync or the Windows Device Center
  3. On your device locate RhoElements application installation and overwrite the DLLs present on the device as follows:

 

For Hybrid applications:

 

For Native applications:

  • Any application developed in RhoStudio which does not use the shared runtime is considered a Native Application.

 

          Option 1: modifying your application on your device.

  • The location of a Native application on your device will depend on the application name, for example by default an application named “MyApp” will reside in \Program Files\MyApp\
  • In your application’s directory you will see four DLLs whose names correspond with the DLLs in this patch, overwrite them with the patched DLLs.
  • Every time you rebuild your application you will need to repeat this step, to apply this patch properly it is recommended you modify your RhoMobile Suite installation.

 

          Option 2: modifying your RhoMobile Suite installation.

  • To upgrade the Motorola WebKit version installed with RhoMobile Suite 2.1.1.7 you need to overwrite the DLLs on your computer, then they will be picked up the next time you build your application
  • On a PC this can be done by browsing to [Drive]:\MotorolaRhoMobileSuite2.1.1.7\ruby\lib\ruby\gems\1.9.1\gems\rhoelements-2.1.1.7.1\libs\data
  • In this directory you will see four DLLs whose names correspond with the DLLs in this patch, overwrite them with the patched DLLs.

 

RhoElements_Icon_TB.jpg

 


 



When RhoElements 1.x was transitioned into part of RhoMobile Suite 2.0 one of the many changes was a push towards developing native applications.  You don't have to create applications natively however, you can use the shared runtime.

 

What is the Shared Runtime?

 

The Shared runtime allows developers to create hybrid applications using HTML and Javascript without having to worry about Ruby or downloading device SDKs.  It is a cab file (for Windows Mobile / CE) or an apk file (for Android).  After installing the cab file or apk you will have an application on your device called 'RhoElements', running this will launch the default start page.  You can configure the start page location in the configuration and more information is available at http://docs.rhomobile.com/rhoelements/ConfigurationSettings

 

What is the difference between the 2.x shared runtime and RhoElements 1.x?

 

That's the genius bit... other than feature enhancements to both the framework and our WebKit port there are no architectural differences between the 2.x shared runtime and RhoElements 1.x.  If you're familiar with RhoElements 1.x you're already familiar with the 2.x shared runtime.

 

What devices are supported?

 

Currently only Motorola devices are fully supported by the shared runtime, the primary reason for this is much of the shared runtime functionality is dependant on Motorola value add APIs, e.g. scanning, MSR etc.  In time we will gradually extend support to the full family of devices, keep your eyes on http://docs.rhomobile.com/rhoelements/apicompatibility for the latest API compatibility.

 

What are my upgrade options from a RhoElements 1 application?

 

There are two upgrade routes for existing RhoElements 1 applications:

  1. Download & install the shared runtime and run your application in exactly the same way you were running it under RhoElements 1.x
  2. Transition your application to a native application, taking full advantage of the MVC pattern and enhanced sync capabilities.  Geoff Poremba gave an overview of how to do this at the Americas App Forum and his slides are at https://launchpad.motorolasolutions.com/appforum/presentations/rhomobile/appforum.chicago.pdf

 

Licensing?

 

Upgrading from RhoElements 1.x to the 2.x shared runtime will require a new license.  Upgrade entitlement, costs and maintenance contracts are beyond the scope of this blog post.

 

Where can I get more help?

 

There is a documentation page on the shared runtime at http://docs.rhomobile.com/rhoelements/rhoelements2-webapps, it includes a quick start guide, overview of the configuration and some more advanced topics.

 

How can I obtain the Shared Runtime?

 

I'm a PC

 

Windows choose options.png

  • After the installation process the shared runtime CAB and APK files will be installed under c:\MotorolaRhoMobileSuite<version>\RhoElements2 Shared Runtime\<OS> (by default)

Folder on Windows.png

  • You can also access the shared runtimes from the start menu by clicking:
    • Start --> All Programs --> Motorola RhoMobile Suite --> Runtimes for Web Apps
  • Copy the appropriate CAB file to your Windows Mobile / Windows CE device and install (click on it).  For android mount your device as a drive and copy the APK over, once copied install the apk by clicking on it.
    • You must configure your Android device to install non-market place applications if you have not already done this.

 

I'm a Mac

 

RMS_1.png

  • Double click RhoElemnets2 Shared Runtime

RMS_2.png

  • Double click the folder for the relevant OS and the CAB or APK file will be inside

RMS_3.png

It was good seeing so many familiar faces from Launchpad at our 2012 Americas AppForum  in Schaumburg, IL earlier this month.  Thanks to all those who managed to make it to my session and for those who couldn't make it I understand they'll be posting it online in the coming weeks.

 

In the following blog post I'll walk through the application that I built up during the presentation, "Adding Device Capabilities and HTML5 features to your Application".  You'll find my slides at https://launchpad.motorolasolutions.com/appforum/presentations/rhomobile/Adding%20Device%20Capabilities%20and%20HTML5%20Features%20to%20your%20Application.pdf.  The "Event Attendee Tracker" application is designed to be used at events such as the app forum to keep track of the attendees in each session.

 

1) The Event Attendee Tracker Web Application.

  This shows HTML5 local storage.

  Web App.png

So here's the web application, it doesn't use any device capabilities and so you can run it fully functional in any HTML5 capable web browser (any modern browser).  The idea here is that you're using any device and you're standing at the door of the session keeping track of the number of people that come into the room.  To use the app select the session name from the drop down and then hit the 'add attendee' button as people enter the room.

 

I use the HTML5 concept of 'local storage' to keep track of two important items of data here:

* Which session has been selected in the combo box

* How many people are in each of the sessions.

 

Have a play with the application by downloading "EAT-1.zip", as I say you don't need a device to try this out, just launch it in your browser.

 

Here's the Javascript code when the user hits the 'add attendee' button:

function onAddAttendee()

{
          sId = localStorage.getItem('sID');
          if (sId != -1) 
          {
                    var iAttendees = localStorage.getItem("RE-" + sId);
                    if (iAttendees != 'NaN' && iAttendees != null)
                              attendeeCount.innerHTML = iAttendees; 
                    else
                              attendeeCount.innerHTML = 0;
                    var nAtt = parseInt(attendeeCount.innerHTML) + 1;
                    attendeeCount.innerHTML = nAtt;
                    localStorage.setItem("RE-" + sId, nAtt);
          }
}

 

Notice the lines "localStorage.getItem..." and localStorage.setItem...".  You can think of local storage as a series of name-value pairs.  The sID key refers to the combo box, so retrieving the value for this tells us the currently selected session.  The RE-sID keys refer to the number of attendees in each session, it is this item of data that we're incrementing when the button is pressed.

 

2) The Event Attendee Tracker Application with Scanning

 

OK, so having the ability to keep track of the number of people in the room is quite swish but it's far from the capabilities of a Mobile Device (it's far from the capabilities of a pencil and piece of paper!)  What we're going to do now is to integrate Scanning into our application.

 

Event Attendee Tracker 2.png

 

Now imagine the conference is being attended by delegates who have all been issued with ID badges that have QR code barcodes printed on them, much like the screenshot below which I prepared earlier.

 

DevConfBadge.png

 

These barcodes contain the name and company of the delegate, along with some additional information that we won't be using in this application.

 

Now we will modify our application to use the Scanner capability of the device, try it yourself by loading 'EAT-2.zip' on any Motorola Device.  To do this install the RhoElements shared runtime and modify your config.xml file to point to your application, here's the detailed steps for installation:

 

1) Download RhoMobile Suite from http://www.motorola.com/Business/US-EN/RhoMobile+Suite/Downloads (any version will do)

2) Install RhoMobile Suite on your PC (or Mac)

3) On your PC navigate to C:\MotorolaRhoMobileSuite2.0.5\RhoElements2 Shared Runtime

3.1) You might have to modify the directory slightly if you didn't install to the default location

4) Install the appropriate .cab / .apk file for your device

5) On WM / CE navigate to \Program Files\RhoElements\Config\ and copy config.xml to your PC using activesync (on Android you'll find the config file after launching under com.motorolasolutions.rhoelements)

6) Copy the EAT-2 application to your device filesystem under \eat

7) Modify your config.xml to point your start page to file://\eat\index.html

8) Copy your config.xml back to the device, overwriting the old file and launch RhoElements from the start menu.

 

OK, now you've seen it working, let's take a look at the relevent bits of Javascript to enable the Scanner (http://docs.rhomobile.com/rhoelements/scanner):

 

//  Called on session change
function enableScanner()
{
          scanner.decodeEvent = 'doScan(%json)';  //event handler
          scanner.enable(); //enable default scanner
}

 

function doScan(scanData)
{
          displayScanData(scanData.data);
}

 

That's all it is, pretty simple huh?  The 'enableScanner()' function declares a Javascript function that will be called whenever a barcode is decoded and then enables the Scanner.  Enabling a scanner puts the hardware in a state where pressing the yellow trigger key on the device will start a scan.   Each successful barcode scan will result in the doScan function being called which takes a JSON Object containing the data associated with the scan, here's what the displayScanData function looks like:

 

function displayScanData(scanData)
{
          onAddAttendee();  //  Same code as local storage example
          var attendeeData = getVcardInfo(scanData,'fn') + " : " +           getVcardInfo(scanData,'org');
          var scanInfoField=document.getElementById('scanInfo');
          document.getElementById('scanInfo').innerHTML          =           attendeeData; 
}

 

The QR code is parsed to extract the delegate's name and organisation, this delegate information is then output to the DOM so the greeter can say, "Welcome <name> from <organisation>, I hope you enjoy this session"

 

Again, for the complete code listing, download and have a browse through EAT-2.zip, the ONLY file modified from EAT-1.zip is index.html (search for my initials, 'dcc' to see the changes, that's what I used to make quick changes on the fly during the presentation).  I've also attached a Word document of the barcodes you'll need to play with the app at the bottom of this blog.

 

3) The Event Attendee Tracker Application using WebSQL

 

OK, so those sharp eyed readers amongst you will notice that it's a bit superfluous scanning a barcode on the name badge just to say "Welcome <name>" when the name and organisation are printed right there on the badge in plain text!!

 

We're going to make this application a bit more useful now by adding WebSQL capabilities.  WebSQL is not technically an HTML5 feature as it was removed from the specs for technical reasons.  You'll find it has become a defacto standard adopted by all the major browsers however and is incredibly powerful, giving you an essentially complete SQL interface to a database that is created right there on your device.  WebSQL is particulrly useful in partially connected environments, imagine your worker on the edge of a connection scanning barcodes in a warehouse which are uploaded via AJAX to a server for processing.  When the device loses connection (see the network module for how to detect this, http://docs.rhomobile.com/rhoelements/network), rather than stop the user working you can store the barcodes in a WebSQL database and then upload them when the device re-establishes connection.

 

Event Attendee Tracker 3.png

 

So now whenever we scan a barcode we'll add the delegate to a Web SQL database and display the updated contents of that database on the screen.

 

We need to modify our doScan function we dicussed earlier, rather than display the delegate's name / organisation now we'll just insert it into the database along with the time they entered:

 

function doScan(scanData) {
          dbInsertScanData(scanData.data, scanData.time);
}

 

Now for the SQL 'nitty gritty', here's the code for creating the database:

 

function dbInit() {
          //  Estimated size of around 5MB
          db = openDatabase('EventTracker', '1.0', 'Attendee Tracker', 5000000); 
          db.transaction(function(tx)
          {
                    tx.executeSql("CREATE TABLE sessionAttendees (sessionId TEXT,scanData TEXT,scanTime TEXT)", [],
                    function(tx) {},
                    onError);
          });}

 

A few things to point out here:

1) We create the database with a size of 5MB, this seems to be the industry standard and if you want to specify a value greater than 5000000 here you'll need to also modify your config.xml to increase the size WebKit allocates for each database.

2) The line "CREATE TABLE sessionAttendees (sessionId TEXT,scanData TEXT,scanTime TEXT)" is standard SQL, you could run that against any database engine

3) Each transaction takes two anonymous Javascript functions, the first is executed on success and the second is executed if the transaction failed.  In this example we do nothing on success and we have a standard error handler for any errors.

 

The code for inserting the scanned data into the database looks like this:

 

function dbInsertScanData( scanData, checkInTime) {
          sessionId = localStorage.getItem('sID');
          db.transaction(
                    function(tx) {
          tx.executeSql("INSERT INTO sessionAttendees ( sessionId,scanData,scanTime) VALUES (?,?,?)", 
[sessionId, scanData,checkInTime],
                              function(tx, result) {
                                        onAddAttendee();  // as Local Storage
                                        fnDbLoadData(sessionId);
                              },
                              onError);
                    }
  );
}

 

Hopefully it should be easy to follow, again the SQL is fairly standard, this example showing the INSERT syntax.  Notice that I call fnDbLoadData after each scan, this ensures the latest database data is read and displayed on the page.  The code for this is shown below:

 

function fnDbLoadData(sessionId) 
{
          db.transaction(function(tx) {
                    tx.executeSql("SELECT sessionId, scanData, scanTime 
                                        FROM sessionAttendees WHERE sessionId=? 
                                        ORDER BY scanTime DESC", [sessionId], function(tx, result) {
                              for (var i = 0, item = null; i < result.rows.length; i++) {
                                        //  Add Rows to the HTML
                                          //  record = result.rows.item(i);
                                        //  scanTime = record['scanTime'];
                              } 
                    }
          }
}

 

Well, this isn't the full code, it's been edited for brevity and this isn't a tutorial on processing recordsets returned from DBMS transactions, the way you do this is common with every other language you have used.

 

Again for the full code listing just take a look at "EAT-3.zip"

 

It's beyond the scope of this blog to discuss the full WebSQL syntax.  If you do a google search for 'WebSQL' you'll find a number of hits which I won't link to here as they're not authoritative.  I would suggest searching wider afield than the W3C spec, that doesn't contain many examples.

 

4) Adding a battery icon

 

OK, so we're doing good, we're scanning barcodes as people arrive, greeting them and keeping a detailed log of who is late for each session so we can tell their managers... but all this is for nothing if our device's battery dies as we're half way through the conference!

 

To avoid our users having running out of juice we'll display a battery icon on the page so they know when to charge, here's the code for doing this in Javascript:

 

function showBattery()
{
          battery.visibility = 'visible';
          battery.left = 210;
          battery.top = 9;
          battery.color = '#0373BD';
          battery.layout = 'up';
}

 

If you want to see the documentation for the battery module then head over to http://docs.rhomobile.com/rhoelements/battery, you'll see this example shows the battery indicator around the center of a VGA screen, near the top.  Those readers who can interpret hex colours will also see the battery indicator will be a pastel shade of blue.

 

Event Attendee Tracker 4.png

 

You can see the updated application at "EAT-4.zip", though it's only a two line change from "EAT-3.zip" to uncomment the call to showBattery() on page load.

 

That pretty much covers the Event Attendee application so have a play and leave a comment below if you feel like it. I covered more than just this application in my presentation including application cache and cross platform considerations so watch the whole recording when it's posted if you want to learn more.

 

Here's the link to the slides again: https://launchpad.motorolasolutions.com/appforum/presentations/rhomobile/Adding%20Device%20Capabilities%20and%20HTML5%20Features%20to%20your%20Application.pdf

Overview

 

Speaking with many of our customers one common question I get asked all the time is "how can we extend the functionality of our RhoElements applications with native code" and one way to do this is by writing an NPAPI plugin.

 

NPAPI (Netscape Plugin API) is an API designed to allow browsers to call native code; It's been around for quite a while (hence the 'Netscape' in the name) but the simplicity of the interface has allowed for its longevity.  RhoElements implements NPRuntime to allow you to write scriptable plugins and this blog post will guide you through an example to get you started.

 

Note this blog is an example of how to write an NPAPI, it should not be considered absolute best practise as for reasons of clarity I have omitted full error handling and there may be more efficient ways to achieve the same result.

 

Prerequisites

 

  • Although NPAPI worked with the first release of RhoElements there have been several bug fixes since then and you are advised to use RhoElements version 1.0.3 as a minimum.
  • Currently NPAPI is only supported in RhoElements on Windows Mobile and Windows CE devices however we will be extending this functionality to Android in the future.
  • Your NPAPI will only be found by RhoElements if it has been copied to the NPAPI Directory, as defined in your RhoElements configuration file.

 

The Goal

 

We are going to create a "Sensor" plugin which will interface with a series of hardware sensors, in reality we will stub out the hardware interface but it shows how the example could work in a real world scenario.

 

final.png

The above image shows our RhoElements application running, using NPAPI to interface with both a temperature and pressure sensor, it works as follows:

  • User presses 'Create' to instantiate a sensor of the desired type (temperature or pressure).  This will create a new Javascript object.
  • User selects the checkbox to start the desired sensor(s).  This will call a method on the javascript object representing that sensor.
  • Every 3 seconds (default) the sensor will report its reading in the message window at the bottom of the display
  • The user can optionally change the poll interval to 1 second or retrieve the current value instantly

 

What is the Javascript doing?

 

First we will take a look at the Javascript behind the page above before moving onto the C++ code of the NPAPI.

 

Referencing the NPAPI

 

Out of the box RhoElements does not know about the Sensor NPAPI we are about to create (how could it?!) so we need to let the current page know that we are going to refer to an external plugin.

 

<embed id="embed1" type="application/x-motorolasolutions-mysensor" hidden=true> </embed>

 

The above line of HTML code will be parsed by the RhoElements browser which will then look in its plugin directory to locate the appropriate NPAPI.  The NPAPI Directory is defined in your RhoElements configuration so ensure you have copied the DLL to the appropriate location.  By default this location is \Program Files\RhoElements\NPAPI on Windows Mobile and CE.

 

Object construction

 

Pressing the button to create either a temperature or a pressure sensor will call the following Javascript:

function fnCreateObject(whichObj)
{
          if (whichObj == 'temperature')
                    if (tempObj == null)
                    {
                              tempObj = new MySensor();
                              tempObj.sensorType = 'temperature';
                    }
                    else
                              alert('Temperature sensor already created');
          else if (whichObj == 'pressure')
                    if (pressureObj == null)
                    {
                              pressureObj = new MySensor();
                              pressureObj.sensorType = 'pressure';
                    }
                    else
                              alert('Pressure sensor already created');
}

 

MySensor is defined by our NPAPI as a constructable object, so we are able to create objects of the type exported by the plugin.  Once we have created the object we set the 'sensorType' property to give it some state.

 

Starting the sensors

 

'Starting' the sensors will instruct the sensors to begin polling their hardware interfaces and reporting the current value (be it temperature or pressure).  The following javascript starts the sensors monitoring with some additional error handing:

function fnMonitorSensor(whichSensor, isChecked)
{
          if (whichSensor == 'temperature')
          {
                    if (tempObj == null)
                    {
                              alert('You have not Created the Sensor');
                              theForm.cb_tempSensor.checked = false;
                    }
                    else
                    {
                              tempObj.monitor(isChecked);
                    }
          }
          else if (whichSensor == 'pressure')
          {
                    if (pressureObj == null)
                    {
                              alert('You have not Created the Sensor');
                              theForm.cb_pressureSensor.checked = false;
                    }
                    else
                    {
                              pressureObj.monitor(isChecked);
                    }
          }
}

 

The key code is on lines 12 and 24 which calls a method on the javascript object to start or stop sensor monitoring.  The objects are defined as global in the javascript file for simplicity.

 

Other Javascript Functions

 

The code extracts above show how we are creating a new Javascript object, setting a property and invoking a method on it.  The other functionality exposed by MySensor is accessed in a very similar way, there is a property representing the poll interval which can be set using the radio buttons for each sensor and another property for the current sensor value, which is retrieved in the same way you would retrieve any Javascript variable:

 

addSensorOutput('Current Temp: ' + tempObj.currentValue + ' Kelvin');

 

Interaction with the page

 

In our example we require the NPAPI to be able to interact with the web page, so it can write a message to the information box at the bottom of the page whenever the poll interval expires or we ask for the current value.  This is achieved by having the NPAPI invoke a javascript function on the page which I have called 'addSensorOutput'

 

function addSensorOutput(newOutput)
{
          //alert(newOutput);
          document.getElementById("sensorOutput").value = newOutput + "\n" + document.getElementById("sensorOutput").value;
          //sensorDiv.innerHTML = newOutput + "<br>" + sensorDiv.innerHTML;
}

 

The javascript can do whatever you like but in the case above I populate the text area.  The NPAPI will invoke this Javascript function directly by locating it in the DOM so it is important not to change the name of the function.

 

Please see the source code for the sample page 'MySensor.htm' to better understand how it works.

 

The C++ code of the NPAPI

 

A visual studio project for building this sample NPAPI is attached to this blog and can be used as the starting point for your own NPAPI if desired.  You will need Visual Studio 2008 and the Windows Mobile 5.0 platform SDK in order to compile it.  I would recommend studying the code to best understand exactly what is going on in NPAPI (along with reading the NPAPI Plugin development document attached to this blog) but to get you going I will pick out the important bits of code here.

 

Declaring our plugin type

 

You may recall we used an embed tag on our HTML page (MySensor.htm) to embed a plugin of type 'application/x-motorolasolutions-mysensor' on the page.  In common with all supporting browsers RhoElements knows which types are implemented by plugins by querying the MIME Types exposed in the resource file (.rc).  Our 'MySensor' resource exposes the MIME type as follows:

 

VALUE "MIMEType", "application/x-motorolasolutions-mysensor"

 

If you have multiple MIME types supported by a plugin you can separate them with a ';'.

 

When the browser comes across an embed tag the NPP_New function is called (which is part of the NPAPI framework).  The MySensor NPP_New creates a new 'CMySensorPlugin' which is a class I have defined myself.

 

NPError NPP_New(NPMIMEType pluginType,
                NPP instance,
                uint16_t mode,
                int16_t argc,
                char* argn[],
                char* argv[],
                NPSavedData* saved)
{   
  if(instance == NULL)
    return NPERR_INVALID_INSTANCE_ERROR;

  NPError rv = NPERR_NO_ERROR;

  if (strcmp(pluginType, "application/x-motorolasolutions-mysensor") == 0)
  {
            CMySensorPlugin * pMySensorPlugin = new CMySensorPlugin(instance);
            if(pMySensorPlugin == NULL)
                    return NPERR_OUT_OF_MEMORY_ERROR;

            CPluginInfo* pluginInfoObject = new CPluginInfo();
                    pluginInfoObject->iPluginType = 0;
                    pluginInfoObject->pPlugin = (void *)pMySensorPlugin;
            instance->pdata = (void *)pluginInfoObject;
  }
  return rv;
}

 

The constructor for CMySensorPlugin is as follows:

 

CMySensorPlugin::CMySensorPlugin(NPP pNPInstance) :
  m_pNPInstance(pNPInstance),
  m_pNPStream(NULL),
  m_bInitialized(FALSE),
  m_pScriptableObject(NULL)
{
          // Must initialise this before getting NPNVPluginElementNPObject, as it'll
          // call back into our GetValue method and require a valid plugin.
          pNPInstance->pdata = this;

    // Say that we're a windowless plugin.
    NPN_SetValue(m_pNPInstance, NPPVpluginWindowBool, false);

          //  Instantiate the values of the methods / properties we possess
          sMonitor_id = NPN_GetStringIdentifier("monitor");
          sPollInterval_id = NPN_GetStringIdentifier("pollInterval");
          sCurrentValue_id = NPN_GetStringIdentifier("currentValue");
          sSensorType_id = NPN_GetStringIdentifier("sensorType");

          //  Export onto the webpage the JS object 'MySensor'.  This enables us
          //  to say var myObj = new MySensor();
          NPObject *sWindowObj;
          NPN_GetValue(m_pNPInstance, NPNVWindowNPObject, &sWindowObj);
          NPObject *mySensorObject =NPN_CreateObject(m_pNPInstance,GET_NPOBJECT_CLASS(MySensorPluginObject));
          NPVariant v;
          OBJECT_TO_NPVARIANT(mySensorObject, v);
          NPIdentifier n = NPN_GetStringIdentifier("MySensor");
          NPN_SetProperty(m_pNPInstance, sWindowObj, n, &v);
          NPN_ReleaseObject(mySensorObject);
          NPN_ReleaseObject(sWindowObj);
}

 

Pay particular attention to line 24 which is creating an instance of 'CMySensorPluginObject' and adding it to the page at line 28;  this is a 'Scriptable' object, meaning you can call it from Javascript.  The scriptable object is added to the page as 'MySensor' allowing you to create new MySensor()'s in your Javascript.  The 'MySensorPluginObject' is also a class I have defined myself, inheriting from the 'ScriptablePluginObjectBase' which is part of the NPAPI framework.

 

The constructor also instantiates the names for our parameters and methods in lines 17-20.  MySensor has a single method, 'monitor' and 3 parameters.

 

Object Construction

 

Let us now look at what happens in the NPAPI when we call the javascript line:

tempObj = new MySensor();

 

What's going on here?  We already exported a 'MySensor' (MySensorPluginObject) to the page as part of the CMySensorPlugin constructor (above)... what we now want to happen is for tempObj to be another instance of MySensor (another MySensorPluginObject object).

 

Before creating MySensorPluginObjects it is first necessary to invoke the NPAPI Macro to declare it, as below:

 

DECLARE_NPOBJECT_CLASS_WITH_BASE(MySensorPluginObject,
                                 AllocateMySensorPluginObject);

 

Notice the Macro takes function which will be called whenever a new sensor object is created, AllocateMySensorPluginObject, this is where you can perform any creation and initialisation of the object.

 

Creating a new MySensorPlugin object via Javascript will cause its 'Construct' method to be called, shown below.

bool MySensorPluginObject::Construct(const NPVariant *args, uint32_t argCount,
                                     NPVariant *result)
{
          //  Where the JS Object is created, called when we say:
          //  var myObj = new MySensor();
          bool bRetVal = false;
          //  Create Object, expect no arguments
          if (argCount == 0)
          {
                    NPObject* genericObj = NPN_CreateObject(mNpp, GET_NPOBJECT_CLASS(MySensorPluginObject));
                    if (!genericObj)
                              return false;
                    MySensorPluginObject* obj = (MySensorPluginObject*)genericObj;
                    OBJECT_TO_NPVARIANT(genericObj, *result);
                    //  We have a function in our plugin to output text to a text box
                    MessageToUser("Creating Sensor");
                    bRetVal = true;
          }
  return bRetVal;
}

 

All we do in the MySensor example above is to allocate another MySensorPluginObject, just as we did when we first embedded the plugin, and notify the user.  We have now allocated two MySensorPluginObjects, one resident on the page enabling us to say new MySensor() and one which has been assigned to the javascript variable 'tempObj'.

 

Whenever we call NPN_CreateObj the function 'AllocateMySensorPluginObject' will be called, this is because of how we called the DECLARE_NPOBJECT_CLASS_WITH_BASE macro above.

 

The function to allocate a new MySensor looks as follows:

static NPObject * AllocateMySensorPluginObject(NPP npp, NPClass *aClass)
{
          //  Called in response to NPN_CreateObject
          MySensorPluginObject* obj = new MySensorPluginObject(npp);
          //  Setting the default properties of the created object.
          obj->m_iPollInterval = 3000;
          obj->m_iCurrentValue = 0.0;
          obj->m_hStopSensorMonitor = CreateEvent(NULL, FALSE, FALSE, NULL);
          obj->m_iSensorType = -1;

          //  Create a Hidden Window so our sensor thread can re-synchronize back
          //  to the main thread
          obj->hWindow = CreateWindow(L"SensorWindow", NULL, 0, 0, 0, 0, 0, NULL, (HMENU) 0, NULL, NULL);
          if (obj->hWindow == NULL)
          {
                    WNDCLASS wndclass;
                    memset (&wndclass, 0, sizeof wndclass);
                    wndclass.lpfnWndProc = obj->NpapiProc;
                    wndclass.hInstance = NULL;
                    wndclass.lpszClassName = L"SensorWindow";
                    RegisterClass (&wndclass);
                    obj->hWindow = CreateWindow(L"SensorWindow", NULL, 0, 0, 0, 0, 0, NULL, (HMENU) 0, NULL, NULL);
          }
          SetWindowLong(obj->hWindow, GWL_WNDPROC, (DWORD)obj->NpapiProc);
          return obj;
}

 

Notice this function creates a new instance of the scriptable object and returns a pointer to that instance.  To reiterate what was said earlier, MySensorPluginObject inherits from ScriptablePluginObjectBase which in turn inherits from NPObject, this method's return type.

 

AllocateMySensorPluginObject initialises the variables associated with the sensor (in this case the poll interval e.t.c.) and creates a (hidden) window which will be associated with the object.  NPAPI is not thread safe, our sensor will be receiving values on a different thread so this hidden window is required to resynchronize back to the calling thread.

 

Setting a property

 

Now let us look at what happens when you set a javascript property on your scriptable object, as below:

tempObj = new MySensor();
tempObj.sensorType = 'temperature';

 

To backtrack slightly, any scriptable NPAPI object (in our case MySensorPluginObject) should inherit from the ScriptablePluginObjectBase class, doing so provides the necessary functions to make it scriptable.  Of particular note in this article are:

  • Construct - when new objects are created in Javascript, as illustrated above.
  • HasProperty - To determine whether an object has a specific property
  • HasMethod - To determine whether an object has a specific method
  • GetProperty - To return the value of a property
  • SetProperty - To set the value of a property
  • Invoke - To invoke an object's method.

 

We have overridden all these methods in our implementation of MySensorPluginObject to customise the behaviour for our MySensor JavaScript object.

 

When we call tempObj.sensorType = 'temperature'; the first thing the framework does is to determine whether this property exists, by calling the HasProperty function:

bool MySensorPluginObject::HasProperty(NPIdentifier name)
{
          //  Called by the plugin framework to query whether a JS object
          //  has a specified property, we have three properties.
          return (name == sPollInterval_id ||
                              name == sCurrentValue_id ||
                              name == sSensorType_id);
}

 

Since sSensorType_id holds 'temperature' this function will return true.  A couple of notes here:

  • This comparison is case sensitive (as is Javascript).  To make the comparisons case insensitive you could do it yourself here (e.g. by converting both parameters to lower case, see 'Invoke' later)
  • HasMethod will also be called, even when trying to set / get a property, for this reason you can not have methods and properties of the same name in NPAPI.

 

The framework is clever enough at this stage to realise you are setting a property and therefore calls 'SetProperty' with the value to set.  GetProperty would be called at this stage if you had called var myVal = tempObj.sensorType.

bool MySensorPluginObject::SetProperty(NPIdentifier name, const NPVariant *value)
{
          //  Sets the specified property to the specified value.
          bool bRetVal = false;
          if (name == sSensorType_id)
          {
                    //  mySensor.sensorType = 'temperature';
                    char szSensor[1024];
                    memset(szSensor, 0, 1024);
                    sprintf(szSensor, NPVARIANT_TO_STRING(*value).UTF8Characters);
                    if (strcmp(szSensor, "temperature") == 0)
                              this->m_iSensorType = 0;
                    else if (strcmp(szSensor, "pressure") == 0)
                              this->m_iSensorType = 1; 
                    bRetVal = true;
          }
          else if (name == sPollInterval_id)
          {
                    //  mySensor.pollInterval = [value];
                    this->m_iPollInterval = (int)NPVARIANT_TO_DOUBLE(*value); 
                    bRetVal = true;
          }
          return bRetVal;
}

The sensor type (received as an NPVariant and processed as a string) just sets a member variable in the sensor object (m_iSensorType) which is used later to determine whether we're reading Kelvin or Pascals.  SetProperty is common for all properties, setting the poll interval will again set a member variable but setting the 'currentValue' property will have no effect.  Remember our MySensor object has a 'currentValue' property but by design we do not allow users to set this.

 

Retrieving a Property

 

For completeness the code for retrieving a property is also included here, it is similar to setting a property in that first 'HasProperty' is called but the context of the call will cause the framework to return the property's value:

bool MySensorPluginObject::GetProperty(NPIdentifier name, NPVariant *result)
{
          //  Retrieve the value of a property.  *result is an out parameter
          //  into which we should store the value
          bool bReturnVal = false;
          VOID_TO_NPVARIANT(*result); 

          if (name == sCurrentValue_id)
          {
                    //  Called by: var sensorVal = mySensor.currentValue;
                    //  Return the current value to the web page.
                    DOUBLE_TO_NPVARIANT(this->m_iCurrentValue, *result);
                    bReturnVal = true;
          }
          if (!bReturnVal)
                    VOID_TO_NPVARIANT(*result);
          return bReturnVal;
}

 

Only the sensor's current value is retrievable, making the other properties write only.  The value is returned in the *result pointer which is an NPVariant, the NPAPI framework provides a number of macros for converting to NPVariants, in this case we are returning a double value.

 

Starting the Sensor

 

Now lets look what happens when we call:

tempObj.monitor(isChecked);

 

Our only method provided by the sensors is 'monitor' which takes a boolean, true if the sensors should be started and false if they should be stopped.  Similar to properties when the framework encounters an object method call it will call the 'HasMethod' function to determine if the Javascript object supports that method, our HasMethod is as follows:

bool MySensorPluginObject::HasMethod(NPIdentifier name)
{
          //  Called by the plugin framework to query whether an object
          //  has a specified method, we only have one method, 'monitor()'
          return (name == sMonitor_id);
}

 

After HasMethod returns true the MySensorPluginObject 'Invoke' method is called, as below:

bool MySensorPluginObject::Invoke(NPIdentifier name, const NPVariant *args,
                               uint32_t argCount, NPVariant *result)
{
          //  Called when a method is called on an object
          bool bReturnVal = false;
          VOID_TO_NPVARIANT(*result);
          //  Convert to lower case to make our methods case insensitive
          char* szNameCmp = _strlwr(NPN_UTF8FromIdentifier(name));
          NPIdentifier methodName =  NPN_GetStringIdentifier(szNameCmp);
          NPN_MemFree(szNameCmp);
          //  mySensor.monitor(bool)
          if (methodName == sMonitor_id)
          {
                    //  Expect one argument which is a boolean (start / stop)
                    if (argCount == 1 && NPVARIANT_IS_BOOLEAN(args[0]))
                    {
                              if (NPVARIANT_TO_BOOLEAN(args[0]))
                              {
                                        //  mySensor.monitor(true);
                                        //  Create a thread to monitor the sensor 
                                        CloseHandle(CreateThread(NULL, 0,
                                        (LPTHREAD_START_ROUTINE)SensorMonitorThread, this, 0, NULL));
                              }
                              else
                              {
                                        //  mySensor.monitor(false);
                                        //  Stop monitoring the sensor
                                        SetEvent(m_hStopSensorMonitor);
                              }
                              //  Monitor has no return value
                              VOID_TO_NPVARIANT(*result);
                              bReturnVal = true;
                    }
          }
          if (!bReturnVal)
                    VOID_TO_NPVARIANT(*result);
          return bReturnVal;
}

 

Note that this function demonstrates how to make method names case insensitive.  The functionality is fairly self explanatory: provided the method name is 'monitor' and there is a single boolean parameter then we either start or stop a separate thread (SensorMonitorThread) to read from the sensor.

 

For completeness the code for the monitoring thread is below (though this code is not specific to NPAPI)

 

DWORD MySensorPluginObject::SensorMonitorThread(LPVOID lpParameter)
{
          MySensorPluginObject* pSensor = (MySensorPluginObject*)lpParameter;
          bool exitThread = false;
          DWORD dwEvent;
          HANDLE hWaitHandles[1];
          hWaitHandles[0] = pSensor->m_hStopSensorMonitor;
          DEBUGMSG(TRUE, (L"Sensor Monitor Thread Starting\n"));

          while (true)
          {
                    //  Wait for an exit event (indicating stop the thread) or timeout
                    //  Note if we change the timeout value we have to wait until the next cycle
                    //  before the new timeout value is read... this is just an example.
                    dwEvent = WaitForMultipleObjects(
                              1,
                              hWaitHandles,
                              FALSE,
                              pSensor->m_iPollInterval);
                    switch (dwEvent)
                    {
                    case WAIT_OBJECT_0:
                              {
                                        goto _exitThread;
                              }
                    case WAIT_TIMEOUT:
                              {
                                        //  Create a fake sensor reading to send to the page
                                        char szSensorReading[512];
                                        if (pSensor->m_iSensorType == 0)
                                        {
                                                  float currentValue = (float)((rand() % 100 + 10000) / 100.0);
                                                  //  truncate the output
                                                  pSensor->m_iCurrentValue = (int)(currentValue * 100);
                                                  sprintf(szSensorReading, "Sensor Reading: %.02f Kelvin", currentValue);
                                        }
                                        else
                                        {
                                                  float currentValue = (float)((rand() % 100 + 1000) / 100.0);
                                                  //  truncate the output
                                                  pSensor->m_iCurrentValue = (int)(currentValue * 100);
                                                  sprintf(szSensorReading, "Sensor Reading: %.02f Pascals", currentValue);
                                        }
                                        //  Contention here if timeout is too small but this is just a demo
                                        //  Resynchronise with the main thread.
                                        SendMessage(pSensor->hWindow, WM_USER + 1, (WPARAM)pSensor, (LPARAM)szSensorReading);
                              }
                    }  //  End Switch
          }          //  End While !exitThread
_exitThread:
          DEBUGMSG(TRUE, (L"Sensor Monitor Thread Exiting\n"));
          return 0;
}

 

 

Notes about the monitoring thread:

  • Changing the poll interval will only take effect after the current poll interval has expired (this was to keep the example simple)
  • rand() is used in place of real sensors and we store the value in m_iCurrentValue, this is the value retrieved if we say myVal = tempObj.currentValue;  I have cheated a bit and cast m_iCurrentValue to an integer to make it easier to truncate to 2 decimal places.
  • NPAPI is not thread safe, in order to synchronize with the calling thread we send a message to the hidden window associated with this JavaScript object, which was created when the JS object was created.

 

Interacting with the DOM from NPAPI

 

Finally, we want the NPAPI to be able to communicate with the page's DOM, to allow it to call a javascript function to notify the user when the sensor changes.  This is achieved with the method below:

void MySensorPluginObject::MessageToUser(char* szMessage)
{
          NPVariant functionval;
          NPVariant rval;
          NPObject *sWindowObj;
          NPN_GetValue(mNpp, NPNVWindowNPObject, &sWindowObj);
          //  Populate 'functionval' with the name of our function
          NPN_GetProperty(mNpp, sWindowObj, NPN_GetStringIdentifier("addSensorOutput"), &functionval);
          NPVariant arg;
          if (NPVARIANT_TO_OBJECT(functionval) == 0)
                    return;
          //  Create the argument to call 'addSensorOutput' with
          char szSourceMessage[1024];
          if (m_iSensorType == 0)
                    sprintf(szSourceMessage, "Temperature: %s", szMessage);
          else if (m_iSensorType == 1)
                    sprintf(szSourceMessage, "Pressure: %s", szMessage);
          else
                    sprintf(szSourceMessage, "%s", szMessage);
          //  Add the string argument to our javascript function to an argument, 'arg'
          STRINGZ_TO_NPVARIANT(szSourceMessage, arg);
          //  Invoke the Javascript function on the page
          NPN_InvokeDefault(mNpp, NPVARIANT_TO_OBJECT(functionval), &arg, 1,
                                                            &rval);
          //  Clean up allocated memory
          NPN_ReleaseVariantValue(&functionval);
          NPN_ReleaseVariantValue(&rval);
          NPN_ReleaseObject(sWindowObj);
}

 

addSensorOutput is a Javascript function on the current page.  From a handle to the window (sWindowObj) we retrieve the Javascript function (functionval) and then call that function (NPN_InvokeDefault) with the appropriate argument which will be a string.

 

This blog has now shown two ways to interact with the page:

  • The CMySensorPlugin constructor used the m_pNPInstance variable to interact with the page
  • The 'MessageToUser method of 'MySensorPluginObject' used the mNpp variable, provided automatically by the framework since we are a child of ScriptablePluginObjectBase.

In both these examples m_pNPInstance and mNpp point to the same thing and provide an interface to the page.

 

 

Next Steps

 

What has been covered here is only a very simple NPAPI plugin, obviously the capabilities of NPAPI extend far beyond writing a simple, scriptable object. 

Because the online resources for NPAPI are far from extensive (and often implementation specific) our team have created a document to explain the NPAPI interface in more detail, though I would recommend understanding the sample above before delving deeper into the detail - you can get the document as an attachment to this blog.

I get a lot of questions about how the licensing model for RhoElements works.

 

You can license your RhoElement runtime by visiting https://softwarelicensing.motorolasolutions.com/. The following documentation is taken from https://softwarelicensing.motorolasolutions.com/documentation/index.html, you should bookmark that site as it will always be kept up to date.  Note that since the licensing site is shared between RhoElements and PocketBrowser much of the information below is worded quite generically.

 


 

 

Overview

Accessing the License Site

Changing your Username / Password

Types of Accounts

Licensing Restrictions

Deployment Licenses

End Users

Walkthrough 1: Licensing a Device

Walkthrough 2: Applying for a Deployment License

Overview of the Licensing System

Licensing the Runtime

Cancelling Licenses

Applying for a Deployment License

Resellers

Walkthrough 1: Assigning Licenses to End Users

Overview of the Licensing System

Assigning Licenses to End Users

Overview


The Motorola Solutions Software licensing site is used to manage your licenses for the following software products:
- Motorola RhoElements, http://www.motorolasolutions.com/rhoelements.
- Motorola PocketBrowser, http://www.motorola.com/pocketbrowser.
Note that it is not currently possible to license both RhoElements and PocketBrowser on the same device.

 

Accessing the Licensing Site


To license your software you will first need to log in to the Software licensing site, http://softwarelicensing.motorolasolutions.com.  You will have received an email when your account was created detailing your log-in instructions, please check your spam folder as it may have incorrectly be categorised as such.  If you have forgotten your password there is a link to reset it, provided you know your username which will be the email address given when your account was created.  You must access the site using Internet Explorer or an extension / plug-in which mimics Internet Explorer if your browser supports that.

Once logged into the licensing site the header will appear similar to the below:


Example header shown on all pages of the Software licensing site

Information about your account is shown on the right side of the header, the username and company in this case are darryncampbell@motorolasolutions.com and PB Testing.  The type of account is an End User account. 

End users are presented with up to three 'tabs': "Orders", "Licenses" and potentially "Deployment Licenses" shown at the bottom of the header and explained further in the following sections.

 

You can search in the currently displayed 'tab' by entering your term in the search box, the filtered results will then be shown in the accordions.

 

Changing your Username and Password


Because the initially generated password is not very memorable the first thing you will want to do when logging into the site is to change your password.  Clicking on the (edit) next to your username in the header will bring up the password change tab which defaults to an expanded 'Edit Username' accordion, use this field to change the username which you use to access the licensing site.  Note that when changing your username you must choose a valid email address as this will also serve as the mailing address to which all licensing site emails will be sent.

 


Username / Password change screen with 'Edit Username' accordion expanded

To change your password click on the 'Change Password' heading to expand the accordion and from there specify your new password.

 

Types of Accounts


There are two main types of accounts on the licensing site, Resellers and End Users.  Reseller accounts are designed for companies selling Software licenses and provide the ability to transfer licenses to other (End User) accounts but do not allow licenses to be assigned to devices.  End User accounts are designed for individuals or companies to manage their licenses and provide the ability to assign runtime licenses to their devices as well as cancel licenses and set up deployment licenses.

If you believe your account is not of the correct type then please contact the Motorola Support Desk at http://www.symbol.com/services/contactsupport.

 

Licensing Restrictions


Different versions of software require different licenses and users are not automatically entitled to free upgrades.  The table below shows which versions of PocketBrowser and RhoElements are compatible with which license types:

 

Product Name
RhoElements Versions
RhoElements-1.0Any version in the form 1.x
Product Name
PocketBrowser Versions
SPB 1.x.xAny version in the form 1.x
SPB 2.0 for Windows CE
SPB 2.0 for Windows Mobile
Any version in the form 2.0.x
MPB 2.1/2.2 for Windows CE
MPB 2.1/2.2 for Windows Mobile
Any version in the form 2.1.x;
2.2.0 or 2.2.1
MPB 2.22 for Windows CE & Windows MobileVersion 2.2.2
MPB 2.2 SW Maintenance UpgradeVersion 2.2.2
MPB 3.0 for Windows CE & Windows MobileAny version in the form 3.0.x
RhoElements Licenses / Versions PocketBrowser Licenses / Versions

Tables showing which versions of software apply to which license types

Customers who have purchased a Software Support Contract ARE entitled to free software upgrades in line with the terms of the agreement.  Please contact the Motorola Support Desk at http://www.symbol.com/services/contactsupport if you wish to apply for an upgrade.

Previous versions of all software are available from Support Central (http://support.symbol.com).

 

You can determine the version of software you are running as it is shown on the splash screen when the software starts up on the device.  If the software is currently unlicensed it will also appear on the nag screen which is displayed every 5 minutes.

 

Deployment Licenses


Sometimes known as corporate licenses a deployment license provides the user with a way of licensing your software on multiple devices using a single key.  Rather than licensing each device in your infrastructure individually by keying in the UUID you can apply to receive a single registration key which can be applied to multiple devices by simply scanning a barcode or adding a registry setting.

Deployment licenses are a legal agreement entered into between Motorola and the end user, as such they can only be applied for by the end user and not their reseller.  For more details on applying for a deployment license see 'End Users: Applying for a Deployment License'.

End users will automatically be given the option to apply for a deployment license when they have purchased more than 50 licenses but users still must purchase individual licenses for each terminal being licensed.  A deployment agreement does not permit users to license more terminals than they have purchased licenses for.  If your company has multiple software licensing accounts whose total licenses add up to more than 50, but individually each account contains less than 50 licenses you may wish to merge the accounts, to do this contact the Motorola Support Desk at http://www.symbol.com/services/contactsupport .

 

End Users


End User Walkthrough 1: Licensing a Device


This is a simplified diagram showing the steps for an end user to assign a license to a single device.  For a more detailed description including screen shots from the licensing site then please see the 'End Users: Licensing the Runtime' section.

 


Diagram showing stages for an End User to license a single device (click it to enlarge)

End User Walkthrough 2: Applying for a Deployment License


This is a simplified diagram showing the steps for an end user to apply for a deployment license.  For a more detailed description including screen shots from the licensing site then please see the 'End Users: Applying for a Deployment License' section.

 


Diagram showing stages for an End user to apply for a Deployment License (click it to enlarge)

End Users: Overview of the Licensing System


When an End User logs into the licensing system they are given up to three 'tabs' and the Orders tab is shown by default.

 

 

End Users: Orders Tab

 


The Orders tab as seen by an End User (click it to enlarge)

The orders tab presented to the End User has up to two accordion panes, "Existing Orders" and "Deployment License Applications".

Existing Orders.  For the majority of users the orders tab will only show the 'Existing Orders' accordion.  Existing Orders displays the transactions sold to the end user by their reseller and the order number will therefore most often start with a 'T'.  If you look at the above example you will see the top entry is T536428 which was transferred in the 'Resellers: Assigning Licenses to End Users' above.  To see the licenses contained in each order then click 'View Order' in the same row as the order; this will also allow you to see how many of the licenses in the order have been allocated to devices.

 

Deployment License Applications.  If you have over 50 licenses in your account you will also see the 'Deployment License Applications' accordion, which will be colored Red if you are entitled to a deployment license but have not yet applied for it.  For more details on applying for a deployment license see the End Users: Applying for a Deployment License section below.

Note that the 'Deployment License Applications' accordion, if visible, will be the default accordion expanded when an end user logs in to the site and is also duplicated under the 'Licenses' Tab.

 

End Users: Licenses Tab

 


The Licenses tab as seen by an End User (click it to enlarge)

The Licenses tab presented to the End User has up to four accordion panes, "Assign a License", "Assigned Licenses", "License Cancellation Requests" and "Deployment License Applications"

Assign a License.

 

For most End Users this will be the most important feature of the licensing site.

This screen shows your pool of licenses available to license to devices.  Each license type will show the number of free licenses available and to assign these to devices follow the instructions in the End Users: Licensing the Runtime section.  If you have a deployment license for a particular license type you will be unable to assign additional licenses individually and therefore the 'Total Unallocated' column shows the number of devices you are legally entitled to register via the deployment license.

Assigned Licenses.

 

 


The expanded 'Assigned Licenses' Accordion (click it to enlarge)

The assigned licenses accordion shows the licenses you have assigned to individual devices, it will not show devices licensed assigned via deployment license.  Each license shows the license ID as well as details you entered when assigning the license such as serial number and group information; the 'License ID' associated with each license is the easiest way of identifying licenses when contacting Motorola customer support.

 

Clicking 'View Licenses' to the right of any license will show the barcodes used to register the software on the device or allow you to download the registry settings, use this if you did not register the device when you initially assigned the license or wish to re-register the device after a complete wipe of permanent storage.  You can also print or download the registry settings using the two icons on the far right of the table row.

 

Clicking 'Request Cancellation' will begin the license cancellation process, covered in more detail in the End Users: Cancelling Licenses section.  Once you have cancelled a license you will no longer be able to view it but it will still be shown in the 'Assigned Licenses' table, as illustrated above.  Even though it still shows in the table the cancelled license will have been returned to the user's pool of unused licenses.

Note that if you have a deployment agreement for a particular license type then assigned licenses of that type will not show in the 'Assigned Licenses' accordion even if they were previously licensed individually.

 

License Cancellation.

 

The license cancellation accordion pane shows the licenses which the End User has requested be cancelled.  The process for cancelling licenses is explained in the End Users: Cancelling Licenses section.

 


The expanded 'Assigned Licenses' Accordion (click it to enlarge)

The table shows the progress of each cancellation request.  When you initially make the request the status will be set to 'Awaiting Response' which means it is waiting for a representative from the Software Request Administrator team processes your request, you can view the status of your request by clicking on the 'View Request' link.

 

Deployment License Applications.

 

If you have over 50 licenses in your account you will also see the 'Deployment License Applications' accordion, which will be colored Red if you are entitled to a deployment license but have not yet applied for it.  For more details on applying for a deployment license see the End Users: Applying for a Deployment License section.

 

Note that the 'Deployment License Applications' accordion, if visible, is also duplicated under the 'Orders' Tab.

 

End Users: Deployment Licenses Tab


 


The Deployment Licenses tab as seen by an End User (click it to enlarge)

Once you have followed the steps described at End Users: Applying for a Deployment License and successfully obtained your deployment license you will see the 'Deployment Licenses' tab in the header which can be used to manage your deployment licenses.

Clicking 'View License' will bring up the deployment license barcode which can be scanned, either on screen using an imager barcode reader or printed off to be scanned by a laser scanner.  Registry settings can also be downloaded from this dialog to be included in your device build or deployment procedure.

 

The quantity column shows the number of licenses you have purchased for a particular license type, under the terms of the deployment license agreement you can not license more than this number of devices without purchasing additional licenses.  Clicking 'View Agreement' will bring up a dialog similar to that shown below:

 


Example of a Deployment License Agreement screen (click it to enlarge)

The deployment license agreement is a legal agreement between the end user and Motorola Solutions stating how many devices can be licensed, which versions of software can be licensed and the order numbers thereof.

 

Note the deployment license agreement above does not correspond to the 'Deployment Licenses Tab' directly above it, the latter is the result of applying for the deployment license described at End Users: Applying for a Deployment License.

 

End Users: Licensing the Runtime

Most End Users will only use the licensing site to license their devices individually, to do this go to the 'Licenses' tab and click 'Assign License' against the type and version of software you wish to assign (See End Users: Licenses Tab).

 


Assigning a License to a Device (click it to enlarge)

You will see the dialog box shown above.

 

You can find UUID Part 1, UUID Part 2 and Checksum by starting the software runtime on your device; these values are shown on the licensing splash screen after you click the screen and press 'Next'.

 


PocketBrowser Licensing screen on device

 


RhoElements Licensing screen on device

A checksum is a way of ensuring you type in the correct values for UUID1 and UUID2, if you receive an error complaining the checksum is not correct then please ensure you have entered the two UUIDs correctly.  Please do not use the UUIDs reported by the Windows Operating system, they may not be the same as those used by the licensing system.

 

It is not essential to give the serial number to license the device, however it is strongly advised to do so.  The serial number can be used to identify the device when contacting support and will be used if the license needs to be cancelled at a later stage.

 

It is recommended you accept the default company display name, again this will aid in identifying the licenses if you need to contact support.  The Group By field is a free text field into which you can enter your own grouping information, eg. you could group 5 licenses to "Arizona Store" and another 4 licenses to "Sales Team".  These groupings will be shown in the 'Assigned Licenses' accordion as well as be search-able via the search box when the 'Licenses Tab' is selected.

 

After you have entered the required information press 'Submit' to be shown the 'View License' dialog:

 


The View License Dialog (click it to enlarge)

You can now license your device in one of four ways:

 

1. If your device has an imager scanner you can scan the barcodes directly off your monitor.  On your device press 'Next' in the software licensing wizard until you are asked to 'Scan your company barcode', do so and then proceed to also scan the registration barcode.  Your device should now report that it is licensed.  Note in the above example image the company name is given as 'DEMO - NOT FOR RESALE', when viewing your licenses this will be replaced with your company name.
2. Similar to step 1 you can press the 'Print' button on the 'View License' dialog to print the barcodes and scan them with your laser or 2D scanner.
3. When prompted by your device to scan the registration barcodes you can enter the text manually, this is not recommended as the registration code is a hexadecimal key and it is very easy to make mistakes.
4. Pressing the 'Download' button will allow you to download some registry settings, apply these settings to your device to license your software.  Note that this fourth method may, depending on your Operating System, be undone by cold booting your device unless you take precautions to ensure the registry setting persists across cold boots.

 

End Users: Cancelling Licenses

The most common reasons for cancelling a license are:

You have sent your device for repair and in doing so components have been replaced meaning the device's UUID has changed.  The software no longer reports it is licensed on the device.

You made an error when licensing the device, for example you licensed the same device twice or you attempted to license the wrong version of your software.

License cancellations must be approved by a human and therefore will not be automatically and immediately processed online.  Attempting to cancel licenses just to re-use the same license on a different device will not be approved.

To request a license be cancelled select the 'Licenses' tab and expand the 'Assigned Licenses' accordion.

 


Cancelling a License (click it to enlarge)

Locate the license you wish to cancel and select the 'Request Cancellation' link.  You will be presented with the 'Cancel License Request' dialog shown above.  From the drop down select the reason for cancellation and try to provide as much detail as possible, this will enable the request to be processed as quickly as possible.

 

The request administrator will either accept the cancellation request, in which case the license has been cancelled successfully or request more information from the end user; such as device serial numbers, duplicate license IDs or even just 'phone support'.  You will receive an email when the status of the request is updated, if the status is 'License Cancelled' then no further action need be taken.  Once cancelled although the license is still shown under the 'Assigned Licenses' accordion (with status 'License Cancelled') it has returned to your pool of unassigned licenses.  If the status is 'Response Received' then more information is required of the End User, click on 'View Request' to supply additional information, this back and forth request / response will continue until the license has been cancelled.

 

 


Life cycle of a Cancellation Request, shown by clicking 'View Request' (click it to enlarge)

Provided the End User has given sufficient information about the cancellation request it is uncommon for cancellation to take more than a single request / response.  The above screenshot shows the life cycle of an example cancellation request.  

 

End Users: Applying for a Deployment License


When a user has 50 or more software licenses in their account they are entitled to apply for a deployment license (More).  To apply for a deployment license expand the 'Deployment License Applications' accordion under either the 'Orders' or 'Licenses' tabs.  If are entitled to a deployment license but have not yet applied for it then this accordion box will be colored red, if you are not entitled to a deployment license then the accordion will not be present.

 


Applying for a Deployment License Step 1 (click it to enlarge)

To begin the Deployment License application wizard click 'Apply online now' next to the type and version of software for which you wish to apply for a license.

 


Applying for a Deployment License Step 2 (click it to enlarge)

The deployment license is a legal agreement between the End user and Motorola Solutions and as such Motorola Solutionss require a physical address for the end user, if no such address is entered in the database then the wizard will complain at this stage.  Please contact your reseller in the first instance or the Motorola Solutions Support Desk at http://www.symbol.com/services/contactsupport to provide your company address if it is not already in the system.

 

Enter the requested information and press 'Next'.  The email address should be the the same as that shown in the licensing site header, in the top right hand corner of the screen.

 


Applying for a Deployment License Step 3 (click it to enlarge)

Read and accept the deployment license agreement, you can view this agreement later from the 'Deployment Licenses' tab.

 

Once you accept the agreement you will be shown the 'View License' dialog, again this can be displayed later from the 'Deployment Licenses' tab and is nearly identical to the 'View License' dialog described in the End Users: Licensing the Runtime section.  A deployment license can be applied to a device in exactly the same way a traditional license can, i.e. scanning barcodes on the software runtime license screen or applying registry settings to the device but the deployment license will work on multiple devices, not just one device with a specific UUID.

 

Resellers


Reseller Walkthrough 1: Assigning Licenses to End Users


This is a simplified diagram showing the steps for a reseller to assign a license to an end user.  For a more detailed description including screen shots from the licensing site then please see the 'Resellers: Assigning Licenses to End Users' section.

 


Diagram showing stages of Reseller assigning a license to an End User (click it to enlarge)

Resellers: Overview of the Licensing System


When a Reseller logs into the licensing system they are given three 'tabs' and the Orders tab is shown by default

 

Resellers: Orders Tab



The Orders tab as seen by a Reseller (click it to enlarge)

The orders tab presented to the Reseller has three accordion panes, "Create New Transaction", "Existing Orders" and "Transactions".

 

Existing Orders is expanded by default and contains the orders sold to the reseller by Motorola Solutions.  Each order will contain a number of licenses and can be identified by their Order Number (assigned by Motorola Solutions) and their Purchase Order number, to search for a specific order type into the search bar in the page header.  After typing a search term the shown orders will reduce to those filtered by the search term, the number of filtered orders is given in brackets in the accordion header.  Note that entering a search term will filter all three accordions, not just the currently expanded one.

 

Transactions, when expanded, shows a history of past transactions, which are licenses sold by the reseller to an end user.  Transaction Order Numbers will always start with a 'T'.  To resend the transaction to your end user you can click the envelope icon associated with the transaction.  Clicking 'View Transaction' will show which products were included in the order.

 

Create New Transaction, is used to send licenses to end users.  Resellers can only send licenses they have in their pool which is populated by receiving 'Existing Orders'.  The process of sending licenses to end users is explained in more detail in the section, 'Resellers: Assigning Licenses to End Users

 

Resellers: Licenses Tab



The Licenses tab as seen by a Reseller (click it to enlarge)

The licenses tab presented to the Reseller has two accordion panes, "Assigned Licenses" and "License Cancellation Requests".  In most cases both of these panes will be empty, containing no licenses.  The only reason licenses will be present under this tab is if the current Reseller account existed on the old licensing site, before 2008.  In the past it was possible for resellers to assign licenses to devices however under the new licensing site they must transfer their licenses to an end user account (by creating a transaction), as explained in the highlighted yellow text in the screenshot.  The sole purpose of this page is to provide a historical record of license assignments for this reseller.

 

 

Resellers: Customers Tab



The Customers tab as seen by a Reseller (click it to enlarge)

The customers tab shows all the users to whom you, the reseller, have transferred licenses.  From this screen you can edit any of the attributes associated with the customer accounts such as contact name, contact address etc.  A customer account can have multiple users, essentially multiple log-ins to the single customer account enabling multiple users within an organization to manage the end user's licenses.  The customer account is initially created as described below in 'Resellers: Assigning Licenses to End Users' which creates a single user for the account whose email address is the same as the customer account's email.  To create additional users for a customer's account click on 'Create User' in the same row as the customer and enter the user's email address; an email will then be sent to the specified email address informing them of their username and password.  Emails relating to the customer account such as Order Confirmations will be sent to all users of the account rather than just the customer email address.

 

No facilities are given to delete users, merge customer accounts or modify user details.  Please contact the Motorola Solutions Support Desk at http://www.symbol.com/services/contactsupport if you need additional assistance.

 

Resellers: Assigning Licenses to End Users


The most important function of the reseller account is the ability to transfer licenses to end users, this is achieved by selecting the Orders tab and expanding the 'Create New Transaction' Accordion.  From here you need to enter the details of the customer who is to receive the order.

 


The Reseller's Create Transaction Screen (1) (click it to enlarge)

The first step is to enter the email address of the customer to receive the order, if this is an existing customer the Customer Email field will suggest existing accounts matching the input after a short delay, as shown above.  Enter the email address and tab or click to move to the next field.

 


The Reseller's Create Transaction Screen (2) (click it to enlarge)

If the email address is recognized as an existing customer then the rest of the fields will be pre-populated by the existing data.  You can take the opportunity here if needed to edit any of the existing data by clicking on 'Edit Customer Details' which will enable the text fields and click 'Finished Editing' when done.

 

If this is a new customer you will be required to fill in the customer details manually.  It is recommended you fill in as much detail as possible, especially the address as this will be required later if the customer applies for a deployment license.  At minimum you must complete the Customer Email, Customer Name and Country fields and you can complete the rest later via the 'Customers' tab.

"Purchase Order Number" can be used to assign your own order number to the transaction whilst the CC Email field can contain a comma separated list of additional email recipients of the order confirmation, separated by semi colons eg. a.n.other@motorolasolutions.com;recipient@motorolasolutions.comNote that email confirmations are sent to all users under the customer account.


Once you have completed the details of the customer to receive the order you need to populate the order with licenses by clicking on the 'Add Order Items' button, shown below.

 


Adding Licenses to a Transaction (click it to enlarge)

The drop down list of products will only contain the types of licenses the reseller account has in its license pool, selecting a license type from the drop down will show the maximum number of licenses which can be assigned to this end user, this will be the number of licenses of this type in the pool.  Enter the actual number of licenses to include in the transaction in the quantity box and click 'Add Item'.  Repeat these steps to add more than one license type to the order.  Press Confirm and an order confirmation email will be sent to the end user informing them they have received new licenses.

 

The above example has resulted in a single 'MPB 2.2 SW Maintenance Upgrade' license assigned to Order Number: T536428.  We can add additional licenses to this order at a later date by expanding the 'Transactions' accordion, locating the transaction T536428 and pressing 'View Transaction'.

 


Adding Additional Licenses to a Transaction (click it to enlarge)

Items are added to the order in batches, when we first created the transaction the batch 1 licenses were attached.  Using the above screen we can attach batch 2 licenses in exactly the same way.  When you confirm the additional batch another email is sent to the end user informing them of their additional licenses.

 

Filter Blog

By date:
By tag: