About Joerg

After some years in product management now back in software development as a free developer who loves JAVA and Android but is open for everything including COBOL, ASSEMBLER and Objective-C.

Configuring the Layout of Android’s AlertDialog

Android’s AlertDialog.Builder is a handy little tool to create small dialogs for error messages, warnings, confirmation of delete actions, etc. But when it comes to adapting the layout to the general look and feel of your app there is unfortunately no good documentation available. This article summarizes my findings in this area.

 The structure of the AlertDialog layout

Objects of type AlertDialog are created by calling the create() or show() method of a properly configured AlertDialog.Builder object. There is a version of the constructor for AlertDialog.Builder which has the resource id of an XML style as parameter. Instead of using this parameter you can set the style with

<item name="android:alertDialogTheme">@style/... </item>

in the style file of your app. Some general style properties like windowBackground or dialog style properties like buttonBarStyle can be set this way but there are properties like the background of the message text that cannot be modified this way. To understand why, you have to look at the way an alert dialog constructs its layout:

AlertDialog delegates the job of creating the dialog’s layout to it’s superclass Dialog and to an Android internal class com.android.internal.app.AlertController. The AlertController class does this by using an XML layout file which is part of the Android SDK (for version 19 you find the different versions under …/platforms/android-19/data/res/values/alert_dialog…) and an XML style that you define in your app theme with

<item name="android:alertDialogStyle">@style/...</item>

Let’s have a look at the layout file first. As an example let’s take the standard holo design of Android SDK version 19 which I have abbreviated for this article:

    <LinearLayout android:id="@+id/topPanel"
        <View android:id="@+id/titleDividerTop"
            android:background="@android:color/holo_blue_light" />
        <LinearLayout android:id="@+id/title_template"
            <ImageView android:id="@+id/icon"
                ... />
            <com.android.internal.widget.DialogTitle android:id="@+id/alertTitle"
                ... />
        <View android:id="@+id/titleDivider"
            android:background="@android:color/holo_blue_light" />
    <!-- If the client uses a customTitle, it will be added here. -->
    <LinearLayout android:id="@+id/contentPanel"
        <ScrollView android:id="@+id/scrollView"
            <TextView android:id="@+id/message"
    <LinearLayout android:id="@+id/buttonPanel"
            <Button android:id="@+id/button2"
            <Button android:id="@+id/button3"
            <Button android:id="@+id/button1"
             ... />

As this is a complex structure let’s walk through this top down:

The top structure is a linear, vertically oriented layout that contains three vertically oriented layouts for the title, the message and the button bar.


The linear layout for the title (topPanel) consists of views for the divider lines above (titleDividerTop) and below (titleDivider) the title and a horizontal linear layout (title_template) that contains the icon (icon) and the title text  itself (alertTitle). This is the part of the alert dialog that has the most restrictions:

The design of the divider lines is hard coded in the layout file and can therefore not be changed by a style parameter. Especially the color of the lines (Android’s holo_blue_light) will hurt the overall design of many apps. The only solution here is to adjust the view layout parameter after the AlertDialog has been shown:

// Set title divider color
AlertDialog alert = ... .show();
int titleDividerId = getResources().getIdentifier("titleDivider", "id", "android");
View titleDivider = alert.findViewById(titleDividerId);
if (titleDivider != null)

The test of titleDivider against null is your life insurance against null pointer exceptions in case a new Android version decides to rename or remove the identifier of the title divider view.

The text view for the title itself is a special subclass of TextView called com.android.internal.widget.DialogTitle whose only difference to Android’s standard TextView is that it has a special onMeasure() method. Apart from the source code there is no documentation available for this class. As you can see in the layout file you can set a style for this view with a windowTitleStyle item. The text size of the title cannot (!) be set this way as in onMeasure() it is either read from a style file set with the textAppearanceMedium style item or (if this item is not available) from Androids predefined TextAppearance_Medium style.


