Skip to content

MimiSDK 5 Migration Guide

This document outlines the various changes required to migrate to MimiSDK 5 from a previous 4.x.x version of MimiSDK.

MimiSDK 5 introduces several API-breaking changes to be aware of.

What is new

The following section describes all changes that are considered breaking API, removal of previously deprecated functionality or significant behavioral changes.


  • The initial configuration and previously deprecated flag alwaysShowHearingResults inside MimiConfiguration class, has been removed as detailed hearing results are no longer visible for the Consumer Electronic variant of the mSDK.
  • The legacy ConfigurationController inside MimiCore has been replaced by a brand new version of the class with the same name. This new class exposes now the remoteConfig value to be consumed as a MimiObservable. For more info about this and other similar methods, please scroll to the New Observable Pattern section.


The ProcessingController.resetParams() method is no longer a publicly available method as it is meant to be used only internally.

New way of handling Forcibly Logged Out Users

In this new version we also removed the legacy MimiCore.failedToRefreshTokenForUser object that listened constantly to unsuccessful token auth refresh events that would eventually log the current user out of the session.
From now on, the recommended way to handle these events is to observe the UserController.mimiUser and its loadingState property, and react accordingly (maybe showing an alert dialog when this one gets the value LoadingState.Failure with its cause field set to MimiCoreException.ForciblyLoggedOut.

New Observable Pattern

In this new 5.0.0 version of the MimiSDK, we took the decision of getting rid of the classic Android Listener/Callback approach due to the constraints that these imposed upon new written code. Instead, we decided to adopt the Observable/Subscriber pattern, thanks to which, integrators will be able to sign up for updates on specific variables.
When these variables change, or certain events get triggered internally, their new values will be emitted and consumed reactively by those who have subscribed previously to their updates.

With this new approach, we will avoid to manually forward these events across multiple classes and also improve the visual clarity of critical values such as the mimiUser or the latestTestResults.
This was particularly painful for scenarios where the final value of a parameter that was meant to be read by the integrators, was dependent on the complete success of diverse and chained I/O operations. If this value was not mapped correctly, this could lead to bugs related with incorrect visual representations within our UI components.

New Mimi Components

To achieve and implement the new Observable pattern mentioned above, we introduced several new constructs, classes and methods such as:

MimiObservable and MimiObserver

MimiObservable<T> is a new component that encapsulates any object of type T allowing integrators to subscribe to stream of subsequent updates on this object by registering a MimiObserver on it.
Please note that the observe method will never finish unless the integrator removes/disposes the reference to the observer method manually. Also this is a suspended method, so in order to receive asynchronous updates of the observed parameter, one will need to call it from within a coroutine scope:

    myCoroutineScope.launch { 
        MimiCore.userController.mimiUser.observe { newMimiUser ->
            // execute any action on the fetched user
AsyncState and LoadingState

AsyncState is a special read only class, that maps any given value, to a given LoadingState. This construct becomes really handy when dealing with objects or variables that are meant to change or be updated through the lifecycle of the MSDK, such as a MimiUser or MimiTestResults.

Since each value is mapped to a loading state, one can interpret more accurately, whether the read value is: - In the middle of an update -> InProgress - Valid or Idle -------------> Done - in an error state ----------> Failure

Another interesting scenario that can be found very often in this new release, is wrapping a given object with both MimiObservable and AsyncState classes.
In this case, after subscribing to objects wrapped in this specific way, one will listen to updates containing information of a given value and its associated loading state on that given moment.

A good example of this is the mimiUser contained inside the MimiCore.testsController:

    val mimiUser: MimiObservable<AsyncState<MimiUser?>>
    val userValue: MimiUser = mimiUser.state.value
    val userLoadingState: LoadingState = mimiUser.state.loadingState
Note: Accessing and persisting the raw value of a MimiObservable via the x.state.value accessor is not encouraged, as it can lead to undesired loss of sync with the original MimiObservable parameter.

@MsdkInternalApi Annotation

Due to the multi-modular nature of our MSDK, sometimes we need to declare certain variables or methods as public API even though they are not meant to be accessed or used by integrators.

In order to identify these only-for-internal-use structures, we created a specific annotation for it. The @MsdkInternalApi will help integrators to notice when they are trying to use a restricted component, by throwing a visual IDE compilation warning.
The usage of constructs tagged with this specific annotation by integrators is highly discouraged, as this code may change or be removed without prior notice on future releases, as well as cause unexpected issues or errors that can alter the internal logic of the mSDK.

New Mimi Core and Controller classes

We have reworked internally the structure of the singleton MimiCore object needed to access the main SDK controllers.
Nevertheless from a external/public facing point of view, its usage will remain the same as in the legacy version, having to provide a valid set of credentials via the MimiCore.start() method in order to run all the Mimi logic correctly.

Please note however, that some of the legacy functionality might have been migrated and/or renamed some methods among certain controllers.

Please check the Changelog for the specific method renaming.


The legacy AuthController class, has been removed and its functionality migrated to the UserController class.

We need to make a special mention here as well, as the authentication logic is now handled entirely by the method suspend fun authenticate(route: MimiAuthRoute): MimiUser inside the UserController class.
Depending on the concrete integration needs, one will need to provide the specific MimiAuthRoute sealed class.


We have limited the handling of the HearingTest class to the strictly necessary actions. Therefore all methods that loaded (individually or in bulk) or deleted Hearing Tests were removed.
Instead we created equivalent methods to execute their counterpart logic on MimiTestResults objects, namely: - submitTest(hearingTest: HearingTest): Unit will submit a new Hearing Test - submitTestForResult(hearingTest: HearingTest): MimiTestResult will submit a new Hearing Test and get returned the MimiTestResult associated with that previously submitted test. - deleteTestResult(id: String): Unit will delete the test result associated with that id. - loadLatestTestResults(): MimiTestResults will load a MimiTestResults object filled with the latest test results for the available Test Paradigms.

Deprecation of Controller Listeners

As we mentioned above, we wanted to get rid of the classic listener pattern to inform about changes on the main pieces of information in our SDK. Therefore, the TestsControllerListener and UserControllerListener interface classes have also been removed.
From now on, the integrators will need to subscribe to the newly latestTestResults: MimiObservable<AsyncState<MimiTestResults>> and the mimiUser: MimiObservable<AsyncState<MimiUser?>> inside the TestController and UserController classes respectively to listen for changes happening on the Latest Tests and the current Mimi User objects.