Android SDK

The U Grok It SDK for Android enables easy integration of RFID functionality into an Android app. Here are the basics of using the SDK. The SDK works with several IDEs. We recommend Android Studio (2.3.3). Alternatively, IntelliJ IDEA (2016.2.4) works as well.

The SDK requires Android API level 11 (Android 3.0, Honeycomb) or later.

Eclipse Support

In the past the Android SDK has supported the Eclipse IDE. Additional features, specifically those requiring resources (images and layouts) are not well supported in Eclipse. Therefore Eclipse is no longer supported for new development. Existing apps are still supported amd can upgrade to use the newest Android SDK, but cannot use the new UI building blocks (UgiTitleBar, UgiStatusImageView, UgiFooter).

Downloading and Installation

The contents of UGrokItAndroidSdk.zip are:

  • UGrokItApi-release.aar
    Android archive containing all parts of the U Grok It API. This is the more modern way of packaging an Android library and is used by Android Studio and IntelliJ, but is not supported by some Android development environments.
  • libs/ and res/ (folders)
    Old-style packaging of the U Grok It library, may be useful with some older Android development environments.
  • html (folder)
    The HTML documentation
  • ApiDemo (folder)
    The ApiDemo sample application with files arranged for Android Studio or IntelliJ
Download the SDKs
iOS, Android, Windows, Cordova, Xamarin
Get Grok Demo from Google play
If you do not have access to Google play, you can download the apps here and install them manually
The ApiDemo sample app

The APIDemo application demonstrates use of the API.

NOTE: The minimum Android SDK version is set to 10, which is rather old. This is done to maximize compatibility. If you do not have SDK 10 downloaded, API Demo will not compile. You can either download Android SDK 10, or you can change the minimum Android SDK version, which is in AndroidManifest.xml

Android Studio

This imports ApiDemo into a new Android Studio project:

  • Unzip the SDK (creates a UGrokItAndroidSdk folder)
  • In Android Studio, select "Open an Existing Android Studio Project" from the opening dialog, or Open from the File menu
    • Inside the UGrokItAndroidSdk folder, select ApiDemo/build.gradle
    • In the "Run" menu, choose "Run ApiDemo" or 'Debug ApiDemo".
  • In the "Run" menu, choose "Run ApiDemo" or 'Debug ApiDemo". Click "Edit Configurations", click the "+" and choose "Android Application". For "Module", choose "ApiDemo" and click "Run" or "Debug".
IntelliJ

To open ApiDemo:

  • Unzip the SDK (creates a UGrokItAndroidSdk folder)
  • In IntelliJ, do File>Open and inside the UGrokItAndroidSdk folder, select ApiDemo/build.gradle
  • At the "Import Project from Gradle" dialog, click "Use defualt Gradle wrapper", then click OK"
  • In the "Run" menu, choose "Run ApiDemo" or 'Debug ApiDemo".
Integrating the API into an existing app
Android Studio

To integrate the U Grok It API into an existing app in Android Studio:

  • Unzip the SDK (creates a UGrokItAndroidSdk folder)
  • Copy UGrokItApi-release.aar from the SDK into your application's libs/ folder (in the module, not the top project level)
  • Edit build.gradle (for the module, not the project) and add
    • At the top level (the end of the file is fine):
      repositories {
          flatDir { dirs "libs" }
      }
    • In the "dependencies" section:
      compile(name:"UGrokItApi-release", ext:"aar")
      
    • You should see a yellow warning bow with"Sync Now".
  • If you ARE NOT using Gradle
    • Copy the libs/ folder from the SDK into your application's folder
    • Choose File > Project Structure
    • Click the Libraries tab
    • Click "+", choose Java, go into libs/ and choose ugrokitapi.jar, gson-2.3.1.jar, arm64-v8a, armembi, armembi-v7a, mips, mips64, x86 and x86_64, click Ok, click Ok again
    • rename the library if desired
  • Edit AndroidManifest.xml and add:
    <uses-permission android:name="android.permission.RECORD_AUDIO" />
    <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
    <uses-permission android:name="android.permission.INTERNET" />
    
    • MODIFY_AUDIO_SETTINGS is needed to temporarily set the volume when connecting to the Grokker. The volume is reset when the connection is not active.
    • INTERNET is used in a few specific cases, all of which can be disabled. See SDK Internet Usage.