A standard text message is displayed in a TextView with the id message wrapped within a ScrollView. The TextView reads its style from the textAppearanceMedium style item as well. Therefore you can only set one text size for the title and the text message in your style file for the AlertDialog. If you want different sizes you can do it only programmatically after the AlertDialog has been shown.

Button Bar

The button bar consists of a linear layout with horizontal orientation (id buttonPanel) whose style can be set with a buttonBarStyle style item. It contains three buttons with the ids button2, button3 and button1 (yes, in this order) whose style can be set with buttonBarButtonStyle. In addition to that you can set a divider line on top of the button bar with a dividerHorizontal style item.

Setting the background of the AlertDialog items

AlertDialog leaves as already mentioned most of the layout work to an internal class called com.android.internal.app.AlertController. Among other things AlertController sets the backgrounds of the different areas of the dialog (title, message, buttons). It does so by reading a bunch of style parameters from a style file that is set with

<item name="android:alertDialogStyle">@style/MepAlertDialogStyle</item>

in the base theme of your app which means in parallel to setting alertDialogTheme (!). The style items look like this:

<style name="MyAlertDialogStyle">
    <item name="android:fullDark">@color/...</item>
    <item name="android:topDark">@color/...</item>
    <item name="android:centerDark">@color/...</item>
    <item name="android:bottomDark">@color/...</item>
    <item name="android:fullBright">@color/...</item>
    <item name="android:topBright">@color/...</item>
    <item name="android:centerBright">@color/...</item>
    <item name="android:bottomBright">@color/...</item>
    <item name="android:bottomMedium">@color/...</item>
    <item name="android:centerMedium">@color/...</item>

The way how AlertController does the background layout of the different views is  a bit complex. The details are only available in the sources of it’s setBackground() method. The general idea is to start with a light or dark background and then iterate between dark and bright when going from top through center to the bottom.

What top, center and bottom (plus “full” under certain circumstances) actually means depends on which views are actually available. For example top will be the title view if it exists. If not it will be the message view. A medium background is (if at all) only used for the button bar. The easiest way to get the style you want is to play a little with the style parameters until you have the backgrounds that you want. The centerMedium parameter that still exists is actually not used anymore by AlertController.

 A boilerplate for an AlertDialog style

The safest way to get a working style is to copy the style elements from one of Android’s standard styles and modify the items to your need. The following boilerplate is based upon the holo light theme of Android platform version 19.

<style name="AppBaseTheme" parent="android:Theme.Holo.Light">
    <item name="android:alertDialogTheme">@style/MyAlertDialogTheme</item>
    <item name="android:alertDialogStyle">@style/MyAlertDialogStyle</item>

<style name="MyBorderlessButton">
    <!-- Set background drawable and text size of the buttons here -->
    <item name="android:background">...</item>
    <item name="android:textSize">...</item>

<style name="MyButtonBar">
    <!-- Define a background for the button bar and a divider between the buttons here -->
    <item name="android:divider">....</item>
    <item name="android:dividerPadding">...</item>
    <item name="android:showDividers">...</item>
    <item name="android:background">...</item>

<style name="MyAlertDialogTitle">
    <item name="android:maxLines">1</item>
    <item name="android:scrollHorizontally">true</item>

<style name="MyAlertTextAppearance">
    <!-- Set text size and color of title and message here -->
    <item name="android:textSize"> ... </item>
    <item name="android:textColor">...</item>

<style name="MepAlertDialogTheme">
    <item name="android:windowBackground">@android:color/transparent</item>
    <item name="android:windowTitleStyle">@style/MyAlertDialogTitle</item>
    <item name="android:windowContentOverlay">@null</item>
    <item name="android:windowMinWidthMajor">@android:dimen/dialog_min_width_major</item>
    <item name="android:windowMinWidthMinor">@android:dimen/dialog_min_width_minor</item>
    <item name="android:windowIsFloating">true</item>
    <item name="android:textAppearanceMedium">@style/MyAlertTextAppearance</item>
    <!-- If you don't want your own button bar style use
    instead of @style/MyButtonBar and @style/MyBorderlessButton
    <item name="android:buttonBarStyle">@style/MyButtonBar</item>
    <item name="android:buttonBarButtonStyle">@style/MyBorderlessButton</item>

