package com.arcao.trackables.data.service; import android.content.SharedPreferences; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import com.arcao.geocaching.api.GeocachingApi; import com.arcao.geocaching.api.data.DeviceInfo; import com.arcao.geocaching.api.data.UserProfile; import com.arcao.geocaching.api.data.type.MemberType; import com.arcao.geocaching.api.exception.GeocachingApiException; import org.scribe.model.Token; import org.scribe.model.Verifier; import org.scribe.oauth.OAuthService; import javax.inject.Inject; import javax.inject.Named; import javax.inject.Provider; import javax.inject.Singleton; import rx.Observable; import timber.log.Timber; @Singleton public class AccountService { private static final String PREF__USER_NAME = "USER_NAME"; private static final String PREF__ACCESS_TOKEN = "ACCESS_TOKEN"; private static final String PREF__MEMBER_TYPE = "MEMBER_TYPE"; private static final String PREF__AVATAR_URL = "AVATAR_URL"; private static final String PREF__OAUTH_TOKEN_FORMAT = "OAUTH_TOKEN_%s"; private final SharedPreferences mSharedPreferences; private final GeocachingApi geocachingApi; private final Provider<OAuthService> oAuthServiceProvider; private final Provider<DeviceInfo> deviceInfoProvider; @Inject public AccountService(@Named("AccountSharedPreference") SharedPreferences mSharedPreferences, GeocachingApi geocachingApi, Provider<OAuthService> oAuthServiceProvider, Provider<DeviceInfo> deviceInfoProvider) { this.mSharedPreferences = mSharedPreferences; this.geocachingApi = geocachingApi; this.oAuthServiceProvider = oAuthServiceProvider; this.deviceInfoProvider = deviceInfoProvider; login(); } private void login() { try { if (isAccount()) geocachingApi.openSession(getAccessToken()); } catch (GeocachingApiException e) { Timber.e(e.getMessage(), e); } } public void logout() { geocachingApi.closeSession(); mSharedPreferences.edit() .remove(PREF__USER_NAME) .remove(PREF__ACCESS_TOKEN) .remove(PREF__MEMBER_TYPE) .remove(PREF__AVATAR_URL) .apply(); } public boolean isAccount() { return getMemberType() != MemberType.Guest; } @Nullable public String getUserName() { return mSharedPreferences.getString(PREF__USER_NAME, null); } @Nullable public String getAvatarUrl() { return mSharedPreferences.getString(PREF__AVATAR_URL, null); } @NonNull public MemberType getMemberType() { if (getUserName() == null || getAccessToken() == null) return MemberType.Guest; return MemberType.getById(mSharedPreferences.getInt(PREF__MEMBER_TYPE, MemberType.Guest.getId())); } public Observable<String> startOAuthLogin() { return Observable.create(subscriber -> { OAuthService oAuthService = oAuthServiceProvider.get(); Token requestToken = oAuthService.getRequestToken(); storeOAuthRequestToken(requestToken); String authUrl = oAuthService.getAuthorizationUrl(requestToken); Timber.i("AuthorizationUrl: " + authUrl); subscriber.onNext(authUrl); subscriber.onCompleted(); }); } public Observable<Void> finishOAuthLogin(String verifier) { return Observable.create(subscriber -> { try { OAuthService oAuthService = oAuthServiceProvider.get(); Token requestToken = loadOAuthRequestToken(); Token accessToken = oAuthService.getAccessToken(requestToken, new Verifier(verifier)); // get account name geocachingApi.openSession(accessToken.getToken()); UserProfile userProfile = geocachingApi.getYourUserProfile(false, false, false, false, false, false, deviceInfoProvider.get()); // add account if (isAccount()) { logout(); } addAccount( userProfile.getUser().getUserName(), geocachingApi.getSession(), userProfile.getUser().getAvatarUrl(), userProfile.getUser().getMemberType() ); removeOAuthRequestToken(); login(); subscriber.onCompleted(); } catch (Exception e) { subscriber.onError(e); } }); } // ---------- helper methods ------------- private void addAccount(@NonNull String userName, @NonNull String accessToken, @Nullable String avatarUrl, @NonNull MemberType memberType) { mSharedPreferences.edit() .putString(PREF__USER_NAME, userName) .putString(PREF__ACCESS_TOKEN, accessToken) .putString(PREF__AVATAR_URL, avatarUrl) .putInt(PREF__MEMBER_TYPE, memberType.getId()) .apply(); } private void storeOAuthRequestToken(@NonNull Token token) { mSharedPreferences.edit() .putString(String.format(PREF__OAUTH_TOKEN_FORMAT, 0), token.getToken()) .putString(String.format(PREF__OAUTH_TOKEN_FORMAT, 1), token.getSecret()) .putString(String.format(PREF__OAUTH_TOKEN_FORMAT, 2), token.getRawResponse()) .apply(); } private void removeOAuthRequestToken() { mSharedPreferences.edit() .remove(String.format(PREF__OAUTH_TOKEN_FORMAT, 0)) .remove(String.format(PREF__OAUTH_TOKEN_FORMAT, 1)) .remove(String.format(PREF__OAUTH_TOKEN_FORMAT, 2)) .apply(); } @NonNull private Token loadOAuthRequestToken() { String token = mSharedPreferences.getString(String.format(PREF__OAUTH_TOKEN_FORMAT, 0), ""); String secret = mSharedPreferences.getString(String.format(PREF__OAUTH_TOKEN_FORMAT, 1), ""); String rawResponse = mSharedPreferences.getString(String.format(PREF__OAUTH_TOKEN_FORMAT, 2), ""); return new Token(token, secret, rawResponse); } @Nullable private String getAccessToken() { return mSharedPreferences.getString(PREF__ACCESS_TOKEN, null); } }