IntelliJ

To integrate the U Grok It API into an existing app in IntelliJ:

  • Unzip the SDK (creates a UGrokItAndroidSdk folder)
  • If you ARE using Gradle
    • Copy UGrokItApi-release.aar from the SDK into your application's libs/ folder (in the module, not the top project level)
    • Edit build.gradle (for the module, not the project) and add
      • In the "repositories" section:
        flatDir { dirs "libs" }
        
      • In the "dependencies" section:
        compile(name:"UGrokItApi-release", ext:"aar")
        
    • You should see a yellow warning bow with"Sync Now".
  • If you ARE NOT using Gradle
    • Copy the libs/ folder from the SDK into your application's folder
    • Choose File > Project Structure
    • Click the Libraries tab
    • Click "+", choose Java, go into libs/ and choose ugrokitapi.jar, gson-2.3.1.jar, arm64-v8a, armembi, armembi-v7a, mips, mips64, x86 and x86_64, click Ok, click Ok again
    • rename the library if desired
  • Edit AndroidManifest.xml and add:
    <uses-permission android:name="android.permission.RECORD_AUDIO" />
    <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
    <uses-permission android:name="android.permission.INTERNET" />
    
The Ugi singleton object and housekeeping chores

The API is accessed through the Ugi object (Ugi is short for U Grok It). Import Ugi.h:

  import com.ugrokit.api.*;
The Ugi object requires a reference to the application object, and is normally created in the onCreate() method of the application:
public class ApiDemoApp extends Application {
  
  private Ugi ugi;
  public Ugi getUgi() { return ugi; }

  @Override public void onCreate() {
    super.onCreate();
    ugi = Ugi.createSingleton(this);
    ugi.openConnection();
  }
}

The rest of the application accesses the Ugi object via the Application object's getUgi() method.

Housekeeping

A production level app needs to do a few housekeeping functions:

  • Region Setting
    A new Grokker must be configured for the region of the world that it will operate in.
  • Firmware Update
    From time to time, we will release firmware updates for the Grokker.

Calling Ugi.createSingleton(this) as shown above will use standard UI built into the SDK for these functions.

If you want to customize this UI or if you want to be more restrictive about how and when firmware updates are done, you can pass your own configuration delegate object to Ugi.createSingleton(Context context, UgiConfigurationDelegate configurationDelegate)

Activities

Activities that use U Grok It need to notify the Ugi object of state changes. U Grok It uses these notifications to:

  • Know when the app is active
    When the app becomes inactive, U Grok It closes the connection to the Grokker and stops using the audio input/output. To know when the app is active, U Grok It counts the number of active Activities.
  • Screen rotation
    If the Android device is phone-sized and has the audio jack on top, U Grok It will rotate the screen to correct for the user having to hold the device upside down. This is only done when an Activity is active.

This notification can be done by subclassing the UgiActivity class:

public class ApiDemoActivity extends UgiActivity
  @Override public Ugi getUgi() {
    ApiDemoApp app = (ApiDemoApp)this.getApplication();
    return app.getUgi();
  }
  @Override public boolean ugiShouldHandleRotation() {
    // returning "true" here causes the Ugi code to automatically flip the
    // screen on devices where the audio port is on the top of the phone
    return true;
  }

Or by calling the activityOnCreate(), activityOnDestroy(), activityOnResume() and activityOnPause() methods of the Ugi object.

  private Ugi getUgi() {
    MyApp app = (MyApp)this.getApplication();
    return app.getUgi();
  }

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    // passing "true" here causes the Ugi code to automatically flip the
    // screen on devices where the audio port is on the top of the phone
    getUgi().activityOnCreate(this, true);
  }

  @Override
  public void onDestroy() {
    getUgi().activityOnDestroy(this);
    super.onDestroy();
  }

  @Override
  public void onResume() {
    getUgi().activityOnResume(this);
    super.onResume();
  }

  @Override
  public void onPause() {
    getUgi().activityOnPause(this);
    super.onPause();
  }
