Now that Palm Pre SDK is out, what does it take to develop for that phone? - palm-pre

I'd like to know what languages and tools (debuggers, IDEs, profilers, libraries, etc) are available for those wanting to develop for Palm Pre.
Also, I'd like to know what technological restrictions exists that one has to be aware of.

There is a library of JavaScript functions for interacting with the base system (phone-level stuff) and CSS tags, styles, etc, for rendering in the Palm WebOS style.
The SDK comes with a script "palm-generate" which builds a set of configuration files and folder structure. The "palm-package" script builds an isntaller, and nother script, "palm-install" load the installer into the emulator's file system (or a real palm, I believe...mine is on order and should be here Monday!!!).
It is easy enough to find this code, and it isn't at all original, but I thought it would be valuable to give a glimpse here...
Hello World - copied from the tutorial in the palm webos sdk
HelloWorld/appinfo.json - meta-information for this application, including a unique name (domain-style), and the root of the application ("index.html")
{
"id": "com.yourdomain.hello",
"title": "Hello World",
"type": "web",
"main": "index.html",
"icon": "icon.png",
"version": "1.0.0",
"vendor": "Your Company"
}
HelloWorld/sources.json - manifest
[
{
"source": "app\/assistants\/stage-assistant.js"
},
{
"source": "app\/assistants\/first-assistant.js",
"scenes": "first"
}
]
helloWorld/app/assistants/stage-assistant.js - controller for the application. each application consists of a Stage with multiple Scenes; the StageAssistant.setup() method gets control first, providing time to initialize data, connections, etc.
function StageAssistant () {
}
StageAssistant.prototype.setup = function() {
this.controller.pushScene('first');
}
HelloWorld/index.html - the view for the Stage
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPECTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<title>Hello, World!</title>
<script src="/usr/palm/frameworks/mojo/mojo.js" type="text/javascript" x-mojo-version="1"></script>
</head>
<body>
Hello, World! 2:59
</body>
</html>
helloWorld/app/assistants/first-assistant.js - view for the "first" scene
<div id="main" class="palm-hasheader">
<div class="palm-header">Header</div>
<div id="count" class="palm-body-text">count</div>
<div id="MyButton" name="MyButton1" x-mojo-element="Button"></div>
</div>
helloWorld/app/assistants/first-assistant.js - controller for the "first" scene
function FirstAssistant() {
/* this is the creator function for your scene assistant object. It will be passed all the
additional parameters (after the scene name) that were passed to pushScene. The reference
to the scene controller (this.controller) has not be established yet, so any initialization
that needs the scene controller should be done in the setup function below. */
}
FirstAssistant.prototype.handleButtonPress = function(event){
// increment the total and update the display
this.total++;
this.controller.get('count').update(this.total);
}
FirstAssistant.prototype.setup = function() {
/* this function is for setup tasks that have to happen when the scene is first created */
/* use Mojo.View.render to render view templates and add them to the scene, if needed. */
/* setup widgets here */
/* add event handlers to listen to events from widgets */
// set the initial total and display it
this.total=0;
this.controller.get('count').update(this.total);
// a local object for button attributes
this.buttonAttributes = {};
// a local object for button model
this.buttonModel = {
buttonLabel : 'TAP HERE',
buttonClass : '',
disabled : false
};
// set up the button
this.controller.setupWidget("MyButton", this.buttonAttributes, this.buttonModel);
// bind the button to its handler
Mojo.Event.listen(this.controller.get('MyButton'), Mojo.Event.tap, this.handleButtonPress.bind(this));
}
FirstAssistant.prototype.activate = function(event) {
/* put in event handlers here that should only be in effect when this scene is active. For
example, key handlers that are observing the document */
}
FirstAssistant.prototype.deactivate = function(event) {
/* remove any event handlers you added in activate and do any other cleanup that should happen before
this scene is popped or another scene is pushed on top */
}
FirstAssistant.prototype.cleanup = function(event) {
/* this function should do any cleanup needed before the scene is destroyed as
a result of being popped off the scene stack */
this.controller.stopListening(this.controller.get('MyButton'), Mojo.Event.tap, this.handleButtonPress.bind(this));
}

