Categories
Web 2.0

Link YouTube Video with Custom Start Time

Ever wondered if it is possible to link a video that starts at a time you define?

It is not only possible but also dead easy:

http://www.youtube.com/watch?v=GxZuq57_bYM#t=1m26s

The example above features the famous Amen Break, a 6-second drum break of the song Amen Brother by The Winstons. This break can be found in many old school hip-hop and drum ‘n’ bass songs.

So, how does it work?

The added parameter #t=1m26s defines the starting point. #t=… identifies the start time parameter. 1m26s means that the song starts at 1:26. It is, however, also possible to just provide seconds, e.g. #t=86s.

Why is that useful?

Whenever you want to cite parts of a video as e.g. an example or as proof of an argument, jumping to the right start time makes it unnecessary for the reader to search for it.

Share this:
Share
Categories
Android Projects Research

A Tactile Compass for Eyes-free Pedestrian Navigation

The idea came up when I was heading back to the hotel from a conference dinner at MobileHCI 2008 in Amsterdam. I had no orientation. The only guide I had was a map on my Nokia phone. Not being familiar with Amsterdam, the route let me right through the busy areas of the city center.

The day before, a cyclist had stolen a mobile phone right out of the hand of another conference attendee. Knowing that made me quite afraid something similar could happen to me too. Without the phone I would have been completely lost.

Here, serendipity hit. Since my research group was already working on tactile displays for navigation and orientation, I wondered whether it was possible to create a navigation system for mobile phones that guided by vibration only, so it could be left in the pocket.

Back at OFFIS we quickly tested a few prototypes, including a hot/cold metaphor and a compass metaphor. The compass metaphor prevailed. The design was to encode the direction the user should be heading (forward, left, right, backwards) in different vibration patterns. Our testing participants liked that design most. Later we tested the vibration compass design a forest and found that it can replace navigation with a map.

The development and the studies was presented at the 13th IFIP TCI3 Conference in Human-Computer Interaction (INTERACT) in Lisbon, Portugal in September 2011. The article is available here.

If you own an Android phone you can try this vibration compass by downloading our PocketNavigator navigation application for free from the Android market.

 

Share this:
Share
Categories
Research

HaptiMap Bike Navigation System meets Tourists on Borkum

Computer science research goes wild! Starting in July 18, 2011, our Tacticycle, a novel bike navigation system for tourists, will be demonstrated on Borkum. For one week, tourists can rent the system for the cycling trips.

Background

In previous studies we found that tourists actually do not desire strict navigation support. Often, they only start with a rough idea where to go. They plan their route on-the-fly based on their surroundings and their intuition. With the Tacticycle we built a navigation system for bikes that aims at accommodating these usage patterns.

Tacticycle

The Tacticycle can roughly be described as a point of interest (POI) radar. Instead of streets and buildings the user gets a quick overview of the direction and distance of nearby POIs. As a special feature users can select one of these POIs. The Tacticycle then cues the direction of this POI by two vibration motors fixed to the handle bar. Instead of seeing its location on the screen the riders can feel where the POI is, which allows them to keep their eyes on the road.

Share this:
Share
Categories
Research

Digital Helpers for the Blind

Last year, the WDR (German TV broadcaster) together our HaptiMap project partner GeoMobile tested the the PocketNavigator with Mr. Schmidt who is visually impaired.

Actually, the PocketNavigator was not designed for blind users, since it only gives very coarse directions (straight, left, right, behind) via vibration patterns. However, to my surprise, Mr. Schmidt seemed to be able to get along with it quite well. He navigated by the white cane as usual but took the directions as orientation cues.

Screenshot of the PocketNavigators main map view

The test also showed that the PocketNavigator is not yet ready to be used by visually impaired users. During the test Mr. Schmidt accidentally hit the touch screen and changed the travel destination, which caused him ending up in front of a house.

Altogether, he was quite fond of the general principle. He concludes that the system would not be an “extra workload” when being on the move.

The video is available here: Digitale Helfer für Blinde, 15.10.2010 (German only)

Share this:
Share
Categories
Work

Corporate Intranets – Infrastructures from the Internet’s past

