Skip to content

Flow Configuration

Besides the extension points where client code can plug in customized logic into the flow process, client code can also change the flow process using different settings, such as choosing the preferred activation method, or choosing how to display warning or information messages, either with a dialog or a toast message, etc.

Mobile Service Static Initialization

SAP BTP SDK for Android provides a service initialization module that allows client code to specify which features to use. The Flows component also relies on some of the services passed into SDKInitializer, for example UsageService and CrashService. The corresponding consent steps will appear in the onboarding flow based on whether the service is initialized with SDKInitializer.

Sample client code:

val services = mutableListOf<MobileService>()
services.add(LogService())
services.add(UsageService())
services.add(CrashService(false))
SDKInitializer.start(this, * services.toTypedArray())
List<MobileService> services = new ArrayList<>();
services.add(new UsageService());
SDKInitializer.INSTANCE.start(this, services.toArray(new MobileService[0]), null);

Configuration Options

To configure the flow, use FlowOptions, for example, to choose either the Discovery Service or QR code to retrieve the complete application configuration, determine how to display some of the information messages from the flows component, or decide whether to let the flows component handle the end user license agreement or have the client code handle it.

To configure these options, use a child class of FlowOptions.

/**
 * Shows the [Info] message either with a dialog or a [Toast]
 */
open fun infoMessageOption(): InfoMessageOption = InfoMessageOption.TOAST

/**
 * Chooses the activation method: [ActivationOption.CHOOSE_BETWEEN_DS_QR],
 * [ActivationOption.DS_ONLY], or [ActivationOption.QR_ONLY]
 */
open fun activationOption(): ActivationOption = ActivationOption.CHOOSE_BETWEEN_DS_QR

/**
 * The OAuth client id to use for the authentication. In a mobile service application, there
 * might be several OAuth clients defined for OAuth authentication. If one of them is intended
 * to be used as the client, this function should return the id. If it's 'null', or flow cannot
 * find the match, the first one in the OAuth client list will be used.
 *
 * Deprecated. Please see 'getEffectiveOAuthClient' in 'FlowActionHandler'.
 */
open fun effectiveOAuthClientId(): String? = null

/**
 * Option to say whether to exclude 'EULA' step from the onboarding flow. 'True' means client
 * code is going to handle the EULA itself.
 */
open fun excludeOnBoardingEulaScreen() = false

/**
 * For multiple user mode, when creating a new account, whether to exclude the 'EULA' or not.
 */
open fun excludeEulaWhenCreateAccount() = excludeEulaWhenCreateAccount

/**
 * Specifies whether confirmation is needed when executing the reset flow. Default is 'true', otherwise
 * the client app needs to handle this.
 */
open fun isResetConfirmationNeeded() = needConfirmWhenReset

/**
 * When activating the app using the QR code scan, this option determines whether to display the QR code
 * confirmation screen after the QR code has been scanned.
 */
open fun requireQRCodeConfirmScreen() = requireQRCodeConfirmScreen

/**
 * The customized theme for onboarding screens, which MUST be extended from
 * '@style/FioriTheme_Onboarding'
 */
open fun getApplicationTheme() = appTheme

/**
 * The predefined onboarding flows use the same Fiori design, which is fullscreen mode,
 * and has a transparent Android status bar. To allow the custom flow to use this same Fiori
 * design, change this to 'true'. By default it's false.
 */
open fun isApplyFioriStyleForCustomFlow() = fioriStyleForCustomFlow

Note

As of version 3.4, the function, effectiveOAuthClientId(), is deprecated. Using FlowActionHandler.getEffectiveOAuthClient, the client code can have more control over how to determine the effective OAuth client to be used for onboarding.

By default, the flow framework uses a toast to display information messages and lets the user choose the activation method, either Discovery Service or QR code.

The comment for each function explains the purpose of that function. For getApplicationTheme() and isApplyFioriStyleForCustomFlow, see Theme and Style for detailed information.

To use this feature, create an instance of FlowOptions, then save it into FlowContext and start a flow.

val flowContext = FlowContext(
    flowOptions = flowOptions = FlowOptions(
        appTheme = R.style.AppTheme
    )
)

