Wednesday, June 27, 2012

Creating a Basic Theme And Using The Image Border Wizard



Codename One themes are effectively a set of UIID's mapped to a Style object, we can create a new theme by adding it in the Designer tool and customizing the UIID values.


We can add a component style to a component such as Button, typically UIID's are named with the same name as the Component class. You can modify the UIID of a component by invoking setUIID(String) on an arbitrary component or changing the UIID property in the GUI builder.


Styles can have one of 4 states:
  1. Default (unselected) - the way a component appears when its in none of the other states.
  2. Selected - shown when the component has focus or is active (on a touch screen device this only appears when the user interacts with the device with touch or with a physical key).
  3. Pressed - shown when the component is pressed. This is only active for Button's.
  4. Disabled - shown when the component is disabled.

You can add a style to any one of the states in the Designer to make the component appear as expected in those cases.
  

When editing the style of the component you can customize multiple things such as the background image, the way such a background image is displayed or a gradient/solid color background. You can customize colors, fonts, padding/margin, border etc.


Borders are a remarkably powerful tool for customizing a Component. The most powerful approach is the 9-piece image border which is easiest to use when using the Image Border Wizard.


The image border wizard allows you to take an image and "cut it" into 9 distinct pieces: 4 corners, top, bottom, left, right & center.
The corners are placed as usual in the edges of the component and the other elements are tiled to fill up the available space.


Its important when using a gradient effect within the image border to make sure the center pieces are as narrow as possible to avoid a case of a "broken" gradient.

Friday, June 15, 2012

Push It Real Good

Push notification is one of those things that seems simpler going in...

Please notice that this code and implementation is highly experimental and we are still working out the kinks. It is also only enabled for paid accounts in Codename One due to some of the server side infrastructure we need to maintain to support this feature.

Push notification allows you to send a message to a device, usually a simple text message which is sent to the application or prompted to the user appropriately. When supported by the device it can be received even when the application isn't running and doesn't require polling which can drain device battery life.
The keyword here is "when supported" unfortunately not all devices support push notification e.g. Android device that don't have the Google Play application (formerly Android Market) don't support push and must fall back to polling the server... Not ideal.

Currently we support pushing to Google authorized Android devices: C2DM (Cloud To Device Messaging) and to iOS devices: Push Notification.
For other devices we will fallback to polling the server in a given frequency, not an ideal solution by any means so we give you the option to not fallback.

This is how Apple describes push notification (image source Apple):

The "provider" is the server code that wishes to notify the device. It needs to ask Apple to push to a specific device and a specific client application. There are many complexities not mentioned here such as the need to have a push certificate or how the notification to APNS actually happens but the basic idea is identical in iOS and Android's C2DM.

Codename One hides some but not all of the complexities involved in the push notification process. Instead of working between the differences of APNS/C2DM & falling back to polling, we effectively do everything that's involved.

Push consists of the following stages on the client:
  1. Local Registration - an application needs to register to ask for push. This is done by invoking:
    Display.getInstance().registerPush("gmail email account for C2DM", fallback);

    The fallback flag indicates whether the system should fallback to polling if push isn't supported.
    On iOS this stage prompts the user indicating to him that the application is interested in receiving push notification messages.
  2. Remote registration - once registration in the client works, the device needs to register to the cloud. This is an important step since push requires a specific device registration key (think of it as a "phone number" for the device).  Normally Codename One registers all devices that reach this stage so you can push a notification for everyone, however if you wish to push to a specific device you will need to catch this information! To get push events your main class (important, this must be your main class!) should implement the PushCallback interface. The registeredForPush(String) callback is called with the unique device ID that can be used later on when pushing to this particular device.
  3. In case of an error during push registration you will receive the dreaded: pushRegistrationError.
    This is a very problematic area on iOS, where you must have a package name that matches EXACTLY the options in your provisioning profile which is setup to support push. It is also critical that you do not use a provisioning profile containing a * character in it.
  4. You will receive a push callback if all goes well.

Sending the push requires two different things for Google and  iOS. In C2DM (Google) you send a push via a gmail address (you need to apply to get a larger quota) and once you have that quota you can just start sending push notifications.

To prove that you indeed have the account you need a Google auth key which you can retrieve by calling:

https://codename-one.appspot.com/googleAuth?email=youremail@gmail.com&password=yourpassword

The key occasionally expires so be sure to refresh it. You can optionally send us your Google credentials when pushing a message via the server API and we will retrieve the key automatically.
For privacy concerns we recommend setting up a separate account that will be used for push alone and not using your standard Google account to perform push operations.

For iOS developers must download a push certificate from the iOS provisioning portal for the given application. Notice that by enabling push you will probably need to regenerate the provisioning profile as well and download/replace your existing provisioning profile.
The certificate must be converted to a p12 certificate as I explained in the provisioning profile tutorial.  

Currently we don't have the option to send the iOS certificate as part of the push request so you will have to host it somewhere and provide us with the link.

To send a push message use the following web API:
https://codename-one.appspot.com/sendPushMessage?auth=googleAuthKey&
packageName=packageNameOfApplication&
email=gmailAccount&
device=theDeviceKey&
type=1&
production=true/false&
certPassword=pass&
cert=CertificateURL

Notice the following arguments in particular:
  • device - this is an optional argument, to send to all devices just omit this argument. To send to a particular device you need to provide its key which was given in the registeredForPush() callback.
  • type - this must currently be set to 1, there will be additional types in the future
  • production - iOS has production and development push services each of which requires a different certificate. Its important to pick the right one. Pass true for production and false for development.
  • cert - the URL for the iOS push certificate which you are hosting.
  • certPassword - the password of the certificate

