Skip to content

Third-party Integration

UFAndroidClient has a set of APIs that allow a third party application to interact with it.

To integrate the UFAndroidClient into your application you must:

  1. Import the module uf-client-service-api (see Module uf-client-service-api section)
  2. Bind to the UFAndroidClient service (see Bind to UFAndroidClient service section)

The module uf-client-ui-example is provided as an example of a third party application. The uf-client-ui-example is able to:

  1. show the current service status (Log page);
  2. open the preferences page of UFAndroidClient (Settings page)
  3. grant / deny authorization to execute an action during a soft update

Module uf-client-service-api

The module uf-client-service-api contains all of the classes that a third party application must include to handle the communication with the UFAndroidClient.

uf-client-service-api contains three classes:

  1. UFServiceCommunicationConstants: class with the message constants
  2. UFServiceMessage: a data class which contains the current state of the service
  3. UFServiceConfiguration: a data class that contains the current configuration of the service

To import this module:

  1. configure your project to use jitpack (see jitpack documentation).
  2. add implementation 'com.github.Kynetics:uf-android-client:<version>' in your gradle dependencies (e.g. implementation 'com.github.Kynetics:uf-android-client:v0.3.3')

Bind to UFAndroidClient service

UFAndroidClient is a bound service, it allows components (such as activities) to bind to the service, send requests, receive responses, and perform interprocess communication.

To bind to the service create an intent with:

  1. action = UFServiceCommunicationConstants.SERVICE_ACTION
  2. package = UFServiceCommunicationConstants.SERVICE_PACKAGE_NAME

This is an example of how to bind an Application with the service:

private Messenger mService;

private ServiceConnection mConnection = new ServiceConnection() {
        public void onServiceConnected(ComponentName className,
                                       IBinder service) {
            mService = new Messenger(service);

            Toast.makeText(MainActivity.this, R.string.connected,
                    Toast.LENGTH_SHORT).show();
            try {
                Message msg = Message.obtain(null,
                        UFServiceCommunicationConstants.MSG_REGISTER_CLIENT);
                msg.replyTo = mMessenger;
                mService.send(msg);
            } catch (RemoteException e) {
                Toast.makeText(MainActivity.this, "service communication error",
                        Toast.LENGTH_SHORT).show();
            }
            mIsBound = true;
        }
        ...
    };


void doBindService() {
        final Intent intent = new Intent(UFServiceCommunicationConstants.SERVICE_ACTION);
        intent.setPackage(UFServiceCommunicationConstants.SERVICE_PACKAGE_NAME);
        intent.setFlags(FLAG_INCLUDE_STOPPED_PACKAGES);
        final boolean serviceExist = bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
        if(!serviceExist){
            Toast.makeText(getApplicationContext(), "UpdateFactoryService not found",Toast.LENGTH_LONG).show();
            unbindService(mConnection);
            this.finish();
        }
    }

Messages

The UFAndroidClient service uses Android Messenger to receive input and to notify its status. The main characteristic of a message are these fields:

  1. what the message code, specify the kind of action (mandatory)
  2. data, the message payload (optional)
  3. replyTo, messenger where replies to this message can be sent (optional)

For more details see the official documentation.

Messages sent by third party applications

Client subscription

To subscribe to the service the application has to send a message with the field what equal to UFServiceCommunicationConstants.MSG_REGISTER_CLIENT (to receive the response from the service, the field replyTo must also be set)

Client unsubscription

To unsubscribe from the service the application has to send a message with the what field equal to UFServiceCommunicationConstants.MSG_UNREGISTER_CLIENT

Service configuration

To configure the service the application has to send a message with:

  1. what = UFServiceCommunicationConstants.MSG_CONFIGURE_SERVICE
  2. data = A bundle object with a serializable object:
    • key = UFServiceCommunicationConstants.SERVICE_DATA_KEY
    • value = an instance of UFServiceConfiguration (use the UFServiceConfiguration.builder() builder to obtain the instance)

Example

final Bundle data = new Bundle();
HashMap<String,String> targetAttributes = new HashMap<>(2);
targetAttributes.put("attribute1","attributeValue1");
targetAttributes.put("attribute2","attributeValue2");
final Bundle data = new Bundle();
data.putSerializable(SERVICE_DATA_KEY, UFServiceConfiguration.builder()
                    .withControllerId("controllerId")
                    .withTenant("tenant")
                    .withUrl("https://personal.updatefactory.io")
                    .witArgs(targetAttributes)
                    .build());

Message msg = Message.obtain(null,
                    UFServiceCommunicationConstants.MSG_CONFIGURE_SERVICE);
msg.replyTo = mMessenger;
msg.setData(data);
Authorization response

When the service sends an Authorization request message (e.g. authorization to download or install an OTA update file) the application has to respond with an Authorization response that indicates whether the action is allowed or not. The message response fields are:

  1. what = UFServiceCommunicationConstants.MSG_AUTHORIZATION_RESPONSE
  2. data = a boolean with key UFServiceCommunicationConstants.SERVICE_DATA_KEY

Example

private void sendPermissionResponse(boolean response){
        Message msg = Message.obtain(null, MSG_AUTHORIZATION_RESPONSE);
        msg.getData().putBoolean(SERVICE_DATA_KEY, response);
        try {
            mService.send(msg);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }
Resume suspend state

After an authorization is denied, it is possible to grant it in a second moment by sending a message with the field what equal to UFServiceCommunicationConstants.MSG_RESUME_SUSPEND_UPGRADE

Sync request

Sending a message with the what field equal to UFServiceCommunicationConstants.MSG_SYNCH_REQUEST, the service responds with two messages:

  1. the first contains the configuration of the service (see Configuration status section).
  2. the second contains the last notification message sent by the service (see Current status section).

Messages sent by UFAndroidClient service

Authorization request

When the service finds a Soft update, it asks to the client for the authorization to download, and then to install the update. These kind of requests are made sending a message with:

  1. what = UFServiceCommunicationConstants.MSG_AUTHORIZATION_REQUEST
  2. data = key SERVICE_DATA_KEY; possible values are of type String:
    • DOWNLOAD when the service is requesting authorization to download OTA update file
    • UPDATE when the service is requesting authorization to proceed with installation of OTA update file
Configuration status (response to sync)

In response to a sync request the service sends a message that describes its current configuration:

  1. what = UFServiceCommunicationConstants.MSG_SERVICE_CONFIGURATION_STATUS
  2. data = an instance of UFServiceConfiguration

Example to retrieve UFServiceConfiguration from the message

final Serializable serializable = msg.getData().getSerializable(SERVICE_DATA_KEY);
if(!(serializable instanceof UFServiceConfiguration)) {
    UFServiceConfiguration ufServiceConfiguration = (UFServiceConfiguration)serializable;
}
Current status (response to sync)

In response to a sync request the service sends a message that describes its current status:

  1. what = UFServiceCommunicationConstants.MSG_SERVICE_STATUS
  2. data = an instance of UFServiceMessage

Example to retrieve UFServiceConfiguration from the message

final Serializable serializable = msg.getData().getSerializable(SERVICE_DATA_KEY);
if(!(serializable instanceof UFServiceConfiguration)) {
    UFServiceMessage messageObj = (UFServiceMessage)serializable;
}

References

Kynetics - UFAndroidClient repository

Kynetics - Update Factory

Kynetics Technical note on Update Factory

Kynetics Slideshare