Skip to content

Start Flow

Before Starting a Predefined Flow

Before starting a predefined flow, there are two configurations to be completed.

ActivityLifecycleCallbacks

For most of the features to be used in your mobile app, they will need to know the state of the app, for example whether the app is in the background or not. Therefore, registering an ActivityLifecycleCallbacks to the application is a must.

//in onCreate of application
registerActivityLifecycleCallbacks(AppLifecycleCallbackHandler.getInstance())
//in onCreate of application
registerActivityLifecycleCallbacks(AppLifecycleCallbackHandler.getInstance());

DiscoveryServiceProvider

In the app development stage you can set the Discovery Service URL for development into DiscoveryServiceProvider when the application starts.

//in onCreate of application
DiscoveryServiceProvider.set("....")
//in onCreate of application
DiscoveryServiceProvider.set("....");

Then, when the onboard flow comes to the Discovery Service activation step, you only need to input the email domain to get the complete application information published to the Discovery Service.

Note

For detailed information about how to configure the Discovery Service, refer to the online help.

APIs to Start a Flow

There are two APIs to start a flow.

@JvmStatic
fun start(activity: Activity, flowContext: FlowContext) {
  ...
}

@JvmStatic
fun start(fragment: Fragment, flowContext: FlowContext) {
    ...
}

Some information will be needed when starting a flow: the application configuration information, customized flow options, etc. This information will be saved into the flowContext.

data class FlowContext(
        /** The application configuration*/
    private var appConfig: AppConfig? = null

    /** The predefined flow type*/
    private var flowType: FlowType = FlowType.ONBOARDING

    /** The flow state listener */
    private var flowStateListener: FlowStateListener? = null

    /** The screen settings */
    private var screenSettings: MutableList<ScreenSettings> = mutableListOf()

    /** The customized flow */
    private var flow: Flow? = null

    /** The flow action handler */
    private var flowActionHandler: FlowActionHandler = FlowActionHandler()

    /** The flow options to control how to show 'info' type message, which activation method to use*/
    private var flowOptions: FlowOptions = FlowOptions()

    /** Single/Multiple user mode switch */
    private var multipleUserMode: Boolean = false

    /**
     * In the case that the client code wants to use a single activity to start different flows
     * and be able to identify which flow finishes in 'onActivityResult', this variable can be
     * specified.
     */
    val flowRequestCode: Short = FlowConstants.FLOW_ACTIVITY_REQUEST_CODE,

    /** The user ID of the user that forgot their passcode. */
    val forgotPasscodeUserId: String? = null,
)

The parameters are:

Parameter Description
appConfig The application information that the mobile app uses to talk to mobile services. This is mandatory for onboarding. AppConfig.Builder is provided to build an instance easily.
enabledServices Specify which features the client application wants to use.
screenSettings Customize the screens inside the flow.
flowStateListener Provide customized logic and insert it into the flow execution process at certain points.
flowActionHandler Provide customized logic for certain cases, such as the customize passcode validation logic for example.
flowOptions Pass in options, such as specifying which activation method to use, how to show information message from the flows component, either with a dialog or a toast message. See Flow configuration for details.
multipleUserMode Boolean value to indicate single user or multiple user mode
flowType Predefined flow type, onboarding, reset, etc.
flow Customized flow instance. If this property is provided, flowType will be ignored by the flows component
flowRequestCode The request code that the client code wants to monitor. If the client code wants to start different flows in one activity, this property can be provided.
forgotPasscodeUserId When executing the 'Forgot Passcode' flow, this property must be provided in FlowContext, otherwise, a runtime exception will be reported.

Sample client code:

val flowContext = FlowContext(
    flowType = FlowType.ONBOARDING,
    appConfig = AppConfig.Builder().applicationId("myapp").build(),
    flowStateListener = WizardFlowStateListener())
Flow.start(activity, flowContext)
FlowContext flowContext = new FlowContextBuilder()
    .setApplication(prepareAppConfig())
    .setFlowStateListener(new WizardFlowStateListener())
    .build();
Flow.start(activity, flowContext);

After starting a flow, the flowContext will be saved into a FlowContextRegistry. The client code can then get flowContext from FlowContextRegistry at a later time in order to update some of the properties and start another flow. For example:

val flowContext = FlowContextRegistry.flowContext.copy(flowType = FlowType.RESTORE)
Flow.start(activity, flowContext)
FlowContext flowContext = new FlowContextBuilder(FlowContextRegistry.getFlowContext())
                        .setFlowType(FlowType.CHANGEPASSCODE)
                        .build();
Flow.start(this, flowContext);

Note

Since Java does not have the 'copy' function on FlowContext, unlike Kotlin, we can get the FlowContext instance from FlowContextRegistry, then pass it to FlowContextBuilder to copy the instance and modify the property as needed.

Since SAP BTP SDK for Android 3.3, two new APIs have been added into FlowContext to retrieve the current user id and the offline encryption key.

    fun getCurrentUserId(): String?
    fun getOfflineEncryptionKey(): String?

The two APIs can only be called after the onboarding or restore flow, otherwise null will be returned. getOfflineEncryptionKey will only retrieve the key saved in the user passcode protected secure store during the onboarding flow.

To get the flow execution status, which is either done or canceled, the client activity needs to override the onActivityResult function:

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)
    if (requestCode == FlowConstants.FLOW_ACTIVITY_REQUEST_CODE) {
        if (resultCode == Activity.RESULT_OK) {
            //start your main business activity.
            startActivity(Intent(this, MainActivity::class.java))
        } else {
            Snackbar.make(fab, "Flow cancelled.", Snackbar.LENGTH_LONG).show()
        }
    } else if( requestCode == 100 ) {
        //If flowRequestCode is provided in flow context, client code can check the request code here.
    }
}

For more information about enabledServices and screenSettings in FlowContext, see Flow Configuration and flowStateListener and flowActionHandler in Extension Points.


Last update: January 7, 2021