Its very much like writing web applications but you'll need to download the webOS SDK from http://developer.palm.com/ and a palm emulator.
All the information is there and its easy to get going if you use the eclipse IDE

It is a web-based OS, so I would assume it's somewhat similar to doing PhoneGap development, if you are at all familiar with their framework.
Javascript with custom API calls will drive most of the applications and it looks like they are configuring their SDK to work well with Eclipse IDE. Of course HTML and CSS will cover the front end of things.
A good beginner page explaining what you are looking for can be found here: http://developer.palm.com/index.php?option=com_content&view=article&id=1603

Related

SAPUI5: Extend Control, renderer has html tags with event

I extend a Control to create a new custom control in UI5 and this control renders a tree as UL items nicely. Now I need to implement a collapse/expand within that tree. Hence my renderer writes a tag like
<a class="json-toggle" onclick="_ontoggle"></a>
and within that _ontoggle function I will handle the collapse/expand logic.
No matter where I place the _ontoggle function in the control, I get the error "Uncaught ReferenceError: _ontoggle is not defined"
I am missing something obvious but I can't find what it is.
At the moment I have placed a function inside the
return Control.extend("mycontrol",
{_onToggle: function(event) {},
...
Please note that this event is not one the control should expose as new event. It is purely for the internals of how the control reacts to a click event.
I read things about bind and the such but nothing that made sense for this use case.
Took me a few days to crack that, hence would like to provide you with a few pointers.
There are obviously many ways to do that, but I wanted to make that as standard as possible.
The best suggestion I found was to use the ui5 Dialog control as sample. It consists of internal buttons and hence is similar to my requirement: Render something that does something on click.
https://github.com/SAP/openui5/blob/master/src/sap.ui.commons/src/sap/ui/commons/Dialog.js
In short, the solution is
1) The
<a class="json-toggle" href></a>
should not have an onclick. Neither in the tag nor by adding such via jQuery.
2) The control's javascript code should look like:
sap.ui.define(
[ 'sap/ui/core/Control' ],
function(Control) {
var control = Control.extend(
"com.controlname",
{
metadata : {
...
},
renderer : function(oRm, oControl) {
...
},
init : function() {
var libraryPath = jQuery.sap.getModulePath("mylib");
jQuery.sap.includeStyleSheet(libraryPath + "/MyControl.css");
},
onAfterRendering : function(arguments) {
if (sap.ui.core.Control.prototype.onAfterRendering) {
sap.ui.core.Control.prototype.onAfterRendering.apply(this, arguments);
}
},
});
control.prototype.onclick = function (oEvent) {
var target = oEvent.target;
return false;
};
return control;
});
Nothing in the init(), nothing in the onAfterRendering(), renderer() outputs the html. So far there is nothing special.
The only thing related with the onClick is the control.prototype.onclick. The variable "target" is the html tag that was clicked.

jquery.mobile: no event triggered when loading an external page into the dom

Ok, first off do NOT confuse my use of the word "external" with the keyword external used in anchor tags. That's NOT what this is about.
I have a multiple page document and everything there works fine. I also have several other .html pages that are rarely ever used (i.e. about page) so I don't want to clutter the dom with them but rather load them as needed.
So, starting with the about.html page, when loaded, this page will (or should) give some info about the device it's running on as well as the version number of my app and whether or not there's a later version available (some people turn off automatic updates).
Before I go further, I want to put it on the record that the about.html page is working in another app when it's loaded with the rel="external" attribute set but I'm trying to move away from that.
So, inside my index.html I have a header with a nav bar and the anchor tag is straight forward:
<div data-role="popup" id="homeMenu" data-theme="b">   
     <ul data-role="listview" data-inset="true" >
        <li>About</li>