<style name="MepAlertDialogStyle">
    <!-- Define background colors of title, message, buttons, etc. here -->
    <item name="android:fullDark">...</item>
    <item name="android:topDark">...</item>
    <item name="android:centerDark">...</item>
    <item name="android:bottomDark">...</item>
    <item name="android:fullBright">...</item>
    <item name="android:topBright">...</item>
    <item name="android:centerBright">...</item>
    <item name="android:bottomBright">...</item>
    <item name="android:bottomMedium">...</item>
    <item name="android:centerMedium">...</item>

The wonder world of Android’s video recording

More than a year ago I started to develop an an app that looked very simple and straight forward to do: The user starts a timer that counts down the time and and when the timer reaches zero the app records a video whose maximum file size and length can be preconfigured. Sounds easy, doesn’t it? I can tell you it was not. But I finally got an app who does that (see here), runs on all Android versions from 2.1 on and seems to work even well with the newest generation of Samsung devices (here I still keep my fingers crossed). But it was a bunch of work to find out how to do it. Here is the story.

As this was my first video recording app I started with reading the guide on Android Developers. This guide tells you the steps that you have to follow. It does not tell you about the caveats. So please read this guide first (if you haven’t already) and then continue reading here.

Opening the camera with Camera.open() contains already a small trap. The guide does not mention that Camera.open() returns a null pointer in case that the device has only a front facing camera which is for example true for the first generation Nexus 7. In this case you have to use Camera.open(id) with the correct camera id. But Camera.open(id) was only introduced with Android 2.3 (API level 9). This was the first case where I was forced to write version dependent code. This code snippet opens the first back facing camera it finds and opens the first camera it can get otherwise.