Auto-rotation

The "true" passed to activityOnCreate causes the Ugi code to automatically flip the screen on devices where the audio port is on the top of the phone.

Opening and Closing a connection to the grokker

Communication with the grokker is done via the audio port. For an application that uses U Grok It functionality all the time, this is done in the application's onCreate() and onTerminate() methods. For an application that only uses U Grok It occasionally, the connection can be opened and closed at the appropriate points.

  getUgi().openConnection();
  getUgi().closeConnection();

openConnection returns immediately, it does not wait for a connection to the grokker to actually be established. If a grokker is connected, the connection takes less than a second for the connection sequence. Your app can get notification of connection state changes by adding a connection state listener:

  getUgi().addConnectionStateListener(this);

The state-changed method looks like this:

@Override public void connectionStateChanged(Ugi.ConnectionStates connectionState) {
  //Log.i(TAG, "connectionStateChanged: " + connectionState);
  if (connectionState == Ugi.ConnectionStates.CONNECTED) {
    // Connection was established...
  }
}

Usually a state changed method is not needed, using the Inventory methods described below takes care of this.

Inventory

Finding RFID tags is accomplished by running inventory. Once inventory is started, the grokker continually looks for RFID tags and reports them back to the Android device.

Starting inventory returns a UgiInventory object that holds the results of the inventory. The application can either save the UgiInventory object or can use the getActiveInventory() method to get to it.

UgiInventory does some useful aggregation of the raw data from the grokker and reports back to your application via an InventoryDelegate object. Inventory can be run either with a configuration built from one of the pre-defined inventory types or with a custom UgiRfidConfiguration object.

The application can tell the grokker to report all RFID tags it finds:

  getUgi().startInventory(this,                                  // inventory delegate
                          UgiRfidConfiguration.LOCATE_DISTANCE); // inventory configuration

Or the application can pass a specific tag to find:

  UgiEpc epc = new UgiEpc("35fffffff99c70a063405c48");
  getUgi().startInventory(this,                                 // inventory delegate
                          UgiRfidConfiguration.LOCATE_DISTANCE, // inventory configuration
                          epc);                                 // EPC to find

Or the application can pass an array of tags to find:

  ArrayList<UgiEpc> epcs = new ArrayList<UgiEpc>();
  epcs.add(new UgiEpc("35fffffff99c70a063405c48"));
  epcs.add(new UgiEpc("35fffffff956734504747454"));
  getUgi().startInventory(this,                                 // inventory delegate
                          UgiRfidConfiguration.LOCATE_DISTANCE, // inventory configuration
                          epcs);                                // EPCs to find

Inventory runs until the application stops it.

  getUgi().getActiveInventory().stopInventory(this);
Inventory Delegate methods

The inventory code reports back to the application via the inventory delegate object. The delegate object must implement the Ugi.UgiInventoryDelegate protocol, as well as a specific protocol for each method the delegate wants to implement. In this example only inventoryTagChanged is used:

public class ApiDemoActivity extends Activity implements UgiInventoryDelegate,
                                                         UgiInventoryDelegate.InventoryTagChangedListener {
}

Only a subset of the inventory delegate methods are discussed here.

New tag found

When a new tag is found, the delegate is notified via inventoryTagFound (the detailedPerReadData is nil unless the Grokker was told to return detailed per-read data).

... implements UgiInventoryDelegate.InventoryTagFoundListener ...

@Override public void inventoryTagFound(UgiTag tag, UgiInventory.DetailedPerReadData[] detailedPerReadData) {
  // tag was found for the first time
}