Last week, in a staff meeting of my research institute, a discussion on the use of Web 2.0 technology came up. Reflecting on the discussions, I realized that actually the typical IT infrastructure we find in companies today has fallen years behind what we use in everyday life.

Today’s practices in companies

In enterprises a huge part of the work is to share information and thoughts, and to store and share documents. But what are the practices today?

  • To share information with the collages there are two ways: either writing a mail to the “everyone” list (don’t you dare!) or submitting it for the newsletter (how many people may actually take the time to read all of it?).
  • To share documents the most common practice in all projects I have witnessed so far is attaching them to a mail. This is a lot of fun, in particular if you have a tight quota and need to clear the inbox regularly. Within the company, documents can be stored and shared by putting them onto a server that is accessed as a network drive. To be able to find documents later an elaborate set of rules and directory templates has been created, which – in theory – tell you where to store your document.

Today’s practices on the internet

But if we take a look at the tools we use every day on the internet I wonder if we are not wasting a huge potential here

  • Google allows me to search the biggest pile of data mankind has ever created (Internet!) in the blink of an eye. But I cannot index my institute’s document server with Google Desktop, because the search index will be stored on Google server
  • Twitter and Facebook allow me to easily share information with others. But I cannot just use Facebook or Twitter to post a rant about something stupid in my company, because it may negatively affect the employer’s image
  • Dropbox helps me accessing documents from different computers and sharing them with others. I cannot just store a document in a shared Dropbox folder to provide my team with instant read/write access to it, since it may involve storing sensitive material on an external server

So, what tools are out there that can replace Google, Twitter, Facebook, and Dropbox but at the same time respect the companies’ need for privacy and security? How would it affect work if such tools were in place in the intranet already?

Share this:
Share
Categories
Research

A Vibro-tactile “Friend Sense” for Keeping Groups Together

Being able to sense the location of people can be beneficial if you visit a crowded, noisy, and chaotic place with your friends, such as a festival. Usually, for a good nightly experience, it is important that the group stays together. However, when everyone has different needs at different times (getting food, visiting the lavatory …) it becomes increasingly challenging to keep everyone together, which is contradictory to a joyful night out.

Thanks to GPS and mobile Internet, different solutions exist where the mobile phone of each friend communicates its GPS location to a server, which then forwards the location to all the other friends’ mobile devices. The problem with existing implementations, such as Google Latitude or Glympse, is that they use maps to communicate these locations. It is more than just inconvenient to read a map while walking through a dense crowd.

We therefore investigated whether the skin can be used to communicate the location of people and therefore be turned into a “friend sense”. Our solution is quite simple, as we wanted to implement it on everyday smartphones. The user can select to “follow” one of the friends. The application then calculates the relative location of this friend, such as “left-hand side”. This information is then encoded into vibration patterns. By learning the meaning of the patterns, the user can understand where the friend is without even taking the device out of the pocket.

We tested this concept on a festival with two groups à 6 friends each. Three of each group could sense the others while three only shared their locations. Over the night we repeatedly probed the participant’s mood and the subjective level of attention they devoted to keeping the group together. In both cases, we could find statistically significant differences between users and non-users of the “friend sense”. The friends that were able to sense the other were more relaxed, felt more confident, and subjectively devoted less attention to keep the group together.

More details on FriendSense and this study can be found in A Tactile Friend Sense for Keeping Groups Together, a work-in-progress to be published as part of the extended abstract of the CHI ’11 conference.

Share this:
Share
Categories
Android Research

Android User Hate Parade

Stupid! – Garbage – Hate it!!!!!!!

…. these are some of the few comments when publishing apps in the Android Market for free. This can be really frustrating for developers. Here are some of the worst example I have encountered in my life as an Android developer:

The “it does not work -> 1 star” fraction

Examples:

  • “poor! doesnt work on my G1 keeps force closing! Uninstalled!”
  • “Keeps forcing close fix it and it is horrible. Hate it!!!!!!!!! One star and I am uninstalling this stupid thing”

Guys, I can understand your anger, but please, just send the developer a mail, describe the error and the circumstances where it occurred in as much detail as possible, and give the developer a chance to learn about it and fix it!

