(Android) Slate+ Expand Samples with Riiiver

This is a sample app with which you can learn how to integrate the Riiiver SDK into your companion app for Slate+.
With this app you'll find:

- Expansion of UX with Slate+ by utilizing the Riiiver SDK.
- How the Riiiver functions, piece(s) and iiidea(s), work.
- User Interface provided by our SDK, e.g. login screen, iiidea list screen.


How does this sample demonstrate?
  • (1) Scan BLE devices nearby.
  • (2) Connect to Slate+ evaluation board(EVB).

    • Discover the service and characteristics provided as Riiiver_Demo by QCLI.
  • (3) Login to Riiiver.

  • (4) Complete the setup of the functions.
  • (5) Assign the Riiiver functions that'll be triggered by pushing the button on the EVB.
    • Push the button and find the result that appears on the display of the EVB.
Screenshots

app_journey

Out of scope for this Sample App
  • This app is not a template. Integrate our SDK to your app as you like, e.g. you can choose a suitable architecture for your app.
  • This app does not implement data storage that keeps the app state even after killing and relaunching the app.
  • This app does not implement a complete paring of BLE connection. The Riiiver functions only work when the connection is alive between Slate+ and your mobile phone.
Prepare for development using Riiiver SDK
Preparing for development
What this section describes:
  • Sign up as a developer
  • [resource file] erconfiguration.json

To develop with Riiiver SDK, sign up as a developer and register information about your service. Please visit our developer site and sign up by following the instructions.

Riiiver Developer Site

The required information is as follows:

  • Your company information.
  • Your application information.
  • Your device information.

Riiiver SDK reads vendor and app information by referring to the erconfiguration.json file. The VendorId and AppId should be the IDs that Riiiver has given you when you registered your vendor and app information.

The prepared erconfiguration.json file must be located in the directory of res/raw.

Using Riiiver SDK features
Initialize the Riiiver SDK
What this section describes:
  • [method] initialize(Context, String, Int, List<String>)
  • [method] addListener(ERSdkListener)
  • [protocol] ERSdkListener

Be sure to execute the initialize(Context, String, Int, List<String>) method before using any of the methods provided in the Riiiver SDK.

The implementation is designed to return immediately if it has already been initialized, so it does not matter how many times it is called. The argument is passed the ID of the device supported by the application as an Array of String. If you have not registered your device information, please visit our developer site and register it first.

Also, since the ERSdkListener protocol is provided to delegate processing to the app side when an event occurs in the Riiiver SDK, we use the addListener(ERSdkListener) method to set the delegate after initialization is completed. This method is also implemented to do nothing if the delegate instance is the same, so it does not matter how many times it is called.

The ERSdkListener protocol provides the following delegate methods, so please implement the necessary processing.

Methods of ERSdkListener
  • startApplet(ERAppelt, ERError?)

    Called when the execution of iiidea is started.

  • endApplet(ERApplet, ERBlockName, Map<String, Any>?, ERError?)

    Called when the execution of iiidea has finished. ERBlockName is the type of Piece (trigger, service, or action) that terminated. In case of abnormal termination, it will tell which Piece has been reached. Also, ERError contains error information.

  • onLogin(List<ERApplet>)

    Called when login to Riiiver is completed.

  • onLogout(ERError?)

    Called when users log out of Riiiver.

Note
- `Applet` is the name of iiidea when developing Riiiver. Please read "iiidea" instead of "applet" as it is used in the code and documentation.
- `Block` is the name of piece when developing Riiiver. Please read "piece" instead of "block" as it is used in the code and documentation.
Use the authentication features(login and out)
What this section describes:
  • [method] getLoginUrl()
  • [method] verifyCodeOf(Uri)
  • [method] logout()

An authentication page is provided to login to Riiiver. Please open the URL in the return value of the getLoginUrl() method

When a user completes the login operation on the authentication page, a redirect will occur. The redirect URL is registered as a part of your application information via our developer site. If you have not registered, please visit our developer site and register the redirect URL. Please add it in AndroidManifest.xml so that the app can be launched via a custom scheme.

<intent-filter>
    <action android:name="android.intent.action.VIEW" />
    <category android:name="android.intent.category.DEFAULT" />
    <category android:name="android.intent.category.BROWSABLE" />
    <data android:scheme="$your_redirect_uri" />
</intent-filter>

Also add the parameter of deeplinks to your composable function where you want to receive the redirect. When the app is launched via a custom scheme, a short-lived authorization code is given as a query parameter in the URL. The parameter is named token. So the parameter for uriPattern of NavDeepLink should be your_redirect_uri:///weblogin?token={token}. To complete the login to Riiiver, please invoke verifyCodeOf(Uri) method.

If you want to log out of Riiiver, execute the logout() method at any time.

Display the iiidea list and the settings screen
What this section describes:
  • [class] ERUserWebPagesView
  • [protocol] ERUserWebPagesViewDelegate

We provide a web page that aggregates a iiidea store for users to search for and obtain iiidea, and a list view for users to set or delete already obtained iiidea. The ERUserWebPagesView class, which inherits from the WebView class, is provided as a class for displaying these web pages. The loadPage(ERPageType) method can be executed to display the page.

Some iiidea require the use of device's permissions or OAuth authentication for third-party services at runtime, so when a user requests those permissions on a web page, the ERUserWebPagesViewDelegate protocol is provided to delegate the handling of those events to the app side. The following delegate methods are provided for this delegate, so please implement the necessary processing.