When I run the app in a simulator, the about.html gets loaded into the dom and becomes the active page so that part is working but not one event that I can figure out gets triggered.
I have tried all of the following:
$("body").on("pagecontainerbeforeshow", function( event, ui ) {
console.log("Going to: " +ui.toPage[0].id);
});
$(document).on('pagecreate', function() {
$(':mobile-pagecontainer').on('pagecontainerbeforeshow', function(event, ui) {
console.log('pagecontainerbeforeshow triggered');
console.log("Going to: " +ui.toPage[0].id);
});
});
// $( "#aboutPage" ).on("pagecontainerbeforeshow", function( event ) {
$( "#aboutPage" ).on("navigate", function( event ) {
console.log("aboutPage Ready!");
initMenu();
onAboutReady();
$('#aboutPage').on("swiperight", function () {
// I know, I know... one step at a time ;-)
window.location.href = 'index.html';
}); 
});
I would imagine that I can't attach an event handler to the about page as the about page doesn't yet exist in the dom so there must be another way to attach an event that actually gets fired.
What am I missing here?
Turns out the answer is easier than one might think! Instead of trying to trap an event for specific page that's not in the dom, simply trap the event for all pages, add in a switch statement and viola!
$("body").on("pagecontainerbeforeshow", function( event, ui ) {
console.log("pagecontainerbeforeshow -> Going to: " +ui.toPage[0].id);
switch(ui.toPage[0].id)
{
case "aboutPage": // <div id="aboutPage" data-role="page"
break;
}
});

controlling google earth with a controling application

If I were to write an application that controls another application which I don't have the binaries to,
For example, an application that by itself would open Google Earth and place the camera in a specific point my application would tell it, say -24,131, and then command google earth to save the image to a specific folder.
What is the approach to this?
How can I know the functions that are being executed and fire them on behalf of a control program like that?
Also, I will also need to know that downloading of images was finished so I can grab the image.
I saw there is an API for google earth, but I don't know if I can use it to control google-earth (the application itself)
You can use the Google Earth API (developers.google.com/earth/) to control a Google Earth globe instance.
See Javascript code snapshot here:
var ge;
google.load("earth", "1");
function init() {
google.earth.createInstance('map3d', initCB, failureCB);
}
function initCB(instance) {
ge = instance;
ge.getWindow().setVisibility(true);
ge.getOptions().setStatusBarVisibility(true);
ge.getNavigationControl().setVisibility(ge.VISIBILITY_AUTO);
ge.getLayerRoot().enableLayerById(ge.LAYER_BORDERS, true);
ge.getLayerRoot().enableLayerById(ge.LAYER_ROADS, true);
var lookAt = ge.createLookAt('');
lookAt.setLatitude(41.26);
lookAt.setLongitude(-100.00);
lookAt.setRange(800000.0);
ge.getView().setAbstractView(lookAt);
}
function failureCB(errorCode) {
alert(errorCode);
}
google.setOnLoadCallback(init);
See HTML code here:
<!DOCTYPE html>
<head>
<script src="http://www.google.com/jsapi"></script>
</head>
<style>
body {
margin:20px;
height:100%;
width:98%;
}
#map3d {
width:75%;
float:right;
}
</style>
<body>
<div id="map3d"></div>
</body>
</html>
The you can use wkhtml2pdf (code.google.com/p/wkhtmltopdf/) function wkhtmltoimage, or PhantomJs (github.com/ariya/phantomjs/wiki/Screen-Capture) to get an image version.
Hope it helps!
Cheers,
Mihai

Where to init Kendo Mobile Application in Durandal

