tag:blogger.com,1999:blog-334729012024-03-05T07:09:23.675+01:00Erik's DiaryDiary for Erik Wetterberg, system developer living in Helsingborg, Sweden.Erikhttp://www.blogger.com/profile/07865795210715993795noreply@blogger.comBlogger81125tag:blogger.com,1999:blog-33472901.post-39849856563983302932015-11-15T13:48:00.001+01:002015-11-15T13:48:58.138+01:00Web components lifecycle methods 3: filling in the gapsAs we have seen in my previous posts the web component standard defines only four lifecycle methods:<br />
<br />
<ol>
<li>createdCallback when the element is created, but possibly not attached to a document</li>
<li>attachedCallback when the element is added to a document</li>
<li>detachedCallback when the element is removed from the document</li>
<li>attributeChangedCallback, when an attribute is changed</li>
</ol>
<div>
They are also all callbacks: they are called after the standard processing, so you cannot override the standard processing. This is a very small model. If you compare with the lifecycle for an <a href="http://developer.android.com/reference/android/app/Activity.html" target="_blank">Android Activity</a> you will see that the activity also has calls like:</div>
<div>
<ul>
<li>onPause() Another activity comes into the forground</li>
<li>onResume() User returns to the activity</li>
<li>onStop() The activity is no longer visible</li>
</ul>
<div>
There are no corresponding callbacks in the web component standard. Most importantly ther is no callback method for when your element is displayed to the user. The attachedCallback will be called when your element is added to the DOM, but it might very well be hidden, specially since the practice to use hidden DOM elements for things like tabs, menues etc is so common in the HTML world. <b>And there is no visibleCallback that is called when your element is shown.</b><br />
<b><br /></b></div>
</div>
<h3>
<b>Filling the gap 1: listen to the resize event</b></h3>
<div>
First step is probably to listen to the 'resize' event. This event is trigger when the browser window is resized, so it's pretty likely that you need to listen to it anyhow, if you ned to re-render or something when the window size changes. The right place to set up this listener is in attachedCallback:<br />
<blockquote class="tr_bq">
window.addEventListener("resize", me.redraw);</blockquote>
And you should remove it in detachedCallback:<br />
<blockquote class="tr_bq">
window.removeEventListener("resize", this.redraw);</blockquote>
Now this might do, if you can make sure that your page triggers a resize event when the visibility of your element changes (like some sort of tabbing, page navigation etc). But it is a bit of overkill, since the resize event will go to all elements in the page and not just the ones affected by the change. It is also far from certain that the components you use do trigger resize events, so you might need to patch them.<br />
<h3>
Filling the gap 2: expose a draw method</h3>
This approach is more precise: you expose a draw method (or event) on your element, and the code in the page calls this method when needed. If you look at Googles implementation of <a href="https://elements.polymer-project.org/elements/google-chart" target="_blank">web components for Google Charts</a> this is the approach they have taken with the drawChart() method. Following this approach will simplify for users that use your component and have experience from Google charts. Unfortunately there is as far as I know no standard for this, so you cant really count on other components calling this method.<br />
<br />
Of course you can combine these two approaches, expose a draw() method on your element, and then listen to the resize event and call the method when it occurs. </div>
Erikhttp://www.blogger.com/profile/07865795210715993795noreply@blogger.com0tag:blogger.com,1999:blog-33472901.post-51114819888797016432015-10-19T20:06:00.002+02:002015-10-19T20:07:30.150+02:00Web Components lifecycle methods 2:attributeChangedCallbackThe Web Component callback attributeChangedCallback seems simple enough. Whenever an attribute of your custoim component is changed, it will be called. The purpose of it is to support dynamic use cases: the web site developer can use standard HTML setAttribute to change attributes for your component, and the callback gives you a chance to react on the changes. Without it, or without an implementation of it, your component will not handle changes. But how does it actually work:<br />
<h3>
Case 1: modify a custom attribute</h3>
<div>
The first case is pretty straightforward: we have a custom component that defines some custom attributes. I use my own <a href="https://github.com/erikwett/upper88-wordcloud" target="_blank">upper88-wordcloud</a> throughout. It defines a couple of custom attributes, rows and options. When they are updated the callback is called, and I simply rerender the component. I use this in the <a href="http://upper88.com/#!/wordcloud" target="_blank">demo page </a> with this little code snippet:</div>
<div>
<br /></div>
<pre>window.setInterval(function() {
var chart = document.getElementById('hello_cloud');
if (chart) {
chart.setAttribute('rows', JSON.stringify([
['Hello', getRandomValue()],
['Word', getRandomValue()],
['Cloud', getRandomValue()]
], null, 2));
}
}, 3000);
</pre>
<br />
As expected this leads to that the component is rerendered with modified data every 3 seconds. Note also that this is a callback: it is called after the attribute has been changed, so you can use the getAttribute method and you will get the new value. Also if you check in the attributes property you will get the new value. So far so good.<br />
<h3>
Case 2: modify standard attribute</h3>
<div>
My custom element extends HTMLelement and has of course the standard HTML attributes, like title. It also has the standard support for data-xxx attributes, which will be saved in the dataset property. Are they also covered by the callback??</div>
<div>
<br /></div>
<div>
To try this I added the following to the function above:</div>
<div>
<br /></div>
<pre> chart.setAttribute('title','New title'+getRandomValue());
chart.setAttribute('data-xxx','data-yyy'+getRandomValue());
</pre>
<br />
And yes, this also works, and in the same way. The callback is called after the attribute has been updated, so you can use this also in your component.<br />
<br />
<h3>
Case 3: modify standard properties</h3>
<div>
Now using setAttribute to modify titles works but its a bit complicated. The title is available as a property, and can be modified directly, like this:</div>
<div>
<br /></div>
<pre>chart.title = 'New title'+getRandomValue();
</pre>
<br />
(I use the helper function getRandomValue() to make sure I actually update the value)
And yes, this works too. So it seems we can use the callback to monitor changes, it covers changes not made with setAttribute also.<br />
<h3>
Conclusion</h3>
<div>
The attributeChangedCallback helps you develop WebComponents that support dynamic changes. Developers using your component can dynamically modify component instan ces using standard javascript techniques like setAttribute. You can use the callback to monitor changes not only in your custom attributesbut also in standard HTML attributes.</div>
Erikhttp://www.blogger.com/profile/07865795210715993795noreply@blogger.com0tag:blogger.com,1999:blog-33472901.post-5983400209719815182015-10-17T11:13:00.001+02:002015-10-19T18:17:00.797+02:00Web Components lifecycle methods 1: createdCallback and attachedCallbackThe Web Components standard includes only four lifecycle callback methods:<br />
<table>
<tbody>
<tr><th>Method</th><th>Called when</th></tr>
<tr><td>createdCallback</td><td>the element is created</td></tr>
<tr><td>attachedCallback</td><td>the element is inserted into the DOM</td></tr>
<tr><td>detachedCallback</td><td>the element is removed from the DOM</td></tr>
<tr><td>attributeChangedCallback(attrName, oldVal, newVal)</td><td>an attribute is changed</td></tr>
</tbody>
</table>
<br />
This is a very simple model and its simplicity has a cost if you try to build your own custom components or use web componets in your site. But lets see how they work.<br />
<br />
<h4>
Create and add elements</h4>
<div>
The two first methods are called when your page is loaded. Order is pretty obvious: first elements are created, then they are attached to the DOM. Lets investigate how they work in more detail.<br />
There are different ways to create a HTML element, and part of the beauty with Web Components is that you can use all of them: creating your custom HTML element is just like creating a DIV. In this post I will look at three diferent ways to create a custom HTML element:<br />
<br />
<ol>
<li>include in a standard HTML page</li>
<li>create in javascript, with document.createElement</li>
<li>include in a HTML template (in my case in a Polymer iron-page element)</li>
</ol>
<h4>
Use web components in a standard HTML page</h4>
<div>
<br /></div>
<div>
For this case I have created a small standard web page loaded a Web Component (in this case my own <a href="https://github.com/erikwett/upper88-wordcloud" target="_blank">upper88-wordcloud</a>) and created two elements using this custom element. I then open then page in Chrome and set breakpoints in both createdCallback and attachedCallback.</div>
<div>
<ol>
<li>the callbacks are called in this order:</li>
<ol>
<li>createdCallback element 1</li>
<li>attachedCallback element 1</li>
<li>createdCallback element 2</li>
<li>attachedCallback element 2</li>
</ol>
<li>already in createdCallback my elements know of their environment, that is <a href="https://developer.mozilla.org/en-US/docs/Web/API/Node/parentElement" target="_blank">parentElement </a>and <a href="https://developer.mozilla.org/en-US/docs/Web/API/Node/parentNode" target="_blank">parentNode </a>are already set, and <a href="https://developer.mozilla.org/en-US/docs/Web/API/Node/parentElement" target="_blank">parentElement </a>has html content. </li>
<li>HTML initial reflow has not been made, so your element might have no size yet (I have written about this <a href="http://eriksdiary.blogspot.se/2015/09/web-components-no-size-in.html" target="_blank">here</a>)</li>
</ol>
<h4>
Create web component in javascript</h4>
</div>
<div>
For a more dynamic case creating your element with javascript might be an alternative. Web Components support this also, but it will work slightly different.</div>
<div>
To test this I added an empty div to my plain HTML page and a small javascript script:</div>
<br />
<pre>var wc88 = document.createElement('upper88-wordcloud');
wc88.setAttribute("rows", '[ ["web",10],["components",15],["rocks!",20] ]');
document.getElementById('wc').appendChild(wc88);
</pre>
<ol>
<li><span style="font-family: inherit;">callbacks for the javascript element are of course called after the others, with createdCallback first and attachedCallback after</span></li>
<li>when createdCallback is called parentElement and parentNode are both null, since the browser does not know where the element will end up. In attachedCallback they are set.</li>
<li>HTML reflow has been made so the element actually has a size in the attachedCallback.</li>
</ol>
<h4>
Use web components in a HTML template</h4>
</div>
<div>
If you are building a Polymer site it's verey likely that you do not use any of these to methods but instead use your web component in a HTML template, which in turn another web component will actually attach to the document. This is the way for example the Polymer component iron-page works. An example of this is my homepage <a href="http://upper88.com/">upper88.com</a>. In that page I use Polymer and iron-pages for page navigation. Note that irob-pages use css display:none to hide the none active sheets, so they will be added to the dom even if the user does not see them (in fact even if the user never navigates to the page). There are three upper88-wordclod elements in this page.</div>
<div>
<ol>
<li>Callback order:</li>
<ol>
<li>createdCallback element 1</li>
<li>createdCallback element 2</li>
<li>createdCallback element 3</li>
<li>attachedCallback element 1</li>
<li>attachedCallback element 2</li>
<li>attachedCallback element 3</li>
</ol>
<li>elements know their environment already in createdCallback, parentElement is set</li>
<li>No reflow has been made, so the element has no size</li>
</ol>
<h4>
Conclusion</h4>
</div>
<div>
As you can see the behavour is slightly different in the different scenarios. Even if you can trust the createdCallback to be called first and the attachedCallback to be called after that for each element, you cannot know if createdCallback has been called for all elements before the first attachedCallback or whether the browser will process the elements one by one. And even if parentElement and parentNode might be available in createdCallback (that surprised me) it also might not.</div>
<div>
So, some rules:</div>
<div>
<ul>
<li>do not make anything in createdCallback that depends on the element environment even if it might work in your page</li>
<li>do not count on knowing element size etc in attachCallback, they might not be available yet</li>
<li>test your web component in all three scenarios: standard HTML page, javascript creation and HTML template</li>
</ul>
And still we have only tested this in Chrome.... </div>
Erikhttp://www.blogger.com/profile/07865795210715993795noreply@blogger.com0tag:blogger.com,1999:blog-33472901.post-80338533358679323482015-09-30T18:58:00.000+02:002015-09-30T18:58:22.248+02:00Another web component - upper88-titleIn the weekend I published my second web component - <a href="https://github.com/erikwett/upper88-title" target="_blank">upper88-title</a>. Like my first one this is a vanilla JS web component, that does not use Polymer or any other library, apart from the web components polyfill. It might also be the smallest web component ever in terms of lines of code...<div>
<br /></div>
<div>
What it does is very simple: it allows you to tag some html in your web page as title, and the web component will grab the text (skip html tags) and set it as document title. So you don't have to type the same text over again - and can avoid the risk of forgetting to update the document title, it will always show the same text as that displayed in the actual page.</div>
<div>
<br /></div>
<div>
A little more advanced is that you can use Polymer data binding (even if the component itslef does not depend on Polymer) to set the content of both the HTML tag and document title at the same time. </div>
<div>
<br /></div>
<div>
Tried to publish it on <a href="https://customelements.io/" target="_blank">customelements.io</a> but it seems like the job that updates the site is broken, so you can't see it there yet.</div>
Erikhttp://www.blogger.com/profile/07865795210715993795noreply@blogger.com0tag:blogger.com,1999:blog-33472901.post-10067050986459311582015-09-15T18:42:00.000+02:002015-09-15T18:42:02.347+02:00Polymer summit 2015During the day I've followed Polymer Summit 2015 over the net. Lots of good talks and useful information. I do belive that the approach of Custoim HTML elements is the future, but even though Polymer is on it's way, I don'ät think tehey are really there yet.<br />
<br />
Pros:<br />
<br />
<ul>
<li>the approach of components that can be reused, extended and combined into new components</li>
<li>some really awesome components are available out there, both from Google and others</li>
</ul>
<div>
Not cons, but stuff they have to work on:</div>
<div>
<ul>
<li>dependencies,build system etc: when you start a polymer project, bower will download that feels like half the internet for you, <span style="text-align: center;">not really manageable, and my previous experiences from build system have not been to good. You really need a good build system, and preferanbvle a CDN so you don'ät have to manage all this</span><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiYh21nqFP_HnLdMKTasr3IxsdoJA2oPh-49_UTTrbYw9wpnMDYmBLmPnTy5Em5zybo4-upKYqpX1B65N1lWTQH7KEIEhGepfzGzaukSAy1wXGuh3SVew8PIlha_uSXbcBnJCygew/s1600/components.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiYh21nqFP_HnLdMKTasr3IxsdoJA2oPh-49_UTTrbYw9wpnMDYmBLmPnTy5Em5zybo4-upKYqpX1B65N1lWTQH7KEIEhGepfzGzaukSAy1wXGuh3SVew8PIlha_uSXbcBnJCygew/s1600/components.PNG" /></a></li>
<li>the kiving of HTML, CSS and javascript in one file seems like a step backward.</li>
</ul>
<div>
But yes,. I do think web components is the future, I only wonder when we will be there....</div>
</div>
Erikhttp://www.blogger.com/profile/07865795210715993795noreply@blogger.com0tag:blogger.com,1999:blog-33472901.post-32761271672196307682015-09-15T15:42:00.000+02:002015-09-15T15:42:13.738+02:00Web Components: no size in attachedCallbackWhen I made the <a href="https://customelements.io/erikwett/upper88-wordcloud/" target="_blank">upper88-wordclod</a> web component everything worked fine when I had hard-coded sizes in the beginning. The <a href="https://github.com/timdream/wordcloud2.js" target="_blank">library </a>worked well and gave the ouput I expected (well, actually a bit better, it's an awesome library).<br />
<br />
But when I switched to a size set with CSS it stopped working. After some debugging I realized that the element had no size yet. When attachedCallback(which is the place where you would render your element for the first time) is called, the element has no size set yet, so if your code (or a library you might use) relies on getting the height or width of the element ity won't work.<br />
<br />
The recommended way is to remove all sizing from javascript and do it in CSS instead, which will work, but in my case that was not an option. Instead I had to add a call to setTimeout to make the actual rendering take place a bit later, after sizes have been calculated. That seems to work well, you don't actually see the delay and I have had no problem with the solution.Erikhttp://www.blogger.com/profile/07865795210715993795noreply@blogger.com0tag:blogger.com,1999:blog-33472901.post-22535612106708192252015-09-14T18:47:00.001+02:002015-09-14T18:47:20.005+02:00First web component published - upper88-wordcloudYesterday I published my first web component, It is a custom component called <a href="https://customelements.io/erikwett/upper88-wordcloud/" target="_blank">upper88-wordcloud</a>. Very basic so far, you set the data using the attribute rows and optionally minimum and maximum font size using an options attribute.<br />
<br />
An example:<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: left; margin-right: 1em; text-align: left;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjOzzNc-0hL4V8ZmRGrhvnczlfHDdrfg2j3VWY9YU6kFhwpuvWOotEYHpC_CQ42pBOkUM2eNz5HrkKeh1Q7Wd2XeCO05vSiz41-X0I2oyu82EvZcfgfCjiScGkkNn-vZBuokpwtow/s1600/wordcloud.PNG" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjOzzNc-0hL4V8ZmRGrhvnczlfHDdrfg2j3VWY9YU6kFhwpuvWOotEYHpC_CQ42pBOkUM2eNz5HrkKeh1Q7Wd2XeCO05vSiz41-X0I2oyu82EvZcfgfCjiScGkkNn-vZBuokpwtow/s320/wordcloud.PNG" width="309" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Goldmedals from Track and Field World Championship 2015</td></tr>
</tbody></table>
Html for this:<br />
<upper88-wordcloud options='{"maxFont":60}' rows='[["Kenya", 7], ["Jamaica", 7], ["United States", 6], ["Great Britain", 4], ["Ethiopia", 3], ["Poland", 3], ["Canada", 2], ["Germany", 2], ["Russia", 2], ["Cuba", 2]]'><br />
</upper88-wordcloud%gt;<br />
<br />
Size, background color etc are set using CSS.<br />
<br />
For rendering the actual word cloud the component uses a library available on GitHub, <a href="http://timdream.org/wordcloud2.js/#love" target="_blank">wordcloud2.js </a>by Tim Dream. A great library, and it supports rendering the wordcloud as a set of HTML span's, which feels like the best way to go for a custom element.<br />
<br />
So far the component is very basic and doesn't expose much of the flexibility that the library has. There is definitely room for improvement.Erikhttp://www.blogger.com/profile/07865795210715993795noreply@blogger.com0tag:blogger.com,1999:blog-33472901.post-90204346997321375292015-06-18T10:01:00.002+02:002015-06-18T10:01:52.794+02:00Polymer 1.0 First impressions<span style="font-family: Arial, Helvetica, sans-serif;">Recently at Google I/O Google announced Polymer 1.0 to be available and ready for production. Since I think that Web Components might very likely be the future for the web and since I tried Polymer 0.5 in some prototypes I thought I would give it a go and try <a href="https://developers.google.com/web/tools/polymer-starter-kit/">Polymer starter kit</a>.</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">If you do this make sure your Internet connection is fast: downloading the starter kitr is fast, but then downloading all dependencies takes ages, so this is no quick start.</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">Once you actually get started it's easy enough to start building. IUt took me just a few hours to build a small site with a few pages, working navigation etc. And it looked pretty OK:</span><br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh0Rh2ymv37UUY1cMNkrF-XrS4xT2pNgWhORd100gmDyuuDRzZMb5QjbUs_tbokUVMetKz-iJdV6CeCGB4HyXJTv-kg3MgvDtib389tUJ5apSgd4PejZT2dBSPjf2B1OrDYVSoxkQ/s1600/polymersite.PNG" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><span style="font-family: Arial, Helvetica, sans-serif;"><img border="0" height="223" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh0Rh2ymv37UUY1cMNkrF-XrS4xT2pNgWhORd100gmDyuuDRzZMb5QjbUs_tbokUVMetKz-iJdV6CeCGB4HyXJTv-kg3MgvDtib389tUJ5apSgd4PejZT2dBSPjf2B1OrDYVSoxkQ/s320/polymersite.PNG" width="320" /></span></a></div>
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">Some reflections:</span><br />
<br />
<ul>
<li><span style="font-family: Arial, Helvetica, sans-serif;">I do like materialized design, clean, simply and looks modern. You get that more or less for free</span></li>
<li><span style="font-family: Arial, Helvetica, sans-serif;">Materialized design are also good for us that are not graphic designers: you get usefulk set of icons to use, and it uses texts a lot, which is good</span></li>
<li><span style="font-family: Arial, Helvetica, sans-serif;">the polymer elements are easy to work with</span></li>
</ul>
<div>
<span style="font-family: Arial, Helvetica, sans-serif;">So creating a site locally was pretty easy. Deploying is another thing, more on that later, when I actually managed to publish my new site.</span></div>
Erikhttp://www.blogger.com/profile/07865795210715993795noreply@blogger.com0tag:blogger.com,1999:blog-33472901.post-10072752691671863032014-05-11T12:01:00.000+02:002014-05-11T12:01:07.892+02:00In Android May is month number fourSo I published my Android app yesterday. But it didn't work as expected. Information was missing in the display. After debugging I found out that the missing information was not there in the parsed result either. Was there a bug in the XML parser? I debugged that too, but could not find anything that was wrong. Yet when I made the same search in the browser the information was there in the result.<br />
<br />
And then I found it! It turned out that my app was searching not today's date, but a month ago. Most of the information was the same, but some was missing. The reason for this was that I pretty late in the project removed the ASAP I had used before and instead used a date field, automatically filled in with a date, that should have been today's, but was actually a month ago.<br />
<br />
And the reason for this is how Android Calendar work:<br />
<br />
<ul>
<li>calendar.get(Calendar.MONTH) will get you the month number <b>where January is month zero</b></li>
<li>calendar.get(Calendar.DAY_OF_MONTH) will get you the day of the month, <b>where the first day is one</b></li>
</ul>
Not very intuitive, even if I assume ther is some logic in it. Anyway, a quick bugfix and new upload to Google Play means that very few users, if any, have been affected.Erikhttp://www.blogger.com/profile/07865795210715993795noreply@blogger.com0tag:blogger.com,1999:blog-33472901.post-14060515521652500062014-05-10T16:14:00.001+02:002014-05-10T16:14:40.332+02:00New app publishedToday I published a new app on Google play: <a href="https://play.google.com/store/apps/details?id=com.upper88.skaneresa">Skåne Transport</a><br />
<br />
It is an app for Local Transport in my home region, Skåne in the south of Sweden. It helps you find trains and busses (and perhaps ferrys) when travelling in Skåne and to adjacent regions like Copenhagen, Göteborg etc.<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiwKRxCAJx9fHEHIF6QCSebfwMIhs61uJEIMdGf32bqZ7pfwuj3qJ4F93jcbGREELJrvDefZqho8CNNbl9UMbc8pDInyBEqKmKuWNNB0s8S7gEY84rSgayfbifawMkOu6ZPdDLI3w/s1600/skanetrafik_start_en.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiwKRxCAJx9fHEHIF6QCSebfwMIhs61uJEIMdGf32bqZ7pfwuj3qJ4F93jcbGREELJrvDefZqho8CNNbl9UMbc8pDInyBEqKmKuWNNB0s8S7gEY84rSgayfbifawMkOu6ZPdDLI3w/s1600/skanetrafik_start_en.png" height="320" width="192" /></a><br />
From a user perspective I have had two goals for the app:<br />
<br />
<ol>
<li>It should be easy to search. You should be able to do most of your searches without typing. I do this by keeping history, making it easy to add favorites and having a preloaded list of the most important stations with the app when it is installed. The user also has the option to use her current location.</li>
<li>The information should be as accurate as possible. If I have information about delays, the app shows te delayed time rather than the one from the timetable (colored in red so that it should be clear for the user that there is a delay)</li>
</ol>
<div>
I'm pretty satisfied with the result. Let's see what the users think.</div>
Erikhttp://www.blogger.com/profile/07865795210715993795noreply@blogger.com0tag:blogger.com,1999:blog-33472901.post-34822426410035371532011-06-12T10:43:00.003+02:002011-06-12T10:49:56.597+02:00First Android app publishedYesterday I published my first Android app on Android market, <a href="https://market.android.com/details?id=com.upper88.unsilence">UnSilence</a>. The background is that I tend to forget to turn my cellphone back to normal after I've set it to silent during a meeting. I have missed too many calls beacuse of that...<div><br /></div><div>So UnSilence helps you be allowing you to set your phone to silent (with or without vibaration) for a period of time, and then automatically turn sound back on.</div><div><br /></div><div>The main design goal was too keep it simple, one click to start the app, and one click to set to silent, that's all. </div>Erikhttp://www.blogger.com/profile/07865795210715993795noreply@blogger.com0tag:blogger.com,1999:blog-33472901.post-48802195732753053592011-03-18T14:40:00.011+01:002011-03-18T19:48:50.849+01:00Servlet http proxyFor a while I have been working on a project where we are trying to integrate a windows-based service in a Java EE environment. Basically the problem is to host an Ajax application under an application server like IBM Webspehere or Apache Tomcat. We also want to support portlets following the JSR 268 specifikation.<br /><br />I googled around a bit and found lots of useful stuff, but nothing that did all that we wanted. The mainly problems was with headers and cookies, since we need to keep a session to the servicein the background we need to make those work. So I ended up writing my own. Not much code, but it might be useful for someone else, as it is pretty general stuff.<br /><br /><span style="font-weight: bold;">The service method<br /><br /></span>Since we want to handle all HTTP calls, we override the service method of <a href="http://download.oracle.com/javaee/5/api/javax/servlet/http/HttpServlet.html">HttpServlet</a>. If you want only some methods (GET and PUT for example) to work you might just override doGet and doPost for example, but we want it all.. The implementation looks like this:<br /><blockquote>protected void service(HttpServletRequest req, HttpServletResponse resp)<br /> throws ServletException, IOException {<br /> String qry = req.getQueryString();<br /> URL url = new URL(protocol, host, port, req.getRequestURI()<br /> + (qry == null ? "" : "?" + qry));<br /> HttpURLConnection urlConnection = (HttpURLConnection) url<br /> .openConnection();<br /> urlConnection.setDoOutput(true);<br /> urlConnection.setDoInput(true);<br /> urlConnection.setUseCaches(false);<br /> urlConnection.setInstanceFollowRedirects(false);<br /> urlConnection.setRequestMethod(req.getMethod());<br /> handleRequestHeaders(req, urlConnection);<br /> handlePostData(req, urlConnection);<br /> // make the call - get response code<br /> int responseCode = urlConnection.getResponseCode();<br /><br /> resp.setStatus(responseCode);<br /> if (responseCode != HttpURLConnection.HTTP_OK)<br /> log.info("HTTP code:" + responseCode + " "<br /> + urlConnection.getResponseMessage() + " URL["<br /> + url.toString() + "] " + req.getMethod());<br /> else<br /> log.debug("HTTP code:" + responseCode + " URL[" + url.toString()<br /> + "] " + req.getMethod());<br /> handleResponseHeaders(resp, urlConnection);<br /> // send output to client<br /> handleContent(resp, urlConnection, responseCode);<br />}<br /></blockquote><br />This is pretty straight forward. The protocol (http/https), server and port to use are configurable. We take the URI from the request and add the query string, if there is one. Together with the configure host etc, this forms the new URL, which we open, using the same method as in the call. We set some parameters, request headers and post data if there is any.<br /><br />We then call the URL, check the HTTP response code, and take care of the headers and the response, which all are sent to the client.<br /><br /><span style="font-weight: bold;">Handle headers</span><br />The part that we really needed was the headers. This simply transfers the headers between the two connections, with a few exceptions:<br /><blockquote><br />private void handleRequestHeaders(HttpServletRequest req,<br /> HttpURLConnection urlConnection) {<br /> // set request headers<br /> Enumeration e = req.getHeaderNames();<br /> while (e.hasMoreElements()) {<br /> String key = (String) e.nextElement();<br /> if (!"Host".equalsIgnoreCase(key)<br /> && !"Accept-Encoding".equalsIgnoreCase(key)) {<br /> String value = req.getHeader(key);<br /> log.debug("Request Header: " + key + ": " + value);<br /> urlConnection.setRequestProperty((String) key, value);<br /> }<br /> }<br /> //add your own headers here<br /> }<br /></blockquote><br />There are two headers that we dont want to transfer from the client's request to our new request:<br /><ol><li>The Host header, since this will be our proxy server. The new Host header will be added automatically, so we don't need to think about it.</li><li>The Accept-Encoding header. This is a fix, the Accept-Encoding header turns gzip on, and since we have not implemented gzip in our proxy we don't want it. Another alternative would be to turn gzipping of requests off in our web server, perhaps this would have been better. If we do transfer th Accept-Encoding header, both servers might zip the content, which will not work.</li></ol>Finally in this method we add our own headers, which is basically the reason why we need the proxy at all.<br /><br />When we get the response back from the server we have the corresponding method to handle the response headers:<br /><blockquote><br />private void handleResponseHeaders(HttpServletResponse resp,<br /> HttpURLConnection urlConnection) {<br /> // set response headers<br /> Map<string,>> headers = urlConnection.getHeaderFields();<br /> Set<map.entry<string,>>> entrySet = headers.entrySet();<br /> for (Map.Entry<string,>> entry : entrySet) {<br /> String key = entry.getKey();<br /> List<string>> headerValues = entry.getValue();<br /> for (String value : headerValues) {<br /> if (key != null && !"Server".equalsIgnoreCase(key)) {<br /> log.debug("Response Header: " + key + ": " + value);<br /> resp.addHeader(key, value);<br /> }<br /> }<br /> }<br /> }</blockquote><br />This is basically the same as the request headers. In this case we just filter the Server header, where our proxy application server will add its own name.<br /><br />Finally to set it up in web.xml we configure the URLs we want the proxy to handle, set the protocol, host and port and we are ready to go.Erikhttp://www.blogger.com/profile/07865795210715993795noreply@blogger.com0tag:blogger.com,1999:blog-33472901.post-62077471342402901272010-09-09T14:47:00.002+02:002010-09-09T14:57:10.174+02:00NoClassDefFoundError in BlackBerryI have been struggling a few days with a strange error in BlackBerry. My app works fine in the emulator, but when you start it on BlackBerry Bold (software version 4.5) you get a NoClassDefFoundError. On BlackBerry Storm (software version 4.6) it works fine, but on Bold2 (version 5.0) again you get NoClassDefFoundError.<br /><br />The <a href="http://www.blackberry.com/developers/docs/4.5.0api/java/lang/NoClassDefFoundError.html">documentation </a>says:<br /><blockquote>Thrown if the Java Virtual Machine tries to load in the definition of a class (as part of a normal method call or as part of creating a new instance using the new expression) and no definition of the class could be found.<br /><br />The searched-for class definition existed when the currently executing class was compiled, but the definition can no longer be found. </blockquote><br /><br />I have gone through all the changes since the last working version and I finally found it. I had added some fields like this:<br /><blockquote><br />fldPortHttp = new TextField("Port:", "", 20, Field.EDITABLE | BasicEditField.FILTER_NUMERIC);<br /></blockquote><br />This worked well, with no compilation errors and in the emulator, but caused the NoClassDefFoundError at runtime. The solution was simply to change to:<br /><blockquote><br />fldPortHttp = new BasicEditField("Port:", "", 20, Field.EDITABLE | BasicEditField.FILTER_NUMERIC);<br /></blockquote>Erikhttp://www.blogger.com/profile/07865795210715993795noreply@blogger.com0tag:blogger.com,1999:blog-33472901.post-64051349353191759282010-05-09T16:02:00.003+02:002010-05-10T19:15:27.173+02:00The future for mobile javaThe last three years or so I have worked mostly with mobile java, starting with Java ME and later moving into BlackBerr and Android. A lot of things has happened, three ears ago Android existed, but ther were hardly any phones available and BlackBerry did exist, but I knew nothing about it.<br /><br />Today the future of Java ME is uncertain. Programming in Java is a good option on most mobile platforms (except iPhone), but the strongest alternatives are Android and BlackBerry, not Java ME.<br /><br />There are of course different reasons for this. On the technical side, the User Interface options are very limited. LCDUI is very restricted, you very quickly end up with skipping the higher level API, because it is too restricted, and using the Canvas API, where you basically have to paint everything yourself. Doing input in a canvas based interface is difficult, you can react on key down and up, but the standard does not really allow you to tell if the devices even has a keyboard, or if you need to display a virtual keyboard on the screen. <br /><br />An even worse problem is the fragmentation of the market. Java implementations differ, and even if it is very probable that your java me code will run on most devices (if it is well written) verifying that it does is not a smal task. And if you want it too look good it is even worse. Emulators do not help much either, verifing that something runs in the emulator does not guarantee that it will work on the device. And it is not even sure that there is an emultor for your target device.<br /><br />And phone manufacturers keep making new models all the time... Apple basically has one platform and offers upgrade for old versions (sometimes free of charge, sometimes at a small charge) but the competition has not learned from this. Instead they have incompatible version on different devices, where you basically have to test on, if not all, several different versions. Just keeping up with the new models from the main manufacturers ( there are only four or five) takes a lot of time. The so called java verification does not guarantee that your application will run on all Java ME implementations with the features you need, instead you have to verify it again and again as there are new devices.<br /><br />All in all this leads to that Java ME is not a good alternative for your application development today. The future of java om the mobile is rather in Android or BlackBerry. That is if not one of the major manufacturers take steps to fix this. And frankly I don't see this happening. <br /><br />An exception to this is possibly Symbian. Java ME implementation on Symbian is pretty good. But it seems like Nokia is more interested in promoting development in C++, or rather the very restricted C++ available on Symbian.Erikhttp://www.blogger.com/profile/07865795210715993795noreply@blogger.com1tag:blogger.com,1999:blog-33472901.post-23510303698654660832010-01-06T21:04:00.002+01:002010-01-06T21:12:44.484+01:00New Antenna releaseToday I released version 1.2.1 of <a href="http://antenna.sourceforge.net/">Antenna</a>. The new version includes both bug fixes and new features.<br /><br />I made a mistake in the 1.2.0 release, which leads to a Null Pointer Exception if the Wireless Toolkit can not be detected. Antenna can detect a lot of toolkit's, but not all, so this has given users some poblems. A patch has been in the repository for a whil, but now it is in a release also.<br /><br />When the 1.2.0 release was made, ther was no Java ME SDK for Mac available, but now there is. Unfortunately the file we used in 1.2.0 to detect Java ME SDK 3.0 is not included in the Mac version, so toolkit detection fails. This is fixed in the 1.2.1 release, which should work with Java ME SDK for Mac ( I haven't tested it myself, since I don't have a mac).<br /><br />The realease also includes som contributed patches:<br />- obfusactor arguments can now be passed to WtkPackage<br />- Key stor type can be set in WtkSign<br />- WtkRapc can build libraries<br /><br />More info on antenna and the release is available <a href="http://antenna.sourceforge.net/">here</a>.Erikhttp://www.blogger.com/profile/07865795210715993795noreply@blogger.com0tag:blogger.com,1999:blog-33472901.post-87625238287412679682010-01-01T15:28:00.003+01:002010-01-01T15:43:04.219+01:00Supporting BlackBerry touch devicesOur BlackBerry application is built using BlackBerry software version 4.5. Unfortunately this means that we can not handle touch events, since they are only supported from version 4.7. Since most of our users have 4.5 or 4.6 this is not an option. Up til now the application has had very limited functionality on touch devices like BlackBerry Storm, running in the so called *compatibility mode' with the virtual keyboard displayed all the time and only about half the screen available for our application.<br /><br />But now we have made a few changes:<br />We upgraded the Storm device software (to version 4.7.0.181). This solved the problem with the virtual keyboard, which now can be displayed only when needed.<br /><br />We revised our application. The main problem is our custom object, which did not work well. This seems to be because the <a href="http://www.blackberry.com/developers/docs/4.2.1api/net/rim/device/api/ui/Field.html#navigationMovement%28int,%20int,%20int,%20int%29">navigationMovement </a>method is not called on a touch device. Since we had some application logic in this method in our custom object, it did not work well. The solution was to move the code to the <a href="http://www.blackberry.com/developers/docs/4.2.1api/net/rim/device/api/ui/Field.html#moveFocus%28int,%20int,%20int,%20int%29">moveFocus</a> mthod, which is called both on touch and keyborad devices.<br /><br />In the long run we probably will have to provide different installations for users with 4.5/4.6 or 4.7 software version. Still we do not support more advanced touch screen usage.Erikhttp://www.blogger.com/profile/07865795210715993795noreply@blogger.com0tag:blogger.com,1999:blog-33472901.post-17889389859596559952009-09-27T10:25:00.003+02:002009-09-27T10:30:27.261+02:00Antenna 1.2.0 with support for Java ME SDK 3.0 releasedYesterday I made the new antenna version with support for Java ME SDK 3.0 available for download. The testers have been positive so far, so it is ready for more general use.<br /><br />The changes are documented in <a href="http://antenna.sourceforge.net/setup.php">here</a>. You will also find the matrix with toolkits ad optional libraries there, it seems like Blogger don't really like my html table...<br /><br />The download is available <a href="http://sourceforge.net/project/showfiles.php?group_id=67420">here</a>.Erikhttp://www.blogger.com/profile/07865795210715993795noreply@blogger.com0tag:blogger.com,1999:blog-33472901.post-27034304216536711372009-09-23T14:32:00.004+02:002009-09-24T13:08:11.212+02:00Java Me toolkit's and support for optional JSR'sAs a part of the new Antenna release I have reviewed the toolkits supported and which JSR's they support. The result is the matrix below.<br /><br />As you see, many JSR's are widely supported, while others are supported only by a few manufacturers. If you need Bluetooth, PDA, Wireless Messaging, SVG or Mobile Media, they are available in most emulators. But if you need Internationalization, or Open GL your choice is more limited.<br /><br />Many manufacturers have their own additional APIs. Most used is Nokia UI, which is actually also supported by Sony Ericsson.<br /><br /><table border="1"><br /><tbody><br /><tr><br /><td><b>JSR API Support</b></td><br /><td><b>Antenna property</b></td><br /><td><b>Sun WTK 2.5</b></td><br /><td><b>Java ME SDK 3.0</b></td><br /><td><b>MOTODEV Studio for Java ME</b></td><br /><td><b>Nokia S60 3rd Edition SDK</b></td><br /><td><b>Nokia N97 SDK</b></td><br /><td><b>Nokia S40 5</b><sup><b>th</b></sup><b>ed</b></td><br /><td><b>Sony Ericsson SDK 2.5</b></td><br /><td><b>Sprint WTK 3.3.2</b></td><br /><td><b>LG SDK 1.3 for Java ME</b></td><br /></tr><br /><tr><br /><td>CLDC version</td><br /><td></td><td>1.0,1.1</td><td>1.0,1.1</td><td>1.1</td><td>1.1</td><td>1.1</td><td>1.0, 1.1</td><td>1.0, 1.1</td><td>1.0, 1.1</td><td>1.0, 1.1</td></tr><br /><tr><br /><td>MIDP version</td><br /><td><br /></td><br /><td>1.0,2.0,2.1</td><td>1.0,2.0,2.1</td><td>2.1(2.0)</td><td>2.0,2.1</td><br /><td>2.0,2.1</td><td>1.0,2.0,2.1</td><td>1.0,2.0,2.1</td><td>1.0,2.0,2.1</td><br /><td>1.0,2.0,2.1</td><br /></tr><br /><tr><br /><td>JSR 75 PDA</td><br /><td>optionalpda</td><br /><td>x</td><td>x</td><td>x</td><td>x</td><td>x</td><td>x</td><td>x</td><td>x</td><td>x</td><br /></tr><br /><tr><br /><td>JSR 82 Bluetooth</td><br /><td>Bluetooth</td><br /><td>x</td><td>x</td><td>x</td><td>x</td><td>x</td><td>x</td><td>x</td><td>x</td><td>x</td><br /></tr><br /><tr><br /><td>JSR 135 Mobile Media 1.2</td><br /><td>mmapi</td><br /><td>x</td><td>x</td><td>x</td><td>x</td><td>x</td><td>x</td><td>x</td><td>x</td><br /><td>x</td><br /></tr><br /><tr valign="top"><br /><td>JSR 172 Web Services</td><br /><td>j2mews</td><br /><td>x</td><td>x</td><td>x</td><td>x</td><td>x</td><td>x</td><td>x</td><td>x</td><td>x</td><br /></tr><br /><tr valign="top"><br /><td>JSR 177 Security and Trust Services</td><br /><td>satsa</td><br /><td>x</td><td>x</td><td>x</td><td>x</td><td>x</td><td>x</td><td>x</td><td>x</td><td>x</td><br /></tr><br /><tr valign="top"><br /><td>JSR 179 Location</td><br /><td>locationservices</td><br /><td>x</td><td>x</td><td>x</td><td>x</td><td>x</td><td></td><td>x</td><td>x</td><td>x</td><br /></tr><br /><tr valign="top"><br /><td>JSR 180 SIP</td><br /><td>sipapi</td><br /><td>x</td><td>x</td><td>x</td><td>x</td><td></td><td></td><td>x</td><td>x</td><td>x</td><br /></tr><br /><tr valign="top"><br /><td>JSR 184 Mobile 3D Graphics</td><br /><td>java3d</td><br /><td>x</td><td>x</td><td>x</td><td>x</td><td>x</td><td>x</td><td>x</td><td>x</td><td>x</td><br /></tr><br /><tr><br /><td>JSR 120 WMA 1.0</td><br /><td>wma</td><td>x</td><td>x</td><td>x</td><td>x</td><td>x</td><td>x</td><td>x</td><td>x</td><br /><td>x</td><br /></tr><br /><tr><br /><td>JSR 205 Wireless Messaging 2.0</td><br /><td>wma2</td><br /><td>x</td><td>x</td><td>x</td><td>x</td><td>x</td><td>x</td><td>x</td><td>x</td><td>x</td><br /></tr><br /><tr valign="top"><br /><td>JSR 209 AGUI</td><br /><td>agui</td><br /><td></td><td>x</td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><br /></tr><br /><tr valign="top"><br /><td>JSR 211 Content Handler</td><br /><td>contenthandler</td><br /><td>x</td><td>x</td><td>x</td><td></td><td></td><td>x</td><td>x</td><td>x</td><td>x</td><br /></tr><br /><tr valign="top"><br /><td>JSR 226 Scalable 2D Vector Graphics</td><br /><td>s2dvgapi</td><br /><td>x</td><td>x</td><td>x</td><td>x</td><td>x</td><td>x</td><td>x</td><td>x</td><td>x</td><br /></tr><br /><tr valign="top"><br /><td>JSR 229 Payment</td><br /><td>papi</td><br /><td>x</td><td>x</td><td></td><td></td><td></td><td></td><td>x</td><td>x</td><td>x</td><br /></tr><br /><tr valign="top"><br /><td>JSR 234 Advanced Multimedia Supplements</td><br /><td>ams</td><br /><td>x</td><td>x</td><td>x</td><td>x</td><td>x</td><td>x</td><td>x</td><td>x</td><td>x</td><br /></tr><br /><tr valign="top"><br /><td>JSR 238 Mobile Internationalization</td><br /><td>miapi</td><br /><td>x</td><td>x</td><td>x</td><td></td><td></td><td></td><td>x</td><td>x</td><td>x</td><br /></tr><br /><tr valign="top"><br /><td>JSR 239 Java Binding for OpenGL ES</td><br /><td>opengl</td><br /><td>x</td><td>x</td><td>x</td><td></td><td></td><td></td><td>x</td><td></td><td>x</td><br /></tr><br /><tr valign="top"><br /><td>JSR 256 Mobile Sensor</td><br /><td>mobilesensor</td><br /><td></td><td>x</td><td></td><td></td><td>x</td><td></td><td></td><td></td><td>x</td></tr><br /><tr valign="top"><br /><td>JSR 257 Contactless Communication</td><br /><td>rfid</td><br /><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td>x</td><br /></tr><br /><tr valign="top"><br /><td>JSR 280 XML</td><br /><td>xml</td><br /><td><br /></td><br /><td>x</td><br /><td><br /></td><br /><td><br /></td><td><br /></td><td><br /></td><td><br /></td><td><br /></td><td><br /></td> </tr><br /><tr valign="top"><br /><td>JSR 300 DRM</td><br /><td>drm</td><br /><td><br /></td><br /><td><br /></td><br /><td><br /></td><br /><td><br /></td><br /><td><br /></td><br /><td><br /></td><br /><td><br /></td><br /><td><br /></td><br /><td>x</td><br /></tr><br /><tr valign="top"><br /><td>G24 MOTO2MOTO</td><br /><td>G24</td><br /><td><br /></td><br /><td><br /></td><br /><td>x</td><br /><td><br /></td><br /><td><br /></td><br /><td><br /></td><br /><td><br /></td><br /><td><br /></td><br /><td><br /></td><br /></tr><br /><tr valign="top"><br /><td>Motorola APIs</td><br /><td>motorola</td><br /><td><br /></td><br /><td><br /></td><br /><td>x</td><br /><td><br /></td><br /><td><br /></td><br /><td><br /></td><br /><td><br /></td><br /><td><br /></td><br /><td><br /></td><br /></tr><br /><tr valign="top"><br /><td>Nokia UI API</td><br /><td>nokiaui</td><br /><td><br /></td><br /><td><br /></td><br /><td><br /></td><br /><td><br /></td><br /><td>x</td><br /><td>x</td><br /><td>x</td><br /><td><br /></td><br /><td><br /></td><br /></tr><br /><tr valign="top"><br /><td>eSWT API</td><br /><td>eswt</td><br /><td></td><td></td><td></td><td></td><td>x</td><td></td><td></td><td></td><td></td><br /></tr><br /><tr valign="top"><br /><td>IAP Info</td><br /><td>iapinfo</td><br /><td></td><td></td><td></td><td></td><td>x</td><td></td><td></td><td></td><td></td><br /></tr><br /></tbody></table>Erikhttp://www.blogger.com/profile/07865795210715993795noreply@blogger.com0tag:blogger.com,1999:blog-33472901.post-51377770867845517132009-09-19T17:07:00.003+02:002009-09-19T17:10:50.548+02:00Antenna: Support for LG SDK 1.3 for Java ME and Nokia N97 SDKToday I added support for LG SDK 1.3 for Java ME and Nokia N97 SDK to <a href="http://antenna.sourceforge.net/">antenna</a>. This is available now in the repository and hopefully soon as a binary download.Erikhttp://www.blogger.com/profile/07865795210715993795noreply@blogger.com0tag:blogger.com,1999:blog-33472901.post-46734228480800532892009-08-26T22:06:00.002+02:002009-08-26T22:11:14.029+02:00Antenna Java ME SDK 3.0 version now availableMy patch for <a href="http://antenna.sourceforge.net/index.php">antenna</a> is now comitted into the repository and is available for download. Still no build available, you have to get the sourcecode yourself and build it, or send me a mail and I will send you a jar file. Hopefully the pre-built version will be available soon. Documentation is also not updated yet, but you will find some in this blog.Erikhttp://www.blogger.com/profile/07865795210715993795noreply@blogger.com0tag:blogger.com,1999:blog-33472901.post-17139037781109457822009-07-08T06:08:00.006+02:002009-07-08T09:26:53.376+02:00Antenna support for Java ME SDK 3.0For building our Java ME application we use <a href="http://antenna.sourceforge.net/">Antenna</a>. It is a great tool, that makes automated builds possible and also works well as your regular build tool. But it lacks support for Java ME SDK 3.0 and other newer toolkits. Since we need that, I have made a contribution to the Antenna project, added as a patch yesterday.<br />If you want to try the modified verions, send me a mail and I will send you the jar.<br /><br /><span style="font-weight: bold;">How it works</span><br /><br />A key property of your Antenna setup is the wtk.home property. It should point to the base directory of your WTK/Java ME SDK installation. Antenna uses this to detect which toolkit you are using. In the older version toolkits are hardcoded into Antenna sourcecode. In the new version textfiles are used to set up available toolkits and their properties. Antenna goes through a list of toolkits, described in the text file autodetect.txt, and checks if the unique files for that specific toolkit are available. If they are, the right toolkit have been found, and properties are loaded from a properties file.<br /><br />This makes it easy to add a new toolkit or new properties for the existing one.<br /><br /><span style="font-weight: bold;">Supported toolkits</span><br /><br />I have tested the new version with the following toolkits:<br />- SUN Java ME SDK 3.0<br />- Sun WTK 2.5.2<br />- MOTODEV SDK for Java ME v2<br />- Nokia S60_3rd_FP2_SDK_v1.1 (Symbian)<br />- SPRINT WTK 332<br />- Samsung_SDK_11 (autodetected as WTK 2.5.2)<br />- SonyEricsson WTK 2.5.2<br />- Nokia S40 5th Edition SDK Feature<div id=":54" class="ii gt"><wbr>Pack 1<br /></div><br />I have also made some tests with Mpowerplayer, but the stub for CLDC 1.1 provided with Mpowerplayer seems not to match the specification. If I replace it with the one from Suns WTK 2.5.2 it seems OK. I have not tested Mpowerplayers preverifier, since it is Mac based and I use a Windows PC.<br /><br /><span style="font-weight: bold;">Antenna setup</span><br /><br />Antenna properties are described <a href="http://antenna.sourceforge.net/index.php#setup">here</a>. They work as before, with the new feature that additional libraries can be defined dynamically, in the toolkit properties file, without any need for changes in Antenna source code. If I set up a property for a toolkit like this:<br /><code><br />jsr999=lib/jsr999.jar<br /></code><br />I can then turn it on in my ant file by setting the property <span style="font-style: italic;">wtk.jsr199.enabled</span> to <span style="font-style: italic;">true</span>. I can also turn on all defined additional libraries by setting property <span style="font-style: italic;">wtk.all.enabled</span> to <span style="font-style: italic;">true</span>. During development I used this, since Antenna checks that all jar files are available.<br /><br />Adding a new Toolkit<br />You can add a new toolkit to antenna just by editing a text file and adding another. Do like this:<br />First you add a new line to the file autodetext.txt (in the res directory). It should look something like this:<br /><code><br />#sony ericsson<br />sonyericwtk2;lib/semc_ext_jp8.jar;lib/cldcapi11.jar<br /></code><br />Lines starting with # are comments. The lines defining toolkits should start with the toolkit property filename and then contain a list of files that are unique to this toolkit. File names should be relative to wtk.home.<br /><br />Then you add a properties file, in this case sonyericwtk2.properties. It looks something like this:<br /><code><br />name="Sony Ericsson WTK2"<br />include=wtk25<br />nokiaui=lib/nokiaext.jar<br />semc=lib/semc_ext_jp8.jar<br />vodafone=lib/vscl21.jar<br /></code><br /><br />The properties you could use are:<br /><br /><ul><li>name: a descriptive name for the toolkit. Use this always.</li><li>preverifyversion: 1 means WTK 1 style, support only CLDC 1.0, 2 means WTK 2 style, include Target parameter in preverify command, 3 means WTK 3 style, only add parameter cldc1.0 if cldc 1.0 is used</li><li>emulator: exe or jar file for emulator</li><li>cldc10,cldc11: libraries for cldc versions</li><li>midp10,midp20,midp21: libraries for midp versions</li><li>include: include another toolkit definition. Useful if the toolkit is an add-on to another toolkit, like WTK 2.5 or Java ME SDK 3.0</li></ul>All other properties will be taken for add-on libraries that will be added to classpath if wtk.[propertiy].enabled is true, or if wtk.all.enabled is true.<br /><br />Please let me know if you have any problems or improvement suggestions.Erikhttp://www.blogger.com/profile/07865795210715993795noreply@blogger.com0tag:blogger.com,1999:blog-33472901.post-34641042872283983032009-06-30T09:25:00.002+02:002009-06-30T09:31:13.083+02:00Catch System.out from BlackBerry simulatorJust a little trick I just learned. Sometimes I want a quick and easy logging, just to see what's happening in my program. The easiest approach, specially early in the project is simply using System.out. But when you run your program in the emulator you don't see system out anywhere. To see it you need the command line parameter <span style="font-style: italic;">/app-param=JvmDebugFile.</span><br /><br />Just run the emulator as follows:<br /><code><br />fledge /handheld=9000 "/app-param=JvmDebugFile:bblog.txt"<br /></code><br /><br />In the bblog.txt you will get a lot of info, and your System.out output.Erikhttp://www.blogger.com/profile/07865795210715993795noreply@blogger.com3tag:blogger.com,1999:blog-33472901.post-69125451685192430712009-06-17T11:50:00.000+02:002009-06-17T12:00:25.115+02:00Java ME automated buildSo far I have built my Java ME application using <a href="http://java.sun.com/javame/downloads/sdk30.jsp">Sun Java ME SDK 3.0</a> and before the SDK was available with Sun <a href="http://java.sun.com/products/sjwtoolkit/wtk2.5.2/">Wireless Toolkit</a>. But now we need to streamline the process and introduce automated build.<br /><br />The tool we use for this is ant, with an add-on for Java ME called <a href="http://antenna.sourceforge.net/">antenna</a>. Antenna is an open source project, which provides support for operations like obfuscating, updating manifest and JAD files and signing.<br /><br /><span style="font-weight: bold;">Setup<br /></span>To use antenna you need to setup the antenna tasks, using taskdef, and define some properties:<br /><code><br /> <taskdef resource="antenna.properties" classpath="${basedir}\tools\antenna.jar" /><br /> <property name="wtk.home" location="C:\WTK2.5.2"/><br /> <property name="wtk.cldc.version" value="1.1"/><br /> <property name="wtk.midp.version" value="2.0"/><br /> <property name="wtk.proguard.home" value="${basedir}\tools\proguard4.3"/><br /></code> <br />As you can see, we have a directory called tools, where we keep the antenna jar and also a <a href="http://proguard.sourceforge.net/">proguard</a> installation, which we need for obfuscation.<br />Antenna also needs to know where your wireless toolkit is installed and which versions of CLDC and MIDP you use. That's it!<br /><br /><span style="font-weight: bold;">Package</span><br />Antennas main function is packaging your application into jar and jad files, preverified, obfuscated and with correct manifest and jad files. You can do this step-by-step, with different tasks for each step, but you can also use the wtkpackage task to make them all.This is the approach we have taken.<br /><code><br /><code><</code>target name="package" depends="compile"<code>></code><br /> <code><</code>mkdir dir="${dist.dir}"/<code>></code><br /> <code><</code>copy file="${basedir}/myapp.jad" overwrite="true" failonerror="true" tofile="${dist.dir}/myapp.jad"/<code>></code><br /> <br /> <code><</code>wtkpackage jarfile="${dist.dir}/myapp.jar"<br /> jadfile="${dist.dir}/myapp.jad"<br /> obfuscate="true"<br /> preverify="true"<code>></code><br /> <br /> <code><</code>fileset dir="${class.dir}"/<code>></code><br /> <code><</code>fileset dir="${res.dir}"/<code>></code><br /><br /> <code><</code>exclude_from_manifest name="myapp-dir"/<code>></code><br /> <code><</code>exclude_from_manifest name="myapp-host"/<code>></code><br /><br /> <code><</code>/wtkpackage<code>></code><br /> <code><</code>copy file="${dist.dir}/myapp.jad" overwrite="true" failonerror="true" tofile="${dist.dir}/myappu.jad"/<code>></code><br /><br /> <code><</code>/target<code>></code><br /></code><br />Comments:<br /><ol><li>compilation is separate, our package task is made after the compilation</li><li>we keep a jad template in the project basedir, which we copy to the dist dir</li><li>wtkpackage will create the jar file and update the jad file. We also want it to preverify and obfuscate using proguard<br /></li><li>in ${class.dir} we have all classes that should be included</li><li>all used resources are in ${res.dir} </li><li>we have two parameters in our JAD template that should be only in the JAD file and not in the Manifest file. This allows for changing them without resigning.</li><li>as a last step we copy the jad file. This is to have an unsigned copy for use in emulators and phones that don't support the Verisign certificate we use (Nokia S40..)</li></ol><span style="font-weight: bold;">Signing the application</span><br />Antenna also supports signing using the very straightforward wtksign task:<br /><code><br /><target name="sign" depends="package"><br /> <wtksign<br /> keystore="${basedir}/../cert/keystore.ks"<br /> jarfile="${dist.dir}/myapp.jar"<br /> jadfile="${dist.dir}/myapp.jad"<br /> storepass="******"<br /> certpass="******"<br /> certalias="myalias"<br /> /><br /><br /> </target><br /></code><br /><br />This will add signature information to the JAD file using the certificate in the keystore and the JAD and jar files are redy to use.Erikhttp://www.blogger.com/profile/07865795210715993795noreply@blogger.com0tag:blogger.com,1999:blog-33472901.post-74588672180602625762009-06-03T08:35:00.002+02:002009-06-03T08:59:27.673+02:00Going native on BlackBerryOur application is currently based on Java ME and uses the lcdui to a 100%, even though there are some fixes to make it work better on BlackBerry. Since BlackBerry is getting more and more popular in the market we have decided to make a version that uses the BlackBerry native UI instead of Java ME standard lcdui.<br /><br />BlackBerry does not allow combining its native UI with lcdui, which means we will have to convert everything, including the midlet. The majority of the code is however in our own classes, since 90% of tha application is Canvas-based. It seems quite possible to make them work in both environments.<br /><br />Major changes will be:<br />- our midlet is replaced by a <a href="http://www.blackberry.com/developers/docs/4.7.0api/net/rim/device/api/ui/UiApplication.html">UIApplication</a><br />- the Canvas will be replaced by a <a href="http://www.blackberry.com/developers/docs/4.7.0api/net/rim/device/api/ui/container/MainScreen.html">MainScreen</a><br />- instead of the List we use we will have a <a href="http://www.blackberry.com/developers/docs/4.7.0api/net/rim/device/api/ui/component/KeywordFilterField.html">KeywordFilterField</a>, which will gives the users better functionality.<br /><br />Our components will be placed in the MainScreen (instead of a Java ME Canvas). To make this work we will use an interface for painting with two different implementations, that encapsulate Java ME Graphics and BlackBerry <a href="http://www.blackberry.com/developers/docs/4.7.0api/net/rim/device/api/ui/Graphics.html">Graphics</a>. We will also need to handle the different Font classes and lcdui Image versus BlackBerry Bitmap.<br /><br />Our immediate gains will be:<br />- scalable fonts, which is a problem for us now, since the Lcdui fonts on BlackBerry Bold are very large<br />- some UI improvements, like the KeyWordFilterField instead of the List etc<br />We will also gain access to possiblities like opening an input field on top of ouyr Canvas, with we really need and have a better looking app.Erikhttp://www.blogger.com/profile/07865795210715993795noreply@blogger.com1tag:blogger.com,1999:blog-33472901.post-22517306160207516612009-05-05T13:22:00.003+02:002009-05-05T13:31:25.120+02:00Java ME Search EngineFinding information on Java ME issues can be time consuming. A lot of information is available on the Internet, and Google finds lots of it. But most of the time you get Java ME information mixed with a lot of Java SE information.<br /><br />To solve this I have collected a lot of Java ME resources and created a Google customized Search Engine. This is a first try, based on some links I had collected. There is certainly a lot more resources available out there. If you know one, don't hesitate to send me a mail.<br /><br />Here is the search box:<br /><br /><form action="http://www.google.com/cse" id="cse-search-box"><span style="font-size:130%;">Java ME Search Engine</span><br /> <div><br /> <input name="q" size="31" type="text"><br /> <input name="sa" value="Search" type="submit"><br /><br /> </div><br /></form><br /><br /><script type="text/javascript" src="http://www.google.com/coop/cse/brand?form=cse-search-box&lang=en"></script>Erikhttp://www.blogger.com/profile/07865795210715993795noreply@blogger.com0