The UgiTag object contains information about the tag including:

  • Its EPC code
  • The time the tag was first read, the time the tag was most recently read
  • The total number of times this tag has been read
  • A history of how many times this tags has been read in recent time intervals (the default being the number of reads per 500ms going back 10 seconds, but this is configurable)
Subsequent finds of previously found tag

When a tag is found again, the delegate is notified via inventoryTagSubsequentFinds (the detailedPerReadData is nil unless the Grokker was told to return detailed per-read data).

... implements UgiInventoryDelegate.InventoryTagSubsequentFindsListener ...

@Override public void inventoryTagSubsequentFinds(UgiTag tag, int count, UgiInventory.DetailedPerReadData[] detailedPerReadData) {
  // tag found count more times
}
Tag visibility changed

When a tag is first found, has not been seen for a while (by default 10 seconds, but configurable), or is seen again after not being seen for awhile, the delegate is notified via:

... implements UgiInventoryDelegate.InventoryTagChangedListener ...

@Override public void inventoryTagChanged(UgiTag tag, boolean firstFind) {
  if (firstFind) {
    // tag was found for the first time
  } else if (tag.getisVisible()) {
    // tag was not visible, is now visible again
  } else {
    // tag is no longer visible
  }
}

Usually the delegate either implements inventoryTagChanged, or implements inventoryTagFound (and sometimes inventoryTagSubsequentFinds).

Tag filtering

The delegate can filter which tags are kept track of via:

... implements UgiInventoryDelegate.InventoryFilterListener ...

@Override public boolean inventoryFilterTag(UgiTag tag) {
  if (this tag should be ignored) {
    return true;
  } else {
    return false;
  }
}

If this method returns true, the tag is ignored entirely; inventoryTagFound, inventoryTagSubsequentFinds and inventoryTagChanged are never called for it.

List of found tags

While inventory is running, the app can access the list of found tags via the tags property of the UgiInventory object.

@property (readonly, retain) NSArray *tags;

Usage is typically:

  for (UgiTag tag : getUgi().getActiveInventory().getTags()) {
    // do something with tag
  }
Tag Access (read, write, ...)

Methods in UgiInventory allow tag access for reading, writing and locking. All of these functions work similarly.

Tag programming (changing tag EPC)

While inventory is running, the app can program tags via:

  UgiEpc oldEpc = new UgiEpc("1234567890abcdef12345678");
  UgiEpc newEpc = new UgiEpc("35fffffff956734504747454");
	getUgi().getActiveInventory().programTag(oldEpc, newEpc, UgiInventory.NO_PASSWORD,
																					 new UgiInventory.TagAccessCompletion() {
		@Override
		public void exec(UgiTag tag, UgiInventory.TagAccessReturnValues result) {
			if (result == UgiInventory.TagAccessReturnValues.OK) {
				// tag programmed successfully
			} else {
				// tag programming was unsuccessful
			}
		}
	});

Sometime after the programTag method is called, the completion will be with the success or failure of the programming.

Grokker Configuration
Inventory

The UgiRfidConfiguration object holds the configuration to be used during inventory. Several pre-defined types can be used. Values that can be configured include:

  • Power level
    Initial, minimum and maximum power levels can be set. If a range is provided (minimum != maximum), then the power level is varied over this range.
  • Q value
    Initial, minimum and maximum Q values can be set. If a range is provided (minimum != maximum), then the Q value is dynamically adjusted based on the number of tags in range
  • Session
    The inventory session (0, 1, 2, or 3)
  • Power level and sensitivity for writing tags
    The power level and sensitivity used when writing data to tags
  • Sensitivity
    The reader sensitivity

For more detailed information about RFID and configuration, see RFID Configuration

Sounds

The sounds that the grokker makes when tags are found can be configured.

SDK Internet Usage

The SDK uses the Internet in a few cases, see SDK Internet Usage for details.

Localization

The SDK contains user visible strings for updating firmware, setting region of the world, and UI building blocks. It is localized into Spanish, French and German. If you are interested in localizations to other languages, contact us.