Flow.start(activity, flowContext) { _, resultCode, _ ->
    if( resultCode == RESULT_OK ) {
        logger.debug("Done")
    }
}
FlowContext flowContext = new FlowContextBuilder()
    .setFlowOptions(new FlowOptions() {
        @Override
        public int getApplicationTheme() {
            return R.style.AppTheme;
        }
    })
    .build();
Flow.start(activity, flowContext, (code, result, data) -> null);

Screen Settings

All the onboarding screens used in the flows component can be customized with the screenSettings of FlowContext.

To customize an onboarding screen, the client code needs to create an instance of the corresponding ScreenSettings, then put it into screenSettings list of FlowContext when starting a flow. For example:

val eulaSettings = EulaScreenSettings.Builder()
    .setAgreeButtonText("OK")
    .setRejectButtonText("Cancel")
    .setTitle("My EULA title")
    .build()
val flowContext = FlowContext(
    appConfig = AppConfig.Builder().applicationId("app_id").build(),
    multipleUserMode = true,
    screenSettings = listOf(eulaSettings),
    flowOptions = FlowOptions(
        appTheme = R.style.AppTheme
    )
)
Flow.start(this@WelcomeActivity, flowContext) {
    ...
}
EulaScreenSettings eulaScreenSettings = new EulaScreenSettings.Builder()
    .setAgreeButtonText("OK")
    .setRejectButtonText("Cancel")
    .build();

FlowContext flowContext = new FlowContextBuilder()
    .setApplication(appConfig)
    .setMultipleUserMode(false)
    .setFlowOptions(new FlowOptions() {
        @Override
        public int getApplicationTheme() {
            return R.style.AppTheme;
        }
    })
    .addScreenSettings(eulaScreenSettings)
    .build();
Flow.Companion.start(context, flowContext, (code, result, data) -> null);

Two of the onboarding ScreenSettings classes are special because they can be used for different purposes. These are ConsentScreenSettings and the activation screen.

ConsentScreenSettings can be used for either usage data collection consent or crash report upload consent. To ensure that the right settings instance and settings are applied to the screen, you need to ensure that the screenCategory of ConsentScreenSettings is provided correctly to the client code. For example, for the usage consent screen, the settings should be initialized as follows:

val usageSetting = ConsentScreenSettings.Builder()
    .setScreenCategory(ConsentScreenSettings.ScreenCategory.USAGE_DATA_COLLECTION.name)
    .setScreenType(ConsentScreenSettings.ScreenType.FORCE_READ_ALL)
    .addContentPage(
        ConsentScreenSettings.ContentPage(
            resources.getString(com.sap.cloud.mobile.flowv2.R.string.get_usage_permission_title),
            resources.getString(com.sap.cloud.mobile.flowv2.R.string.get_usage_permission_explanation),
            "Learn More", "http://www.sap.com"
        )
    )
    .build()

For the crash report upload consent screen, the screen category should be:

val crashReportSettings = ConsentScreenSettings.Builder()
    .setScreenCategory(ConsentScreenSettings.ScreenCategory.CRASH_REPORT_UPLOAD.name)
    ...

You can use the activation screen in either the activation method selection step or in the Discovery Service activation step. Therefore the screenType needs to be specified in the ActivationScreenSettings instance accordingly. For example:

val discoverySetting = ActivationScreenSettings.Builder()
    .setInstruction("Instruction")
    .setScreenType(ActivationScreenSettings.ActivationScreenType.ACTIVATION_METHOD_DISCOVERY)
    .build()

val chooseActivationSetting = ActivationScreenSettings.Builder()
    .setInstruction("Instruction")
    .setScreenType(ActivationScreenSettings.ActivationScreenType.CHOOSE_ACTIVATION_METHOD)
    .build()
ActivationScreenSettings discoverySettings = new ActivationScreenSettings.Builder()
    .setInstruction("Instruction")
    .setTitle("title")
    .setScreenType(ActivationScreenSettings.ActivationScreenType.ACTIVATION_METHOD_DISCOVERY)
    .build();

ActivationScreenSettings chooseActivationSettings = new ActivationScreenSettings.Builder()
    .setInstruction("Instruction")
    .setTitle("title")
    .setScreenType(ActivationScreenSettings.ActivationScreenType.CHOOSE_ACTIVATION_METHOD)
    .build();

Last update: May 28, 2021