The “my obscure feature is not present -> 1 star” fraction

Examples

  • “No “dk” map [Ingen dk kort]”
  • “Not in Russian [?? ?? ??????]”

Yes, you may want to have the app in Russian, Urdu, and Aramaic, but as a hobby developer one has limited resources. Please respect that many apps are developed on a very tight or even non-existent budget. Why not just be glad  to have that many apps for free?

The “I hate your app -> 1 star” fraction

Examples

  • “Stupid!”
  • “Garbage”
  • “Slow and no instructions”

These guys would probably even rate the app with 0 stars if that was possible. The comment “no instructions” was even wrong at the time of writing, since there was a manual accessible from the main menu.

*update*

The “Weird -> 1 star” fraction (proposed by Niels).

Example

  • “Has swear word on end button if you don’t do well. Not something I want my kid playing.”
  • “My mom is crying. Uninstalled”
  • “Stupid and offincive to my pet rabbit bayleigh”.

Conclusions

If you download, rate, and comment apps, please be nice with your developers. Many of us are guys like you and me, only spending their free time to work on their apps. Please accept that you cannot get perfect solutions in no-time. Rather help us to improve our apps and appreciate that we deliver them for free!

Share this:
Share
Categories
Research

N95 vs iPhone 2G – Usability Matters!

Usability matters! It matters much more than features. A tangible example of this was presented by Scott Jensen at a keynote talk at MobileHCI ’10 in Lisbon, Portugal.

He compared the Nokia N95 with the Apple 2G, which were both top-notch devices in 2008. The Nokia N95 was a brilliant piece of technology that contained many features that got standard later in many other phones. The iPhone 2G was lacking many if these exciting technology, such as

3G

GPS

MMS

5-MP Camera

Video Telephony

Video Output on TV

As we all know, the iPhone became the probably most popular cell phone, at least in the US and in Europe. From my perspective, the iPhone was the first phone that actually made all the advanced technology usable while being on the move. If you’d like to experience what I mean, try to enter a URL with a num pad keyboard.

Share this:
Share
Categories
Android NDK

OpenAL on Android

Although being slightly late with 3D Audio Support for Android 2.3 announced – this tutorial shows how to compile OpenAL for Android, so you can provide 3D Sound in your apps with 2.2 and below. The code has successfully been tested with the Nexus One (2.2) and the G1 (1.6).

Update: the resulting project for download as a single .zip file. To run the example create a directory called wav on your device’s SD card and put a sound file called lake.wav into it.

Update: some people reported latency issues. It can possibly be fixed in the OpenAL source. See last paragraph for a possible solution.

Update: if you are using a NativeActivity, and the app crashes on device = alcOpenDevice( NULL ); please take a look at Garen’s fix to the getEnv() method: http://pielot.org/2010/12/14/openal-on-android/#comment-1160

 

Preparation

Understand how to compile NDK resources

This tutorial requires working with the Android NDK. We will have to compile OpenAL from source into a native Shared Object and then build a Java Native Interface to work with it. The techniques I use to work with the NDK (on Windows) have been described in a previous tutorial. You might want to take a look to understand what exactly I am doing.

Remember to PRESS F5 after you COMPILED the SHARED OBJECT. Otherwise, Eclipse will not use the new .so.

Create HelloOpenAL Project

Create a normal Android SDK Project.

package org.pielot.helloopenal;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;

public class HelloOpenAL extends Activity {
 /** Called when the activity is first created. */
 @Override
 public void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.main);
 }

 private native int play(String filename);
}

Compile OpenAL for Android

The first step will be to compile OpenAL for Android. The goal will be to produce a Shared Object library libopenal.so that can be loaded into Android apps.

Download patched source of OpenAL

 

Thanks to Martins Mozeiko and Chris Robinson a version of OpenAL exists that has been adapted to the Android platform. Go to http://repo.or.cz/w/openal-soft/android.git and download latest version of the patched OpenAL sourcecode. For this tutorial I used version that can be downloaded here.

Extract into project folder. Rename top folder of downloaded source from ‘android’ to ‘openal’.

Create config.h

