From 4d0a0725c93f84e3282b16554a950fbf83813d43 Mon Sep 17 00:00:00 2001 From: Alex Ning Date: Sun, 14 Oct 2018 11:24:38 +0800 Subject: Use OkHttp3 Authenticator instead of OkHttp Interceptor to handle the case when the request fails with code 401. Refresh the access token in a synchronized block to avoid getting more than one access tokens and getting duplicate posts when performing multiple unauthorized requests. Minor bugs fixed. --- .../AccessTokenAuthenticator.java | 43 ++++++++++++ .../CommentMultiLevelRecyclerViewAdapter.java | 22 +++--- .../infinityforreddit/FetchSubscribedThing.java | 30 ++------ .../infinityforreddit/FetchUserInfo.java | 23 ++---- .../infinityforreddit/Infinity.java | 4 +- .../infinityforreddit/MainActivity.java | 43 ++++-------- .../infinityforreddit/NetworkModule.java | 32 +++++++-- .../infinityforreddit/OkHttpInterceptor.java | 48 ------------- .../infinityforreddit/PostFragment.java | 49 +++++-------- .../PostPaginationScrollListener.java | 24 +------ .../infinityforreddit/PostRecyclerViewAdapter.java | 82 +++++++++++----------- .../infinityforreddit/RedditUtils.java | 1 - .../infinityforreddit/RefreshAccessToken.java | 75 +++++++------------- .../infinityforreddit/ViewPostDetailActivity.java | 28 ++++---- .../infinityforreddit/VoteThing.java | 53 +++----------- 15 files changed, 221 insertions(+), 336 deletions(-) create mode 100644 app/src/main/java/ml/docilealligator/infinityforreddit/AccessTokenAuthenticator.java delete mode 100644 app/src/main/java/ml/docilealligator/infinityforreddit/OkHttpInterceptor.java (limited to 'app/src/main/java/ml/docilealligator') diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/AccessTokenAuthenticator.java b/app/src/main/java/ml/docilealligator/infinityforreddit/AccessTokenAuthenticator.java new file mode 100644 index 00000000..595eb958 --- /dev/null +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/AccessTokenAuthenticator.java @@ -0,0 +1,43 @@ +package ml.docilealligator.infinityforreddit; + +import android.content.SharedPreferences; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; + +import java.io.IOException; + +import okhttp3.Authenticator; +import okhttp3.Headers; +import okhttp3.Request; +import okhttp3.Response; +import okhttp3.Route; + +class AccessTokenAuthenticator implements Authenticator { + private SharedPreferences mAuthInfoSharedPreferences; + + AccessTokenAuthenticator(SharedPreferences authInfoSharedPreferences) { + mAuthInfoSharedPreferences = authInfoSharedPreferences; + } + + @Nullable + @Override + public Request authenticate(@NonNull Route route, @NonNull Response response) throws IOException { + if (response.code() == 401) { + String accessToken = response.request().header(RedditUtils.AUTHORIZATION_KEY).substring(RedditUtils.AUTHORIZATION_BASE.length()); + synchronized (this) { + String accessTokenFromSharedPreferences = mAuthInfoSharedPreferences.getString(SharedPreferencesUtils.ACCESS_TOKEN_KEY, ""); + if (accessToken.equals(accessTokenFromSharedPreferences)) { + String newAccessToken = RefreshAccessToken.refreshAccessToken(mAuthInfoSharedPreferences); + if (!newAccessToken.equals("")) { + return response.request().newBuilder().headers(Headers.of(RedditUtils.getOAuthHeader(newAccessToken))).build(); + } else { + return null; + } + } else { + return response.request().newBuilder().headers(Headers.of(RedditUtils.getOAuthHeader(accessTokenFromSharedPreferences))).build(); + } + } + } + return null; + } +} diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/CommentMultiLevelRecyclerViewAdapter.java b/app/src/main/java/ml/docilealligator/infinityforreddit/CommentMultiLevelRecyclerViewAdapter.java index 71817ab3..41864d3b 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/CommentMultiLevelRecyclerViewAdapter.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/CommentMultiLevelRecyclerViewAdapter.java @@ -1,6 +1,7 @@ package ml.docilealligator.infinityforreddit; import android.content.Context; +import android.content.SharedPreferences; import android.graphics.ColorFilter; import android.support.annotation.NonNull; import android.support.v4.content.ContextCompat; @@ -29,19 +30,22 @@ class CommentMultiLevelRecyclerViewAdapter extends MultiLevelAdapter { private Context mContext; private Retrofit mRetrofit; private Retrofit mOauthRetrofit; + private SharedPreferences mSharedPreferences; private ArrayList mCommentData; private MultiLevelRecyclerView mMultiLevelRecyclerView; private String subredditNamePrefixed; private String article; private Locale locale; - CommentMultiLevelRecyclerViewAdapter(Context context, Retrofit retrofit, Retrofit oauthRetrofit, ArrayList commentData, + CommentMultiLevelRecyclerViewAdapter(Context context, Retrofit retrofit, Retrofit oauthRetrofit, + SharedPreferences sharedPreferences, ArrayList commentData, MultiLevelRecyclerView multiLevelRecyclerView, String subredditNamePrefixed, String article, Locale locale) { super(commentData); mContext = context; mRetrofit = retrofit; mOauthRetrofit = oauthRetrofit; + mSharedPreferences = sharedPreferences; mCommentData = commentData; mMultiLevelRecyclerView = multiLevelRecyclerView; this.subredditNamePrefixed = subredditNamePrefixed; @@ -136,7 +140,7 @@ class CommentMultiLevelRecyclerViewAdapter extends MultiLevelAdapter { ((CommentViewHolder) holder).scoreTextView.setText(Integer.toString(commentItem.getScore() + 1)); } - VoteThing.voteThing(mContext, mOauthRetrofit, new VoteThing.VoteThingListener() { + VoteThing.voteThing(mOauthRetrofit,mSharedPreferences, new VoteThing.VoteThingListener() { @Override public void onVoteThingSuccess(int position) { commentItem.setVoteType(1); @@ -154,13 +158,13 @@ class CommentMultiLevelRecyclerViewAdapter extends MultiLevelAdapter { ((CommentViewHolder) holder).scoreTextView.setText(Integer.toString(commentItem.getScore())); ((CommentViewHolder) holder).downvoteButton.setColorFilter(minusButtonColorFilter); } - }, commentItem.getFullName(), RedditUtils.DIR_UPVOTE, ((CommentViewHolder) holder).getAdapterPosition(), 1); + }, commentItem.getFullName(), RedditUtils.DIR_UPVOTE, ((CommentViewHolder) holder).getAdapterPosition()); } else { //Upvoted before ((CommentViewHolder) holder).upvoteButton.clearColorFilter(); ((CommentViewHolder) holder).scoreTextView.setText(Integer.toString(commentItem.getScore() - 1)); - VoteThing.voteThing(mContext, mOauthRetrofit, new VoteThing.VoteThingListener() { + VoteThing.voteThing(mOauthRetrofit, mSharedPreferences, new VoteThing.VoteThingListener() { @Override public void onVoteThingSuccess(int position) { commentItem.setVoteType(0); @@ -174,7 +178,7 @@ class CommentMultiLevelRecyclerViewAdapter extends MultiLevelAdapter { ((CommentViewHolder) holder).upvoteButton.setColorFilter(ContextCompat.getColor(mContext, R.color.colorPrimary), android.graphics.PorterDuff.Mode.SRC_IN); commentItem.setScore(commentItem.getScore() + 1); } - }, commentItem.getFullName(), RedditUtils.DIR_UNVOTE, ((CommentViewHolder) holder).getAdapterPosition(), 1); + }, commentItem.getFullName(), RedditUtils.DIR_UNVOTE, ((CommentViewHolder) holder).getAdapterPosition()); } } }); @@ -195,7 +199,7 @@ class CommentMultiLevelRecyclerViewAdapter extends MultiLevelAdapter { ((CommentViewHolder) holder).scoreTextView.setText(Integer.toString(commentItem.getScore() - 1)); } - VoteThing.voteThing(mContext, mOauthRetrofit, new VoteThing.VoteThingListener() { + VoteThing.voteThing(mOauthRetrofit, mSharedPreferences, new VoteThing.VoteThingListener() { @Override public void onVoteThingSuccess(int position) { commentItem.setVoteType(-1); @@ -213,13 +217,13 @@ class CommentMultiLevelRecyclerViewAdapter extends MultiLevelAdapter { ((CommentViewHolder) holder).scoreTextView.setText(Integer.toString(commentItem.getScore())); ((CommentViewHolder) holder).upvoteButton.setColorFilter(upvoteButtonColorFilter); } - }, commentItem.getFullName(), RedditUtils.DIR_DOWNVOTE, holder.getAdapterPosition(), 1); + }, commentItem.getFullName(), RedditUtils.DIR_DOWNVOTE, holder.getAdapterPosition()); } else { //Down voted before ((CommentViewHolder) holder).downvoteButton.clearColorFilter(); ((CommentViewHolder) holder).scoreTextView.setText(Integer.toString(commentItem.getScore() + 1)); - VoteThing.voteThing(mContext, mOauthRetrofit, new VoteThing.VoteThingListener() { + VoteThing.voteThing(mOauthRetrofit, mSharedPreferences, new VoteThing.VoteThingListener() { @Override public void onVoteThingSuccess(int position) { commentItem.setVoteType(0); @@ -233,7 +237,7 @@ class CommentMultiLevelRecyclerViewAdapter extends MultiLevelAdapter { ((CommentViewHolder) holder).scoreTextView.setText(Integer.toString(commentItem.getScore())); commentItem.setScore(commentItem.getScore()); } - }, commentItem.getFullName(), RedditUtils.DIR_UNVOTE, holder.getAdapterPosition(), 1); + }, commentItem.getFullName(), RedditUtils.DIR_UNVOTE, holder.getAdapterPosition()); } } }); diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/FetchSubscribedThing.java b/app/src/main/java/ml/docilealligator/infinityforreddit/FetchSubscribedThing.java index bbb7edbb..cfda92de 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/FetchSubscribedThing.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/FetchSubscribedThing.java @@ -1,6 +1,6 @@ package ml.docilealligator.infinityforreddit; -import android.content.Context; +import android.content.SharedPreferences; import android.support.annotation.NonNull; import android.util.Log; @@ -19,20 +19,15 @@ class FetchSubscribedThing { void onFetchSubscribedThingFail(); } - static void fetchSubscribedThing(final Context context, final Retrofit retrofit, final String lastItem, + static void fetchSubscribedThing(final Retrofit retrofit, final SharedPreferences sharedPreferences, + final String lastItem, final ArrayList subscribedSubredditData, final ArrayList subscribedUserData, final ArrayList subredditData, - final FetchSubscribedThingListener fetchSubscribedThingListener, final int refreshTime) { - if(refreshTime < 0) { - fetchSubscribedThingListener.onFetchSubscribedThingFail(); - return; - } - + final FetchSubscribedThingListener fetchSubscribedThingListener) { RedditAPI api = retrofit.create(RedditAPI.class); - String accessToken = context.getSharedPreferences(SharedPreferencesUtils.AUTH_CODE_FILE_KEY, Context.MODE_PRIVATE) - .getString(SharedPreferencesUtils.ACCESS_TOKEN_KEY, ""); + String accessToken = sharedPreferences.getString(SharedPreferencesUtils.ACCESS_TOKEN_KEY, ""); Call subredditDataCall = api.getSubscribedThing(lastItem, RedditUtils.getOAuthHeader(accessToken)); subredditDataCall.enqueue(new Callback() { @@ -52,9 +47,9 @@ class FetchSubscribedThing { fetchSubscribedThingListener.onFetchSubscribedThingSuccess( subscribedSubredditData, subscribedUserData, subredditData); } else { - fetchSubscribedThing(context, retrofit, lastItem, subscribedSubredditData, + fetchSubscribedThing(retrofit, sharedPreferences, lastItem, subscribedSubredditData, subscribedUserData, subredditData, - fetchSubscribedThingListener, refreshTime); + fetchSubscribedThingListener); } } @@ -63,17 +58,6 @@ class FetchSubscribedThing { fetchSubscribedThingListener.onFetchSubscribedThingFail(); } }); - } else if(response.code() == 401) { - RefreshAccessToken.refreshAccessToken(context, new RefreshAccessToken.RefreshAccessTokenListener() { - @Override - public void onRefreshAccessTokenSuccess() { - fetchSubscribedThing(context, retrofit, lastItem, subscribedSubredditData, - subscribedUserData, subredditData, fetchSubscribedThingListener, refreshTime - 1); - } - - @Override - public void onRefreshAccessTokenFail() {} - }); } else { Log.i("call failed", response.message()); fetchSubscribedThingListener.onFetchSubscribedThingFail(); diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/FetchUserInfo.java b/app/src/main/java/ml/docilealligator/infinityforreddit/FetchUserInfo.java index 0a7b323d..bddfc14e 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/FetchUserInfo.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/FetchUserInfo.java @@ -1,6 +1,6 @@ package ml.docilealligator.infinityforreddit; -import android.content.Context; +import android.content.SharedPreferences; import android.support.annotation.NonNull; import android.util.Log; @@ -15,32 +15,17 @@ class FetchUserInfo { void onFetchUserInfoFail(); } - static void fetchUserInfo(final Retrofit retrofit, final Context context, final FetchUserInfoListener fetchUserInfoListener, final int refreshTime) { - if(refreshTime < 0) { - fetchUserInfoListener.onFetchUserInfoFail(); - return; - } - + static void fetchUserInfo(final Retrofit retrofit, SharedPreferences authInfoSharedPreferences, + final FetchUserInfoListener fetchUserInfoListener) { RedditAPI api = retrofit.create(RedditAPI.class); - String accessToken = context.getSharedPreferences(SharedPreferencesUtils.AUTH_CODE_FILE_KEY, Context.MODE_PRIVATE) - .getString(SharedPreferencesUtils.ACCESS_TOKEN_KEY, ""); + String accessToken = authInfoSharedPreferences.getString(SharedPreferencesUtils.ACCESS_TOKEN_KEY, ""); Call userInfo = api.getUserInfo(RedditUtils.getOAuthHeader(accessToken)); userInfo.enqueue(new Callback() { @Override public void onResponse(@NonNull Call call, @NonNull retrofit2.Response response) { if(response.isSuccessful()) { fetchUserInfoListener.onFetchUserInfoSuccess(response.body()); - } else if(response.code() == 401){ - RefreshAccessToken.refreshAccessToken(context, new RefreshAccessToken.RefreshAccessTokenListener() { - @Override - public void onRefreshAccessTokenSuccess() { - fetchUserInfo(retrofit, context, fetchUserInfoListener, refreshTime - 1); - } - - @Override - public void onRefreshAccessTokenFail() {} - }); } else { Log.i("call failed", response.message()); fetchUserInfoListener.onFetchUserInfoFail(); diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/Infinity.java b/app/src/main/java/ml/docilealligator/infinityforreddit/Infinity.java index b427860d..1309bfdb 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/Infinity.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/Infinity.java @@ -9,7 +9,9 @@ public class Infinity extends Application { public void onCreate() { super.onCreate(); - mNetworkComponent = DaggerNetworkComponent.create(); + mNetworkComponent = DaggerNetworkComponent.builder() + .networkModule(new NetworkModule(this)) + .build(); } public NetworkComponent getmNetworkComponent() { diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/MainActivity.java b/app/src/main/java/ml/docilealligator/infinityforreddit/MainActivity.java index 9fd21a68..f0cc810c 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/MainActivity.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/MainActivity.java @@ -26,7 +26,6 @@ import com.bumptech.glide.Glide; import com.bumptech.glide.RequestManager; import java.util.ArrayList; -import java.util.Calendar; import java.util.List; import javax.inject.Inject; @@ -65,8 +64,13 @@ public class MainActivity extends AppCompatActivity { private SubscribedSubredditViewModel mSubscribedSubredditViewModel; private SubscribedUserViewModel mSubscribedUserViewModel; - @Inject - @Named("oauth") + @Inject @Named("user_info") + SharedPreferences mUserInfoSharedPreferences; + + @Inject @Named("auth_info") + SharedPreferences mAuthInfoSharedPreferences; + + @Inject @Named("oauth") Retrofit mOauthRetrofit; @Override @@ -101,28 +105,7 @@ public class MainActivity extends AppCompatActivity { getSupportFragmentManager().beginTransaction().replace(R.id.frame_layout_content_main, mFragment).commit(); } - Calendar now = Calendar.getInstance(); - Calendar queryAccessTokenTime = Calendar.getInstance(); - queryAccessTokenTime.setTimeInMillis(getSharedPreferences(SharedPreferencesUtils.AUTH_CODE_FILE_KEY, Context.MODE_PRIVATE) - .getLong(SharedPreferencesUtils.QUERY_ACCESS_TOKEN_TIME_KEY, 0)); - int interval = getSharedPreferences(SharedPreferencesUtils.AUTH_CODE_FILE_KEY, Context.MODE_PRIVATE) - .getInt(SharedPreferencesUtils.ACCESS_TOKEN_EXPIRE_INTERVAL_KEY, 0); - queryAccessTokenTime.add(Calendar.SECOND, interval - 300); - - if(now.after(queryAccessTokenTime)) { - RefreshAccessToken.refreshAccessToken(this, - new RefreshAccessToken.RefreshAccessTokenListener() { - @Override - public void onRefreshAccessTokenSuccess() { - loadUserData(savedInstanceState); - } - - @Override - public void onRefreshAccessTokenFail() {} - }); - } else { - loadUserData(savedInstanceState); - } + loadUserData(savedInstanceState); View header = findViewById(R.id.nav_header_main_activity); mNameTextView = header.findViewById(R.id.name_text_view_nav_header_main); @@ -191,7 +174,7 @@ public class MainActivity extends AppCompatActivity { private void loadUserData(Bundle savedInstanceState) { if (savedInstanceState == null) { if (!mFetchUserInfoSuccess) { - FetchUserInfo.fetchUserInfo(mOauthRetrofit, this, new FetchUserInfo.FetchUserInfoListener() { + FetchUserInfo.fetchUserInfo(mOauthRetrofit, mAuthInfoSharedPreferences, new FetchUserInfo.FetchUserInfoListener() { @Override public void onFetchUserInfoSuccess(String response) { ParseUserInfo.parseUserInfo(response, new ParseUserInfo.ParseUserInfoListener() { @@ -212,7 +195,7 @@ public class MainActivity extends AppCompatActivity { mKarmaTextView.setText(mKarma); - SharedPreferences.Editor editor = getSharedPreferences(SharedPreferencesUtils.USER_INFO_FILE_KEY, Context.MODE_PRIVATE).edit(); + SharedPreferences.Editor editor = mUserInfoSharedPreferences.edit(); editor.putString(SharedPreferencesUtils.USER_KEY, name); editor.putString(SharedPreferencesUtils.PROFILE_IMAGE_URL_KEY, profileImageUrl); editor.putString(SharedPreferencesUtils.BANNER_IMAGE_URL_KEY, bannerImageUrl); @@ -232,11 +215,11 @@ public class MainActivity extends AppCompatActivity { public void onFetchUserInfoFail() { mFetchUserInfoSuccess = false; } - }, 1); + }); } if (!mInsertSuccess) { - FetchSubscribedThing.fetchSubscribedThing(this, mOauthRetrofit, null, + FetchSubscribedThing.fetchSubscribedThing(mOauthRetrofit, mAuthInfoSharedPreferences, null, new ArrayList(), new ArrayList(), new ArrayList(), new FetchSubscribedThing.FetchSubscribedThingListener() { @@ -263,7 +246,7 @@ public class MainActivity extends AppCompatActivity { public void onFetchSubscribedThingFail() { mInsertSuccess = false; } - }, 1); + }); } } } diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/NetworkModule.java b/app/src/main/java/ml/docilealligator/infinityforreddit/NetworkModule.java index 7371ec39..f157bf4d 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/NetworkModule.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/NetworkModule.java @@ -1,5 +1,9 @@ package ml.docilealligator.infinityforreddit; +import android.app.Application; +import android.content.Context; +import android.content.SharedPreferences; + import javax.inject.Named; import javax.inject.Singleton; @@ -11,11 +15,18 @@ import retrofit2.converter.scalars.ScalarsConverterFactory; @Module class NetworkModule { + Application mApplication; + + public NetworkModule(Application application) { + mApplication = application; + } + @Provides @Named("oauth") @Singleton - Retrofit provideOauthRetrofit() { + Retrofit provideOauthRetrofit(OkHttpClient okHttpClient) { return new Retrofit.Builder() .baseUrl(RedditUtils.OAUTH_API_BASE_URI) + .client(okHttpClient) .addConverterFactory(ScalarsConverterFactory.create()) .build(); } @@ -31,9 +42,20 @@ class NetworkModule { @Provides @Singleton - OkHttpClient provideOkHttpClient() { - OkHttpClient okHttpClient = new OkHttpClient(); - okHttpClient.interceptors().add(new OkHttpInterceptor()); - return okHttpClient; + OkHttpClient provideOkHttpClient(@Named("auth_info") SharedPreferences sharedPreferences) { + OkHttpClient.Builder okHttpClientBuilder = new OkHttpClient.Builder(); + okHttpClientBuilder.authenticator(new AccessTokenAuthenticator(sharedPreferences)); + return okHttpClientBuilder.build(); + } + + @Provides @Named("auth_info") + @Singleton + SharedPreferences provideAuthInfoSharedPreferences() { + return mApplication.getSharedPreferences(SharedPreferencesUtils.AUTH_CODE_FILE_KEY, Context.MODE_PRIVATE); + } + + @Provides @Named("user_info") + SharedPreferences provideUserInfoSharedPreferences() { + return mApplication.getSharedPreferences(SharedPreferencesUtils.USER_INFO_FILE_KEY, Context.MODE_PRIVATE); } } diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/OkHttpInterceptor.java b/app/src/main/java/ml/docilealligator/infinityforreddit/OkHttpInterceptor.java deleted file mode 100644 index 2f341d2c..00000000 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/OkHttpInterceptor.java +++ /dev/null @@ -1,48 +0,0 @@ -package ml.docilealligator.infinityforreddit; - -import java.io.IOException; - -import okhttp3.Interceptor; -import okhttp3.Response; - -class OkHttpInterceptor implements Interceptor { - @Override - public Response intercept(Chain chain) throws IOException { - /*Request request = chain.request(); - - //Build new request - Request.Builder builder = request.newBuilder(); - builder.header("Accept", "application/json"); //if necessary, say to consume JSON - - String token = settings.getAccessToken(); //save token of this request for future - setAuthHeader(builder, token); //write current token to request - - request = builder.build(); //overwrite old request - Response response = chain.proceed(request); //perform request, here original request will be executed - - if (response.code() == 401) { //if unauthorized - synchronized (this) { //perform all 401 in sync blocks, to avoid multiply token updates - String currentToken = settings.getAccessToken(); //get currently stored token - - if(currentToken != null && currentToken.equals(token)) { //compare current token with token that was stored before, if it was not updated - do update - - int code = refreshToken() / 100; //refresh token - if(code != 2) { //if refresh token failed for some reason - if(code == 4) //only if response is 400, 500 might mean that token was not updated - logout(); //go to login screen - return response; //if token refresh failed - show error to user - } - } - - if(settings.getAccessToken() != null) { //retry requires new auth token, - setAuthHeader(builder, settings.getAccessToken()); //set auth token to updated - request = builder.build(); - return chain.proceed(request); //repeat request with new token - } - } - } - - return response;*/ - return null; - } -} diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/PostFragment.java b/app/src/main/java/ml/docilealligator/infinityforreddit/PostFragment.java index 6e6486f0..3d2c6e7b 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/PostFragment.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/PostFragment.java @@ -4,6 +4,7 @@ package ml.docilealligator.infinityforreddit; import android.content.ClipData; import android.content.ClipboardManager; import android.content.Context; +import android.content.SharedPreferences; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.design.widget.CoordinatorLayout; @@ -58,15 +59,15 @@ public class PostFragment extends Fragment implements FragmentCommunicator { private boolean mIsBestPost; private String mSubredditName; - @Inject - @Named("no_oauth") + @Inject @Named("no_oauth") Retrofit mRetrofit; - @Inject - @Named("oauth") + @Inject @Named("oauth") Retrofit mOauthRetrofit; - @Inject + @Inject @Named("auth_info") + SharedPreferences mSharedPreferences; + public PostFragment() { // Required empty public constructor } @@ -122,7 +123,7 @@ public class PostFragment extends Fragment implements FragmentCommunicator { @Override public void onClick(View view) { if(mIsBestPost) { - fetchBestPost(1); + fetchBestPost(); } else { fetchPost(); } @@ -142,7 +143,7 @@ public class PostFragment extends Fragment implements FragmentCommunicator { mPaginationSynchronizer.setLoadSuccess(savedInstanceState.getBoolean(LOAD_SUCCESS_STATE)); mPaginationSynchronizer.setLoadingState(savedInstanceState.getBoolean(LOADING_STATE_STATE)); PostRecyclerViewAdapter adapter = new PostRecyclerViewAdapter(getActivity(), mOauthRetrofit, - mPostData, mPaginationSynchronizer, mIsBestPost); + mSharedPreferences, mPostData, mPaginationSynchronizer, mIsBestPost); mPostRecyclerView.setAdapter(adapter); if(mIsBestPost) { mPostRecyclerView.addOnScrollListener(new PostPaginationScrollListener( @@ -167,7 +168,7 @@ public class PostFragment extends Fragment implements FragmentCommunicator { } }); if(mIsBestPost) { - fetchBestPost(1); + fetchBestPost(); } else { fetchPost(); } @@ -176,12 +177,7 @@ public class PostFragment extends Fragment implements FragmentCommunicator { return rootView; } - private void fetchBestPost(final int refreshTime) { - if(refreshTime < 0) { - showErrorView(); - return; - } - Log.i("fetch best post", "start" + refreshTime); + private void fetchBestPost() { mFetchPostErrorLinearLayout.setVisibility(View.GONE); mProgressBar.setVisibility(View.VISIBLE); @@ -212,7 +208,9 @@ public class PostFragment extends Fragment implements FragmentCommunicator { if(isAdded() && getActivity() != null) { mPostData = postData; mLastItem = lastItem; - PostRecyclerViewAdapter adapter = new PostRecyclerViewAdapter(getActivity(), mOauthRetrofit, postData, mPaginationSynchronizer, mIsBestPost); + PostRecyclerViewAdapter adapter = new PostRecyclerViewAdapter( + getActivity(), mOauthRetrofit, mSharedPreferences, + postData, mPaginationSynchronizer, mIsBestPost); mPostRecyclerView.setAdapter(adapter); mPostRecyclerView.addOnScrollListener(new PostPaginationScrollListener( @@ -230,19 +228,6 @@ public class PostFragment extends Fragment implements FragmentCommunicator { showErrorView(); } }); - } else if(response.code() == 401) { - // Error indicating that there was an Authentication Failure while performing the request - // Access token expired - RefreshAccessToken.refreshAccessToken(getActivity(), - new RefreshAccessToken.RefreshAccessTokenListener() { - @Override - public void onRefreshAccessTokenSuccess() { - fetchBestPost(refreshTime - 1); - } - - @Override - public void onRefreshAccessTokenFail() {} - }); } else { Log.i("Post fetch error", response.message()); showErrorView(); @@ -284,7 +269,9 @@ public class PostFragment extends Fragment implements FragmentCommunicator { if(isAdded() && getActivity() != null) { mPostData = postData; mLastItem = lastItem; - PostRecyclerViewAdapter adapter = new PostRecyclerViewAdapter(getActivity(), mRetrofit, postData, mPaginationSynchronizer, mIsBestPost); + PostRecyclerViewAdapter adapter = new PostRecyclerViewAdapter( + getActivity(), mRetrofit, mSharedPreferences, + postData, mPaginationSynchronizer, mIsBestPost); mPostRecyclerView.setAdapter(adapter); mPostRecyclerView.addOnScrollListener(new PostPaginationScrollListener( @@ -329,7 +316,7 @@ public class PostFragment extends Fragment implements FragmentCommunicator { @Override public void onClick(View view) { if (mIsBestPost) { - fetchBestPost(1); + fetchBestPost(); } else { fetchPost(); } @@ -358,7 +345,7 @@ public class PostFragment extends Fragment implements FragmentCommunicator { (mPostRecyclerView.getAdapter()).notifyDataSetChanged(); } if(mIsBestPost) { - fetchBestPost(1); + fetchBestPost(); } else { fetchPost(); } diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/PostPaginationScrollListener.java b/app/src/main/java/ml/docilealligator/infinityforreddit/PostPaginationScrollListener.java index 98ea7c1c..04db981d 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/PostPaginationScrollListener.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/PostPaginationScrollListener.java @@ -57,7 +57,7 @@ class PostPaginationScrollListener extends RecyclerView.OnScrollListener { @Override public void retry() { if (isBestPost) { - fetchBestPost(1); + fetchBestPost(); } else { fetchPost(subredditName, 1); } @@ -78,7 +78,7 @@ class PostPaginationScrollListener extends RecyclerView.OnScrollListener { if((visibleItemCount + firstVisibleItemPosition >= totalItemCount) && firstVisibleItemPosition >= 0) { if(isBestPost) { - fetchBestPost(1); + fetchBestPost(); } else { fetchPost(mSubredditName, 1); } @@ -87,12 +87,7 @@ class PostPaginationScrollListener extends RecyclerView.OnScrollListener { } - private void fetchBestPost(final int refreshTime) { - if(refreshTime < 0) { - loadFailed(); - return; - } - Log.i("fetch best post pag", "start"); + private void fetchBestPost() { isLoading = true; loadSuccess = false; mPaginationSynchronizer.setLoadingState(true); @@ -136,19 +131,6 @@ class PostPaginationScrollListener extends RecyclerView.OnScrollListener { loadFailed(); } }); - } else if(response.code() == 401) { - //Access token expired - RefreshAccessToken.refreshAccessToken(mContext, - new RefreshAccessToken.RefreshAccessTokenListener() { - @Override - public void onRefreshAccessTokenSuccess() { - fetchBestPost(refreshTime - 1); - } - - @Override - public void onRefreshAccessTokenFail() { - } - }); } else { Toast.makeText(mContext, "Error getting best post", Toast.LENGTH_SHORT).show(); Log.i("best post", response.message()); diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/PostRecyclerViewAdapter.java b/app/src/main/java/ml/docilealligator/infinityforreddit/PostRecyclerViewAdapter.java index 44b4919a..1a6c093a 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/PostRecyclerViewAdapter.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/PostRecyclerViewAdapter.java @@ -2,6 +2,7 @@ package ml.docilealligator.infinityforreddit; import android.content.Context; import android.content.Intent; +import android.content.SharedPreferences; import android.graphics.ColorFilter; import android.graphics.drawable.Drawable; import android.net.Uri; @@ -46,6 +47,7 @@ class PostRecyclerViewAdapter extends RecyclerView.Adapter mPostData; private Context mContext; private Retrofit mOauthRetrofit; + private SharedPreferences mSharedPreferences; private PaginationSynchronizer mPaginationSynchronizer; private RequestManager glide; private SubredditDao subredditDao; @@ -57,10 +59,11 @@ class PostRecyclerViewAdapter extends RecyclerView.Adapter postData, PaginationSynchronizer paginationSynchronizer, boolean hasMultipleSubreddits) { + PostRecyclerViewAdapter(Context context, Retrofit oauthRetrofit, SharedPreferences sharedPreferences, ArrayList postData, PaginationSynchronizer paginationSynchronizer, boolean hasMultipleSubreddits) { if(context != null) { mContext = context; mOauthRetrofit = oauthRetrofit; + mSharedPreferences = sharedPreferences; mPostData = postData; mPaginationSynchronizer = paginationSynchronizer; this.hasMultipleSubreddits = hasMultipleSubreddits; @@ -91,17 +94,16 @@ class PostRecyclerViewAdapter extends RecyclerView.Adapter params = new HashMap<>(); - params.put(RedditUtils.GRANT_TYPE_KEY, RedditUtils.GRANT_TYPE_REFRESH_TOKEN); - params.put(RedditUtils.REFRESH_TOKEN_KEY, refreshToken); + Map params = new HashMap<>(); + params.put(RedditUtils.GRANT_TYPE_KEY, RedditUtils.GRANT_TYPE_REFRESH_TOKEN); + params.put(RedditUtils.REFRESH_TOKEN_KEY, refreshToken); - Call accessTokenCall = api.getAccessToken(RedditUtils.getHttpBasicAuthHeader(), params); - accessTokenCall.enqueue(new Callback() { - @Override - public void onResponse(@NonNull Call call, @NonNull retrofit2.Response response) { - try { - JSONObject jsonObject = new JSONObject(response.body()); - String newAccessToken = jsonObject.getString(RedditUtils.ACCESS_TOKEN_KEY); - int expireIn = jsonObject.getInt(RedditUtils.EXPIRES_IN_KEY); + Call accessTokenCall = api.getAccessToken(RedditUtils.getHttpBasicAuthHeader(), params); + try { + Response response = accessTokenCall.execute(); + JSONObject jsonObject = new JSONObject((String) response.body()); - long queryAccessTokenTime = Calendar.getInstance().getTimeInMillis(); + String newAccessToken = jsonObject.getString(RedditUtils.ACCESS_TOKEN_KEY); - SharedPreferences.Editor editor = context.getSharedPreferences(SharedPreferencesUtils.AUTH_CODE_FILE_KEY, Context.MODE_PRIVATE).edit(); - editor.putString(SharedPreferencesUtils.ACCESS_TOKEN_KEY, newAccessToken); - editor.putInt(SharedPreferencesUtils.ACCESS_TOKEN_EXPIRE_INTERVAL_KEY, expireIn); - editor.putLong(SharedPreferencesUtils.QUERY_ACCESS_TOKEN_TIME_KEY, queryAccessTokenTime); - editor.apply(); + sharedPreferences.edit().putString(SharedPreferencesUtils.ACCESS_TOKEN_KEY, newAccessToken).apply(); - Log.i("access token", newAccessToken); - refreshAccessTokenListener.onRefreshAccessTokenSuccess(); - } catch (JSONException e) { - e.printStackTrace(); - refreshAccessTokenListener.onRefreshAccessTokenFail(); - Log.i("main activity", "Error parsing JSON object when getting the access token"); - } - refreshAccessTokenListener.onRefreshAccessTokenSuccess(); - } - - @Override - public void onFailure(@NonNull Call call, @NonNull Throwable t) { - Log.i("call failed", t.getMessage()); - refreshAccessTokenListener.onRefreshAccessTokenFail(); - } - }); + Log.i("access token", newAccessToken); + return newAccessToken; + } catch (IOException | JSONException e) { + e.printStackTrace(); } + + return ""; } } diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/ViewPostDetailActivity.java b/app/src/main/java/ml/docilealligator/infinityforreddit/ViewPostDetailActivity.java index 7ae46899..2df6e6f6 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/ViewPostDetailActivity.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/ViewPostDetailActivity.java @@ -1,6 +1,7 @@ package ml.docilealligator.infinityforreddit; import android.content.Intent; +import android.content.SharedPreferences; import android.graphics.ColorFilter; import android.graphics.drawable.Drawable; import android.net.Uri; @@ -69,14 +70,15 @@ public class ViewPostDetailActivity extends AppCompatActivity { private LoadSubredditIconAsyncTask mLoadSubredditIconAsyncTask; - @Inject - @Named("no_oauth") + @Inject @Named("no_oauth") Retrofit mRetrofit; - @Inject - @Named("oauth") + @Inject @Named("oauth") Retrofit mOauthRetrofit; + @Inject @Named("auth_info") + SharedPreferences mSharedPreferences; + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -380,7 +382,7 @@ public class ViewPostDetailActivity extends AppCompatActivity { scoreTextView.setText(Integer.toString(mPostData.getScore() + 1)); } - VoteThing.voteThing(ViewPostDetailActivity.this, mOauthRetrofit, new VoteThing.VoteThingWithoutPositionListener() { + VoteThing.voteThing(mOauthRetrofit, mSharedPreferences, new VoteThing.VoteThingWithoutPositionListener() { @Override public void onVoteThingSuccess() { mPostData.setVoteType(1); @@ -398,13 +400,13 @@ public class ViewPostDetailActivity extends AppCompatActivity { scoreTextView.setText(Integer.toString(mPostData.getScore())); downvoteButton.setColorFilter(downVoteButtonColorFilter); } - }, mPostData.getFullName(), RedditUtils.DIR_UPVOTE, 1); + }, mPostData.getFullName(), RedditUtils.DIR_UPVOTE); } else { //Upvoted before upvoteButton.clearColorFilter(); scoreTextView.setText(Integer.toString(mPostData.getScore() - 1)); - VoteThing.voteThing(ViewPostDetailActivity.this, mOauthRetrofit, new VoteThing.VoteThingWithoutPositionListener() { + VoteThing.voteThing(mOauthRetrofit, mSharedPreferences, new VoteThing.VoteThingWithoutPositionListener() { @Override public void onVoteThingSuccess() { mPostData.setVoteType(0); @@ -418,7 +420,7 @@ public class ViewPostDetailActivity extends AppCompatActivity { upvoteButton.setColorFilter(ContextCompat.getColor(ViewPostDetailActivity.this, R.color.colorPrimary), android.graphics.PorterDuff.Mode.SRC_IN); mPostData.setScore(mPostData.getScore() + 1); } - }, mPostData.getFullName(), RedditUtils.DIR_UNVOTE, 1); + }, mPostData.getFullName(), RedditUtils.DIR_UNVOTE); } } }); @@ -440,7 +442,7 @@ public class ViewPostDetailActivity extends AppCompatActivity { scoreTextView.setText(Integer.toString(mPostData.getScore() - 1)); } - VoteThing.voteThing(ViewPostDetailActivity.this, mOauthRetrofit, new VoteThing.VoteThingWithoutPositionListener() { + VoteThing.voteThing(mOauthRetrofit, mSharedPreferences, new VoteThing.VoteThingWithoutPositionListener() { @Override public void onVoteThingSuccess() { mPostData.setVoteType(-1); @@ -458,13 +460,13 @@ public class ViewPostDetailActivity extends AppCompatActivity { scoreTextView.setText(Integer.toString(mPostData.getScore())); upvoteButton.setColorFilter(upvoteButtonColorFilter); } - }, mPostData.getFullName(), RedditUtils.DIR_DOWNVOTE, 1); + }, mPostData.getFullName(), RedditUtils.DIR_DOWNVOTE); } else { //Down voted before downvoteButton.clearColorFilter(); scoreTextView.setText(Integer.toString(mPostData.getScore() + 1)); - VoteThing.voteThing(ViewPostDetailActivity.this, mOauthRetrofit, new VoteThing.VoteThingWithoutPositionListener() { + VoteThing.voteThing(mOauthRetrofit, mSharedPreferences, new VoteThing.VoteThingWithoutPositionListener() { @Override public void onVoteThingSuccess() { mPostData.setVoteType(0); @@ -478,7 +480,7 @@ public class ViewPostDetailActivity extends AppCompatActivity { scoreTextView.setText(Integer.toString(mPostData.getScore())); mPostData.setScore(mPostData.getScore()); } - }, mPostData.getFullName(), RedditUtils.DIR_UNVOTE, 1); + }, mPostData.getFullName(), RedditUtils.DIR_UNVOTE); } } }); @@ -501,7 +503,7 @@ public class ViewPostDetailActivity extends AppCompatActivity { if (commentData.size() > 0) { CommentMultiLevelRecyclerViewAdapter adapter = new CommentMultiLevelRecyclerViewAdapter( ViewPostDetailActivity.this, mRetrofit, mOauthRetrofit, - (ArrayList) commentData, + mSharedPreferences, (ArrayList) commentData, mRecyclerView, mPostData.getSubredditNamePrefixed(), mPostData.getId(), getResources().getConfiguration().locale); mRecyclerView.removeItemClickListeners(); diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/VoteThing.java b/app/src/main/java/ml/docilealligator/infinityforreddit/VoteThing.java index fca7176d..432ad988 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/VoteThing.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/VoteThing.java @@ -1,6 +1,6 @@ package ml.docilealligator.infinityforreddit; -import android.content.Context; +import android.content.SharedPreferences; import android.support.annotation.NonNull; import android.util.Log; @@ -27,19 +27,12 @@ class VoteThing { void onVoteThingFail(); } - static void voteThing(final Context context, final Retrofit retrofit, + static void voteThing(final Retrofit retrofit, SharedPreferences authInfoSharedPreferences, final VoteThingListener voteThingListener, final String fullName, - final String point, final int position, final int refreshTime) { - if(context != null) { - if(refreshTime < 0) { - voteThingListener.onVoteThingFail(position); - return; - } - + final String point, final int position) { RedditAPI api = retrofit.create(RedditAPI.class); - String accessToken = context.getSharedPreferences(SharedPreferencesUtils.AUTH_CODE_FILE_KEY, Context.MODE_PRIVATE) - .getString(SharedPreferencesUtils.ACCESS_TOKEN_KEY, ""); + String accessToken = authInfoSharedPreferences.getString(SharedPreferencesUtils.ACCESS_TOKEN_KEY, ""); Map params = new HashMap<>(); params.put(RedditUtils.DIR_KEY, point); params.put(RedditUtils.ID_KEY, fullName); @@ -55,35 +48,17 @@ class VoteThing { @Override public void onFailure(@NonNull Call call, @NonNull Throwable t) { Log.i("call failed", t.getMessage()); - RefreshAccessToken.refreshAccessToken(context, - new RefreshAccessToken.RefreshAccessTokenListener() { - @Override - public void onRefreshAccessTokenSuccess() { - voteThing(context, retrofit, voteThingListener, fullName, point, position, refreshTime - 1); - } - - @Override - public void onRefreshAccessTokenFail() { - } - }); + voteThingListener.onVoteThingFail(position); } }); - } } - static void voteThing(final Context context, final Retrofit retrofit, + static void voteThing(final Retrofit retrofit, SharedPreferences authInfoSharedPreferences, final VoteThingWithoutPositionListener voteThingWithoutPositionListener, - final String fullName, final String point, final int refreshTime) { - if(context != null) { - if(refreshTime < 0) { - voteThingWithoutPositionListener.onVoteThingFail(); - return; - } - + final String fullName, final String point) { RedditAPI api = retrofit.create(RedditAPI.class); - String accessToken = context.getSharedPreferences(SharedPreferencesUtils.AUTH_CODE_FILE_KEY, Context.MODE_PRIVATE) - .getString(SharedPreferencesUtils.ACCESS_TOKEN_KEY, ""); + String accessToken = authInfoSharedPreferences.getString(SharedPreferencesUtils.ACCESS_TOKEN_KEY, ""); Map params = new HashMap<>(); params.put(RedditUtils.DIR_KEY, point); params.put(RedditUtils.ID_KEY, fullName); @@ -99,18 +74,8 @@ class VoteThing { @Override public void onFailure(@NonNull Call call, @NonNull Throwable t) { Log.i("call failed", t.getMessage()); - RefreshAccessToken.refreshAccessToken(context, - new RefreshAccessToken.RefreshAccessTokenListener() { - @Override - public void onRefreshAccessTokenSuccess() { - voteThing(context, retrofit, voteThingWithoutPositionListener, fullName, point, refreshTime - 1); - } - - @Override - public void onRefreshAccessTokenFail() {} - }); + voteThingWithoutPositionListener.onVoteThingFail(); } }); - } } } -- cgit v1.2.3