Skip to content

QR Code Based Onboarding

If you use QR code based onboarding then the end user has to detect a QR code via the device camera or by choosing a saved QR code image from the photo library. This QR code should specify the information required for the onboarding process. After detecting the QR code, it will be handed over to the app for validation. If the app recognizes the given QR code as valid one, then a QR code onboarding confirm screen will be displayed. The QR code confirm screen shows the end user which onboarding will be executed based on the read QR code. If the end user confirms this, then the onboarding will be executed. This happens on Activation screen after is pressed the primary button and it navigates to activation screen.

Please note that the scanner activity of the QR code based onboarding was implemented in the google-vision module. This makes it possible to replace our google play library based scanner implementation by any custom implementation. The class name of the custom implementation has to be set in the settings of the activation activity via the following method:

1
2
3
4
5
6
7
    /**
     * Sets the qr code reader class
     * @param qrReaderClass
     */
    public void setQRReaderClass(String qrReaderClass) {
        this.activationQRReaderClass = qrReaderClass;
    }

Add Launch screen activity and Activation screen activity to your manifest file

The LaunchScreenActivity and the ActivationActivity should be added to the AndroidManifest.xml file in an activity xml tag. It is required to specify also the "action_handler" meta-data tag for the launch screen (the same way as in case of the standard onboarding).

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
        <activity
            android:name="com.sap.cloud.mobile.onboarding.launchscreen.LaunchScreenActivity"
            android:label="@string/app_name"
            android:theme="@style/Theme.AppCompat.Light.NoActionBar">
            <meta-data
                android:name="action_handler"
                android:value="<your_package_name>.WelcomeScreenActionHandlerImpl" />
        </activity>
        <activity
            android:name="com.sap.cloud.mobile.onboarding.activation.ActivationActivity"
            android:label="@string/app_name"
            android:theme="@style/AppTheme.NoActionBar"
            android:parentActivityName="com.sap.cloud.mobile.onboarding.launchscreen.LaunchScreenActivity">
            <meta-data
                android:name="android.support.PARENT_ACTIVITY"
                android:value="com.sap.cloud.mobile.onboarding.launchscreen.LaunchScreenActivity" />
        </activity>

Start the WelcomeScreenActivity

The LaunchScreenActivity can be started with standard startActivityResult method of the Activity and you can configure it via the LaunchScreenSettings class. For example:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
        Intent i = new Intent(getIntent());
        i.setComponent(new ComponentName(
                getPackageName(),
                "com.sap.cloud.mobile.onboarding.launchscreen.LaunchScreenActivity"));
        LaunchScreenSettings settings = new LaunchScreenSettings();
        settings.setLaunchScreenHeadline("Welcome");
        ...
        settings.setWelcomeScreenType(OnboardingType.BARCODE_ONBOARDING);
        settings.setDemoAvailable(true);
        settings.saveToIntent(i);
        ActivationSettings activationSettings = new ActivationSettings();
        activationSettings.setTitle("Activation");
        ...
        activationSettings.saveToIntent(i);

        startActivityForResult(i, LAUNCH_SCREEN);

If you would like to use QR code onboarding process, then you should set the type of the welcome screen to OnboardingType.BARCODE_ONBOARDING as shown in the example above. In this case you have to implement of the startStandardOnboarding method of the WelcomeScreenActionHandler interface in your action handler implementation class and you have to implement also the validateBarcode method of the QRCodeReaderActionHandler interface.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
/**
 * Callback interface to be implemented by the app developer using the QR code reader activity.
 */
public interface QRCodeReaderActionHandler extends ActionHandler {
    /**
     * Validates the barcode read by the QR code reader.
     * This callback function is called by
     * the QR code reader screen activity represented by the fragment parameter.
     * This callback is executed on a worker thread, not on the main thread, therefore
     * do not use UI calls directly.
     * BarcodeValidationException is thrown if the validation fails.
     *
     * @param fragment the caller fragment of the QR code reader activity
     * @param barcode the barcode which will be validated
     */
    void validateBarcode (Fragment fragment, Barcode barcode)
            throws BarcodeValidationException, InterruptedException;
}

In addition, via the setDemoAvailable method you can specify if the demo mode is supported (that is the "Try the demo" button is visible on the welcome screen). If you enable demo mode, then you have to implement of the startDemoMode method of the WelcomeScreenActionHandler interface in your action handler implementation class as well.

Implementation of the callback methods for QR code based onboarding

If you need custom onboarding process you have to implement of the startStandardOnboarding method of the WelcomeScreenActionHandler interface in your action handler implementation class.

The implementation of this method will be executed on a dedicated background thread of the caller activity, more precisely the background thread of the headless fragment of the caller activity. This fragment is handed over to the method as parameter. The second parameter of the callback function transmits the email address typed in by the end user as the address of the discovery service. You can access the caller activity via the getActivity() method of this fragment. Please note that the result of the getActivity call might be null value if there is no active activity in the background, for example due to an ongoing change orientation process.

First of all: the callback method waits for response synchronously, so if you need asynchronous communication, then you have to wait on this thread until the async response arrives. You are allowed block the thread because you are on a dedicated background thread.