To compile OpenAL a file called config.h is needed.Copy it from <PROJECT_HOME>/openal/android/jni to <PROJECT_HOME>/openal/include.

Create Android.mk

To tell the NDK compiler what files to compile, we now need to create Android.mk in <PROJECT_HOME>/jni . The file should contain:

TARGET_PLATFORM := android-3
ROOT_PATH := $(call my-dir)

########################################################################################################
include $(CLEAR_VARS)

LOCAL_MODULE     := openal
LOCAL_ARM_MODE   := arm
LOCAL_PATH       := $(ROOT_PATH)
LOCAL_C_INCLUDES := $(LOCAL_PATH) $(LOCAL_PATH)/../openal/include $(LOCAL_PATH)/../openal/OpenAL32/Include
LOCAL_SRC_FILES  := ../openal/OpenAL32/alAuxEffectSlot.c \
 ../openal/OpenAL32/alBuffer.c        \
 ../openal/OpenAL32/alDatabuffer.c    \
 ../openal/OpenAL32/alEffect.c        \
 ../openal/OpenAL32/alError.c         \
 ../openal/OpenAL32/alExtension.c     \
 ../openal/OpenAL32/alFilter.c        \
 ../openal/OpenAL32/alListener.c      \
 ../openal/OpenAL32/alSource.c        \
 ../openal/OpenAL32/alState.c         \
 ../openal/OpenAL32/alThunk.c         \
 ../openal/Alc/ALc.c                  \
 ../openal/Alc/alcConfig.c            \
 ../openal/Alc/alcEcho.c              \
 ../openal/Alc/alcModulator.c         \
 ../openal/Alc/alcReverb.c            \
 ../openal/Alc/alcRing.c              \
 ../openal/Alc/alcThread.c            \
 ../openal/Alc/ALu.c                  \
 ../openal/Alc/android.c              \
 ../openal/Alc/bs2b.c                 \
 ../openal/Alc/null.c                 \

LOCAL_CFLAGS     := -DAL_BUILD_LIBRARY -DAL_ALEXT_PROTOTYPES
LOCAL_LDLIBS     := -llog -Wl,-s

include $(BUILD_SHARED_LIBRARY)

########################################################################################################

Compile OpenAL

Now compile the source code using the NDK. I used a technique described in another tutorial on Using cygwin with the Android NDK on Windows. I am creating a batch file make.bat in the projects directory containing:

@echo on

@set BASHPATH="C:\cygwin\bin\bash"
@set PROJECTDIR="/cygdrive/d/dev/workspace-android/helloopenal"
@set NDKDIR="/cygdrive/d/dev/SDKs/android-ndk-r4b/ndk-build"

%BASHPATH% --login -c "cd %PROJECTDIR% && %NDKDIR%

@pause:

Save the file and execute it. If there is no error you have just compiled the OpenAL library into a Shared Object! You can find it in <PROJECT_HOME>/libs/armeabi. Now let’s see how we can make use of it.

The Native Interface

The next steps will be to create a Java Native Interface that allows us to access to OpenAL Shared Object.

Define Native Interface in Activity

Extend the HelloOpenAL Activity, so it looks like

package org.pielot.helloopenal;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;

public class HelloOpenAL extends Activity {
 /** Called when the activity is first created. */
 @Override
 public void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.main);

 System.loadLibrary("openal");
 System.loadLibrary("openaltest");
 int ret = play("/sdcard/wav/lake.wav");
 Log.i("HelloOpenAL", ""+ret);
 }

 private native int play(String filename);
}

Implement Native Interface

In <PROJECT_HOME> execute

javah.exe -classpath bin -d jni org.pielot.helloopenal.HelloOpenAL

to create the c header for the native function. Now <PROJECT_HOME>/jni should contain the file org_pielot_helloopenal_HelloOpenAL.h. Create org_pielot_helloopenal_HelloOpenAL.c in <PROJECT_HOME>/jni and fill it with

#include "org_pielot_helloopenal_HelloOpenAL.h"

JNIEXPORT jint JNICALL Java_org_pielot_helloopenal_HelloOpenAL_play
 (JNIEnv * env, jobject obj, jstring filename) {
 return 0;
}