Camera cam = null;

  Camera.CameraInfo info = new Camera.CameraInfo();
  for (int i = 0; i < Camera.getNumberOfCameras(); i++) {
    Camera.getCameraInfo(i, info);
    if (info.facing == CameraInfo.CAMERA_FACING_BACK){
    	cam = Camera.open(i);
  if (cam == null){
    cam = Camera.open(0);
else {
  camera = Camera.open();

When it comes to setting up the media recorder, setting up the video output format and encoding is to my experience the main source of trouble for recording a video in Android. The guide on Android Developer says here:

Set the video output format and encoding. For Android 2.2 (API Level 8) and higher, use the MediaRecorder.setProfile method, and get a profile instance using CamcorderProfile.get(). For versions of Android prior to 2.2, you must set the video output format and encoding parameters: …

This leaves a bunch of problems unmentioned:

  • Android 2.2 (API Level 8) did not bring the full class with all its methods:
    • CamcorderProfile.get(quality) was already available with Android 2.2 (API Level 8), but CamcorderProfile.get(cameraId, quality) came with Android 2.3 (API Level 9).
    • Initially only constants for CamcorderProfile.QUALITY_HIGH and CamcorderProfile.QUALITY_LOW were defined. Most other constants came with Android 3.0 (API Level 11), CamcorderProfile.QUALITY_QVGA and CamcorderProfile.QUALITY_TIME_LAPSE_QVGA came with Android 4.0.3 (API Level 15). I used Java’s introspection API on CamcorderProfile to get the available profile constant in order be prepared for future extensions like e.g. 4k.
    • Checking, which profiles are actually supported with CamcorderProfile.hasProfile (cameraId, quality) came with Android 3.0 (API Level 11).
  • I know at least of one device (Sony Ericsson Xperia Ray with Android 4.0.4) where setting up the MediaRecorder with  MediaRecorder.setProfile() results in an exception when starting the MediaRecorder.
  • On some devices some possible output formats are not available through MediaRecorder profiles, but only by manually setting the output format parameters. For example the Intenso Tab 814 (Android 4.1.1) offers a 320×240 video format which is QVGA for which there is no profile constant in Android 4.1.1.
  • The guide mentions nowhere that you must specify width and height of the video with MediaRecoder.setVideoSize and the video frame rate with MediaRecorder.setVideoFrameRate in case you don’t use camcorder profiles.

So using camcorder profiles is only really well suited for devices with Android 3.0 (API Level 11) at minimum. Nevertheless it seems as if for the newest Generation of Samsung phones (Galaxy Note 3, Galaxy S4, etc.) using camcorder profiles is the only way to get the MediaRecorder up and running. Setting up the video output format values manually resulted either in a completely failed start of the recorder (e.g. on a Galaxy Note 3) or in a low quality video (e.g. on a Galaxy Tab 3 7.1).

In parallel to this approach I implemented two other ways to set up the video output format values:

The “automatic” approach

1) Get the preview size from the camera object (which can e.g on the Xperia Ray be different from the size of the holder of the preview surface!):

videoWidth = cam.getParameters().getPreviewSize().width; 
videoHeight = cam.getParameters().getPreviewSize().height;

This must be done after the preview surface has been created and the surface holder of the preview has been set in the camera object but before unlocking the camera when starting to set up theMediaRecorder.

2) Use these values and some parameters that officially every Android device with a camera must support to set up the media recorder

recorder = new MediaRecorder();
videoFramesPerSecond = 20;
recorder.setVideoSize(videoWidth, videoHeight);

Version 1.0 of my app published more than a year ago used only this approach for video recording and at that time I had next to no crash reports. Interestingly it worked even on the Samsung Galaxy S3. The videoFramesPerSecond parameter is a “high enough” value. From my experience it seems that the cameras take this only as a maximum value that they decrease for the given conditions during the recording.

The “explicit frame size” approach

This method requires Android 3.0 (API Level 11) and above.

1) Let the user choose one of the supported video sizes that you get from Camera.getParameters().getSupportedVideoSizes() if this function does not return null (!!!). If it does return null (an example is here again the Xperia Ray) this means that the size of the preview and the frame size of the recorded video must be identical and you can let the user choose one of the video sizes from Camera.getParameters().getSupportedPreviewSizes(). What does not work is to use one of the supported preview sizes without checking whether or not it is a supported video size. For example the Nexus 7 (first generation with Android 4.4.2) does support a preview size of 480×480 which makes the MediaRecorder start fail when used as a video size. The same Nexus 7 produces by the way some supported video sizes that are way beyond the known resolution of the camera, for example 1280×720. In this case the recording starts but stops after a few seconds and produces a corrupted video.

2) My app chooses values from Camera.getParameters().getSupportedPreviewSizes() that are as close as possible (which means normally identical) to the selected video sizes and sets them as preview sizes in the camera parameters directly after opening the camera, which means before you attach the camera to the surface view holder for the preview:

int previewWidth = ...
previewHeight = ...
Camera.Parameters  camPara = cam.getParameters();
camPara.setPreviewSize(previewWidth, previewHeight);

Just leaving the preview size parameters in the camera as it is would probably work as well but I did not test it.

3) Set up the video recorder in the same way as with the “automatic” approach but use the selected width and height parameters instead.

The advantage of this method is that you get access to all available video sizes. The downside is that even on devices where this method works in principal there can be sizes that don’t work.

My app supports all three methods. Any feedback on which parameters work on which device would be highly welcome.

Finally one last hint that – if I had know this before – would have saved me some hours of debugging. In Android’s Media Framework the process running the app communicates via Interprocess Communication with a another process who runs the media recorder. Detailed warnings and error message (for example “Unsupported video size: 480×480”) come mostly from this other process, the Media Framework layers of the app quite often throw only a run time exception with an integer parameter like -19 whose meaning is nowhere documented. This means that on a Development System like Eclipse it may be sometimes extremely helpful to look at the complete LogCat without the filter set for the messages of your app.

Drawing on top of an image in Android’s ImageView

This is a topic for which I found on the Internet a lot of ideas but they were more workarounds for special situations than general solutions.

