J2ME Polish
J2ME Polish 2.4 Documentation
Enough Software

Customization

Adjusting the design, text and functionality of your products for different customers or use cases is easy with J2ME Polish. In this section you will learn how you can adjust your application with resource assembling, localization and preprocessing.

Customer A wants a slick design, B prefers a simplistic one? And customer C requests some additional functionality? No problem with J2ME Polish!

Setting Up J2ME Polish for Customization

Edit the build.xml script to enable customization within J2ME Polish.

Setting Up Different Resource Roots

To enable customized versions of your application you can set up one base and several customization root directories with J2ME Polish:

  • In the base root you place all common resources, design settings and texts.
  • In each customization root you can include specific resources, design settings and texts that take precedence over the common ones.

Modify your build.xml script and add <root> elements to the <resources> element of the <build> section. In the following example we use the Ant property ${customization} to refer to the actual customization name. This allows us to enable a unlimited number of customizations later onwards:

<resources
	dir="resources/base"
	defaultexcludes="yes"
	excludes="readme.txt"
>
	<root dir="resources/base/images" />
	<root dir="resources/base/sounds" />
	<root dir="resources/${customization}" if="build.${customization}" />
	<root dir="resources/${customization}/images" if="build.${customization}" />
	<root dir="resources/${customization}/sounds" if="build.${customization}" />
</resources>

Using several conditional root directories in your project

Using Customized Configuration Variables

For using preprocessing and adjusting build settings it is useful to define your own project specific configuration variables. You can easily customize your configuration settings by adding appropriate <variable> definitions to your build.xml file:

<variables>
	<variable file="configuration/base/configuration.properties" />
	<variable file="configuration/${customization}/configuration.properties" if="build.${customization}"/>
</variables>

Setting up customized configurations and preprocessing variables

Within each configuration.properties you can now specify your own variables which you can subsequenly use in "if" / "unless" attributes and in your preprocessing code:

cfg.enableSmsSupport=true
cfg.enableServerBackup=true

Defining your own preprocessing variables

Customizing Resources

In the above project structure you can place common resources and settings into resources/base, resources/base/images and resources/base/sounds. Just place specialized settings and resources into the specialized roots, for example resources/customer2, resources/customer2/images and resources/customer2/sounds. Just put the specific versions of images, messages.txt or polish.css files into the appropriate root directory. You do not need to copy the common files into the specific root directories.

sample directory structure

Each root folder will be searched like described in the Resource Assembling section. So you use subdirectories like ${root.dir}/Nokia, ${root.dir}/FullCanvasSize.176+x208+ and so on to include resources or settings only for specific target devices. Note that any subsequent resources will take precedence over former ones. So the image resources/${customization}/logo.png will be used instead of resources/base/Samsung/SGH-D900/logo.png when you target the D900 phone and use the "${customization}" root in the above example.

When you want to add all resources and subdirectories of a root, add the "includeSubDirs" attribute:

<root dir="resources/base/withsubdirs" includeSubDirs="true" />

Including subdirectories of a root

Changing Text Depending on the Customization

Use the Localization Framework to customize any texts by defining them in ${root.dir}/messages.txt or the appropriate subfolder of a root directory. Like in the Resource Assembling step you do not (and should not) repeat any texts that are already defined in your base root, for example in resources/base/messages.txt, and that do not differ in your customized version. In this way you can correct spelling mistakes, grammar and so on for most cases just by editing a single messages.txt file.

Define the <localization> element in your build.xml script for enabling the Localization Framework:

<resources
	dir="resources/base"
	defaultexcludes="yes"
	excludes="readme.txt"
>
	<root dir="resources/base/images" />
	<root dir="resources/base/sounds" />
	<root dir="resources/${customization}" if="build.${customization}" />
	<root dir="resources/${customization}/images" if="build.${customization}" />
	<root dir="resources/${customization}/sounds" if="build.${customization}" />
	<!-- add the localization element for created localized versions 
	     of your application: 	-->
	<localization>
		<locale name="en_US" />
		<locale name="de_DE" encoding="utf-8" unless="test" />
	</localization>
</resources>

Enabling the Localization Framework

