001package com.gigya.android.sdk;
002
003import android.annotation.SuppressLint;
004import android.app.Application;
005import android.content.Context;
006import android.support.annotation.NonNull;
007import android.support.annotation.Nullable;
008
009import com.gigya.android.sdk.account.GigyaAccountClass;
010import com.gigya.android.sdk.account.IAccountService;
011import com.gigya.android.sdk.account.models.GigyaAccount;
012import com.gigya.android.sdk.api.GigyaApiResponse;
013import com.gigya.android.sdk.api.IBusinessApiService;
014import com.gigya.android.sdk.containers.GigyaContainer;
015import com.gigya.android.sdk.containers.IoCContainer;
016import com.gigya.android.sdk.interruption.IInterruptionResolverFactory;
017import com.gigya.android.sdk.network.GigyaError;
018import com.gigya.android.sdk.network.adapter.RestAdapter;
019import com.gigya.android.sdk.providers.IProviderFactory;
020import com.gigya.android.sdk.providers.provider.Provider;
021import com.gigya.android.sdk.session.ISessionService;
022import com.gigya.android.sdk.session.ISessionVerificationService;
023import com.gigya.android.sdk.session.SessionInfo;
024import com.gigya.android.sdk.ui.IPresenter;
025import com.gigya.android.sdk.ui.plugin.GigyaPluginFragment;
026import com.gigya.android.sdk.ui.plugin.IGigyaWebBridge;
027
028import java.util.Arrays;
029import java.util.HashMap;
030import java.util.List;
031import java.util.Map;
032import java.util.TreeMap;
033
034/**
035 * Gigya SDK main interface.
036 * Provides access to the Gigya services.
037 *
038 * @param <T> Generic account scheme. Extended from base GigyaAccount model.
039 */
040public class Gigya<T extends GigyaAccount> {
041
042    //region static
043    public static final String VERSION = "4.0.8";
044
045    private static final String LOG_TAG = "Gigya";
046
047    /**
048     * Gigya default api domain.
049     */
050    private static final String DEFAULT_API_DOMAIN = "us1.gigya.com";
051
052    private static IoCContainer CONTAINER;
053
054    public static IoCContainer getContainer() {
055        if (CONTAINER == null) {
056            CONTAINER = new GigyaContainer();
057        }
058        return CONTAINER;
059    }
060
061    public static void setApplication(Application appContext) {
062        getContainer()
063                .bind(Application.class, appContext)
064                .bind(Context.class, appContext);
065    }
066
067    @SuppressLint("StaticFieldLeak")
068    private static Gigya INSTANCE;
069
070    /*
071    Simplified instance getter for use only after calling getInstance(Context context) at least once.
072    */
073    @SuppressWarnings("unchecked")
074    public static synchronized Gigya<? extends GigyaAccount> getInstance() {
075        if (INSTANCE == null) {
076            return getInstance(GigyaAccount.class);
077        }
078        return INSTANCE;
079    }
080
081    /*
082    Generic account type instance getter.
083    */
084    @SuppressWarnings("unchecked")
085    public static synchronized <V extends GigyaAccount> Gigya<V> getInstance(@NonNull Class<V> accountClazz) {
086        if (INSTANCE == null) {
087            IoCContainer container = getContainer();
088            container.bind(GigyaAccountClass.class, new GigyaAccountClass(accountClazz));
089
090            try {
091                INSTANCE = container.createInstance(Gigya.class);
092            } catch (Exception e) {
093                GigyaLogger.error(LOG_TAG, "Error creating Gigya SDK (did you forget to Gigya.setApplication or missing apiKey?)");
094                e.printStackTrace();
095                throw new RuntimeException("Error creating Gigya SDK (did you forget to Gigya.setApplication or missing apiKey?)Error creating Gigya SDK (did you forget to Gigya.setApplication or missing apiKey?)");
096            }
097        }
098        // Check scheme. If already set log an error.
099        final Class schema = INSTANCE.getAccountSchema();
100        if (schema != accountClazz) {
101            GigyaLogger.error(LOG_TAG, "Scheme already set in previous initialization.\nSDK does not allow to override a set scheme.");
102            throw new RuntimeException("Scheme already set in previous initialization.\nSDK does not allow to override a set scheme.");
103        }
104        return INSTANCE;
105    }
106
107    //endregion
108
109    final private Application _context;
110    /**
111     * SDK main configuration structure.
112     */
113    final private Config _config;
114    final private ConfigFactory _configFactory;
115    final private ISessionService _sessionService;
116    final private IAccountService<T> _accountService;
117    final private IBusinessApiService<T> _businessApiService;
118    final private ISessionVerificationService _sessionVerificationService;
119    final private IInterruptionResolverFactory _interruptionResolverFactory;
120    final private IPresenter<T> _presenter;
121    final private IProviderFactory _providerFactory;
122    final private IoCContainer _container;
123
124    protected Gigya(
125            @NonNull Application context,
126            Config config,
127            ConfigFactory configFactory,
128            ISessionService sessionService,
129            IAccountService<T> accountService,
130            IBusinessApiService<T> businessApiService,
131            ISessionVerificationService sessionVerificationService,
132            IInterruptionResolverFactory interruptionsHandler,
133            IPresenter<T> presenter,
134            IProviderFactory providerFactory,
135            IoCContainer container) {
136        // Setup dependencies.
137        _context = context;
138        _config = config;
139        _configFactory = configFactory;
140        _sessionService = sessionService;
141        _accountService = accountService;
142        _businessApiService = businessApiService;
143        _sessionVerificationService = sessionVerificationService;
144        _interruptionResolverFactory = interruptionsHandler;
145        _presenter = presenter;
146        _providerFactory = providerFactory;
147        _container = container;
148
149        // Setup sdk
150        _sessionService.load();
151        init(false);
152
153        // Must be registered following the init call. Dependent on full parsed config.
154        _sessionVerificationService.registerActivityLifecycleCallbacks();
155    }
156
157    //region INITIALIZE
158
159    /**
160     * Explicitly initialize the SDK.
161     * Using this init() method will set the SDK domain to the default "us1.gigya.com"
162     * see {@link #init(String, String)} to explicitly set the required domain.
163     *
164     * @param apiKey Client API-KEY.
165     */
166    @SuppressWarnings("unused")
167    public void init(@NonNull String apiKey) {
168        init(apiKey, DEFAULT_API_DOMAIN);
169    }
170
171    /**
172     * Explicitly initialize the SDK.
173     *
174     * @param apiKey    Client API-KEY
175     * @param apiDomain Request Domain.
176     */
177    public void init(@NonNull String apiKey, @NonNull String apiDomain) {
178        // Override existing configuration when applied explicitly.
179        _config.updateWith(apiKey, apiDomain);
180        init(true);
181    }
182
183    /**
184     * Implicitly initialize the SDK.
185     * Available Options:
186     * - read JSON assets file.
187     * - parse application manifest meta data tags.
188     * For explicit setting see {@link #init(String, String)} method.
189     */
190    private void init(boolean explicit) {
191        // Will load configuration fields only if none have yet to be set.
192        if (_config.getApiKey() == null) {
193            // Try to from assets JSON file,
194            Config dynamicConfig = _configFactory.load();
195            _config.updateWith(dynamicConfig);
196        }
197
198        // Set next account invalidation timestamp if available.
199        if (_config.getAccountCacheTime() != 0) {
200            _accountService.nextAccountInvalidationTimestamp();
201        }
202
203        if (explicit) {
204            if (_config.getApiKey() == null || _config.getApiKey().isEmpty()) {
205                GigyaLogger.error(LOG_TAG, "Failed to set the SDK Api-Key. Please verify you have correctly initialized the SDK.");
206                throw new RuntimeException("Failed to set the SDK Api-Key. Please verify you have correctly initialized the SDK.");
207            }
208        }
209    }
210
211    //endregion
212
213    //region PUBLIC INTERFACING
214
215    public Class<T> getAccountSchema() {
216        return _accountService.getAccountSchema();
217    }
218
219    public Context getContext() {
220        return _context;
221    }
222
223    /**
224     * Update interruption handling.
225     * By default, the Gigya SDK will handle various API interruptions to allow simple resolving of certain common errors.
226     * Setting interruptions to FALSE will force the end user to handle his own errors.
227     *
228     * @param sdkHandles False if manually handling all errors.
229     */
230    public void handleInterruptions(boolean sdkHandles) {
231        _interruptionResolverFactory.setEnabled(sdkHandles);
232    }
233
234    /**
235     * Return SDK interruptions state.
236     * if TRUE, interruption handling will be optional via the GigyaLoginCallback.
237     */
238    public boolean interruptionsEnabled() {
239        return _interruptionResolverFactory.isEnabled();
240    }
241
242    //endregion
243
244    //region ANONYMOUS APIS
245
246    /**
247     * Send request to Gigya servers.
248     *
249     * @param api           Request method identifier.
250     * @param params        Additional parameters.
251     * @param gigyaCallback Response listener callback.
252     */
253    public void send(String api, Map<String, Object> params, GigyaCallback<GigyaApiResponse> gigyaCallback) {
254        _businessApiService.send(api, params, RestAdapter.HttpMethod.GET.intValue(), GigyaApiResponse.class, gigyaCallback);
255    }
256
257    /**
258     * Send a generic type request to Gigya servers.
259     *
260     * @param api           Request method identifier.
261     * @param params        Additional parameters.
262     * @param requestMethod Request method (GET, POST).
263     * @param clazz         Response class scheme.
264     * @param gigyaCallback Response listener callback.
265     */
266    public <V> void send(String api, Map<String, Object> params, int requestMethod, Class<V> clazz, GigyaCallback<V> gigyaCallback) {
267        _businessApiService.send(api, params, requestMethod, clazz, gigyaCallback);
268    }
269
270    //endregion
271
272    //region GIGYA ACCOUNT & SESSION
273
274    /**
275     * Get current session.
276     *
277     * @return SessionInfo instance.
278     */
279    @Nullable
280    public SessionInfo getSession() {
281        return _sessionService.getSession();
282    }
283
284    /**
285     * Manually set the current session.
286     * Setting a session manually will update the current session persistence state and login state.
287     *
288     * @param session SessionInfo instance.
289     */
290    public void setSession(@NonNull SessionInfo session) {
291        _sessionService.setSession(session);
292    }
293
294    /**
295     * Check if we currently have a valid session.
296     */
297    public boolean isLoggedIn() {
298        return _sessionService.isValid();
299    }
300
301    /**
302     * Logout of Gigya services.
303     * This will clean all session related data persistence.
304     */
305    public void logout() {
306        logout(null);
307    }
308
309    /**
310     * Logout of Gigya services.
311     * This will clean all session related data persistence.
312     *
313     * @param gigyaCallback Response listener callback.
314     */
315    public void logout(GigyaCallback<GigyaApiResponse> gigyaCallback) {
316        GigyaLogger.debug(LOG_TAG, "logout: ");
317
318        _businessApiService.logout(gigyaCallback);
319
320        _sessionService.clear(true);
321
322        _sessionVerificationService.stop();
323
324        // Clear presenter related data (cookies).
325        _presenter.clearOnLogout();
326
327        _providerFactory.logoutFromUsedSocialProviders();
328    }
329
330    //endregion
331
332    //region BUSINESS APIS
333
334    /**
335     * Login with provided id and password.
336     *
337     * @param loginId       LoginID.
338     * @param password      Login password.
339     * @param gigyaCallback Response listener callback.
340     */
341    public void login(String loginId, String password, GigyaLoginCallback<T> gigyaCallback) {
342        GigyaLogger.debug(LOG_TAG, "login: with loginId = " + loginId);
343        final Map<String, Object> params = new TreeMap<>();
344        params.put("loginID", loginId);
345        params.put("password", password);
346        login(params, gigyaCallback);
347    }
348
349    /**
350     * Login with given parameters.
351     *
352     * @param params             parameters map.
353     * @param gigyaLoginCallback Login response callback.
354     */
355    public void login(@NonNull Map<String, Object> params, final GigyaLoginCallback<T> gigyaLoginCallback) {
356        GigyaLogger.debug(LOG_TAG, "login: with params = " + params.toString());
357        _businessApiService.login(params, gigyaLoginCallback);
358    }
359
360    /**
361     * Login given a specific 3rd party provider.
362     *
363     * @param socialProvider     Selected providers {@link GigyaDefinitions.Providers.SocialProvider}.
364     * @param params             Parameters map.
365     * @param gigyaLoginCallback Login response callback.
366     */
367    public void login(@GigyaDefinitions.Providers.SocialProvider String socialProvider, Map<String, Object> params, GigyaLoginCallback<T> gigyaLoginCallback) {
368        GigyaLogger.debug(LOG_TAG, "login: with provider = " + socialProvider);
369        _businessApiService.login(socialProvider, params, gigyaLoginCallback);
370    }
371
372    /**
373     * Request account info.
374     *
375     * @param gigyaCallback Response listener callback.
376     */
377    public void getAccount(@NonNull GigyaCallback<T> gigyaCallback) {
378        GigyaLogger.debug(LOG_TAG, "getAccount: ");
379        getAccount(false, gigyaCallback);
380    }
381
382    /**
383     * Request account info.
384     *
385     * @param invalidateCache Should override the account caching option. When set to true, the SDK will not cache the account object.
386     * @param gigyaCallback   Response listener callback.
387     */
388    @SuppressWarnings("unused")
389    public void getAccount(final boolean invalidateCache, GigyaCallback<T> gigyaCallback) {
390        GigyaLogger.debug(LOG_TAG, "getAccount: overrideCache = " + invalidateCache);
391        if (invalidateCache) {
392            _accountService.invalidateAccount();
393        }
394
395        _businessApiService.getAccount(gigyaCallback);
396    }
397
398    /**
399     * Request account info given parameters map.
400     *
401     * @param params        Request parameter map.
402     * @param gigyaCallback Response listener callback.
403     */
404    public void getAccount(@NonNull final Map<String, Object> params, @NonNull GigyaCallback<T> gigyaCallback) {
405        GigyaLogger.debug(LOG_TAG, "getAccount with params:\n" + params.toString());
406        _businessApiService.getAccount(params, gigyaCallback);
407    }
408
409    /**
410     * Request account info given comma separated array of include parameters & comma separated array of profile extra fields.
411     *
412     * @param include            String[]  array.
413     * @param profileExtraFields String[] array.
414     * @param gigyaCallback      Response listener callback.
415     */
416    public void getAccount(@NonNull final String[] include, @NonNull final String[] profileExtraFields, @NonNull GigyaCallback<T> gigyaCallback) {
417        GigyaLogger.debug(LOG_TAG, "getAccount with include:\n" + Arrays.toString(include)
418                + "\nand profileExtraFields:\n" + Arrays.toString(profileExtraFields));
419        _businessApiService.getAccount(include, profileExtraFields, gigyaCallback);
420    }
421
422    /**
423     * Set account info
424     *
425     * @param account       Updated account object.
426     * @param gigyaCallback Response listener callback.
427     */
428    public void setAccount(T account, GigyaCallback<T> gigyaCallback) {
429        GigyaLogger.debug(LOG_TAG, "setAccount: ");
430        _businessApiService.setAccount(account, gigyaCallback);
431    }
432
433    /**
434     * Set account info given update parameters.
435     *
436     * @param params        Updated account parameters.
437     * @param gigyaCallback Response listener callback.
438     */
439    public void setAccount(Map<String, Object> params, GigyaCallback<T> gigyaCallback) {
440        GigyaLogger.debug(LOG_TAG, "setAccount: with params");
441        _businessApiService.setAccount(params, gigyaCallback);
442    }
443
444    /**
445     * Request verify login given account UID/
446     *
447     * @param UID           Account UID identifier.
448     * @param gigyaCallback Response listener callback.
449     */
450    public void verifyLogin(String UID, GigyaCallback<T> gigyaCallback) {
451        GigyaLogger.debug(LOG_TAG, "verifyLogin: for UID = " + UID);
452        _businessApiService.verifyLogin(UID, gigyaCallback);
453    }
454
455    /**
456     * Register account using email and password combination.
457     * Additional parameters are included to allow additional parameters to be added such as profile.
458     *
459     * @param email    User email identifier.
460     * @param password User password.
461     * @param params   Additional parameters.
462     * @param callback Response listener callback.
463     */
464    public void register(String email, String password, @NonNull Map<String, Object> params, GigyaLoginCallback<T> callback) {
465        GigyaLogger.debug(LOG_TAG, "register: with email: " + email + " and params: " + params.toString());
466        params.put("email", email);
467        params.put("password", password);
468        _businessApiService.register(params, callback);
469    }
470
471    /**
472     * Register account using email and password combination.
473     *
474     * @param email    User email identifier.
475     * @param password User password.
476     * @param callback Response listener callback.
477     */
478    public void register(String email, String password, GigyaLoginCallback<T> callback) {
479        GigyaLogger.debug(LOG_TAG, "register: with email: " + email);
480        final Map<String, Object> params = new HashMap<>();
481        register(email, password, params, callback);
482    }
483
484    /**
485     * Send a reset email password to verified email attached to the users loginId.
486     *
487     * @param loginId       User login id.
488     * @param gigyaCallback Response listener callback.
489     */
490    public void forgotPassword(String loginId, GigyaCallback<GigyaApiResponse> gigyaCallback) {
491        final Map<String, Object> params = new HashMap<>();
492        params.put("loginID", loginId);
493        forgotPassword(params, gigyaCallback);
494    }
495
496    /**
497     * Send a reset email password to verified email attached to the users loginId.
498     *
499     * @param params        Parameter map.
500     * @param gigyaCallback Response listener callback.
501     * @see <a href="https://developers.gigya.com/display/GD/accounts.resetPassword+REST">accounts.resetPassword REST</a> for available parameters.
502     */
503    public void forgotPassword(@NonNull Map<String, Object> params, GigyaCallback<GigyaApiResponse> gigyaCallback) {
504        GigyaLogger.debug(LOG_TAG, "forgotPassword: with given parameters " + params.toString());
505        _businessApiService.forgotPassword(params, gigyaCallback);
506    }
507
508    /**
509     * Add a social connection to existing account.
510     *
511     * @param socialProvider Social provider identifier.
512     * @param loginCallback  Response listener callback.
513     */
514    public void addConnection(@GigyaDefinitions.Providers.SocialProvider String socialProvider, GigyaLoginCallback<T> loginCallback) {
515        GigyaLogger.debug(LOG_TAG, "addConnection: with " + socialProvider);
516        _businessApiService.addConnection(socialProvider, loginCallback);
517    }
518
519    /**
520     * Remove a social connection from an existing account.
521     *
522     * @param socialProvider Social provider identifier.
523     * @param gigyaCallback  Response listener callback.
524     */
525    public void removeConnection(@GigyaDefinitions.Providers.SocialProvider String socialProvider, GigyaCallback<GigyaApiResponse> gigyaCallback) {
526        GigyaLogger.debug(LOG_TAG, "removeConnection: with " + socialProvider);
527        _businessApiService.removeConnection(socialProvider, gigyaCallback);
528    }
529
530    /**
531     * Login to with social provider when the provider session is available (obtained via specific provider login process).
532     *
533     * @param params             Parameter map.
534     * @param gigyaLoginCallback Response listener callback.
535     */
536    public void notifySocialLogin(@NonNull Map<String, Object> params, GigyaLoginCallback<T> gigyaLoginCallback) {
537        GigyaLogger.debug(LOG_TAG, "notifySocialLogin: with parameters: " + params.toString());
538        _businessApiService.notifyNativeSocialLogin(params, gigyaLoginCallback, null);
539    }
540
541    //endregion
542
543    //region NATIVE LOGIN
544
545    /**
546     * Request reference to used Gigya social provider.
547     * Currently supported provider (GOOGLE, FACEBOOK, LINE, WECHAT).
548     *
549     * @param name Provider name.
550     * @return Provider reference or null if not available.
551     */
552    @Nullable
553    public Provider getUsedSocialProvider(String name) {
554        return _providerFactory.usedProviderFor(name);
555    }
556
557    /**
558     * Present social login selection list.
559     *
560     * @param providers          List of selected social providers {@link GigyaDefinitions.Providers.SocialProvider}.
561     * @param params             Request parameters.
562     * @param gigyaLoginCallback Login response callback.
563     */
564    public void socialLoginWith(@GigyaDefinitions.Providers.SocialProvider List<String> providers,
565                                @NonNull Map<String, Object> params, final GigyaLoginCallback<T> gigyaLoginCallback) {
566        GigyaLogger.debug(LOG_TAG, "socialLoginWith: with parameters:\n" + params.toString());
567        _presenter.showNativeLoginProviders(providers, _businessApiService, params, gigyaLoginCallback);
568    }
569
570    //endregion
571
572    //region PLUGINS
573
574    /**
575     * Show Gigya ScreenSets flow using the PluginFragment.
576     * UI will be presented via WebView.
577     *
578     * @param screensSet          Main ScreensSet group identifier
579     * @param fullScreen          Show in fullscreen mode.
580     * @param params              ScreensSet flow parameters.
581     * @param gigyaPluginCallback Plugin callback.
582     */
583    public void showScreenSet(final String screensSet, boolean fullScreen, @NonNull final Map<String, Object> params, final GigyaPluginCallback<T> gigyaPluginCallback) {
584        params.put("screenSet", screensSet);
585        GigyaLogger.debug(LOG_TAG, "showPlugin: " + GigyaPluginFragment.PLUGIN_SCREENSETS + ", with parameters:\n" + params.toString());
586        _presenter.showPlugin(false, GigyaPluginFragment.PLUGIN_SCREENSETS, fullScreen, params, gigyaPluginCallback);
587    }
588
589    /**
590     * Update device information in server.
591     * Device information includes: platform, manufacturer, os & push token.
592     * Use this method manually if your flow requires to update the push service token.
593     * Additional device info is generated at runtime.
594     *
595     * @param newPushToken New provided push token.
596     */
597    public void updateDeviceInfo(@NonNull final String newPushToken) {
598        _businessApiService.updateDevice(newPushToken, new GigyaCallback<GigyaApiResponse>() {
599            @Override
600            public void onSuccess(GigyaApiResponse obj) {
601                GigyaLogger.debug(LOG_TAG, "Successfully update push token. Persisting new token");
602            }
603
604            @Override
605            public void onError(GigyaError error) {
606                GigyaLogger.debug(LOG_TAG, "Failed to update device info.");
607            }
608        });
609    }
610
611    /**
612     * Create an new instance of the GigyaWebBridge.
613     *
614     * @return GigyaWebBridge instance.
615     */
616    @SuppressWarnings("unchecked")
617    public IGigyaWebBridge<T> createWebBridge() {
618        try {
619            return _container.get(IGigyaWebBridge.class);
620        } catch (Exception ex) {
621            ex.printStackTrace();
622            GigyaLogger.error(LOG_TAG, "Exception creating new WebBridge instance");
623        }
624        return null;
625    }
626
627    //endregion
628}