One of my apps contained an ImageView widget into which I had to load a series of pictures one after the other at runtime. The pictures were of different size, some smaller and some larger than the widget’s size, so the images would either be centered or automatically scaled down by the widget. The challenge was to mark certain areas in the picture with a coloured rectangle dynamically created at run time and adjusted using the coordinates of the original, unscaled image.

The general recommendation on the Internet was to subclass ImageView and overwrite OnDraw with a method that first calls the original OnDraw method of ImageView with the canvas that is provided as parameter to OnDraw and then draws into this canvas on top of the already drawn image.

I am meanwhile quite sure that this works only under certain circumstances, for example when you are sure, your image will not be scaled. The problem lies in the provided canvas. The original onDraw method applies a certain transformation matrix to the canvas before it draws the image into the canvas and restores the canvas in its previous state afterwards. This matrix is stored in a private member variable of ImageView and for whatever reason it is not always the same matrix as the one returned from getImageMatrix() calls. Using the debugger I have seen cases where getImageMatrix returned a non-null matrix where onDraw used a null Matrix and therefore did no do any transformation to the canvas at all. So there is no general reliable way to calculate the coordinates for anything you want to draw on top of what ImageView has drawn.

Therefore I used a different approach:

  1. Create a new image bitmap and attach a brand new canvas to it so that the bitmap and the canvas use the same coordinate system.
  2. Draw the image bitmap into the canvas.
  3. Draw everything else you want into the canvas (the rectangles in my case).
  4. Attach the canvas to the ImageView.

Here is the code snippet:

import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.drawable.BitmapDrawable;

ImageView myImageView = ...
Bitmap myBitmap = ...
Paint myRectPaint = ...
int x1 = ...
int y1 = ...
int x2 = ...
int y2 = ...

//Create a new image bitmap and attach a brand new canvas to it
Bitmap tempBitmap = Bitmap.createBitmap(myBitmap.getWidth(), myBitmap.getHeight(), Bitmap.Config.RGB_565);
Canvas tempCanvas = new Canvas(tempBitmap);

//Draw the image bitmap into the cavas
tempCanvas.drawBitmap(myBitmap, 0, 0, null);

//Draw everything else you want into the canvas, in this example a rectangle with rounded edges
tempCanvas.drawRoundRect(new RectF(x1,y1,x2,y2), 2, 2, myPaint);

//Attach the canvas to the ImageView
myImageView.setImageDrawable(new BitmapDrawable(getResources(), tempBitmap));

Multidimensional resource arrays in Android

Android allows you to define an XML resource called typed array which defines a list of other other resources (strings, drawables, etc.) whose items can be accessed using an integer index. Unfortunately these items cannot be typed arrays (as there is no method to access this type of item in the TypedArray class), so it is not possible to define multidimensional resource arrays that way.

As a two dimension resource array was exactly what I needed in one of my recent projects and I found a few hints but no good solution on the Internet I had to put something together myself. Here is what I came up with:

I put the array elements in several typed arrays with identifiers ending in ascending numbers:

<?xml version="1.0" encoding="utf-8"?>
   <array name="myArray_0">
   <array name="myArray_1">

That means the array element myArray[x,y] contains the string “string_x_y” and is the y-th element of the typed array resource myArray_x.

For accessing the array elements I used reflection on Android’s R class as this blog post recommended it as the fastest method. Here is the code snippet:

import java.lang.reflect.Field;

Class<R.array> res;
Field field;

int x, y;
String myString;

x = ...
y = ...

