Skip to content

Quick Start

This step-by-step tutorial leads you through the creation of a simple app that uses the Kinemic Gesture SDK to provide gesture interaction.

We show you how to:

If you are new to developing Android apps, we recommend reading the tutorials on Google's Android developer portal.

You can find more information about the Kinemic Gesture SDK in the Basic Usage Overview, in the Support Library Usage Guide or in our API reference.

Prerequisites

This guide assumes you bought our Kinemic Band that comes with access to our Kinemic Gesture SDK.

Create Your App

Create a new Android app or use your existing app with an empty Activity.

Add the Kinemic Gesture SDK

We provide access to our Android SDK using Artifactory.

To integrate our SDK into your Android application, include the following into your project's build.gradle:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
...

buildscript {
    ...

    dependencies {
        ...

        classpath "org.jfrog.buildinfo:build-info-extractor-gradle:4.5.0"
    }
}

allprojects {
    ...

    apply plugin: "com.jfrog.artifactory"
}

artifactory {
    contextUrl = "https://kinemic.jfrog.io/kinemic"   
    resolve {
        repository {
            repoKey = 'gradle-release'
            maven = true
        }
    }
}

Now you can include the Gesture SDK as a dependency in your module's build.gradle. You will also have to use Java 8:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
android {

  ...

  // Kinemic Gesture SDK requires java 8
  compileOptions {
      sourceCompatibility 1.8
      targetCompatibility 1.8
  }
}

dependencies {

  ...

  implementation 'de.kinemic:gesture-sdk:1.0.1'
}

Congratulations, you are now ready to use our SKD!

Ask for Permissions

In order to search for Bluetooth devices, android requires your app to ask for ACCESS_COARSE_LOCATION permission. A good place to do this in this sample is the Activity's onCreate() method.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    // coarse location permission is needed to scan for bluetooth devices
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        if (this.checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            requestPermissions(new String[] {Manifest.permission.ACCESS_COARSE_LOCATION}, 1);
        }
    }
}

Create an Engine Instance

The central object you will communicate with is an instance of our Engine class. The Engine also holds the bluetooth connection to the Kinemic Band. In most apps you will use a single instance which lives in your Application class. For simplicity, we will create the Engine in our Activity for this quick start guide.

To create an instance of our Engine, you need to supply a Context. Add this code to your Activity's onStart() method to create an Engine instance. All classes of the Kinemic Gesture SDK are located in the de.kinemic.gesture package.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
import de.kinemic.gesture.Engine;

...

private Engine mEngine;

...

@Override
protected void onStart() {
    super.onStart();

    // create an engine instance
    mEngine = new Engine(getApplicationContext());
}

Also, add this code to the onStop() method to release the engine's resources.

1
2
3
4
5
6
7
8
9
...

@Override
protected void onStop() {
    super.onStop();

    // release resources
    mEngine.release();
}

Connect to nearest Kinemic Band

There are two ways to search for and connect to Kinemic Bands, you can either search for Bands and let the user select one or let the Engine connect to the nearest Band. We will use the second approach here with a call to Engine.connectStrongest(). The method takes a callback object which is notified about the current choosen Band and the current confidence of the choice.

Add this code to the Activity's onResume() to connect to the nearest Band.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
...

@Override
protected void onResume() {
    super.onResume();

    // connect to the nearest Kinemic Band
    mEngine.connectStrongest(new SearchCallback() {
        @Override
        public void onBandFound(final @NonNull SearchResult band) {
            float confidence = band.getRssi();
            String currentStrongestBand = band.getMacaddress();

            // you could update your ui here ...
        }

        @Override
        public void onSearchStarted() {

        }

        @Override
        public void onSearchStopped() {

        }
    });
} 

To match the connect call, add the code to disconnect the Band to your Activity's onPause().

1
2
3
4
5
6
7
8
9
...

@Override
protected void onPause() {
    super.onPause();

    // disconnect Kinemic Band
    mEngine.disconnect();
}

Listen for Connection State Changes

The Engine instance lets you register listeners to be notified about state changes and events. Let's create an OnConnectionStateChangeListener to be notified about changes of the connection state to Kinemic Bands.

1
2
3
4
5
6
7
private OnConnectionStateChangeListener mConnectionStateListener = new OnConnectionStateChangeListener() {
    @Override
    public void onConnectionStateChanged(final @NonNull ConnectionState state, final @NonNull ConnectionReason reason) {
        // show a message on screen when connection state changes
        Toast.makeText(MainActivity.this, state.toString(), Toast.LENGTH_SHORT).show();
    }
};

