Skip to content

Introduction

The Flows library provides a default implementation for your app's onboarding and restoring scenarios. These scenarios are based on the existing Foundation and Fiori libraries.

These libraries define their own callback interfaces which should be implemented by the app developer. By using the flows you will get not only the interface, but also a default implementation which links the foundation functionality with the UI's activities.

At the same time all the customization options of the UI are still supported, and additional custom code can be added to flows as well. The flows executes the onboarding and restoring scenarios as a linear step sequence. Custom code can be added through custom steps added by the app developer.

Flow Types

The Flows library currently supports the following scenarios (flow types) for onboardingflows implementation:

  • Onboard
  • Restore
  • Reset
  • Change

The sequence of the steps is determined by the app developer. The proposed default step sequences are listed in this section.

The Onboard Scenario

The Restore Scenario

The Reset Scenario

The Change Scenario

Starting the Flow

First, the caller activity, which is the root activity of the app or a dedicated logon activity, should bind to the service responsible for executing the flows. This can be implemented via the standard bindService method of the caller activity:

1
2
callerActivity.bindService(new Intent(this, FlowManagerService.class),
                callerActivity.connection, Activity.BIND_AUTO_CREATE);
The FlowManagerService.class parameter value addresses the service and the connection parameter value should implement the ServiceConnection callback interface. Please note that the bindService call is async. Therefore, you should implement your own business logic in the caller service in order to wait for the return of the callback methods.

The following is a sample implementation of the callback as inner class:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
ServiceConnection connection = new ServiceConnection() {
        public void onServiceConnected(ComponentName className, IBinder service) {
            // This is called when the connection with the service has been
            // established, giving us the service object we can use to
            // interact with the service.  Because we have bound to a explicit
            // service that we know is running in our own process, we can
            // cast its IBinder to a concrete class and directly access it.
            flowManagerService = ((FlowManagerService.LocalBinder)service).getService();
        }

        public void onServiceDisconnected(ComponentName className) {
            // This is called when the connection with the service has been
            // unexpectedly disconnected -- that is, its process crashed.
            // Because it is running in our same process, we should never
            // see this happen.
            flowManagerService = null;
        }
    };

Once the flowManagerService member variable was successfully initialized (the service was bound), then you can execute the flow.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
        OnboardingContext flowContext = new OnboardingContext();

        EULAScreenSettings eulaScreenSettings;
        String eulaVersion;
        PasscodePolicyStoreStep passcodePolicyStoreStep = new PasscodePolicyStoreStep();
        WelcomeScreenStep welcomeScreenStep = new WelcomeScreenStep();
        BasicAuthStep basicAuthStep = new BasicAuthStep();
        BasicAuthStoreStep basicAuthStoreStep = new BasicAuthStoreStep();
        SettingsDownloadStep settingsDownloadStep = new SettingsDownloadStep();
        SecureStoreStep secureStoreStep = new SecureStoreStep();
        EulaScreenStep eulaScreenStep = new EulaScreenStep();
        WelcomeScreenStoreStep welcomeScreenStoreStep = new WelcomeScreenStoreStep();
        SettingsStoreStep settingsStoreStep = new SettingsStoreStep();

        // Creating flow and configuring steps
        Flow flow = new Flow("onboard");
        flow.setSteps(new Step[] {
                passcodePolicyStoreStep,
                welcomeScreenStep,
                basicAuthStep,
                settingsDownloadStep,
                storeManagerStep,
                basicAuthStoreStep,
                welcomeScreenStoreStep,
                settingsStoreStep,
                eulaScreenStep
        });

        // Preparing flow context
        flowContext.setFlowPresentationActionHandler(
                FlowPresentationActionHandlerImpl(this));
        welcomeScreenStep.setApplicationId("com.sap.test.odata");
        flowContext.setContext(this);
        eulaScreenSettings = new EULAScreenSettings();
        eulaVersion = "0.1";
        eulaScreenStep.setEulaScreenSettings(eulaScreenSettings);
        eulaScreenStep.setEulaVersion(eulaVersion);

Please note that the constructor of the Flows object specifies the type of the flow. In this case, an "onboard" flow was created. Please note also that this example is simplified not following the MVP pattern.

The last step to start the flow is to call the execute method of the service:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
flowManagerService.execute(flow, flowContext, new FlowActionHandler() {
                @Override
                public void onFailure(Throwable t) {
                  //error handling
                }

                @Override
                public void onSuccess(FlowContext result) {
                  //saving the onboarded status
                  //start the app
                }
            });

The flow is executed in a backgound thread; that is, not on the main thread. On the other hand, the flow is executed as a foreground service, not as a backgound service. As the flow starts, the root (or logon) activity should be the foreground activity and the flow opens new activities on top of this caller activity, but the app will be in foreground until the end of the onboarding process.

If the app goes into the backgound, then the flow has to be restarted from the beginning. In case of onboarding flow, the state of the flow is not persisted for security reasons because this would require persisting cipher and passcode information as well.

Custom Step Implementation

You can implement a custom step for the flow as following:

  1. Implement the Step or the AsyncResultStep interface of the flows library.
  2. Create a method with the following signiture:

1
public void methodName(FlowContext flowContext, StepActionHandler stepActionHandler) 
3. Annotate this method with StepName where the parameter of the annotation is the name of the scenario where the given method has to be executed. Multiple StepName annotations are supported on a single method.

1
@StepName("onboard")
4. (Optional) AsyncResultStep implementations have to implement the getResultActionHandler method of the interface.