Again take into consideration that this is an early stage release with multiple bugs.

Monday, June 4, 2012

Understanding Layout Managers

This post is effectively "ripped" out of the new developer guide that is "under development", you can take a part in this process and get the full guide here

Layout managers are installed on the Container class and effectively position the Components within the given container. The LayoutManager class is abstract and allows users to create their own layout managers, however Codename One ships with multiple layout managers allowing for the creation of many layout types.

The layout managers are designed to allow developers to build user interfaces that seamlessly adapt to all resolutions and thus they don’t state the component size/position but rather the intended layout behavior.  To install a layout manager one does something like this:

Container c = new Container(new BoxLayout(BoxLayout.X_AXIS));
c.addComponent(new Button("1"));
c.addComponent(new Button("2"));
c.addComponent(new Button("3"));

This would produce 3 buttons one next to the other horizontally.

There are two major types of layout managers: Constraint based & regular. The regular layout managers like the box layout are just installed on the container and “do their job”. The constraint based layout managers associate a value with a Component sometimes explicitly and sometimes implicitly. Codename One ships with 3 such layouts BorderLayout, TableLayout & GroupLayout.
A constraint layout can/must accept a value when adding the component to indicate its position e.g.:

Container c = new Container(new BorderLayout());
c.addComponent(BorderLayout.CENTER, new Button("1"));
c.addComponent(BorderLayout.NORTH, new Button("2"));
c.addComponent(BorderLayout.SOUTH, new Button("3"));

This will stretch button 1 across the center of the container and buttons 2-3 will be stretched horizontally at the top and bottom of the container. Notice that the order to adding doesn’t mean much once we have a constraint involved...

Flow Layout

Flow layout can be used to just let the components “flow” horizontally and break a line when reaching the end of the component. It is the default layout manager for Codename One but because it is so flexible it could be problematic since it can cause the preferred size of the Container to provide false information triggering endless layout reflows (see below).

Flow layout can be aligned to the left (by default) center or to the right. Components within the flow layout get their natural preferred size by default and are not stretched in any axis.
The layout manager also supports modifying the horizontal alignment of the flow layout in cases where the container grows vertically.

final Container layouts = new Container();        final Button borderLayout = new Button("Border");
final Button boxYLayout = new Button("Box Y");
final Button boxXLayout = new Button("Box X");
final Button flowLayout = new Button("Flow");
final Button flowCenterLayout = new Button("Flow Center");
final Button gridLayout = new Button("Grid");
final Button tableLayout = new Button("Table");
layouts.setLayout(new FlowLayout(Component.CENTER));
layouts.addComponent(borderLayout);
layouts.addComponent(boxYLayout);
layouts.addComponent(boxXLayout);
layouts.addComponent(flowLayout);
layouts.addComponent(flowCenterLayout);
layouts.addComponent(gridLayout);
layouts.addComponent(tableLayout);

Box Layout

Box layout allows placing components in a horizontal or a vertical line that doesn’t break the line. Components are stretched along the opposite axis, e.g. X axis box will flow components horizontally and stretch them vertically.
.

Box layout accepts the axis in its constructor, the axis can be either BoxLayout.X_AXIS or BoxLayout.Y_AXIS.

Border Layout


Border layout is quite unique, its a  constraint based layout that can place up to 5 components in one of the 5 positions: North, South, East, West or Center.

The layout always stretches the North/South components on the X axis to completely fill the container and the East/West components on the Y axis. The center component is stretched to fill the remaining area by default. However, the border layout has a flag to manipulate the behavior of the center component allowing it to be placed in the absolute center without stretching.

Grid Layout


The Grid Layout accepts a predefined grid rows/columns and grants all components within it an equal size based on the dimensions of the largest component. It is an excellent layout for a set of icons in a grid.
It can also dynamically calculate the columns/rows based on available space.

Table Layout

The table layout is far more elaborate than the grid layout and more akin to the HTML table structure. It is a constraint based layout, however it includes a default constraint if none are specified (e.g. using addComponent(cmp) is equivalent to using addComponent((layout.createConstraint(), cmp)).
A table generally gives elements their preferred sizes but stretches them based on column/row. There are abilities within the constraint element to define multiple behaviors such as row/column spanning, alignments and grow behavior.

Layered Layout

The layered layout just places the components in order one on top of the other and sizes them all to the size of the largest component. This is useful when trying to create an overlay on top of an existing component e.g. an “x” button to allow removing the component.

Understanding Preferred Size

The component class contains many useful methods, one of the most important ones is calcPreferredSize() which is invoked to recalculate the size a component “wants” when something changes (by default Codename One calls getPreferredSize() which caches the value).
The preferred size is decided by the component based on many constraints such as the font size, border sizes, padding etc. When a layout places the component it will size it based on its preferred size or ignore its preferred size either entirely or partially. Eg. FlowLayout always gives components their exact preferred size yet BorderLayout resizes the center component by default (and the other components on one of their axis).

Layout Reflow

When adding a component to a form which isn’t shown on the screen there is no need to tell the UI to repaint or reflow. This happens implicitly. However, when adding a component to a UI which is already visible the component will not show by default.
The reason for this is performance based. E.g. imagine adding 100 components to an already visible form with 100 components within it. If we laid out automatically layout would have  happened 100 times when it can happen only once.
That is why when you add components to a form that is already showing you should invoke revalidate or animate the layout appropriately. This also enables the layout animation behavior.