Compile Native Interface

Add new library to Android.mk

########################################################################################################

include $(CLEAR_VARS)

LOCAL_MODULE     := openaltest
LOCAL_ARM_MODE   := arm
LOCAL_PATH       := $(ROOT_PATH)
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../openal/include
LOCAL_SRC_FILES  := org_pielot_helloopenal_HelloOpenAL.c     \

LOCAL_LDLIBS     := -llog -Wl,-s

LOCAL_SHARED_LIBRARIES := libopenal

include $(BUILD_SHARED_LIBRARY)

########################################################################################################

Now compile again. The above created make.bat will do. You now should have two libraries in <PROJECT_HOME>/libs/armeabi/, namely libopenal.so and libopenalwrapper.so.

I you want you can run the app now. It should not crash and print ‘HelloOpenAL   0’ into the log.

Testing OpenAL

Now we have two libraries, one containing OpenAL and the other a native interface. We will now fill the latter with life to demonstrate the use of OpenAL.

Initialize and Release Audio Components

Therefore open org_pielot_helloopenal_HelloOpenAL.c and extend the existing code by:

#include "org_pielot_helloopenal_HelloOpenAL.h"

#include <stdio.h>
#include <stddef.h>
#include <string.h>
#include <AL/al.h>
#include <AL/alc.h>

JNIEXPORT jint JNICALL Java_org_pielot_helloopenal_HelloOpenAL_play
 (JNIEnv * env, jobject obj, jstring filename) {

 // Global Variables
 ALCdevice* device = 0;
 ALCcontext* context = 0;
 const ALint context_attribs[] = { ALC_FREQUENCY, 22050, 0 };

 // Initialization
 device = alcOpenDevice(0);
 context = alcCreateContext(device, context_attribs);
 alcMakeContextCurrent(context);

 // More code to come here ...

 // Cleaning up
 alcMakeContextCurrent(0);
 alcDestroyContext(context);
 alcCloseDevice(device);

 return 0;
}

This code will now acquire the audio resource and release them. You should be able to compile the code and execute the HelloOpenAL app. However, nothing will yet happen, as we still have to load and play sound.

Methods for Loading Audio Data

Now we need to load audio data. Unfortunately, OpenAL does not come with functions for loading audio data. There has been the very popular ALut toolkit, but this is not part of OpenAL anymore. We therefore need to provide our own methods to load .wav files.

The following code snippets have been posted by Gorax at www.gamedev.net. These are one struct and two methods methods to load .wav data and buffer it in the memory.

Add the following code to org_pielot_helloopenal_HelloOpenAL.c. Add the code above JNIEXPORT jint JNICALL Java_org_pielot_helloopenal_HelloOpenAL_play

typedef struct {
 char  riff[4];//'RIFF'
 unsigned int riffSize;
 char  wave[4];//'WAVE'
 char  fmt[4];//'fmt '
 unsigned int fmtSize;
 unsigned short format;
 unsigned short channels;
 unsigned int samplesPerSec;
 unsigned int bytesPerSec;
 unsigned short blockAlign;
 unsigned short bitsPerSample;
 char  data[4];//'data'
 unsigned int dataSize;
}BasicWAVEHeader;

//WARNING: This Doesn't Check To See If These Pointers Are Valid
char* readWAV(char* filename,BasicWAVEHeader* header){
 char* buffer = 0;
 FILE* file = f open(filename,"rb");
 if (!file) {
 return 0;
 }

 if (f read(header,sizeof(BasicWAVEHeader),1,file)){
 if (!(//these things *must* be valid with this basic header
 memcmp("RIFF",header->riff,4) ||
 memcmp("WAVE",header->wave,4) ||
 memcmp("fmt ",header->fmt,4)  ||
 memcmp("data",header->data,4)
 )){

 buffer = (char*)malloc(header->dataSize);
 if (buffer){
 if (f read(buffer,header->dataSize,1,file)){
 f close(file);
 return buffer;
 }
 free(buffer);
 }
 }
 }
 f close(file);
 return 0;
}