Now you can customize any texts in the above example by adding the definitions to resources/${customization}/messages.txt:

MIDlet-Name=My Customized Name
title.main=My Customized Title

Defining customized texts in messages.txt

In your application code you now use Locale for retrieving the correct text:

this.mainScreen.setTitle( Locale.get("title.main") );

Using de.enough.polish.util.Locale for getting customized texts

You can also "abuse" the Localization Framework for setting customized preprocesing/configuration variables in your messages.txt files:

var:cfg.enableSmsSupport=true
var:cfg.enableServerBackup=true

Using the Localization Framework for defining customized variables

Customizing the Look and Feel of Your Application

You can customize the design of your application by defining the appropriate styles in the polish.css file of the applicable resource root or by using preprocessing within a polish.css file or use a combination of both techniques.

In your customized polish.css files you do not need to repeat settings that are already used in the base polish.css file. Instead just define settings that differ from the base design:

/* just using customized colors here and a specialized title: */
colors {
	textColor: #a00;
	textColorFocused: #f00;
	backgroundColor: #eee;
	backgroundColorFocused: #fff;
}

title {
	padding-left: ${ imagewidth( logo.png ) };
	font-style: bold;
	font-color: white;
	text-effect: shadow;
	text-shadow-color: #333;
	background {
		color: #a00;
		image: url ( logo.png );
		anchor: left | vertical-center;
	}
}

Customizing your design, for example in resources/${customization}/polish.css

Note: when you are overwriting an existing style, you inherit all settings from the parent style. Sometimes this is annoying. To disable inheritance for a specific style, just set the "inherit" attribute to "false":

title {
	inherit: false;
	padding-left: ${ imagewidth( logo.png ) };
	font-style: bold;
	font-color: white;
	text-effect: shadow;
	text-shadow-color: #333;
	background {
		color: #a00;
		image: url ( logo.png );
		anchor: left | vertical-center;
	}
}

Disabling inheritance of CSS attributes for the title style

You can also use preprocessing statements to customize your design:

colors {
	//#if cfg.${customization}
		textColor: #a00;
		textColorFocused: #f00;
	//#else
		textColor: #000;
		textColorFocused: #000;
	//#endif
	backgroundColor: #eee;
	backgroundColorFocused: #fff;
}
title {
	//#if ${ exists( logo.png ) }
		padding-left: ${ imagewidth( logo.png ) };
	//#endif
	font-style: bold;
	font-color: white;
	//#if cfg.${customization}
		text-effect: shadow;
		text-shadow-color: #333;
	//#endif
	background {
		color: #a00;
		//#if ${ exists( logo.png ) }
			image: url ( logo.png );
			anchor: left | vertical-center;
		//#endif
	}
}

Customizing your design by using preprocessing in your polish.css file

Customizing the Functionality of Your Application

For some customizations it might be necessary to adjust the functionality of your application as well. You can do this with J2ME Polish by using preprocessing or conditional source folders. You can achieve this by using preprocessing and optionally configuring your build.xml script.

Use Preprocessing to Customize Your Application

Using preprocessing in your application's source code gives you unlimited possibilities for customizing your application. Best practice is to define customization specific variables first as described above:

cfg.enableSmsSupport=true
var:cfg.enableServerBackup=true

Defining your own preprocessing variables

Now you can query those configuration settings in your application code:

public void storeSettings() {
	//#if cfg.enableServerBackup
		storeSetingsOnServer();
	//#else
		storeSettingsInRms();
	//#endif
}

Using preprocessing to adjust the functionality of your application

Use Source Folders to Customize Your Application

Another option is to include customization specific source code folders in your application. You can specify source code folders by defining them in your build.xml scripts <build> section:

<sources>
	<!-- always include the base folder: -->
	<source dir="source/src">
	<!--  include customization specific source folders: -->
	<source dir="source/${customization}" if="build.${customization}">
</sources>

Setting up conditional source code folders

Building the Customized Versions

For building the customized versions of your application, you need to adjust your build.xml script again. For each customization we add two targets: the "enable" target sets up build properties required for the customization, and the "customize" calls the "enable" target first and then the "j2mepolish" target.
For building all customized versions of your application at once, we need to use some <subant> Ant voodoo, because we cannot overwrite defined Ant properties once they are set. Have a look at this example taken from the "blank" sample application:

<project 
	name="blank" 
	default="j2mepolish">
	
	<!-- import user specific properties                          -->
	<property file="${user.name}.properties" />
	
	<!-- The polish.home property needs to point to the directory -->
	<!-- containing the J2ME Polish installation.                 -->
	<property name="polish.home" location="C:\Program Files\J2ME-Polish" />
	
	<!-- import global properties                                 -->
	<property file="${polish.home}/global.properties" />

		
	<!-- the device for the test mode - you can define it on the command-line
	     using the -D switch, e.g. ant -Ddevice=Generic/AnyPhone emulator -->
	<property name="device" value="Nokia/Series60E3" />
	
	

	<!-- Definition of the J2ME Polish task:                      -->
	<taskdef name="j2mepolish" 
		classname="de.enough.polish.ant.PolishTask" 
		classpath="${polish.home}/lib/enough-j2mepolish-build.jar:${polish.home}/lib/jdom.jar"
	/>
	
		
	<!-- build targets, each target can be called via "ant [name]", 
		 e.g. "ant clean", "ant test j2mepolish" or just "ant" for calling the default-target -->
				
	<target name="init">
	  	<property name="test" value="false" />
	  	<property name="customization" value="" />
		<property name="dir.work" value="build/real/${customization}" />
		<property name="dir.dist" value="dist/${customization}" />
		<property name="deploy-url" value="" />
	</target>
	 
	<!-- In this target the J2ME Polish task is used.             -->
	<!-- It has 4 sections:                                       -->
	<!--    1. The info-section defines some general information  -->
	<!--    2. The deviceRequirements-section chooses the devices -->
	<!--       for which the application is build.                -->
	<!--    3. The build-section controls the actual build        -->
	<!--       process.                                           -->	
	<!--    4. The emulator-section calls the emulator            -->
	<target name="j2mepolish" 
			depends="init"
			description="This is the controller for the J2ME build process." 
			>
		<j2mepolish>
		    <!-- general settings, these settings basically form the JAD-attributes. -->
		    <!-- Have a look at the <jad> section for setting specialised attributes.
		         You can also define localized attributes in the resources/messages.txt files -->
			<info
				name="Blank"
				version="1.0.0"
				description="Please describe me"
				vendorName="Enough Software"
				infoUrl="http://www.j2mepolish.org"
				jarName="${polish.vendor}-${polish.name}-${polish.locale}-blank.jar" 
				jarUrl="${deploy-url}${polish.jarName}"
				copyright="Copyright 2007 Your Company. All rights reserved."
			/>
			<!-- selection of supported devices -->
			<deviceRequirements if="test">
				<requirement name="Identifier" value="${device}" />
			</deviceRequirements>
			<deviceRequirements unless="test">
				<requirement name="Identifier" 
				value="Generic/jtwi,Nokia/Series40E3,Nokia/Series60E3,Sony-Ericsson/JavaPlatform6" />
			</deviceRequirements>
		    <!-- build settings -->
			<build
				fullscreen="menu"
				usePolishGui="true"
				workDir="${dir.work}"
				destDir="${dir.dist}"
			>
				<!-- midlets definition -->
				<midlet class="de.enough.polish.sample.email.EmailMidlet" name="Email" />
				<!-- project-wide variables - used for preprocessing.  -->
				<!-- You can set localized variables in the resources/messages.txt files as well.  -->
				<variables includeAntProperties="true" >
					<variable file="configuration/configuration.properties" />
					<!-- allow customized configuration settings: -->
					<variable file="configuration/${customization}/configuration.properties" />
					<!-- Sample configuration options for J2ME Polish
					<variable name="polish.TextField.useDirectInput" value="true" />
					<variable name="polish.TextField.supportSymbolsEntry" value="true" />
					<variable name="polish.MenuBar.useExtendedMenuBar" value="true" />
					<variable name="polish.useScrollBar" value="true" />
					-->
				</variables>
				<!-- Configure the customization settings here: -->
				<resources
					defaultexcludes="yes"
					excludes="readme.txt"
				>
					<root dir="resources/base" />
					<root dir="resources/base/images" />
					<root dir="resources/base/sounds" />
					<root dir="resources/${customization}" if="build.${customization}" />
					<root dir="resources/${customization}/images" if="build.${customization}" />
					<root dir="resources/${customization}/sounds" if="build.${customization}" />
					<!-- add the localization element for created localized
					     versions of your application: 
					-->
					<localization>
						<locale name="en_US" />
						<locale name="de_DE" encoding="utf-8" unless="test" />
					</localization>
				</resources>
				<!-- obfuscator settings: do not obfuscate when the test-property is true -->
				<obfuscator name="ProGuard" unless="test" >
					<!--
					You can set additional parameters here, e.g.:
					<parameter name="optimize" value="false" />
					-->
				</obfuscator>
				<!-- log settings: only use debug setting when the test-property is true -->
				<debug if="test" showLogOnError="true" verbose="true" level="error">
					<filter pattern="de.enough.polish.example.*" level="debug" />
					<filter pattern="de.enough.polish.ui.*" level="warn" />
					<!-- example for writing log entries to the Recordstore Management System: 
					<handler name="rms" />
					-->
				</debug>
				<!-- user defined JAD attributes can also be used: -->
				<jad>
					<attribute name="Nokia-MIDlet-Category" value="Game" if="polish.group.Series40" />
				</jad>	
			</build>
			
			<!-- execution of emulator(s) -->
			<emulator
				wait="true"
				securityDomain="trusted"
				enableProfiler="true"
				enableMemoryMonitor="true"
				enableNetworkMonitor="true"
				if="debug"
				>
				<!-- this is an example for connecting to a debugger - use the ${polish.debug.port} Ant property
				     for getting to know the port of the debugger. In this example the 
				     "connect-debugger" target is also required.
				-->
				<!--
				<debugger name="antcall" target="connect-debugger" port="6001" />
				-->
			</emulator>
                        
			<emulator
				wait="true"
				trace="none"
				securityDomain="trusted"
				enableProfiler="false"
				enableMemoryMonitor="false"
				enableNetworkMonitor="false"
				if="test and not debug"
				>
			</emulator>

		
		</j2mepolish>
	</target>
	
	<target name="setdeploy" 
		description="Call this target first to set the OTA download-URL, e.g. ant setdeploy j2mepolish"
		>
		<property name="deploy-url" value="http://www.company.com/download/" />
	</target>
	
	<target name="enableDebug" 
		>
		<property name="debug" value="true" />
	</target>
	
		
	<target name="enableEmulator" 
		>
		<property name="test" value="true" />
		<property name="dir.work" value="build/test" />
	</target>

	<target 
		name="emulator"
		depends="enableEmulator,j2mepolish"
		description="invokes the emulator"
	>
	</target>

	<target name="enableClean" 
		<delete dir="build" />
		<delete dir="dist" includes="**/*" />
	</target>

	<target  
		name="cleanbuild"
		description="allows a clean build."
		depends="enableClean, j2mepolish"
	/>
	
    <target name="debug" description="debugs the project" depends="enableDebug, enableEmulator, j2mepolish" />
	
	<target name="enableCustomization1">
		<property name="customization" value="customization1" />
		<property name="build.customization1" value="true" />
	</target>
		
	<target name="buildCustomization1"
			description="customizes this project with the settings found in resources/customization1"
			depends="enableCustomization1, j2mepolish"
	/>
	
	<target name="enableCustomization2">
		<property name="customization" value="customization2" />
		<property name="build.customization2" value="true" />
	</target>
		
	<target name="buildCustomization2"
			description="customizes this project with the settings found in resources/customization2"
			depends="enableCustomization2, j2mepolish"
	/>
	
	<target 
		name="buildAllCustomizations"
		description="Builds your application in all customizations." 
		>
		<subant target="buildCustomization1" buildpath="." genericantfile="build.xml" inheritall="false" ></subant>
		<subant target="buildCustomization2" buildpath="." genericantfile="build.xml" inheritall="false" ></subant>
	</target>
	

</project>

Sample build.xml script for customizing your application easily with J2ME Polish

back to top