I am trying to use Kendo's Mobile widgets inside of my PhoneGap Durandal project.
See sample source project here: https://github.com/rodneyjoyce/DurandalKendoMobile/tree/master/App
I don't understand where to put the Kendo initilisation code (the widgets do not render without this):
window.kendoMobileApplication = new kendo.mobile.Application($(document.body), {
skin: "flat"
});
I have tried to put it into the Index.html, shell.html and into a particular Durandal page view (x.html), shell.js, main,js and x.js but none of these work.
My Index page has these links in it:
<script src="css/telerik/js/kendo.all.min.js"></script>
<link href="css/telerik/styles/kendo.mobile.flat.min.css" rel="stylesheet" />
My Durandal View has the following HTML with Kendo Mobile widgets:
<section>
1
<div id="kendoindex">
<div data-kendo-role="view" data-kendo-title="View">
<header data-kendo-role="header">
<div data-kendo-role="navbar">
<span data-kendo-role="view-title">Title</span>
</div>
</header>
<ul data-kendo-role="listview">
<li>Item 1</li>
<li>Item 2</li>
</ul>
</div>
</div>
2
</section>
and my ViewModel for this View:
define(function (require)
{
function viewModel()
{
var self = this;
self.activate = activate;
function activate()
{
//window.kendoMobileApplication = new kendo.mobile.Application($("#kendoindex"), {
// skin: "flat"
//});
}
}
var vm = new viewModel();
return vm;
});
If I don't call kendoMobileApplication then the Kendo Mobile widgets are not rendered (it just shows "1 Title 2" with no CSS (ie. Kendo is not transforming them).
Everything seems to be keyed on where to call this: kendoMobileApplication in Durandal.
I followed the Durandal guidelines to give the Kendo bindings their own namespace: http://durandaljs.com/documentation/KendoUI/
UPDATE 1
I have created a simple Durandal 1.2 project which highlights the problem with Kendo Mobile and Durandal (and PhoneGap, but irrelevant here)), namely:
The only way to get the Mobile controls to render properly is to call kendo.mobile.Application. However this cannot find the right HTML element if it is put into a different file and loaded with Durandal.
I cannot find the right place to put this init code as it throws this error: “Uncaught Error: Your kendo mobile application element does not contain any direct child elements with data-role="view" attribute set. Make sure that you instantiate the mobile application using the correct container.”
kendoIndex.html is NOT Durandal but shows how it should be rendered if the kendo.mobile.Application is called correctly (Run this first to see what we are trying to achieve)
Shell : Has the Kendo Layout which does not get rendered.
Home View: Has the simple Kendo Mobile view – this does not get rendered.
About: A simple HTML page without Kendo
Source is on Guthub – if anyone can get Kendo Mobile working with Durandal I would appreciate it (or at least confirm if it is impossible (Telerik are no help at all on this)).
https://github.com/rodneyjoyce/DurandalKendoMobile/tree/master/App
Here's a working demo, which shows the correct start screen, but doesn't show the about view on navigation click. There's probably some extra work required to either remove kendo's or Durandal's router functionality.
http://rainerat.spirit.de/DurandalKendoMobile/App/#/
There were a couple of things required to make it work.
https://github.com/RainerAtSpirit/DurandalKendoMobile/commits/master
Kendo requires that the host element and all 'view' and 'layout' elements are in the DOM and that 'view' and 'layout' are child of the container element. After updating the view html to reflect this the right place to create the kendo app would be home.js
define(function( require ) {
var ctor = function() {
};
ctor.prototype.activate = function() {
console.log("Home activate");
};
ctor.prototype.viewAttached = function() {
var $kendoHost = $('#kendoHost');
// Workaround for height = 0.
// Additional code required to calculate on windows.resize
$kendoHost.height($(window).height());
this.app = new kendo.mobile.Application($kendoHost, {
skin: "flat"
});
console.log("Home viewAttached", this.app, $kendoHost.height());
};
return ctor;
});
Last kendo determines kendoHost height as 0, which prevents that the correctly rendered view show up. As a workaound I'm using $kendoHost.height($(window).height()); right before creating the app addresses.
As said in my comment above I'm still not sure if I'd recommend combining those two SPA frameworks as you might encounter more glitches like that while building your app. That said I'd love to hear about your progress :).