Methods of ERUserWebPagesViewDelegate.
  • didReceivePermissionRequest(ERPermissionType)

    Called when the request button for a device's permission on a web page is tapped. The type of permission being requested is passed as an argument, so that you can present the user with the permission's usage authorization dialog.

  • didReceiveOpenUrlRequest(String)

    Called when a new URL needs to be opened, such as for OAuth authentication. Open the URL passed as argument.

  • didReceiveCloseRequest()

    Called when the close button on the web page is tapped.

  • onError(ERError)

    Called when an error occurs on a web page.

Once the necessary settings for iiidea have been completed, iiidea can be activated. iiidea is activated and is ready to run.

Pre-install some iiidea(s)
What this section describes:
  • [method] forcedDownloadApplet(List<String>)

If you want to make pre-installed some features when the user installs your application, you can use the forcedDownloadApplet(appletIds:) method to make the iiidea of the ID specified in the argument already obtained.

Get the available iiideas list
What this section describes:
  • [method] getMyApplets(List<String>)
  • [class] ERApplet

This sample app is implemented so that each of the two physical buttons on the Slate+ evaluation board can execute a different iiidea when pressed. For this purpose, the app provides a UI that allows the user to freely select the iiidea to be executed. At this time, the method getMyApplets(List<String>) is used to retrieve the list of iiidea already obtained by the user. By passing a device ID as an argument in the form of a list of String, a list of available iiideas on that device can be obtained. The return value is a list of ERApplet.

The ERApplet class provides properties containing iiidea metadata, as well as methods related to activation deactivation and iiidea execution. When you want to find out if a iiidea is ready to run (activated state), you can call getActivateStatus() method.

Implement the Piece(s) and execute iiidea
What this section describes:
  • [protocol] ERBlockExecutor
  • [protocol] ERBlockDelegate

iiidea is a small application that combines 3 Pieces. We call Trigger Piece for the first one, Service Piece for the second one, and Action Piece for the third one, respectively.

All Pieces implemented in the app or SDK must inherit the ERBlockExecutor protocol. The following methods are defined in this protocol, so please implement the necessary processing.

Methods of ERBlockExecutor
  • enable(ERApplet)

    Called when an ERApplet using this Piece is activated by the user. Return true if the piece can be activated, or false if it cannot be activated.

    Although there is no example implementation in this sample app, the geofence trigger implemented in the SDK, for example, checks whether permission to use location information has been obtained and returns false if permission has not been obtained.

  • execute(ERApplet, ERBlockName, Map<String, Any>?, Map<String, Any>?, ERBlockDelegate)

    Called when an ERApplet that uses this Piece is executed and in the order of execution of this Piece. When the processing of the Piece is completed, you need invoke the completed(Map<String, Any>?. ERError?) method of the ERBlockDelegate. In case of abnormal termination, call that method with the argument ERError.

    Note that this method is called when it turns activated in the case of the first Piece of iiidea, the trigger Piece. It is necessary to make sure that the execution of iiidea starts when the desired event actually occurs. In the QCC5100TriggerPieceCore, which fires when a button on the Slate+ EVB is pressed by the user, the QCC5100TriggerPieceCore instance holds the iiidea id and a ERBlockDelegate for it in the form of map type. And it implements the didTrigger(String, Map<String, Any>?) method to notify events. At the timing when the onCharacteristicChanged(BluetoothGatt, BluetoothGattCharacteristic, ByteArray) method of BluetoothGattCallback is called where the received value corresponds to the button press event, the didTrigger(String, Map<String, Any>?) method is called to start iiidea execution.

  • disable(ERApplet)

    Called when an ERApplet that uses this Piece is deactivated. Implement a process such as releasing resources that needed to be held while waiting for execution.

    For example, the geofence trigger implemented in the SDK stops monitoring location information.

Run iiidea from outside the app using Firebase
What this section describes:.
  • [method] setNotificationToken(String)
  • [method] executeTaskForRemoteNotification(Map<String, String>)
Preparation

The Firebase Cloud Messaging API is used to achieve this. The following files are required to use the function.

  • google-services.json

Add these dependencies in your build.gradle.kts.

// Firebase
implementation(platform("com.google.firebase:firebase-bom:32.7.4"))
implementation("com.google.firebase:firebase-messaging")
FirebaseMessaging Setup

In order to use the FirebaseMessaging APIs, some implementation is required. In this sample, we prepare the FcmService to handle Firebase Messaging tasks, and start it in onCreate(Bundle?) of main activity.

Implement the onNewToken(String) method, which will be called when the new FCM token is issued. And in that method, execute the setNotificationToken(Strng) method to set the FCM token to the Riiiver SDK.

Implement the onMessageReceived(RemoteMessage) method, which is called when a data message is received using Firebase (cf. message type). The received push notification is passed to the Riiiver SDK to delegate subsequent processing. Use the executeTaskForRemoteNotification(Map<String, String>) method.

For Riiiver-based data messages, the RemoteMessage.data contains the classification information of the push notification with the key "notification_id". If your project already uses Firebase, you can branch the process depending on the presence or absence of this key. In other words, determine if this key is included and execute the executeTaskForRemoteNotification(Map<String, String>) method only if it is included.

val notificationId = remoteMessage.data["notification_id"]
notificationId?.let {
    if (it == "link") {
        Timber.i("## Remote push for executing an iiidea")
        QCC5100Queue.enqueue(P2WCommand.DISPLAY)
    }
    riiiverSdkClient.executeTaskForRemoteNotification(remoteMessage)
} ?: run {
    Timber.d("## Remote push does not have a notification_id (Riiiver SDK does not handle it)")
    // do something if needed
}