try {
   res = R.array.class;
   field = res.getField("myArray_" + new Integer(x).toString());

   //set myString to the string resource myArray[x,y]
   myString = getResources().obtainTypedArray(field.getInt(null)).getString(y);


   catch (Exception e) {

Extracting texts from text frames in OpenOffice.org Writer using the Java UNO interface

I recently ran into the challenge to use OpenOffice.org to convert a three digit number of old Microsoft Word documents into simple text files.

Under normal circumstances no big deal: Write a program using the UNO interface to start OpenOffice, load the documents one after the other into OpenOffice Writer (conversion to OpenOffice.org document format is done automatically) and save the documents as simple text documents.

It was, alas, not that simple. For some reason the texts were contained in text frames which seem to be the only text components that get completely lost when you save an OpenOffice Writer document as a text file. Which meant that I had to write some code to extract the text from the text frames myself.

As I did nowhere find a code snippet for this I thought I post with what I finally came up with. Just in case someone else runs into a similar challenge …

The code assumes you have an object oDocument for the document that contains the text frame for example by using the loadComponentFromURL method of the XComponentLoader interface. One way to accomplish this is explained here.

// Get the list of names of all text frames of the document

XTextFramesSupplier xFrameSupplier = UnoRuntime.queryInterface(XTextFramesSupplier.class, oDocument);
if (xFrameSupplier.getTextFrames().hasElements()){
    String elementNames [] = xFrameSupplier.getTextFrames().getElementNames();

    // Create a text cursor for the first text frame
    // To access the other text frames use elementNames[1], elementNames[2], ...

    Object oTextFrame = xFrameSupplier.getTextFrames().getByName(elementNames[0]);
    XTextFrame xTextFrame = (XTextFrame) UnoRuntime.queryInterface(XTextFrame.class, oTextFrame);
    XText xText=xTextFrame.getText(); 
    XTextCursor xTextCursor = xText.createTextCursor();

    // Extract the text 

    String text = xTextCursor.getString();


Finding the file path to a database file embedded in an OpenOffice.org extension (.oxt)

As already mentionend in my previous post, one of the advantages of an OpenOffice.org extension from a user perspective is that you install everything from one file, including an eventually needed database file as is the case for the Jitenize extension.

OpenOffice.org unpacks the contents of an .oxt file and puts it in a separate directory before executing it. The place of this directory depends on the operating system, whether the extension is installed for a single or for all users and the path contains some random directory names. For example on my Ubuntu installation the Jitenize extension can be found at


For writing a platform independent OpenOffice.org extension you therefore need  a way to

  1. find the path to the directory in which the extension sits
  2. extend the path with the file name of the database file using the correct (platform dependent) delimiter sign (“/”, “\” or “:”)

Fortunately the UNO framework has some support for doing this but I had to make intensive usage of Google to find out how and some code snippets that I found simply did not work. So I thought it would be a good idea to publish my final solution here:

// Create path to dictionary database in UNO component package cache in a platform independant way
//The dictionary database of the Jitenize extension is always in the root directory of the UNO extension package
String databasePath;
try {
   XPackageInformationProvider xPackageInformationProvider = PackageInformationProvider.get(m_xContext);
   String packageLocation = xPackageInformationProvider.getPackageLocation("com.fuyosoft.jitenize");
   XFileIdentifierConverter xFileConverter = (XFileIdentifierConverter) UnoRuntime.queryInterface(XFileIdentifierConverter.class, m_xContext.getServiceManager().createInstanceWithContext("com.sun.star.ucb.FileContentProvider", m_xContext));
   databasePath = xFileConverter.getSystemPathFromFileURL(packageLocation + "/dict.sqlite");
} catch (com.sun.star.uno.Exception ex) {
   databasePath = "Exception during construction of path to dictionary database!";

com.fuyosoft.jitenize is the identifier of the extension specified in the description.xml file as explained in this post.

This has been tested with Ubuntu 10.04 and Windows XP. Feedback from any other operating system platform highly welcome!

Writing an OpenOffice.org UNO service in Java with Eclipse

UNO is the component model of OpenOffice.org. It is a small application server integrated into the OpenOffice.org software whose services can be accessed either internally by macros contained in documents or externally by other applications. That way it is for example possible that an application loads a document in OpenOffice.org Writer, changes the formatting of the document and saves it.

Writing an UNO service in Java (C++ and other languages are possible as well but not treated in this post) means:

  • Define the functionality of the service in a language independant way by using the interface definition language of UNO (UNOIDL).
  • Write the implementation of the service by implementing the interface of the UNOIDL definition plus a few other standard interfaces that every UNO service is required to prepare.
  • Compile the UNOIDL specifications and Java classes in one JAR file and put this with the type database and the other files already described here into an .oxt file (of course you can add other things like macros that make use of the UNO service as well).
  • Deploy the service by loading the .oxt file into the Extension Manager of OpenOffice.org.

Chapter 2 of the OpenOffice.org developers manual explains this in all details. Fortunately there is a plugin for Eclipse whose wizard generates an Eclipse project with a complete skeleton for an UNO service. There is a tutorial for installation and usage of this plugin and I recommend from my own experience reading the tutorial and following it’s instructions step by step.

The plugin has some limitations though, so for Jitenize I had to do some manual changes to the project:

  • The plugin wizard lets you only define interfaces with simple or already defined data types. For Jitenize I needed my own record structures. I used the plugin wizard to define the functions of the service with simple data types, added a new UNOIDL description file containing the record structure and changed the function definition afterwards. Btw. adding a new UNOIDL file did not work, I always got the “NOT A UNOIDL CAPABLE FOLDER” error. But adding a simple text file with the .idl suffix worked and this file was compiled automatically with idlc like all other .idl files.
  • After changing the UNOIDL description of the service the parameters of the implementation function of the service of course needed to be changed as well. Here I recommend to read the sections called “Type mapping of xxx” in Chapter 2 of the OpenOffice.org developers manual, especially “Mapping of Interface Types”  explains very well how IN, OUT and INOUT parameters in UNOIDL are mapped to Java.
  • What I did not accomplish was to generate a complete .oxt file with the plugin. The showstoppers were the .jar files for the dictionary lookup that I had added to the project and that did not show up in the .oxt file. I finally gave up and wrote my own shell script that created the .jar file with all .class files needed and created an .oxt file with this .jar file and the other files that the plugin had created for the .oxt file. If you try the same thing make sure you add the .class files in the /bin and in the /build directory of the project’s work space to the jar file.


Components of an OpenOffice.org extension (.oxt)

From a user perspective OpenOffice.org extensions are really easy to handle: Download the extension as one single .oxt file, start any application of the suite, go to the extension manager, load the .oxt file, accept the license agreement if available and you are done.

For developers there are quite a few components to prepare before you can create the .oxt file. To see what is needed let me show you the contents of the Jitenize extension file.

Like .jar files the .oxt files are actually archives in ZIP file format and can be opened and generated with every archive tool that can handle ZIP files, so let’s have a look at the Jitenize extension using the jar command line tool:

> jar tf jitenize_0.8.3.en.oxt

The central information that tells an OpenOffice.org application how to load an extension is in the manifest.xml file:

<?xml version="1.0" encoding="UTF-8"?>
 <manifest:file-entry manifest:full-path="types.rdb" manifest:media-type="application/vnd.sun.star.uno-typelibrary;type=RDB"/>
 <manifest:file-entry manifest:full-path="jitenize.jar" manifest:media-type="application/vnd.sun.star.uno-component;type=Java"/>
 <manifest:file-entry manifest:full-path="Jitenize/" manifest:media-type="application/vnd.sun.star.basic-library"/>
 <manifest:file-entry manifest:full-path="jitenize.xcu" manifest:media-type="application/vnd.sun.star.configuration-data" />

jiteninze.jar and types.rdb contain the main code of the extension written as an UNO service in Java. More on this in a later post.

The Jitenize subdirectory contains the user interface written in BASIC that call the UNO service. The files were generated by writing a macro library in OpenOffice.org Writer and exporting it as a BASIC library (and not as an extension!).

jitenize.xcu contains the information how to extend the menu structure of OpenOffice.org Writer and how to connect the menu items to the BASIC macros. The easiest way that I found to create this file is to use the macro contained in chapter 2.2 of this document. Btw. addon is an old name for what is nowadays called extension, the document is quite outdated, but the macro still works well.

In addition to these four central files a few other files are available:

dict_en.sqlite, sqljet-1.0.7.jar and  antlr-runtime-3.1.3.jar contain the dictionary database and the free sqlite database engine written in Java from TMate Software. The engine is used by the UNO service to whom it is made available by adding the jar files to the classpath defined in the manifest of jitenize.jar.

Finally description.xml contains information about the extension that show up in the extension manager (display name, version, etc.), links to the license file COPYRIGHT and an identifier for the extension that must be worldwide unique (com. fuyosoft.jitenize). The Extension manager uses this identifier to decide whether a newly loaded extension is an update to an already existing extension or not.

<?xml version="1.0" encoding="UTF-8"?>
<description xmlns="http://openoffice.org/extensions/description/2006" xmlns:d="http://openoffice.org/extensions/description/2006" xmlns:xlink="http://www.w3.org/1999/xlink">
 <identifier value="com.fuyosoft.jitenize" />
 <version value="0.8.3.en" />
  <OpenOffice.org-minimal-version value="2.2" name="OpenOffice.org 2.2"/>
  <name xlink:href="http://fuyosoft.com">fuyosoft.com</name>
  <simple-license accept-by="admin" suppress-on-update="true" >
   <license-text xlink:href="COPYRIGHTS"/>

Writing an OpenOffice.org extension (.oxt)

As already mentioned in my last post I just finished an open source project called Jitenize, which is an extension for OpenOffice.org Writer. Looking back I must say, the complexity and the capabilities of the framework for the extensions is impressive. Which means either you take the time to go through the more than 1600 pages of the developers manual or the corresponding Wiki plus the more than 500 pages of Andrew Pitonyak’s Useful Macro Information for OpenOffice.org document or you do what I did: Put these documents in your bookshelf for later usage (you will definitely need them!), use Google to find a few basic programming examples and start developing your code by modifying and extending the examples.

Well, with OpenOffice.org extensions it turned out to be not as easy as usual. There are no so many examples available as for example for Microsoft Office, so sometimes you need to spend quite some time until you find an example of how to program a certain feature. Moreover I found quite often code that for whatever reasons simply did not work with my OpenOffice.org installation (version 3.2). Also the framework is so huge that different people sometimes recommend different ways with very different complexities to accomplish the same goal. Therefore it’s often a good idea to read through more than one forum article, blog post etc. before starting your own implementation.

Therefore I decided to write a small series of post in this blog about certain aspects of the Jitenize sofware, what I did and how I did it, to increase the number of working code examples for OpenOffice.org extension at least a little bit.

Stay tuned!


Creating a recorded desktop session (screencast) for YouTube under Ubuntu

I just finished an open source project called Jitenize and created a short clip for YouTube explaining the installation and usage of the software. As I spent a lot of time with finding the right tools and using them in the right way I thought it might be interesting to share with what I finally came up with:

For recording the desktop session I used recordMyDesktop, The tool is easy to use and you can record a selected part of your desktop so that you can hide things that you do not want to show to the world.

A cheap microphone creates an audio track with a lot of white noise in the background. I decided that I could live for the time being with this quality but if I would do more clips of this kind I would spend some money on a good microphone for sure.

recordMyDesktop creates OGG videos that need to converted to FLV for YouTube. In addition I finally decided to record video and audio separately in several small clips and mount everything in one clip later on. Demonstrating and explaining a software at the same time is much harder than presenting a set of well written slides in a webinar!

For editing the clips and gluing them together I loaded them in PiTiVi, removed the audio track and created titles by adding PNG images that I had created with OpenOffice Impress.

Finally I recorded and edited the audio track with Audacity, exported it in OGG Vorbis format and added the audio track in PiTiVi to the video. Exporting the audio track as MP3 resulted in audio quality problems in PiTiVi.

Last not least I exported the whole clip in FLV format. Here it turned out to be extremely important to find the right settings for the export. After some Google search I found the following parameters that worked for me:

Container: FLV muxer [flvmux]
Audio-Codec: FFmpeg ADPCM Shockwave Flash encoder [ffenc_adpcm_swf]
Video-Code: FFmpeg Flash Video (FLV) encoder [ffenc_flv]

Loading up the video on YouTube worked without problems, you can see the result here.