public interface ConnectSessionResult {
    /**
     * Callback method is invoked when Create Connect Session operation finished with success
     *
     * @param connectUrl String which should be opened in WebView to create connection
     */
    void onSuccess(String connectUrl);

    /**
     * Callback method is invoked when Create Connect Session operation finished with error
     *
     * @param errorMessage String which describes occurred error
     */
    void onFailure(String errorMessage);
} public class SEProvider extends BaseModel implements Serializable {

    @SerializedName(SEConstants.KEY_CODE)
    private String code;

    @SerializedName(SEConstants.KEY_NAME)
    private String name;

    @SerializedName(SEConstants.KEY_MODE)
    private String mode;

    @SerializedName(SEConstants.KEY_STATUS)
    private String status;

    @SerializedName(SEConstants.KEY_AUTOMATIC_FETCH)
    private Boolean automaticFetch;

    @SerializedName(SEConstants.KEY_CUSTOMER_NOTIFIED_ON_SIGN_IN)
    private Boolean customerNotifiedOnSignIn;

    @SerializedName(SEConstants.KEY_INTERACTIVE)
    private Boolean interactive;

    @SerializedName(SEConstants.KEY_IDENTIFICATION_MODE)
    private String identificationMode;

    @SerializedName(SEConstants.KEY_INSTRUCTION)
    private String instruction;

    @SerializedName(SEConstants.KEY_HOME_URL)
    private String homeUrl;

    @SerializedName(SEConstants.KEY_LOGIN_URL)
    private String loginUrl;

    @SerializedName(SEConstants.KEY_LOGO_URL)
    private String logoUrl;

    @SerializedName(SEConstants.KEY_COUNTRY_CODE)
    private String countryCode;

    @SerializedName(SEConstants.KEY_REFRESH_TIMEOUT)
    private int refreshTimeout;

    @SerializedName(SEConstants.KEY_HOLDER_INFO)
    private String[] holderInfo;

    @SerializedName(SEConstants.KEY_MAX_CONSENT_DAYS)
    private Integer maxConsentDays;

    // GETTER AND SETTERS

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getMode() {
        return mode;
    }

    public void setMode(String mode) {
        this.mode = mode;
    }

    public String getStatus() {
        return status;
    }

    public void setStatus(String status) {
        this.status = status;
    }

    public Boolean getAutomaticFetch() {
        return automaticFetch;
    }

    public void setAutomaticFetch(Boolean automaticFetch) {
        this.automaticFetch = automaticFetch;
    }

    public Boolean getCustomerNotifiedOnSignIn() {
        return customerNotifiedOnSignIn;
    }

    public void setCustomerNotifiedOnSignIn(Boolean customerNotifiedOnSignIn) {
        this.customerNotifiedOnSignIn = customerNotifiedOnSignIn;
    }

    public Boolean getInteractive() {
        return interactive;
    }

    public void setInteractive(Boolean interactive) {
        this.interactive = interactive;
    }

    public String getIdentificationMode() {
        return identificationMode;
    }

    public void setIdentificationMode(String identificationMode) {
        this.identificationMode = identificationMode;
    }

    public String getInstruction() {
        return instruction;
    }

    public void setInstruction(String instruction) {
        this.instruction = instruction;
    }

    public String getHomeUrl() {
        return homeUrl;
    }

    public void setHomeUrl(String homeUrl) {
        this.homeUrl = homeUrl;
    }

    public String getLoginUrl() {
        return loginUrl;
    }

    public void setLoginUrl(String loginUrl) {
        this.loginUrl = loginUrl;
    }

    public String getLogoUrl() {
        return logoUrl;
    }

    public void setLogoUrl(String logoUrl) {
        this.logoUrl = logoUrl;
    }

    public String getCountryCode() {
        return countryCode;
    }

    public void setCountryCode(String countryCode) {
        this.countryCode = countryCode;
    }

    public int getRefreshTimeout() {
        return refreshTimeout;
    }

    public void setRefreshTimeout(int refreshTimeout) {
        this.refreshTimeout = refreshTimeout;
    }

    public String[] getHolderInfo() {
        return holderInfo;
    }

    public void setHolderInfo(String[] holderInfo) {
        this.holderInfo = holderInfo;
    }

    public Integer getMaxConsentDays() {
        return maxConsentDays;
    }

    public void setMaxConsentDays(Integer maxConsentDays) {
        this.maxConsentDays = maxConsentDays;
    }

    // EXTRA METHODS

    public boolean isOAuth() {
        return mode.equals("oauth");
    }
} public class Saltbridge {

    @SerializedName(SEConstants.KEY_CONNECTION_ID)
    private String connectionId;

    @SerializedName(SEConstants.KEY_STAGE)
    private String stage;

    @SerializedName(SEConstants.KEY_SECRET)
    private String secret;

    @SerializedName(SEConstants.KEY_API_STAGE)
    private String apiStage;

    @SerializedName(SEConstants.KEY_CUSTOM_FIELDS)
    private Map<String, Object> customFields;

    public String getConnectionId() {
        return connectionId;
    }

    public String getStage() {
        return stage;
    }

    public String getSecret() {
        return secret;
    }

    public String getApiStage() {
        return apiStage;
    }

    public Map<String, Object> getCustomFields() {
        return customFields;
    }
} public class SERequestManager {

    private static SERequestManager instance;

    public static SERequestManager getInstance() {
        if (instance == null) {
            instance = new SERequestManager();
        }
        return instance;
    }

    /**
     * Returns Currencies Rates objects collection for a desired date.
     *
     * Result is returned through callback (`onFetchCurrenciesSuccess(List<SECurrency> list)`).
     *
     * @param customerSecret [optional] current Customer secret code
     * @param ratesDate date for which collection of currencies rates should be returned
     * @param callback callback for request result
     */
    public void fetchCurrenciesRates(
            String customerSecret,
            String ratesDate,
            FetchCurrencyRatesResult callback
    ) {
        new CurrenciesConnector(callback).fetchCurrenciesRates(customerSecret, ratesDate);
    }

    /**
     * Allows to create new Customer.
     *
     * Result is returned through callback (`onCreateCustomerSuccess(String customerSecret)`).
     *
     * @param customerIdentifier a unique identifier of the new Customer
     * @param callback callback for request result
     */
    public void createCustomer(
            String customerIdentifier,
            CreateCustomerResult callback
    ) {
        if (TextUtils.isEmpty(customerIdentifier)) {
            throw new RuntimeException(SEConstants.ERROR_CUSTOMER_IDENTIFIER_IS_NULL);
        }
        new CustomerConnector(callback).createCustomer(customerIdentifier);
    }

    /**
     * Return list of available Providers.
     * Result is returned through callback.
     *
     * @param countryCode code of the provider’s country
     * @param callback callback for request result
     */
    public void fetchProviders(String countryCode, ProvidersResult callback) {
        new ProvidersConnector(callback).fetchProviders(countryCode);
    }

    /**
     * Allows you to create a connect session, which will be used to access Salt Edge Connect for Connection creation.
     * You will receive a connect_url, which allows you to enter directly to Salt Edge Connect with your newly generated connect session.
     * Result is returned through callback.
     *
     * @param customerSecret current Customer secret code
     * @param providerCode the code of the desired Provider
     * @param consentScopes fetching mode, possible values: ['holder_information], ['account_details'], ['transactions_details'] or combinations
     * @param localeCode the language of the Salt Edge Connect page in the ISO 639-1 format.
     * @param callback callback for request result
     */
    public void createConnectSession(
            String customerSecret,
            String providerCode,
            String[] consentScopes,
            String localeCode,
            ConnectSessionResult callback
    ) {
        new ConnectSessionConnector(callback).createConnectSession(
                customerSecret,
                providerCode,
                consentScopes,
                localeCode
        );
    }

    /**
     * Allows you to create a connect session, which will be used to access Salt Edge Connect for Connection creation.
     * You will receive a connect_url, which allows you to enter directly to Salt Edge Connect with your newly generated connect session.
     * Result is returned through callback.
     *
     * @param customerSecret current Customer secret code
     * @param dataMap custom params map
     * @param callback callback for request result
     */
    public void createConnectSession(
            String customerSecret,
            Map<String, Object> dataMap,
            ConnectSessionResult callback
    ) {
        new ConnectSessionConnector(callback).createConnectSession(customerSecret, dataMap);
    }

    /**
     * Allows you to create a connect session, which will be used to access Salt Edge Connect to reconnect a connection.
     * You will receive a connect_url, which allows you to enter directly to Salt Edge Connect with your newly generated connect session.
     * Result is returned through callback.
     *
     * @param customerSecret current Customer secret code
     * @param connectionSecret secret of the Connection which you want to reconnect
     * @param consentScopes fetching mode, possible values: ['holder_information], ['account_details'], ['transactions_details'] or combinations
     * @param localeCode the language of the Salt Edge Connect page in the ISO 639-1 format.
     * @param callback callback for request result
     */
    public void createReconnectSession(
            String customerSecret,
            String connectionSecret,
            String[] consentScopes,
            String localeCode,
            ConnectSessionResult callback
    ) {
        new ConnectSessionConnector(callback).createReconnectSession(
                customerSecret,
                connectionSecret,
                consentScopes,
                localeCode,
                false
        );
    }

    /**
     * Allows you to create a connect session, which will be used to access Salt Edge Connect to reconnect a connection.
     * You will receive a connect_url, which allows you to enter directly to Salt Edge Connect with your newly generated connect session.
     * Result is returned through callback.
     *
     * @param customerSecret current Customer secret code
     * @param connectionSecret secret of the Connection which you want to reconnect
     * @param consentScopes fetching mode, possible values: ['holder_information], ['account_details'], ['transactions_details'] or combinations
     * @param localeCode the language of the Salt Edge Connect page in the ISO 639-1 format.
     * @param overrideCredentials override credentials strategy. If true, the new credentials will automatically override the old ones.
     * @param callback callback for request result
     */
    public void createReconnectSession(
            String customerSecret,
            String connectionSecret,
            String[] consentScopes,
            String localeCode,
            boolean overrideCredentials,
            ConnectSessionResult callback
    ) {
        new ConnectSessionConnector(callback).createReconnectSession(
                customerSecret,
                connectionSecret,
                consentScopes,
                localeCode,
                overrideCredentials
        );
    }

    /**
     * Allows you to create a connect session, which will be used to access Salt Edge Connect to refresh a connection.
     * You will receive a connect_url, which allows you to enter directly to Salt Edge Connect with your newly generated connect session.
     * Result is returned through callback.
     *
     * @param customerSecret current Customer secret code
     * @param connectionSecret secret code of the Connection which you want to reconnect
     * @param localeCode the language of the Salt Edge Connect page in the ISO 639-1 format.
     * @param callback callback for request result
     */
    public void createRefreshSession(
            String customerSecret,
            String connectionSecret,
            String localeCode,
            ConnectSessionResult callback
    ) {
        new ConnectSessionConnector(callback).createRefreshSession(
                customerSecret,
                connectionSecret,
                localeCode
        );
    }

    /**
     * Created SERefreshService and starts refresh through Salt Edge API
     * Result is returned through callback.
     *
     * @param customerSecret current Customer secret code
     * @param connectionData Connection data for refresh
     * @param refreshScopes array of refresh scopes, e.g. {"accounts", "transactions"}
     * @param callback callback for request result
     * @return SERefreshService refresh service object
     */
    public SERefreshService refreshConnectionWithSecret(
            String customerSecret,
            SEConnection connectionData,
            String[] refreshScopes,
            RefreshConnectionResult callback
    ) {
        return new SERefreshService(callback).startRefresh(customerSecret, connectionData, refreshScopes);
    }

    /**
     * Used to create a connection for an OAuth provider.
     * Client will receive a redirect_url, which allows you to enter directly to Salt Edge Connect with your newly generated connect session.
     * All non-saltedge redirects should be opened in external app.
     * On finish the customer will be redirected to return_to URL.
     * Note that clients receive a connection_secret parameter in the return_to URL if the connection was successfully connected and an error_message parameter.
     *
     * Result is returned through callback.
     *
     * @param customerSecret current Customer secret code
     * @param providerCode the code of the desired Provider
     * @param consentScopes fetching mode, possible values: ['holder_information], ['account_details'], ['transactions_details'] or combinations
     * @param localeCode the language of the Salt Edge Connect page in the ISO 639-1 format.
     * @param callback callback for request result
     */
    public void createOAuthConnectSession(
            String customerSecret,
            String providerCode,
            String[] consentScopes,
            String localeCode,
            ConnectSessionResult callback
    ) {
        new ConnectOAuthConnector(callback).createConnectSession(
                customerSecret,
                providerCode,
                consentScopes,
                localeCode
        );
    }

    /**
     * Used to reconnect a connection for an OAuth provider
     * Client will receive a redirect_url, which allows you to enter directly to Salt Edge Connect with your newly generated connect session.
     * All non-saltedge redirects should be opened in external app.
     * On finish the customer will be redirected to return_to URL.
     * Note that clients receive a connection_secret parameter in the return_to URL if the connection was successfully connected and an error_message parameter.
     *
     * Result is returned through callback.
     *
     * @param customerSecret current Customer secret code
     * @param providerCode the code of the desired Provider
     * @param consentScopes fetching mode, possible values: ['holder_information], ['account_details'], ['transactions_details'] or combinations
     * @param localeCode the language of the Salt Edge Connect page in the ISO 639-1 format.
     * @param callback callback for request result
     */
    public void createOAuthReconnectSession(
            String customerSecret,
            String providerCode,
            String[] consentScopes,
            String localeCode,
            ConnectSessionResult callback
    ) {
        new ConnectOAuthConnector(callback).createConnectSession(
                customerSecret,
                providerCode,
                consentScopes,
                localeCode
        );
    }

    /**
     * Used to authorize a connection for an OAuth provider when using client owned provider keys.
     * @see [https://docs.saltedge.com/general/#client_provider_keys]
     *
     * Examples: `<return_to url>?access_token=bc4521d3&state=Pd8b4d0eb`, `<return_to url>#access_token=bc4521d3&state=Pd8b4d0eb`.
     * For both cases, the authorizeQuery that is needed to authorize the connection is `access_token=bc4521d3&state=Pd8b4d0eb`.
     *
     * Result is returned through callback.
     *
     * @param customerSecret current Customer secret code
     * @param connectionSecret secret code of the Connection which you want to reconnect
     * @param authorizeQuery authorization query string
     * @param callback callback for request result
     */
    public void authorizeOAuthConnection(
            String customerSecret,
            String connectionSecret,
            String authorizeQuery,
            FetchConnectionResult callback
    ) {
        new AuthorizeOAuthConnector(callback).authorizeConnection(
                customerSecret,
                connectionSecret,
                authorizeQuery
        );
    }

    /**
     * Allows you to create a lead session, which will be used to access Salt Edge Connect for Connection creation.
     * You will receive a redirect_url, which allows you to enter directly to Salt Edge Connect with your newly generated lead session.
     * Result is returned through callback.
     *
     * @param providerCode the code of the desired Provider
     * @param consentScopes fetching mode, possible values: ['holder_information], ['account_details'], ['transactions_details'] or combinations
     * @param localeCode the language of the Salt Edge Connect page in the ISO 639-1 format.
     * @param callback callback for request result
     */
    public void createLeadSession(
            String providerCode,
            String[] consentScopes,
            String localeCode,
            ConnectSessionResult callback
    ) {
        new LeadSessionConnector(callback).createLeadSession(
                providerCode,
                consentScopes,
                localeCode
        );
    }

    /**
     * Allows you to create a lead session, which will be used to access Salt Edge Connect for Connection creation.
     * You will receive a redirect_url, which allows you to enter directly to Salt Edge Connect with your newly generated lead session.
     * Result is returned through callback.
     *
     * @param dataMap custom params map
     * @param callback callback for request result
     */
    public void createLeadSession(
            Map<String, Object> dataMap,
            ConnectSessionResult callback
    ) {
        new LeadSessionConnector(callback).createLeadSession(dataMap);
    }

    /**
     * Returns a single Connection object.
     * Result is returned through callback.
     *
     * @param customerSecret current Customer secret code
     * @param connectionSecret secret code of the Connection which should be returned if exist
     * @param callback callback for request result
     */
    public void fetchConnection(
            String customerSecret,
            String connectionSecret,
            FetchConnectionsResult callback
    ) {
        String[] secrets = { connectionSecret };
        fetchConnections(customerSecret, secrets, callback);
    }

    /**
     * Returns Connections objects collection.
     * Result is returned through callback.
     *
     * @param customerSecret current Customer secret code
     * @param connectionsSecretsArray array of secrets of the Connections which should be returned if exist
     * @param callback callback for request result
     */
    public void fetchConnections(
            String customerSecret,
            String[] connectionsSecretsArray,
            FetchConnectionsResult callback) {
        new ConnectionsConnector(callback).fetchConnections(customerSecret, connectionsSecretsArray);
    }

    /**
     * Delete Connection.
     * Result is returned through callback.
     *
     * @param customerSecret current Customer secret code
     * @param connectionSecret secret code of the Connection which should be deleted if exist
     * @param callback callback for request result
     */
    public void deleteConnection(
            String customerSecret,
            String connectionSecret,
            DeleteEntryResult callback
    ) {
        new ConnectionDeleteConnector(callback).deleteConnection(customerSecret, connectionSecret);
    }

    /**
     * You can see the list of accounts of a Connection.
     * The accounts are sorted in ascending order of their ID, so the newest accounts will come last.
     * Result is returned through callback.
     *
     * @param customerSecret current Customer secret code
     * @param connectionSecret secret code of the Connection
     * @param callback callback for request result
     */
    public void fetchAccounts(
            String customerSecret,
            String connectionSecret,
            FetchAccountsResult callback
    ) {
        new AccountsConnector(callback).fetchAccounts(customerSecret, connectionSecret);
    }

    /**
     * Return the list of all non duplicated  transactions for an Account of a Connection.
     * The list not includes pending transactions
     * Result is returned through callback.
     *
     * @param customerSecret current Customer secret code
     * @param connectionSecret secret code of the Connection
     * @param accountId Account ID
     * @param callback callback for request result
     */
    public void fetchAllTransactions(
            String customerSecret,
            String connectionSecret,
            String accountId,
            FetchTransactionsResult callback
    ) {
        fetchTransactions(
                customerSecret,
                connectionSecret,
                accountId,
                "",
                false,
                true,
                callback
        );
    }

    /**
     * Return the list of all transactions from transactionId for an Account of a Connection.
     * The list not includes pending transactions
     * Result is returned through callback.
     *
     * @param customerSecret current Customer secret code
     * @param connectionSecret secret code of the Connection
     * @param accountId Account ID
     * @param fromTransactionId the id from which the result list should starts
     * @param callback callback for request result
     */
    public void fetchAllTransactions(
            String customerSecret,
            String connectionSecret,
            String accountId,
            String fromTransactionId,
            FetchTransactionsResult callback
    ) {
        fetchTransactions(
                customerSecret,
                connectionSecret,
                accountId,
                fromTransactionId,
                false,
                true,
                callback
        );
    }

    /**
     * Return the single page of transactions from transactionId for an Account of a Connection.
     * Transaction page contains maximum 100 items.
     * The list not includes pending transactions
     * Result is returned through callback.
     *
     * @param customerSecret current Customer secret code
     * @param connectionSecret secret code of the Connection
     * @param accountId Account ID
     * @param fromTransactionId the ID from which the next page of transactions starts
     * @param callback callback for request result
     */
    public void fetchTransactions(
            String customerSecret,
            String connectionSecret,
            String accountId,
            String fromTransactionId,
            FetchTransactionsResult callback
    ) {
        fetchTransactions(customerSecret,
                connectionSecret,
                accountId,
                fromTransactionId,
                false,
                false,
                callback);
    }

    /**
     * Return the list of transactions for an Account of a Connection.
     * Initiate transactions fetch by params.
     * The list includes posted or pending transactions.
     * Result is returned through callback.
     *
     * @param customerSecret current Customer secret code
     * @param connectionSecret secret code of the Connection
     * @param accountId Account ID
     * @param fromTransactionId the ID from which the next page of transactions starts
     * @param fetchPendingTransactions flag which indicates what type of transactions should be fetched (Normal or Pending)
     * @param fetchAllTransactionsFromId flag which indicates that should be fetched one page or all
     * @param callback callback for request result
     */
    public void fetchTransactions(
            String customerSecret,
            String connectionSecret,
            String accountId,
            String fromTransactionId,
            boolean fetchPendingTransactions,
            boolean fetchAllTransactionsFromId,
            FetchTransactionsResult callback
    ) {
        if (fetchPendingTransactions) {
            new PendingTransactionsFetchConnector(callback).fetchTransactions(
                    customerSecret,
                    connectionSecret,
                    accountId,
                    fromTransactionId,
                    fetchAllTransactionsFromId
            );
        } else {
            new TransactionsConnector(callback).fetchTransactions(
                    customerSecret,
                    connectionSecret,
                    accountId,
                    fromTransactionId,
                    fetchAllTransactionsFromId
            );
        }
    }

    /**
     * Return the list of all pending transactions for an Account of a Connection.
     * Result is returned through callback.
     *
     * @param customerSecret current Customer secret code
     * @param connectionSecret secret of the Connection
     * @param accountId Account ID
     * @param callback callback for request result
     */
    public void fetchPendingTransactionsOfAccount(
            String customerSecret,
            String connectionSecret,
            String accountId,
            FetchTransactionsResult callback
    ) {
        fetchPendingTransactionsOfAccount(
                customerSecret,
                connectionSecret,
                accountId,
                "",
                callback);
    }

    /**
     * Return the list of all pending transactions from transactionId for an Account of a Connection.
     * Result is returned through callback.
     *
     * @param customerSecret current Customer secret code
     * @param connectionSecret secret of the Connection
     * @param accountId Account ID
     * @param fromTransactionId the id from which the result list should starts
     * @param callback callback for request result
     */
    public void fetchPendingTransactionsOfAccount(
            String customerSecret,
            String connectionSecret,
            String accountId,
            String fromTransactionId,
            FetchTransactionsResult callback
    ) {
        new PendingTransactionsFetchConnector(callback).fetchTransactions(
                customerSecret,
                connectionSecret,
                accountId,
                fromTransactionId,
                true
        );
    }

    /**
     * Return the list of all duplicated transactions for an Account of a Connection.
     * Result is returned through callback.
     *
     * @param customerSecret current Customer secret code
     * @param connectionSecret secret of the Connection
     * @param accountId Account ID
     * @param callback callback for request result
     */
    public void fetchDuplicatedTransactionsOfAccount(
            String customerSecret,
            String connectionSecret,
            String accountId,
            FetchTransactionsResult callback
    ) {
        fetchDuplicatedTransactionsOfAccount(
                customerSecret,
                connectionSecret,
                accountId,
                "",
                callback);
    }

    /**
     * Return the list of all duplicated transactions from transactionId for an Account of a Connection.
     * Result is returned through callback.
     *
     * @param customerSecret current Customer secret code
     * @param connectionSecret secret of the Connection
     * @param accountId Account ID
     * @param fromTransactionId the id from which the result list should starts
     * @param callback callback for request result
     */
    public void fetchDuplicatedTransactionsOfAccount(
            String customerSecret,
            String connectionSecret,
            String accountId,
            String fromTransactionId,
            FetchTransactionsResult callback
    ) {
        new DuplicatedTransactionsFetchConnector(callback).fetchTransactions(
                customerSecret,
                connectionSecret,
                accountId,
                fromTransactionId,
                true
        );
    }

    /**
     * Mark a list of transactions as duplicated.
     * Result is returned through callback (`onUpdateTransactionsSuccess(Boolean success, "DUPLICATE")`)
     *
     * @param customerSecret current Customer secret code
     * @param connectionSecret secret of the Connection
     * @param transactionsIds the ids of transactions, that should be marked as duplicated
     * @param callback callback for request result
     */
    public void markTransactionsAsDuplicated(
            String customerSecret,
            String connectionSecret,
            List<String> transactionsIds,
            UpdateTransactionsResult callback
    ) {
        new TransactionsUpdateConnector(callback).markTransactionsAsDuplicated(
                customerSecret,
                connectionSecret,
                transactionsIds
        );
    }

    /**
     * Remove duplicated flag from a list of transactions.
     * Result is returned through callback (`onUpdateTransactionsSuccess(Boolean success, "UNDUPLICATE")`)
     *
     * @param customerSecret current Customer secret code
     * @param connectionSecret secret of the Connection
     * @param transactionsIds the ids of transactions, that should be marked as not-duplicated
     * @param callback callback for request result
     */
    public void markTransactionsAsNotDuplicated(
            String customerSecret,
            String connectionSecret,
            List<String> transactionsIds,
            UpdateTransactionsResult callback
    ) {
        new TransactionsUpdateConnector(callback).markTransactionsAsNotDuplicated(
                customerSecret,
                connectionSecret,
                transactionsIds
        );
    }

    /**
     * Remove transactions older than a specified period.
     * Result is returned through callback (`onTransactionsCleanupStartedSuccess(Boolean success)`)
     *
     * @param customerSecret current Customer secret code
     * @param connectionSecret secret of the Connection
     * @param accountId the id of the account
     * @param keepDays the amount of days for which the transactions will be kept. Transactions older than that will be irreversibly removed. Value should be greater than or equal to 60.
     * @param callback callback for request result
     */
    public void removeTransactions(
            String customerSecret,
            String connectionSecret,
            String accountId,
            int keepDays,
            UpdateTransactionsResult callback
    ) {
        new TransactionsUpdateConnector(callback).removeTransactions(
                customerSecret,
                connectionSecret,
                accountId,
                keepDays
        );
    }

    /**
     * You can see the list of consents of Connection.
     * The consents are sorted in ascending order of their ID, so the newest consents will come last.
     *
     * Result is returned through callback.
     *
     * @param customerSecret current Customer secret code
     * @param connectionSecret secret code of the Connection
     * @param callback callback for request result
     */
    public void fetchConsents(
            String customerSecret,
            String connectionSecret,
            FetchConsentsResult callback
    ) {
        new ConsentsConnector(callback).fetchConsents(customerSecret, connectionSecret);
    }

    /**
     * Consent revoke is an option that allows you to revoke a consent.
     * Result is returned through callback.
     *
     * @param customerSecret current Customer secret code
     * @param connectionSecret secret code of the Connection containing the consents
     * @param consentId unique ID of Consent which should be revoked
     * @param callback callback for request result
     */
    public void revokeConsent(
            String customerSecret,
            String connectionSecret,
            String consentId,
            DeleteEntryResult callback
    ) {
        new ConsentRevokeConnector(callback).revokeConsent(customerSecret, connectionSecret, consentId);
    }
} public class Constants {

    static String CONNECTIONS_SECRETS_ARRAY = "CONNECTIONS_SECRETS_ARRAY";
    public static final String KEY_CUSTOMER_SECRET = "secret";
    public static final String KEY_CUSTOMER_IDENTIFIER = "identifier";
    public static final String KEY_CONNECTION = "connection";
    public static final String KEY_CONNECTION_SECRET = "connection_secret";
    public static final String KEY_REFRESH = "refresh";
    public static final String KEY_OVERRIDE_CREDENTIALS = "override_credentials";
    public static final String KEY_OAUTH = "oauth";
    public static final String[] CONSENT_SCOPES = { SEConsent.SCOPE_ACCOUNT_DETAILS, SEConsent.SCOPE_TRANSACTIONS_DETAILS };
} public class PreferenceRepository {

    private static SharedPreferences sharedPreferences = null;

    public static void init(Context context) {
        sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context.getApplicationContext());
    }

    public static void putStringToPreferences(String key, String value) {
        sharedPreferences.edit().putString(key, value).apply();
    }

    public static String getStringFromPreferences(String key) {
        return sharedPreferences.getString(key, "");
    }

    public static void removeRecordFromPreferences(String key) {
        sharedPreferences.edit().remove(key).apply();
    }

    public static void putConnectionSecret(String connectionSecret) {
        putStringToArrayPreferences(Constants.CONNECTIONS_SECRETS_ARRAY, connectionSecret);
    }

    public static String[] getAllConnectionsSecrets() {
        return getArrayFromPreferences(Constants.CONNECTIONS_SECRETS_ARRAY);
    }

    public static void removeConnectionSecret(String connectionSecret) {
        if (!connectionSecret.isEmpty()) {
            removeStringFromArrayPreferences(Constants.CONNECTIONS_SECRETS_ARRAY, connectionSecret);
        }
    }

    public static boolean connectionSecretIsSaved(String connectionSecret) {
        return !connectionSecret.isEmpty()
                && Arrays.asList(getAllConnectionsSecrets()).contains(connectionSecret);
    }

    private static void putStringToArrayPreferences(String arrayKey, String value) {
        ArrayList<String> list = new ArrayList<>(Arrays.asList(getArrayFromPreferences(arrayKey)));
        if (!list.contains(value)) list.add(value);
        sharedPreferences.edit().putString(arrayKey, new Gson().toJson(list)).apply();
    }

    private static void removeStringFromArrayPreferences(String arrayKey, String value) {
        ArrayList<String> list = new ArrayList<>(Arrays.asList(getArrayFromPreferences(arrayKey)));
        list.remove(value);
        sharedPreferences.edit().putString(arrayKey, new Gson().toJson(list)).apply();
    }

    private static String[] getArrayFromPreferences(String key) {
        String array = sharedPreferences.getString(key, "[]");
        return new Gson().fromJson(array, String[].class);
    }
} public class UITools {

    public static AlertDialog showAlertDialog(Context context, String message) {
        return showAlertDialog(context, message, null);
    }

    public static AlertDialog showAlertDialog(Context context, String message, DialogInterface.OnClickListener listener) {
        AlertDialog.Builder adb = new AlertDialog.Builder(context);
        adb.setIcon(android.R.drawable.ic_dialog_alert)
                .setTitle(R.string.warning)
                .setMessage(message)
                .setPositiveButton(android.R.string.ok, listener);
        return adb.show();
    }

    public static void destroyAlertDialog(AlertDialog dialog) {
        if (dialog != null) {
            dialog.dismiss();
        }
    }

    public static ProgressDialog refreshProgressDialog(Context context, ProgressDialog dialog, int messageResId) {
        return refreshProgressDialog(context, dialog, context.getString(messageResId));
    }

    public static ProgressDialog refreshProgressDialog(Context context, ProgressDialog dialog, String message) {
        destroyProgressDialog(dialog);
        dialog = new ProgressDialog(context);
        dialog.setMessage(message);
        dialog.setIndeterminate(true);
        dialog.show();
        return dialog;
    }

    public static ProgressDialog showProgressDialog(Context context, String message) {
        ProgressDialog dialog = new ProgressDialog(context);
        dialog.setMessage(message);
        dialog.setIndeterminate(true);
        dialog.show();
        return dialog;
    }

    public static void destroyProgressDialog(ProgressDialog dialog) {
        if (dialog != null) {
            dialog.dismiss();
        }
    }

    public static void hideProgress(ProgressDialog dialog) {
        dialog.hide();
    }

    public static void showShortToast(Context context, @StringRes Integer messageResId) {
        Toast.makeText(context, messageResId, Toast.LENGTH_SHORT).show();
    }

    public static void showLongToast(Context context, @StringRes Integer messageResId) {
        Toast.makeText(context, messageResId, Toast.LENGTH_LONG).show();
    }

    public static void showShortToast(Context context, String message) {
        Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
    }

    public static void showLongToast(Context context, String message) {
        Toast.makeText(context, message, Toast.LENGTH_LONG).show();
    }
} public class SEConstants {

    //Base model keys
    public static final String KEY_ID = "id";
    public static final String KEY_CREATED_AT = "created_at";
    public static final String KEY_UPDATED_AT = "updated_at";

    //WebView/Saltbridge keys
    public static final String KEY_STAGE = "stage";
    public static final String KEY_STAGES = "stages";
    public static final String STATUS_FETCHING = "fetching";
    public static final String STATUS_ERROR = "error";
    public static final String STATUS_SUCCESS = "success";
    public static final String KEY_API_STAGE = "api_stage";
    public static final String KEY_CUSTOM_FIELDS = "custom_fields";

    //JSON keys
    public static final String KEY_DATA = "data";
    public static final String KEY_META = "meta";
    public static final String KEY_NEXT_ID = "next_id";
    public static final String KEY_NEXT_PAGE = "next_page";
    public static final String KEY_MESSAGE = "message";
    public static final String KEY_ERROR = "error";
    public static final String KEY_CLASS = "class";
    public static final String KEY_DOCUMENTATION_URL = "documentation_url";
    public static final String KEY_IDENTIFIER = "identifier";
    public static final String KEY_CONNECT_URL = "connect_url";
    public static final String KEY_REDIRECT_URL = "redirect_url";
    public static final String KEY_EXPIRES_AT = "expires_at";
    public static final String KEY_REVOKED_BY = "revoked_by";
    public static final String KEY_REVOKED_AT = "revoked_at";
    public static final String KEY_REMOVED = "removed";
    public static final String KEY_COLLECTED_BY = "collected_by";
    public static final String KEY_FETCH_SCOPES = "fetch_scopes";
    public static final String KEY_SCOPES = "scopes";
    public static final String KEY_TOKEN = "token";

    //String resources
    public static final String LOADING = "Loading";
    public static final String WARNING = "Warning";

    //Providers keys
    public static final String KEY_NAME = "name";
    public static final String KEY_MODE = "mode";
    public static final String KEY_STATUS = "status";
    public static final String KEY_CODE = "code";
    public static final String KEY_CUSTOMER_NOTIFIED_ON_SIGN_IN = "customer_notified_on_sign_in";
    public static final String KEY_AUTOMATIC_FETCH = "automatic_fetch";
    public static final String KEY_INTERACTIVE = "interactive";
    public static final String KEY_IDENTIFICATION_MODE = "identification_mode";
    public static final String KEY_INSTRUCTION = "instruction";
    public static final String KEY_HOME_URL = "home_url";
    public static final String KEY_LOGIN_URL = "login_url";
    public static final String KEY_LOGO_URL = "logo_url";
    public static final String KEY_ALLOWED_COUNTRIES = "allowed_countries";
    public static final String KEY_REFRESH_TIMEOUT = "refresh_timeout";
    public static final String KEY_HOLDER_INFO = "holder_info";
    public static final String KEY_MAX_CONSENT_DAYS = "max_consent_days";
    public static final String KEY_INCLUDE_FAKE_PROVIDERS = "include_fake_providers";

    //Connections keys
    public static final String KEY_SECRET = "secret";
    public static final String KEY_DAILY_REFRESH = "daily_refresh";
    public static final String KEY_FINISHED = "finished";
    public static final String KEY_FINISHED_RECENT = "finished_recent";
    public static final String KEY_PARTIAL = "partial";
    public static final String KEY_CUSTOMER_EMAIL = "customer_email";
    public static final String KEY_PROVIDER_ID = "provider_id";
    public static final String KEY_PROVIDER_CODE = "provider_code";
    public static final String KEY_PROVIDER_NAME = "provider_name";
    public static final String KEY_LAST_FAIL_AT = "last_fail_at";
    public static final String KEY_FAIL = "fail";
    public static final String KEY_FAIL_AT = "fail_at";
    public static final String KEY_LAST_FAIL_MESSAGE = "last_fail_message";
    public static final String KEY_FAIL_MESSAGE = "fail_message";
    public static final String KEY_FAIL_ERROR_CLASS = "fail_error_class";
    public static final String KEY_LAST_REQUEST_AT = "last_request_at";
    public static final String KEY_LAST_SUCCESS_AT = "last_success_at";
    public static final String KEY_SUCCESS_AT = "success_at";
    public static final String KEY_NEXT_REFRESH_POSSIBLE_AT = "next_refresh_possible_at";
    public static final String KEY_STORE_CREDENTIALS = "store_credentials";
    public static final String KEY_SHOW_CONSENT_CONFIRMATION = "show_consent_confirmation";
    public static final String KEY_CONSENT_TYPES = "consent_types";
    public static final String KEY_CONSENT_PERIOD_DAYS = "consent_period_days";
    public static final String KEY_CONSENT_GIVEN_AT = "consent_given_at";
    public static final String KEY_CONSENT_EXPIRES_AT = "consent_expires_at";
    public static final String KEY_LAST_ATTEMPT = "last_attempt";
    public static final String KEY_LAST_STAGE = "last_stage";
    public static final String KEY_CONSENT = "consent";
    public static final String KEY_ATTEMPT = "attempt";
    public static final String KEY_ATTEMPT_ID = "attempt_id";

    //Account keys
    public static final String KEY_NATURE = "nature";
    public static final String KEY_BALANCE = "balance";
    public static final String KEY_CURRENCY_CODE = "currency_code";
    public static final String KEY_EXTRA = "extra";

    //Transaction keys
    public static final String KEY_DUPLICATED = "duplicated";
    public static final String KEY_UNDUPLICATED = "unduplicated";
    public static final String KEY_MADE_ON = "made_on";
    public static final String KEY_AMOUNT = "amount";
    public static final String KEY_DESCRIPTION = "description";
    public static final String KEY_CATEGORY = "category";
    public static final String KEY_ACCOUNT_ID = "account_id";

    //Other keys
    public static final String KEY_CUSTOMER_ID = "customer_id";
    public static final String KEY_CONNECTION_ID = "connection_id";
    public static final String KEY_API_MODE = "api_mode";
    public static final String KEY_API_VERSION = "api_version";
    public static final String KEY_CATEGORIZATION = "categorization";
    public static final String KEY_DEVICE_TYPE = "device_type";
    public static final String KEY_REMOTE_IP = "remote_ip";
    public static final String KEY_EXCLUDE_ACCOUNTS = "exclude_accounts";
    public static final String KEY_IDENTIFY_MERCHANT = "identify_merchant";
    public static final String KEY_USER_PRESENT = "user_present";
    public static final String KEY_INTERACTIVE_HTML = "interactive_html";
    public static final String KEY_INTERACTIVE_FIELDS_NAMES = "interactive_fields_names";
    public static final String KEY_INTERACTIVE_FIELDS_OPTIONS = "interactive_fields_options";
    public static final String KEY_NAMES = "names";
    public static final String KEY_EMAILS = "emails";
    public static final String KEY_PHONE_NUMBERS = "phone_numbers";
    public static final String KEY_ADDRESSES = "addresses";
    public static final String KEY_CITY = "city";
    public static final String KEY_STATE = "state";
    public static final String KEY_STREET = "street";
    public static final String KEY_COUNTRY_CODE = "country_code";
    public static final String KEY_POST_CODE = "post_code";
    public static final String KEY_ENGLISH_NAME = "english_name";
    public static final String KEY_LOCALIZED_NAME = "localized_name";
    public static final String KEY_OPTION_VALUE = "option_value";
    public static final String KEY_SELECTED = "selected";
    public static final String KEY_CREDENTIALS = "credentials";
    public static final String KEY_OVERRIDE_CREDENTIALS_STRATEGY = "override_credentials_strategy";
    public static final String KEY_DISABLE_PROVIDER_SEARCH = "disable_provider_search";
    public static final String KEY_RETURN_TO = "return_to";
    public static final String KEY_LOCALE = "locale";
    public static final String KEY_PROVIDER_MODES = "provider_modes";
    public static final String KEY_FROM_ID = "from_id";
    public static final String KEY_FROM_DATE = "from_date";
    public static final String KEY_TO_DATE = "to_date";
    public static final String KEY_PERIOD_DAYS = "period_days";
    public static final String KEY_CONSENT_ID = "consent_id";
    public static final String KEY_DATE = "date";
    public static final String KEY_QUERY_STRING = "query_string";

    public static final String KEY_JAVASCRIPT_CALLBACK_TYPE = "javascript_callback_type";
    public static final String IFRAME = "iframe";
    public static final String KEY_RATE = "rate";
    public static final String KEY_TRANSACTION_IDS = "transaction_ids";
    public static final String KEY_KEEP_DAYS = "keep_days";
    public static final String KEY_CLEANUP_STARTED = "cleanup_started";

    //ERRORS
    public static final String REQUEST_ERROR = "Request error";
    public static final String ERROR_CANNOT_BE_NULL = "cannot be null";
    public static final String ERROR_COULD_NOT_CONNECT_ACCOUNT = "Could not connect account";
    public static final String ERROR_CLIENT_APP_ID_IS_NULL = "Client App Id cannot be null or empty";
    public static final String ERROR_CLIENT_APP_SECRET_IS_NULL = "Client App Secret cannot be null or empty";
    public static final String ERROR_CUSTOMER_IDENTIFIER_IS_NULL = "Customer identifier cannot be null or empty";
    public static final String ERROR_INVALID_REFRESH_SECRETS = "Invalid refresh secrets";
    public static final String ERROR_URL_EMPTY = "URL is empty";

    //RESULT CODES
    public static final int FILECHOOSER_RESULT_CODE = 666;


} public class SEWebViewTools {

    public static ValueCallback<Uri[]> uploadMessage;

    private static SEWebViewTools instance;

    private ProgressDialog progressDialog;
    private Activity activity;
    private WebViewRedirectListener webViewListener;
    private String returnUrl = SaltEdgeSDK.getReturnToUrl();

    public interface WebViewRedirectListener {

        /**
         * Connect session redirected to Connect Stage URL.
         * Invoked if received SUCCESS stage callback of provider connect flow
         *
         * @param connectionId connection id
         * @param connectionSecret connection secret code
         * @param rawJsonData raw JSON result data
         */
        void onConnectSessionSuccessStage(String connectionId, String connectionSecret, String rawJsonData);

        /**
         * Connect session redirected to Connect Stage URL.
         * Invoked if received ERROR stage callback of provider connect flow
         *
         * @param rawJsonData raw JSON result data
         */
        void onConnectSessionErrorStage(String rawJsonData);

        /**
         * Connect session redirected to Connect Stage URL.
         * Invoked if received FETCHING stage callback of provider connect flow
         *
         * @param connectionId connection id
         * @param connectionSecret connection secret code
         * @param apiStage api stage string
         * @param rawJsonData raw JSON result data
         */
        void onConnectSessionFetchingStage(String connectionId, String connectionSecret, String apiStage, String rawJsonData);

        /**
         * Connect session redirected to Connect Stage URL.
         * Invoked if received Not SUCCESS, not ERROR, not FETCHING stage
         *
         * @param result parsed Saltbridge result object
         * @param rawJsonData raw JSON result data
         */
        void onConnectSessionStageChange(Saltbridge result, String rawJsonData);

        /**
         * Connect session redirected to Return URL.
         * Session is redirected if connection is created or updated.
         * Return URL can contains OAuth authorization query string or connection secret.
         *
         * @return true if WebView should be redirected to Return URL, otherwise return false.
         */
        boolean onRedirectToReturnUrl(String url);
    }

    public static SEWebViewTools getInstance() {
        if (instance == null) {
            instance = new SEWebViewTools();
        }
        return instance;
    }

    @SuppressLint("SetJavaScriptEnabled")
    public void initializeWithUrl(
            Activity activity,
            WebView webView,
            String url,
            WebViewRedirectListener listener
    ) {
        this.activity = activity;
        this.webViewListener = listener;
        progressDialog = UITools.createProgressDialog(activity);
        webView.getSettings().setJavaScriptEnabled(true);
        webView.getSettings().setLoadWithOverviewMode(true);
        webView.getSettings().setAllowFileAccess(true);
        webView.setWebViewClient(new CustomWebViewClient());
        webView.setWebChromeClient(new WebChromeClient() {
            @Override
            public boolean onShowFileChooser(WebView webView,
                                             ValueCallback<Uri[]> filePathCallback,
                                             FileChooserParams fileChooserParams) {
                uploadMessage = filePathCallback;
                startFilePicker();
                return true;
            }

        });
        webView.loadUrl(url);
    }

    public void clear() {
        activity = null;
        webViewListener = null;
    }

    private void startFilePicker() {
        Intent chooserIntent = new Intent(Intent.ACTION_GET_CONTENT);
        chooserIntent.setType("file/*");
        if (activity != null) activity.startActivityForResult(chooserIntent, SEConstants.FILECHOOSER_RESULT_CODE);
    }

    private class CustomWebViewClient extends WebViewClient {
        @Override
        public boolean shouldOverrideUrlLoading(WebView view, String url) {
            SaltEdgeSDK.printToLogcat("SEWebViewTools", "load url: " + url);
            if (isSaltbridgeUrl(url)) {
                String rawJsonData = extractParamsFromRedirectUrl(url, SEApiConstants.PREFIX_SALTBRIDGE);
                onStageChanged(parseSaltbridgeObject(rawJsonData), rawJsonData);
            } else if (isReturnUrl(url)) {
                if (webViewListener != null && webViewListener.onRedirectToReturnUrl(url)) {
                    if (view != null) view.loadUrl(url);
                }
            } else if (view != null) {
                view.loadUrl(url);
            }
            return true;
        }

        @Override
        public void onPageStarted(WebView view, String url, Bitmap favicon) {
            super.onPageStarted(view, url, favicon);
            if (activity != null && !activity.isFinishing()) {
                UITools.showProgress(progressDialog);
            }

        }

        @Override
        public void onPageFinished(WebView view, String url) {
            super.onPageFinished(view, url);
            if (activity != null && !activity.isFinishing()) {
                UITools.destroyProgressDialog(progressDialog);
            }
        }
    }

    private boolean isReturnUrl(String url) {
        return returnUrl != null && !returnUrl.isEmpty() && url.startsWith(returnUrl);
    }

    private boolean isSaltbridgeUrl(String url) {
        return url != null && url.contains(SEApiConstants.PREFIX_SALTBRIDGE);
    }

    public String extractParamsFromRedirectUrl(String redirectUrl, String prefixUrl) {
        return redirectUrl.contains(prefixUrl) ? redirectUrl.substring(prefixUrl.length()) : "";
    }

    private Saltbridge parseSaltbridgeObject(String rawJsonData) {
        SaltbridgeResponse response = null;
        try {
            response = SERestClient.gson.fromJson(rawJsonData, SaltbridgeResponse.class);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return response == null ? null : response.getData();
    }

    private void onStageChanged(Saltbridge saltbridge, String rawJsonData) {
        if (webViewListener == null || saltbridge == null) return;
        String stage = saltbridge.getStage();
        String connectionId = saltbridge.getConnectionId();
        String connectionSecret = saltbridge.getSecret();
        switch (stage) {
            case SEConstants.STATUS_SUCCESS:
                webViewListener.onConnectSessionSuccessStage(
                        connectionId,
                        connectionSecret,
                        rawJsonData
                );
                break;
            case SEConstants.STATUS_ERROR:
                webViewListener.onConnectSessionErrorStage(rawJsonData);
                break;
            case SEConstants.STATUS_FETCHING:
                webViewListener.onConnectSessionFetchingStage(
                        connectionId,
                        connectionSecret,
                        saltbridge.getApiStage(),
                        rawJsonData
                );
                break;
            default:
                webViewListener.onConnectSessionStageChange(saltbridge, rawJsonData);
                break;
        }
    }
} public static final String KEY_CONNECTION_SECRET = "connection_secret"; public static ProgressDialog refreshProgressDialog(Context context, ProgressDialog dialog, int messageResId) {
    return refreshProgressDialog(context, dialog, context.getString(messageResId));
}
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.webkit.WebView;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;
import com.saltedge.sdk.interfaces.ConnectSessionResult;
import com.saltedge.sdk.model.SEProvider;
import com.saltedge.sdk.model.Saltbridge;
import com.saltedge.sdk.network.SERequestManager;
import com.saltedge.sdk.sample.R;
import com.saltedge.sdk.sample.utils.Constants;
import com.saltedge.sdk.sample.utils.PreferenceRepository;
import com.saltedge.sdk.sample.utils.UITools;
import com.saltedge.sdk.utils.SEConstants;
import com.saltedge.sdk.webview.SEWebViewTools;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import static com.saltedge.sdk.sample.utils.Constants.KEY_CONNECTION_SECRET;
import static com.saltedge.sdk.sample.utils.UITools.refreshProgressDialog;
    }

    @Override
    protected void onStart() {
        super.onStart();
        String url = webView.getOriginalUrl();
        if (url == null || url.isEmpty()) {
            requestConnectUrl();
        }
    }

    @Override
    public void onConnectSessionSuccessStage(String connectionId, String connectionSecret, String rawJsonData) {
        PreferenceRepository.putConnectionSecret(connectionSecret);
        UITools.showShortToast(this, R.string.connection_connected);
        closeActivity(true, null);
    }

    @Override
    public void onConnectSessionErrorStage(String rawJsonData) {
        UITools.showAlertDialog(this, "Connect error", this);
    }

    @Override
    public void onConnectSessionFetchingStage(String connectionId, String connectionSecret, String apiStage, String rawJsonData) {
        updateConnectionSecret(connectionSecret);

    }

    @Override
    public void onConnectSessionStageChange(Saltbridge result, String rawJsonData) {
        //TODO
    }

    @Override
    public boolean onRedirectToReturnUrl(String url) {
        UITools.showShortToast(this, R.string.connection_updated);
        if (isOAuthProvider) {
            String connectionSecret = null;
            try {
                Uri uri = Uri.parse(url);
                connectionSecret = URLDecoder.decode(uri.getQueryParameter(KEY_CONNECTION_SECRET), "UTF-8");
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
            updateConnectionSecret(connectionSecret);
        }
        closeActivity(true, null);
        return false;
    }

    /**
     * Error dialog click listener
     *
     * @param dialogInterface - dialog interface
     * @param id - dialog action id
     */
    @Override
    public void onClick(DialogInterface dialogInterface, int id) {
        closeActivity(false, null);
    }

    private ConnectSessionResult connectSessionResult = new ConnectSessionResult() {
        @Override
        public void onSuccess(String connectUrl) {
            try {
                UITools.destroyAlertDialog(progressDialog);
                loadConnectUrl(connectUrl);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onFailure(String errorMessage) {
            handleConnectionError(errorMessage);
        }
    };

    private void setupActionBar() {
        ActionBar actionBar = getSupportActionBar();
        if (actionBar != null) {
            if (isOAuthProvider) {
                actionBar.setTitle(R.string.connecting_oauth);
            } else {
                if (isRefreshConnectionMode()) {
                    actionBar.setTitle(R.string.refreshing);
                } else if (isReconnectConnectionMode()) {
                    actionBar.setTitle(R.string.reconnecting);
                } else {
                    actionBar.setTitle(R.string.connecting);
                }
            }
        }
    }

    private void requestConnectUrl() {
        if (isRefreshConnectionMode()) {
            createRefreshSession();
        } else if (isReconnectConnectionMode()) {
            boolean overrideCredentials = this.getIntent().getBooleanExtra(Constants.KEY_OVERRIDE_CREDENTIALS, false);
            createReconnectSession(overrideCredentials);
        } else {//Create connection
            createConnectSession();
        }
    }

    private boolean isRefreshConnectionMode() {
        return connectionSecret != null && (tryToRefresh != null && tryToRefresh);
    }

    private boolean isReconnectConnectionMode() {
        return connectionSecret != null && (tryToRefresh != null && !tryToRefresh);
    }

    private void createConnectSession() {
        int progressTitle = isOAuthProvider ? R.string.connecting_oauth : R.string.connecting;
        progressDialog = refreshProgressDialog(this, progressDialog, progressTitle);

        String customerSecret = PreferenceRepository.getStringFromPreferences(Constants.KEY_CUSTOMER_SECRET);
        SERequestManager.getInstance().createConnectSession(