As a consequence, you have to be prepared to handle the interrupted flag of the thread. For example: if the user taps on the back button, or if the system destroys the caller fragment, then this thread will be interrupted. If the execution of your callback method was successfully interrupted, that is the normal processing was not completed, then you should throw InterruptedException from your implementation in order to indicate that the processing was cancelled. For example:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
    @Override
    public void startStandardOnboarding(Fragment fragment) throws InterruptedException {
        Log.i(TAG, "createStandardOnboarding");
        Intent i = new Intent();
        i.setComponent(new ComponentName(
                fragment.getActivity().getPackageName(),
                "com.sap.cloud.mobile.fiori.demo.onboarding.DummyLoginActivity"));
        fragment.getActivity().startActivityForResult(i, 1000);
        synchronized (SYNC) {
            while (!responseAvailable) {
                SYNC.wait();
            }
        }
    }

On the other you are also allowed to start new activity on top of the caller activity. Please note that in this case the caller fragment might be destroyed, that is you are not allowed to use the fragment parameter after this point. In addition, the response of the new activity will be called on the caller fragment/activity and therefore you have to implement one more callback method named onActivityResult. For example:

 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
    @Override
    public boolean onActivityResult(Fragment fragment, int requestCode, int resultCode, Intent data) {

        if (requestCode == 1000) {
            if (resultCode == Activity.RESULT_OK) {
                Intent intent = new Intent();
                intent.putExtra("DEMO", false);
                fragment.getActivity().setResult(Activity.RESULT_OK, intent);
                fragment.getActivity().finish();
                synchronized (SYNC) {
                    responseAvailable = true;
                    SYNC.notify();
                }
                return false;
            } else {
                synchronized (SYNC) {
                    responseAvailable = true;
                    SYNC.notify();
                }
                return true;
            }
        }
        return true;

    }
The onActivityResult will get a caller fragment again. Please note that this caller instance might be difference from the one you received from the startOnboardingWithDiscoveryServiceEmail.

The sample implementation of the validateBarcode:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
public class QRCodeReaderActionHandlerImpl implements QRCodeReaderActionHandler {
    final private static String TAG = "QRCodeReaderAHandler"; //abbreviated

    /**
     * Validates all non-null barcodes after a user defined delay. If the validation is
     * interrupted the result is false.
     *
     * @param fragment the caller fragment of the QR code reader activity
     * @param barcode  the barcode which will be validated
     */
    @Override
    public void validateBarcode(Fragment fragment, Barcode barcode)
            throws BarcodeValidationException, InterruptedException {
        Log.i(TAG, "validating barcode: ".concat(barcode == null ? "null" : barcode.displayValue));
        if (barcode == null) {
            throw new BarcodeValidationException("Null barcode");
        }
    }
}

The validateBarcode should be also synchronous method, and it is now allowed open new Intent from this method.

Customizing the QR Code reader screen

You can use the QRCodeReaderSettings object for customize the labels and buttons of the QR code reader screen. The following options are available:

 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
38
39
40
41
42
43
44
    /**
     * setter method for the camera autofocus
     * @param autoFocus the autofocus flag
     */
    public void setAutoFocus(boolean autoFocus) {
        this.autoFocus = autoFocus;
    }

    /**
     * setter method for the title of the validation screen upon failure
     * @param invalidQRTitle the title
     */
    public void setInvalidQRTitle(String invalidQRTitle) {
        this.invalidQRTitle = invalidQRTitle;
    }
    /**
     * setter method for the message of the validation screen upon failure
     * @param invalidQRMessage
     */
    public void setInvalidQRMessage(String invalidQRMessage) {
        this.invalidQRMessage = invalidQRMessage;
    }
    /**
     * setter method for the OK button of the validation screen
     * @param invalidQROk
     */
    public void setOkButtonString(String invalidQROk) {
        this.invalidQROk = invalidQROk;
    }
    /**
     * this method sets the acceptable barcode types. The default type is QR code.
     * @param barcodeFormat
     */
    public void setBarcodeFormat(int barcodeFormat) { 
        this.barcodeFormat = barcodeFormat;
    }

    /**
     * setter method for confirm screen skip setting
     * @param skipConfirmScreen variable to set if the confirm screen should be skipped.
     */
    public void setSkipConfirmScreen (boolean skipConfirmScreen) {
        this.skipConfirmScreen = skipConfirmScreen;
    }

Customizing the QR Code confirm screen

You can use the QRCodeConfirmSettings object for customize the labels and buttons of the QR code reader screen. The following options are available:

 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
    /**
     * setter method for the validation action handler
     * @param actionHandler the action handler
     */
    public void setActionHandler(String actionHandler) {
        this.actionHandler = actionHandler;
    }
    /**
     * setter method for the headline of the confirm screen
     * @param qrCodeConfirmHeadline the headline
     */
    public void setQrCodeConfirmHeadline(String qrCodeConfirmHeadline) {
        this.qrCodeConfirmHeadline = qrCodeConfirmHeadline;
    }
    /**
     * setter method for the detailed description of the confirm screen
     * @param qrCodeConfirmDetail the description
     */
    public void setQrCodeConfirmDetail(String qrCodeConfirmDetail) {
        this.qrCodeConfirmDetail = qrCodeConfirmDetail;
    }

    /**
     * setter method for the continue action of the confirm screen
     * @param qrCodeConfirmContinueTitle the continue action
     */
    public void setQrCodeConfirmContinueTitle(String qrCodeConfirmContinueTitle) {
        this.qrCodeConfirmContinueTitle = qrCodeConfirmContinueTitle;
    }