ALuint createBufferFromWave(char* data,BasicWAVEHeader header){

 ALuint buffer = 0;
 ALuint format = 0;
 switch (header.bitsPerSample){
 case 8:
 format = (header.channels == 1) ? AL_FORMAT_MONO8 : AL_FORMAT_STEREO8;
 break;
 case 16:
 format = (header.channels == 1) ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16;
 break;
 default:
 return 0;
 }

 alGenBuffers(1,&buffer);
 alBufferData(buffer,format,data,header.dataSize,header.samplesPerSec);
 return buffer;
}

WARNING, I had to put spaces into the word f open, f read, and f close. Delete the spaces when you copy that piece of code. For some reason, WordPress does not accept the words without space in a post.

Load Audio Data into Buffer

In method JNIEXPORT jint JNICALL Java_org_pielot_helloopenal_HelloOpenAL_play located the comment

// TODO More Code comes here

and replace it by

// Create audio buffer
 ALuint buffer;
 const char* fnameptr = (*env)->GetStringUTFChars(env, filename, NULL);
 BasicWAVEHeader header;
 char* data = readWAV(fnameptr,&header);
 if (data){
 //Now We've Got A Wave In Memory, Time To Turn It Into A Usable Buffer
 buffer = createBufferFromWave(data,header);
 if (!buffer){
 free(data);
 return -1;
 }

 } else {
 return -1;
 }

 // TODO turn buffer into playing source

 // Release audio buffer
 alDeleteBuffers(1, &buffer);

This piece of code tries to load PCM .wav audio data from the passed filename. The audio data is loaded into an OpenAL buffer. The buffer itself is merely the cached audio data but cannot be played. It therefore has to be attached to a sound source.

Create a playing source from the buffer

In method JNIEXPORT jint JNICALL Java_org_pielot_helloopenal_HelloOpenAL_play located the comment

// TODO turn buffer into playing source

and replace it by

 // Create source from buffer and play it
 ALuint source = 0;
 alGenSources(1, &source );
 alSourcei(source, AL_BUFFER, buffer);

 // Play source
 alSourcePlay(source);

 int        sourceState = AL_PLAYING;
 do {
 alGetSourcei(source, AL_SOURCE_STATE, &sourceState);
 } while(sourceState == AL_PLAYING);

 // Release source
 alDeleteSources(1, &source);

This piece of code creates a sound source from the buffer and plays it once.

Test on the Device

Compile the native code again by using make.bat. It should compile without errors. If you are using Eclipse, select the project HelloOpenAL in the Package Explorer and press F5. Otherwise, Eclipse might not be aware that the Shared Objects were updated.

Next, go to your devices SD Card and add a .wav file. I created a folder called “wav” and put a mono .wav file called “lake.wav” into this folder. Make sure it matches the filename you passed play(String filename) in the HelloOpenAL activity.

Now it time for the big test! Once you start the app, the .wav file should be played once.

This has been tested on the Nexus One and the G1/HTC Dream.

Solving Latency Issues

Some people seem to have experienced a 0.5 sec lag between triggering the sound and the actual playback. In the comments aegisdino suggested the following solution:

In alcOpenDevice() of ALc.c source,
“device->NumUpdates” seems to apply the lag issue.
In normal cases, device->NumUpdates will be 4, then I can feel about 0.5sec lag.
But when I fix it to 1, the lag disappeared.

I did not test the solution, but as NumUpdates was 1 in my version of ALc.c it could be the solution.

Share this:
Share
Categories
Android NDK

Using cygwin with the Android NDK on Windows

This tutorial illustrates how to setup and use the Android NDK under Windows. It will use cygwin for compiling the native code. It has been tested on Windows XP and Windows 7.

This guide assumes that you have Eclipse with ADT and the Android SDK version 3 (1.5) up and running.

There are three important paths:

Eclipse Workspace       D:\Dev\workspace-android
NDK                     D:\Dev\SDKs\android-ndk-r4b
Cygwin                  C:\Cygwin

I am using these paths as they appear on my computer. Please adapt them to use system if necessary. Note that the paths MUST NOT CONTAIN SPACES.

The code for this tutorial is available here

Download NDK

