diff --git a/app/src/main/java/awais/instagrabber/InstaGrabberApplication.java b/app/src/main/java/awais/instagrabber/InstaGrabberApplication.java
index de555f94..36807a6c 100644
--- a/app/src/main/java/awais/instagrabber/InstaGrabberApplication.java
+++ b/app/src/main/java/awais/instagrabber/InstaGrabberApplication.java
@@ -17,7 +17,6 @@ import awais.instagrabber.utils.Constants;
import awais.instagrabber.utils.LocaleUtils;
import awais.instagrabber.utils.SettingsHelper;
import awais.instagrabber.utils.TextUtils;
-import awais.instagrabber.webservices.RetrofitFactory;
import awaisomereport.CrashReporter;
import static awais.instagrabber.utils.CookieUtils.NET_COOKIE_MANAGER;
@@ -87,7 +86,5 @@ public final class InstaGrabberApplication extends Application {
if (TextUtils.isEmpty(settingsHelper.getString(Constants.DEVICE_UUID))) {
settingsHelper.putString(Constants.DEVICE_UUID, UUID.randomUUID().toString());
}
-
- RetrofitFactory.setup(this);
}
}
\ No newline at end of file
diff --git a/app/src/main/java/awais/instagrabber/activities/MainActivity.java b/app/src/main/java/awais/instagrabber/activities/MainActivity.java
index df2369cc..66670534 100644
--- a/app/src/main/java/awais/instagrabber/activities/MainActivity.java
+++ b/app/src/main/java/awais/instagrabber/activities/MainActivity.java
@@ -83,6 +83,7 @@ import awais.instagrabber.utils.TextUtils;
import awais.instagrabber.utils.Utils;
import awais.instagrabber.utils.emoji.EmojiParser;
import awais.instagrabber.viewmodels.AppStateViewModel;
+import awais.instagrabber.webservices.RetrofitFactory;
import static awais.instagrabber.utils.NavigationExtensions.setupWithNavController;
import static awais.instagrabber.utils.Utils.settingsHelper;
@@ -138,6 +139,7 @@ public class MainActivity extends BaseLanguageActivity implements FragmentManage
@Override
protected void onCreate(@Nullable final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ RetrofitFactory.setup(this);
binding = ActivityMainBinding.inflate(getLayoutInflater());
final String cookie = settingsHelper.getString(Constants.COOKIE);
CookieUtils.setupCookies(cookie);
diff --git a/app/src/main/java/awais/instagrabber/utils/Constants.java b/app/src/main/java/awais/instagrabber/utils/Constants.java
index 0c92f0fd..4c064e81 100644
--- a/app/src/main/java/awais/instagrabber/utils/Constants.java
+++ b/app/src/main/java/awais/instagrabber/utils/Constants.java
@@ -111,6 +111,7 @@ public final class Constants {
public static final int SHOW_ACTIVITY_REQUEST_CODE = 1738;
public static final int SHOW_DM_THREAD = 2000;
public static final int DM_SYNC_SERVICE_REQUEST_CODE = 3000;
+ public static final int GLOBAL_NETWORK_ERROR_DIALOG_REQUEST_CODE = 7777;
public static final String ACTION_SHOW_ACTIVITY = "show_activity";
public static final String ACTION_SHOW_DM_THREAD = "show_dm_thread";
diff --git a/app/src/main/java/awais/instagrabber/webservices/RetrofitFactory.java b/app/src/main/java/awais/instagrabber/webservices/RetrofitFactory.java
index ce8cbfa7..71c78a4e 100644
--- a/app/src/main/java/awais/instagrabber/webservices/RetrofitFactory.java
+++ b/app/src/main/java/awais/instagrabber/webservices/RetrofitFactory.java
@@ -1,7 +1,5 @@
package awais.instagrabber.webservices;
-import android.app.Application;
-
import androidx.annotation.NonNull;
import com.google.gson.FieldNamingPolicy;
@@ -11,9 +9,11 @@ import com.google.gson.GsonBuilder;
import java.io.File;
import awais.instagrabber.BuildConfig;
+import awais.instagrabber.activities.MainActivity;
import awais.instagrabber.repositories.responses.Caption;
import awais.instagrabber.utils.Utils;
import awais.instagrabber.webservices.interceptors.AddCookiesInterceptor;
+import awais.instagrabber.webservices.interceptors.IgErrorsInterceptor;
import okhttp3.Cache;
import okhttp3.OkHttpClient;
import retrofit2.Retrofit;
@@ -25,7 +25,7 @@ public final class RetrofitFactory {
private static RetrofitFactory instance;
- private final Application application;
+ private final MainActivity mainActivity;
private final int cacheSize = 10 * 1024 * 1024; // 10 MB
private final Cache cache = new Cache(new File(Utils.cacheDir), cacheSize);
@@ -33,11 +33,11 @@ public final class RetrofitFactory {
private Retrofit retrofit;
private Retrofit retrofitWeb;
- public static void setup(@NonNull final Application application) {
+ public static void setup(@NonNull final MainActivity mainActivity) {
if (instance == null) {
synchronized (LOCK) {
if (instance == null) {
- instance = new RetrofitFactory(application);
+ instance = new RetrofitFactory(mainActivity);
}
}
}
@@ -50,20 +50,21 @@ public final class RetrofitFactory {
return instance;
}
- private RetrofitFactory(@NonNull final Application application) {
- this.application = application;
+ private RetrofitFactory(@NonNull final MainActivity mainActivity) {
+ this.mainActivity = mainActivity;
}
private Retrofit.Builder getRetrofitBuilder() {
if (builder == null) {
final OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder()
- .addInterceptor(new AddCookiesInterceptor())
.followRedirects(false)
.followSslRedirects(false)
.cache(cache);
if (BuildConfig.DEBUG) {
// clientBuilder.addInterceptor(new LoggingInterceptor());
}
+ clientBuilder.addInterceptor(new AddCookiesInterceptor())
+ .addInterceptor(new IgErrorsInterceptor(mainActivity));
final Gson gson = new GsonBuilder()
.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
.registerTypeAdapter(Caption.class, new Caption.CaptionDeserializer())
diff --git a/app/src/main/java/awais/instagrabber/webservices/interceptors/IgErrorsInterceptor.java b/app/src/main/java/awais/instagrabber/webservices/interceptors/IgErrorsInterceptor.java
new file mode 100644
index 00000000..413f0e03
--- /dev/null
+++ b/app/src/main/java/awais/instagrabber/webservices/interceptors/IgErrorsInterceptor.java
@@ -0,0 +1,108 @@
+package awais.instagrabber.webservices.interceptors;
+
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.StringRes;
+
+import org.json.JSONObject;
+
+import java.io.IOException;
+
+import awais.instagrabber.R;
+import awais.instagrabber.activities.MainActivity;
+import awais.instagrabber.dialogs.ConfirmDialogFragment;
+import awais.instagrabber.utils.Constants;
+import awais.instagrabber.utils.TextUtils;
+import okhttp3.Interceptor;
+import okhttp3.Request;
+import okhttp3.Response;
+import okhttp3.ResponseBody;
+
+public class IgErrorsInterceptor implements Interceptor {
+ private static final String TAG = IgErrorsInterceptor.class.getSimpleName();
+
+ private final MainActivity mainActivity;
+
+ public IgErrorsInterceptor(@NonNull final MainActivity mainActivity) {
+ this.mainActivity = mainActivity;
+ }
+
+ @NonNull
+ @Override
+ public Response intercept(@NonNull final Chain chain) throws IOException {
+ final Request request = chain.request();
+ final Response response = chain.proceed(request);
+ if (response.isSuccessful()) {
+ return response;
+ }
+ checkError(response);
+ return response;
+ }
+
+ private void checkError(@NonNull final Response response) {
+ final int errorCode = response.code();
+ switch (errorCode) {
+ case 429: // "429 Too Many Requests"
+ // ('Throttled by Instagram because of too many API requests.');
+ showErrorDialog(R.string.throttle_error);
+ return;
+ case 431: // "431 Request Header Fields Too Large"
+ // show dialog?
+ Log.e(TAG, "Network error: " + getMessage(errorCode, "The request start-line and/or headers are too large to process."));
+ return;
+ }
+ final ResponseBody body = response.body();
+ if (body == null) return;
+ try {
+ final String bodyString = body.string();
+ final JSONObject jsonObject = new JSONObject(bodyString);
+ String message = jsonObject.optString("message", null);
+ if (!TextUtils.isEmpty(message)) {
+ message = message.toLowerCase();
+ switch (message) {
+ case "user_has_logged_out":
+ showErrorDialog(R.string.account_logged_out);
+ return;
+ case "login_required":
+ showErrorDialog(R.string.login_required);
+ return;
+ case "not authorized to view user": // Do we handle this in profile view fragment?
+ case "challenge_required": // Since we make users login using browser, we should not be getting this error in api requests
+ default:
+ Log.e(TAG, "checkError: " + bodyString);
+ return;
+ }
+ }
+ final String errorType = jsonObject.optString("error_type", null);
+ if (TextUtils.isEmpty(errorType)) return;
+ if (errorType.equals("sentry_block")) {
+ showErrorDialog(R.string.sentry_block);
+ return;
+ }
+ if (errorType.equals("inactive user")) {
+ showErrorDialog(R.string.inactive_user);
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "checkError: ", e);
+ }
+ }
+
+ @NonNull
+ private String getMessage(final int errorCode, final String message) {
+ return String.format("code: %s, internalMessage: %s", errorCode, message);
+ }
+
+ private void showErrorDialog(@StringRes final int messageResId) {
+ if (messageResId == 0) return;
+ final ConfirmDialogFragment dialogFragment = ConfirmDialogFragment.newInstance(
+ Constants.GLOBAL_NETWORK_ERROR_DIALOG_REQUEST_CODE,
+ R.string.error,
+ messageResId,
+ R.string.ok,
+ 0,
+ 0
+ );
+ dialogFragment.show(mainActivity.getSupportFragmentManager(), "network_error_dialog");
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index f65ff8c9..af62d980 100755
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -473,4 +473,10 @@
Removed keyword: %s from filter list
Marked as seen
Delete unsuccessful
+ Throttled by Instagram because of too many API requests. Wait for some time before retrying.
+ Error
+ This account has been logged out.
+ Login required!
+ Sentry block.
+ User is inactive!