What are the recommended ways to debug Worklight applications?

I'm finding it incredibly slow to fix issues that are specific to the iOS portion of my app. I'd like the know the recommended way to debug Worklight apps when the browser debugger isn't available.
In particular, I'm working on issues with WL.JSONStore which only works on iOS and Android. I can't use the browser debugger to see what's going on. When I do WL.Logger.debug() statements, nothing is showing up in the Xcode console, and the iPad simulator console (Cordova) only displays a few lines. There have also been periods this week that no output is printed anywhere.
I have downloaded and installed Weinre too, but none of the print statements appear to show up in its console and in general I just don't see information about the areas I need.
Thanks in advance for your suggestions.
General Worklight 5.0.6 Debugging
Look at the training module titled Debugging your applications. (Direct PDF link)
Debug Tips for JSONStore on Worklight 5.0.6
Try console.log('message') or WL.Logger.debug('message') inside jsonstore.js and your code ([app-name].js, etc.). The output should show up in Xcode's console and Android's LogCat.
Reset the Simulator or Emulator and/or call WL.JSONStore.destroy().
Make sure you're running on a supported environment:
Android >=2.2 ARM/x86 Emulator or Devices
iOS >=5.0 Simulator or Device
Try turning encryption off (ie. do not pass a password to WL.JSONStore.init or WL.JSONStore.initCollection).
Look at the SQLite Database file generated by JSONStore. This only works if encryption is off.
Android:
$ adb shell
$ cd /data/data/com.[app-name]/databases/wljsonstore
$ sqlite3 jsonstore.sqlite
iOS
$ cd ~/Library/Application Support/iPhone Simulator/6.1/Applications/[id]/Documents/wljsonstore
$ sqlite3 jsonstore.sqlite
Try looking at the searchFields with .schema and selecting data with SELECT * FROM [collection-name];. To exit sqlite3 type .exit. Take a look at this StackOverflow question for an example.
(Android Only) Enable verbose JSONStore.
adb shell setprop log.tag.jsonstore-core VERBOSE
adb shell getprop log.tag.jsonstore-core
(iOS >=6.0 and Safari >=6.0 Only) Try to use the JavaScript debugger. Set break points inside jsonstore.js. Helpful lines:
Bridge to Native code:
cdv.exec(options.onSuccess, options.onFailure, pluginName, nativeFunction, args);
Success Callbacks returning from Native code:
deferred.resolve(data, more);
Failure Callbacks returning from Native code:
deferred.reject(new ErrorObject(errorObject));
Write Proper Tests (Unit, Functional, Integration -- get test coverage). Here's a template that uses QUnit and Sinon.js to create a Sandbox environment where you can test how JSONStore handles different types of data/calls:
<!DOCTYPE HTML>
<html>
<head>
<title>JSONStore Test App</title>
<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-1.11.0.css">
<script src="http://code.jquery.com/qunit/qunit-1.11.0.js"></script>
<script src="http://sinonjs.org/releases/sinon-1.6.0.js"></script>
<script>
//QUnit configuration flags, no need to change it.
QUnit.config.requireExpects = true;
</script>
</head>
<body id="content" style="display: none;">
<!-- Test results will be appended to the div below, no need to make changes here. -->
<div id="qunit"></div>
<script>
//Start Worklight
WL.Client.init({connectOnStartup : false});
//Hook into the deviceready event
document.addEventListener("deviceready", onDeviceReady, false);
//onDeviceReady will be called when JSONStore/Cordova is ready
function onDeviceReady () {
//Auto executing function that holds the test
(function (jQuery) { //The variable jQuery is usable inside.
//Mock WL.Client.invokeProcedure using a Stub.
//This is only useful if you need to link a Worklight Adapter
//to a JSONStore collection to reproduce your issue or bug.
//API Doc: http://sinonjs.org/docs/#stubs
var fakeAdapter = sinon.stub(WL.Client, "invokeProcedure", function (invocationData, options) {
//DO NOT Create a real adapter, just mock the reponse here if it's relevant to the bug.
var ADAPTER_RESPONSE = {invocationResult: {fakeKey: [{fn: 'carlos'}, {fn: 'mike'}]}};
options.onSuccess(ADAPTER_RESPONSE);
});
//[**Explain your test here**]
var EXPECTED_ASSERTIONS = 2; //every assertion is a deepEqual below.
asyncTest('[**Meaningful title here**]', EXPECTED_ASSERTIONS, function () {
//Destroy first to make sure we don't depend on state
WL.JSONStore.destroy()
.then(function () {
//[**Start writting your test here**]
//The test below is an example, it does the following:
// - Initializes a collection linked to a fake adapter (see stub above).
// - Checks if initialization worked by checking the collection name.
// - Loads data from the fake adapter (see stub above).
// - Checks if load worked by checking the number of documents loaded.
var collections = {
col1 : {
searchFields : {fn: 'string'},
adapter : {name: 'fakeAdapter',
load: {
procedure: 'fakeProcedure',
params: [],
key: 'fakeKey'
}
}
}
};
return WL.JSONStore.init(collections);
})
.then(function (response) {
//Prep for your assertion
var ACTUAL_VALUE = response.col1.name;
var EXPECTED_VALUE = 'col1';
var COMMENT = 'Checking for the right collection name';
//Do your assertion using deepEqual
//API Doc: http://api.qunitjs.com/deepEqual/
deepEqual(ACTUAL_VALUE, EXPECTED_VALUE, COMMENT);
return WL.JSONStore.get('col1').load();
})
.then(function (response) {
//Prep for your assertion
var ACTUAL_VALUE = response; //load returns number of documents loaded
var EXPECTED_VALUE = 2; //two documents are returned by the fake adapter (stub)
var COMMENT = 'Checking if load worked';
//Do the assertion using deepEqual
deepEqual(ACTUAL_VALUE, EXPECTED_VALUE, COMMENT);
start();//call start() after you finish your test succesfully
})
.fail(function (error) {
deepEqual(false, true, 'Failure callback should not be called' + error.toString());
start();//call start() after you finish your test with a failure
});
});
}(WLJQ)); //end auto executing function that holds the test
} //end wlCommonInit
</script>
</body>
</html>
Expected output of the code above:
Side-note: Here's a general article about the PhoneGap/Cordova workflow for a specific developer. There's a part of debugging, just browser-based though. Some of it applies to IBM Worklight development too.
cnandreu provides great tips here. Still, visibility is pretty poor and these approaches didn't really solve my problem. I would like to also suggest what I've found to be most useful in my project (aside from WL.Logger.debug() everywhere):
JSConsole has been indispensable (http://jsconsole.com/). In reality, I don't actually use it that much like it's intended. However, I've found that it's startup warning message does something with WL.Logger.debug() (and console.log()) that enables the statements to actually print to the console so I can see what I'm doing.
In iOS 6 Safari on the Mac lets you inspect the DOM of an attached device. It's moderately useful, especially for hybrid UI issues that only are misbehaving when running natively on iOS. I don't find it super helpful otherwise. See more at https://developer.apple.com/library/safari/#documentation/AppleApplications/Reference/SafariWebContent/DebuggingSafarioniPhoneContent/DebuggingSafarioniPhoneContent.html
The single most useful technique I've been using has been to write status messages to the UI. Yes, it's an ugly prehistoric way to do things, but everything else - including 80s error print statements to the console - have failed miserably. Here's what I do (using Dojo & JavaScript):
var v = dom.byId('audio_status');
if (v) { v.innerHTML += "recording file ["+filename+"]"; }
Where audio_status is the ID of a DIV that displays the debug content.
This stuff is ugly, but at least we can see something.

Resources