Part 1 in an as yet unknown number of articles using a (very) simple camera application to demonstrate building first class Android applications using “Pascal for Java” – i.e. Oxygene Cooper. In this first instalment we will look at the basics – the components we are going to need and the basic UI of the application.
As I said, this will be a very simply camera application. As such it will have the bare minimum of user interface elements, consisting of simply a preview or viewfinder and a button for actually capturing the photo.
So first, let’s create a new project.
Getting Started
This is very straightforward. We simply choose the Android application template provided with Oxygene. I named it “nz.co.deltics.demo.camera“. The default project template actually contains some layout and some code that we will not need, but initially it’s the only template we have. Being VisualStudio we can of course create our own project template for future use if we prefer to start with something completely “empty”.
For now though, this will do and we are created a project consisting of almost everything we need for our app:
The “Properties” item in our project contains the Android manifest for our app but is also the item that provides access to various configurable aspects of our project such as the target Android version, the location of asset and resource folders, compiler settings etc etc.
For our purposes the manifest, layout and the initial activity of our app are our first areas of interest.
Manifest Declarations
First we must add some permissions and features to the manifest that our application is going to need. Since we are implementing a camera application we must ensure that our app indicates it’s reliance on camera hardware being present and requests permission to use it. The two might seem to go hand in hand, but we might be writing an app which can use an existing camera app to take pictures in which case we would want to be sure that a camera exists but don’t need permission to use it ourselves since we would be asking another app to take pictures for us.
But in this case we will be taking the pictures ourselves so we need both the hardware and the permission to use it.
Also, since we intend capturing images and saving them, we will need permission to write to storage on the Android device. These are all declared in the application manifest. This is an XML file AndroidManifest.android-xml, and in this project initially looks like this:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="nz.co.deltics.demo.camera"> <!-- the android:debuggable="true" attribute is overwritten by the compiler when the debug info option is set --> <application android:label="@string/app_name" android:icon="@drawable/icon" android:debuggable="true"> <activity android:label="@string/app_name" android:name="nz.co.deltics.demo.camera.MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> <uses-sdk android:minSdkVersion="4" /> </manifest>
First we add the camera hardware feature that we need. Oxygene provides code completion support for Android XML files in the Visual Studio editor. In this case the entry we need is a uses-feature:
We also need to add two uses-permission entries, one for CAMERA (to be given permission to access the camera that we said must exist) and the other for WRITE_EXTERNAL_STORAGE. When we’re done, our manifest now looks like this:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="nz.co.deltics.demo.camera"> <!-- the android:debuggable="true" attribute is overwritten by the compiler when the debug info option is set --> <application android:label="@string/app_name" android:icon="@drawable/icon" android:debuggable="true"> <activity android:label="@string/app_name" android:name="nz.co.deltics.demo.camera.MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> <uses-sdk android:minSdkVersion="4" /> <uses-feature android:name="android.hardware.camera" /> <uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> </manifest>
One last thing to look at in the manifest is the label attribute of the Application element. This is the name of our application as it will appear on screen in the Android launcher. The value of this attribute indicates that the text for the name will be taken from a string resource called “app_name“.
In our project there is a “values” item and within that a strings.android-xml file. Opening that in the editor we find:
<?xml version="1.0" encoding="utf-8"?> <resources> <string name="app_name">nz.co.deltics.demo.camera</string> <string name="my_button_text">Click Me!</string> <string name="my_button_text_2">%1$d clicks!</string> </resources>
Here we can change the name of our application to something a little more user friendly and we won’t be needing the other two entries so we can simply remove those, leaving us with:
<?xml version="1.0" encoding="utf-8"?> <resources> <string name="app_name">Demo Camera</string> </resources>
Now we can turn our attention to the user interface.
The User Interface
On Android, just as with iOS, the user interface can be assembled programmatically in code or pre-defined in a resource file. On Android these resources are XML files called a layout and in our project we have a layout item and within that we can see that we already have a layout file created for us called main.layout-xml. Opening that we find:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" android:gravity="center_vertical|center_horizontal"> <Button android:id="@+id/MyButton" android:text="@string/my_button_text" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </LinearLayout>
This layout consists of a LinearLayout element configured to center any content both vertically and horizontally. Being the root element of the layout, this will fill the screen and so it’s content – a single button – will be centered on the screen. We see that the text (i.e. caption) for the button is a reference to one of those string entries that we removed from the strings xml file.
We need something a little different. I want the majority of the screen to be dedicated to a preview of the camera, with a button to capture an image tucked to one side. As far as I know, there is no specific “Camera Preview” control as such as there is for a “Button” for example. So for the preview/viewfinder we will place a FrameLayout which we will later configure in code.
I’m still learning Layout techniques (one reason for keeping things very simple in this example) so the layout I ended up with may not be the ideal way to define what I want, but it works (or seems to) and this is what I have:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="fill_parent" android:layout_height="fill_parent" > <FrameLayout android:id="@+id/camera_preview" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_weight="1" /> <Button android:id="@+id/button_capture" android:text="Capture" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" /> </LinearLayout>
Just to demonstrate that it’s possible, the text of my Button does not use the “@string/” format so on this occasion the button text will be simply what I have specified in the layout. It generally makes sense to use string references to ensure consistent use throughout an application (and to facilitate support for different languages), but it’s not mandatory.
The “id” attributes of the FrameLayout and Button are important as these are how we will identify these layout elements in our code later on. So far we have been dealing only with the resources in our application.
Now let’s look at some code.
The MainActivity
So far, everything we have looked at will be very familiar to anyone who has done any Android work with Eclipse or Android Studio or any other Java IDE for Android. The code is where Oxygene set’s itself apart from the Java world, whilst simultaneously remaining firmly planted within it. Here is the implementation of the MainActivity class created for us in our project:
namespace nz.co.deltics.demo.camera; interface uses java.util, android.app, android.content, android.os, android.util, android.view, android.widget; type MainActivity = public class(Activity) private Count: Integer := 0; public method onCreate(savedInstanceState: Bundle); override; method ButtonOnClick(v: View); end; implementation method MainActivity.onCreate(savedInstanceState: Bundle); begin inherited; // Set our view from the "main" layout resource ContentView := R.layout.main; // Get our button from the layout resource, // and attach an event to it var myButton: Button := Button(findViewById(R.id.MyButton)); myButton.OnClickListener := new interface View.OnClickListener(onClick := @ButtonOnClick); end; method MainActivity.ButtonOnClick(v: View); begin inc(Count); (v as Button).Text := WideString.format(String[R.string.my_button_text_2], Count); end; end.
This is obviously recognisable as Pascal but if you were to show it to an Android developer familiar with Java they would also recognise it as an Android application.
We will take a closer look in the next article in the series. For now let’s just remove the code that is part of the project template that we don’t need. As we have already seen, the project template consists of an app with a single button. The code in the MainActivity configures that button to respond to a Click event by incrementing a counter and then updating the button caption to indicate the number of clicks that have taken place.
We aren’t interested in the counter, but the business of the button responding to clicks is something that we can keep although we will change the names of some things so that they make a bit more sense:
namespace nz.co.deltics.demo.camera; interface uses java.util, android.app, android.content, android.os, android.util, android.view, android.widget; type MainActivity = public class(Activity) public method onCreate(savedInstanceState: Bundle); override; method CaptureClick(v: View); end; implementation method MainActivity.onCreate(savedInstanceState: Bundle); var btnCapture: Button; begin inherited; // Set our view from the "main" layout resource ContentView := R.layout.main; // Get our button from the layout resource, // and attach an event to it btnCapture := Button(findViewById(R.id.button_capture)); btnCapture.OnClickListener := new interface View.OnClickListener(onClick := @CaptureClick); end; method MainActivity.CaptureClick(v: View); begin // TODO: Capture image from the camera end; end.
What did we do:
- We removed the Count member variable of the MainActivity class
- I changed from an inline variable declaration for the Button reference to a more ‘traditional’ Pascal pre-declaration. Oxygene supports both. This is just my preference. And I changed the name to btnCapture. Again, just my preference.
- The ID passed to findViewById() was change to the id assigned to the button in the layout. Notice that this is not a string but a reference to a member of the id member of an R object. The R member is generated for us from the resources in a build step that occurs prior to compilation. Again, this is identical to “normal” Android development.
- I changed the name of the method that responds to the button click to CaptureClick to better reflect it’s use.
- Finally, I removed the code from the CaptureClick() method and put a TODO item to remind me that this is where I need to add code to actually capture the camera image, when the time comes.
That’s it.
We now have an app with a UI ready to function as a very simple camera application.
Next time I will show how I implemented the camera preview to provide a “viewfinder” for the camera.
Interesting post – having not yet experimented with Oxygene, I’d be interested to understand how much of that project could be recycled say for a similar iOS camera app.
I believe except the concept for the app, there is nothing you could reuse because with oxygene, you’re only using another language. The underlying structures and patterns are different for each platform.
So, what’s the difference to doing that directly in Eclipse with the Android plugin – which is free? Except the missing I got all the same hassle as in a Java project.
Missing {{ }} parenthesis was eaten by wordpress 😉
There’s a lot more to the Oxygene language than just the lack of curly braces. Oxygene has literally dozens of language features (small and large) that make a huge difference to your day-to-day coding. It’s not (just) a matter of liking Pascal- over C-based languages.
Indeed, and I touched on a couple of these in Part 2. 🙂
So far admittedly not very much except that you aren’t using Eclipse or Java which is itself enough of a benefit for some people. Such as myself, for example. 🙂
Luckily the new IDE, Android Studio, is much more user friendly than Eclipse. Secondly if you ask your question on StackOverflow for Android development in Java instead of Pascal there are 100 times as many people to help you out. I am a Pascal fan, but only for native Windows development.
Yep, but you can ask the question in Java and then apply the answer in Pascal. This limits the exposure to Java to “being able to understand it” as opposed to “being forced to write it“. 🙂
See my reply to your other comment w.r.t what I found with Android Studio over the weekend.
As you describe coding the layout file by hand, does this mean Oxygene/VS doesn’t integrate with a visual designer? Given the ‘quality’ of the Eclipse visual designer for Android, that might not be a terrible loss, though it gives rise to the question of why bother with XML layout files at all – why not just code it all in Oxygene Pascal…?
That’s a valid point and having never really been satisfied with the sort of revision tracking that is obtained with (text) DFM’s over the years I suspect that building the UI in code is still the most effective way of keeping a handle on changes in the UI, if that’s a concern.
As for integration, as far as I know there is no direct integration with the Eclipse or any other layout designer but equally since the layout files are just Android resources you can use any Android layout tool you wish. From what I gather though, even experienced Android devs prefer working directly with the XML.
It’s the same with xib files and Xcode for Cocoa – there is no direct integration as such (well, there is at the technical/language support level but not of the “double-click and it opens in Xcode” variety), but you can still edit the xib file directly using Xcode. Having Xcode running on the host Mac with Oxygene in a Windows VM, it’s not really much different than a “floating form designer”.