Go to http://developer.android.com/sdk/ndk/index.html and download the Android NDK for Windows. At the time of writing, android android-ndk-r4b was the latest version. Copy the folder into D:\dev\SDKs\

Install Cygwin

Download setup.exe from http://cygwin.com/. The direct link is http://cygwin.com/setup.exe. Execute setup.exe and select a server to download the Cygwin files from. Then a huge list appears where you can select the components to download.

Add “Devel/make” and “Shells/bash”. Search for “make” and “shell” to find them. Press next to download. I installed all files to C:\cygwin.

Create Android Project

Create a new standard Android project. I called it HelloNDK and used the following code.

package org.pielot.hellondk;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;

public class HelloNDK extends Activity {
	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);

		System.loadLibrary("hellondk");
		int result = sayHello();
		Log.i("HelloNDK", "" + result);
	}

	private native int sayHello();
}

Make sure to compile it using the Android SDK. Javac.exe won’t work! Running this code should fail, as there is no native library yet.

Create Java Native Interface

Make sure your PATH contains your Java SDKs /bin directory. Open a terminal (cmd.exe) and enter javah. Receiving something like this means everything is alright.

Now, in the terminal, go to the root of your project in Eclipse’s workspace D:\Dev\workspace-android\HelloNDK. Enter

javah.exe -classpath bin/classes -d jni org.pielot.hellondk.HelloNDK

When no error occurs, the compilation was successful. Since some comments below report from difficulties with this step, you might want to check if HelloNDK.class is really located in bin/classes/org/pielot/hellondk/. If not, try changing bin/classes/… to bin/… or src/… . It appears to have worked for others.

Now you should find a new folder jni in your project, containing the file org_pielot_hellondk_HelloNDK.h

/* DO NOT EDIT THIS FILE - it is machine generated */
#include
/* Header for class org_pielot_hellondk_HelloNDK */

#ifndef _Included_org_pielot_hellondk_HelloNDK
#define _Included_org_pielot_hellondk_HelloNDK
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     org_pielot_hellondk_HelloNDK
 * Method:    sayHello
 * Signature: ()I
 */
JNIEXPORT jint JNICALL Java_org_pielot_hellondk_HelloNDK_sayHello
  (JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif

For my convenience, I usually create a .bat file including the above javah command and put it into the project folder.

Implement the Native Interface

Now we have to provide an implementation of the generated header file. Create org_pielot_hellondk_HelloNDK.c in the same folder as org_pielot_hellondk_HelloNDK.h and fill it with:

#include "org_pielot_hellondk_HelloNDK.h"

JNIEXPORT int JNICALL Java_org_pielot_hellondk_HelloNDK_sayHello
 (JNIEnv * env, jobject obj) {

 return 42;
}

Inform the Compiler what Files to Compile

Next, we have to inform the NDK compiler what files should be compiled. In the /jni folder we therefore create “Android.mk”:

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE    := hellondk
LOCAL_SRC_FILES := org_pielot_hellondk_HelloNDK.c

include $(BUILD_SHARED_LIBRARY)

Compiling the Native Code

In the HelloNDK project folder create a batch file named “make.bat”. Fill it with:

@echo on

@set BASHPATH="C:\cygwin\bin\bash"
@set PROJECTDIR="/cygdrive/d/dev/workspace-android/hellondk"
@set NDKDIR="/cygdrive/d/dev/SDKs/android-ndk-r4b/ndk-build"

%BASHPATH% --login -c "cd %PROJECTDIR% && %NDKDIR%

@pause:

This file will NOT WORK WHEN EXECUTED FROM WITHIN ECLIPSE. Thus, always find it with the Windows Explorer and execute it by double-clicking.

If successful it should look like

In the HelloNDK project directory you now should find libs/armeabi/libhellondk.so created.

Loading and Testing library

If you now run the HelloNDK Activity, you should see no exceptions. In LogCat, something like

12-05 13:42:45.311: INFO/HelloNDK(24329): 42

should appear. Voila! You have done it!

One last note: if you are just working on the C code, Eclipse will not realize that the native lib has been updated. To make sure that the latest version of the lib will be used, mark the HelloNDK project in Eclipse’s project explorer and hit F5.

Share this:
Share