We register listeners in the onResume() method of your Activity and unregister them in onPause(). Both methods should look like this now.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
@Override
protected void onResume() {
    super.onResume();

    // register listeners
    mEngine.registerOnConnectionStateChangeListener(mConnectionStateListener);

    // connect to the nearest Kinemic Band
    mEngine.connectStrongest( 

        ...

    );
}

@Override
protected void onPause() {
    super.onPause();

    // unregister listeners
    mEngine.unregisterOnConnectionStateChangeListener(mConnectionStateListener);

    // disconnect Kinemic Band
    mEngine.disconnect();
}

Listen for Gesture Events

As with the OnConnectionStateChangeListener, you register a OnGestureListener, to be notified about gesture events.

1
2
3
4
5
6
7
private OnGestureListener mGestureListener = new OnGestureListener() {
    @Override
    public void onGesture(final @NonNull Gesture gesture) {
        // show a message on screen for each gesture event
        Toast.makeText(MainActivity.this, gesture.toString(), Toast.LENGTH_SHORT).show();
    }
};

Don't forget to Engine.registerOnGestureListener() and Engine.unregisterOnGestureListener() the OnGestureListener in your Activity's onResume() and onPause() methods.

Give Haptic Feedback to the User

It is a good idea to give users feedback when they interact with your app via gestures. One way to do this is haptic feedback which uses the vibration motor in the Kinemic Band.

Let's add some haptic feedback for every gesture by calling :javaEngine.buzz() in the :javaOnGestureListener.onGesture() callback.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
private OnGestureListener mGestureListener = new OnGestureListener() {
    @Override
    public void onGesture(final @NonNull Gesture gesture) {
        // show a message on screen for each gesture event
        Toast.makeText(MainActivity.this, gesture.toString(), Toast.LENGTH_SHORT).show();

        // give haptic feedback for every gesture
        mEngine.buzz(300);
    }
};

Next Steps

Congratulations! You wrote your first app with gesture control using the Kinemic Gesture SDK!

Want more? Take a look at our guides and best practices like

or dive directly into our API Reference.

Sources

If you missed something, here is the full code of your Activity:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
package com.example.quickstart;

import android.Manifest;
import android.content.pm.PackageManager;
import android.os.Build;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.widget.Toast;
import de.kinemic.gesture.ConnectionState;
import de.kinemic.gesture.Engine;
import de.kinemic.gesture.Gesture;
import de.kinemic.gesture.OnConnectionStateChangeListener;
import de.kinemic.gesture.OnGestureListener;
import de.kinemic.gesture.OnDigitListener;
import de.kinemic.gesture.SearchCallback;
import de.kinemic.gesture.SearchResult;

public class MainActivity extends AppCompatActivity {

    private Engine mEngine;

    private OnConnectionStateChangeListener mConnectionStateListener = new OnConnectionStateChangeListener() {
        @Override
        public void onConnectionStateChanged(final @NonNull ConnectionState state, final @NonNull ConnectionReason reason) {
            // show a message on screen when connection state changes
            Toast.makeText(MainActivity.this, state.toString(), Toast.LENGTH_SHORT).show();
        }
    };

    private OnGestureListener mGestureListener = new OnGestureListener() {
        @Override
        public void onGesture(final @NonNull Gesture gesture) {
            // show a message on screen for each gesture event
            Toast.makeText(MainActivity.this, gesture.toString(), Toast.LENGTH_SHORT).show();

            // give haptic feedback for every gesture
            mEngine.buzz(300);
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // coarse location permission is needed to scan for bluetooth devices
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            if (this.checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
                requestPermissions(new String[] {Manifest.permission.ACCESS_COARSE_LOCATION}, 1);
            }
        }
    }

    @Override
    protected void onStart() {
        super.onStart();

        // create an engine instance
        mEngine = new Engine(getApplicationContext());
    }


    @Override
    protected void onStop() {
        super.onStop();

        // release resources
        mEngine.release();
    }

    @Override
    protected void onResume() {
        super.onResume();

        // register listeners
        mEngine.registerOnConnectionStateChangeListener(mConnectionStateListener);
        mEngine.registerOnGestureListener(mGestureListener);

        // connect to the nearest Kinemic Band
        mEngine.connectStrongest(new SearchCallback() {
            @Override
            public void onBandFound(final @NonNull SearchResult band) {
                float confidence = band.getRssi();
                String currentStrongestBand = band.getMacaddress();

                // we could update our ui here ...
            }

            @Override
            public void onSearchStarted() {

            }

            @Override
            public void onSearchStopped() {

            }
        });
    }

    @Override
    protected void onPause() {
        super.onPause();

        // unregister listeners
        mEngine.unregisterOnConnectionStateChangeListener(mConnectionStateListener);
        mEngine.unregisterOnGestureListener(mGestureListener);

        // disconnect Kinemic Band
        mEngine.disconnect();
    }
}