From c9d342471bbb339a155dad548291258742bbb7c2 Mon Sep 17 00:00:00 2001 From: Ammar Githam Date: Sun, 6 Sep 2020 22:27:41 +0900 Subject: [PATCH] Add update checker back, with updated handling. Check description. FlavorTown will check if current app was installed from F-droid and not show the update dialog if true. You can now skip an update. You can now force check for an update by clicking More -> Version (even if you set to skip the update). --- .../instagrabber/activities/MainActivity.java | 3 + .../settings/MorePreferencesFragment.java | 51 ++++++-- .../awais/instagrabber/utils/Constants.java | 2 + .../awais/instagrabber/utils/FlavorTown.java | 110 ++++++++++++++---- .../instagrabber/utils/SettingsHelper.java | 9 +- .../instagrabber/utils/UpdateChecker.java | 34 +++--- .../preference_list_divider_material.xml | 18 +++ app/src/main/res/layout/dialog_update.xml | 20 ++++ app/src/main/res/layout/item_pref_divider.xml | 5 + app/src/main/res/values/strings.xml | 2 + 10 files changed, 204 insertions(+), 50 deletions(-) create mode 100644 app/src/main/res/drawable/preference_list_divider_material.xml create mode 100644 app/src/main/res/layout/dialog_update.xml create mode 100644 app/src/main/res/layout/item_pref_divider.xml diff --git a/app/src/main/java/awais/instagrabber/activities/MainActivity.java b/app/src/main/java/awais/instagrabber/activities/MainActivity.java index 4a13bff4..e9d2265a 100644 --- a/app/src/main/java/awais/instagrabber/activities/MainActivity.java +++ b/app/src/main/java/awais/instagrabber/activities/MainActivity.java @@ -40,6 +40,7 @@ import awais.instagrabber.interfaces.FetchListener; import awais.instagrabber.models.SuggestionModel; import awais.instagrabber.models.enums.SuggestionType; import awais.instagrabber.utils.Constants; +import awais.instagrabber.utils.FlavorTown; import awais.instagrabber.utils.Utils; import static awais.instagrabber.utils.NavigationExtensions.setupWithNavController; @@ -91,6 +92,8 @@ public class MainActivity extends BaseLanguageActivity { } setupScrollingListener(); setupSuggestions(); + FlavorTown.updateCheck(this); + FlavorTown.changelogCheck(this); } private void setupSuggestions() { diff --git a/app/src/main/java/awais/instagrabber/fragments/settings/MorePreferencesFragment.java b/app/src/main/java/awais/instagrabber/fragments/settings/MorePreferencesFragment.java index 738a75dc..2ce0f50c 100644 --- a/app/src/main/java/awais/instagrabber/fragments/settings/MorePreferencesFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/settings/MorePreferencesFragment.java @@ -2,24 +2,31 @@ package awais.instagrabber.fragments.settings; import android.content.Context; import android.content.Intent; +import android.content.res.Resources; +import android.util.Log; import android.widget.Toast; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; import androidx.navigation.NavDirections; import androidx.navigation.fragment.NavHostFragment; import androidx.preference.Preference; import androidx.preference.PreferenceCategory; import androidx.preference.PreferenceScreen; +import awais.instagrabber.BuildConfig; import awais.instagrabber.R; import awais.instagrabber.activities.Login; import awais.instagrabber.utils.Constants; +import awais.instagrabber.utils.FlavorTown; import awais.instagrabber.utils.Utils; import static awais.instagrabber.utils.Utils.settingsHelper; public class MorePreferencesFragment extends BasePreferencesFragment { + private static final String TAG = "MorePreferencesFragment"; + private final String cookie = settingsHelper.getString(Constants.COOKIE); @Override @@ -31,7 +38,8 @@ public class MorePreferencesFragment extends BasePreferencesFragment { accountCategory.setIconSpaceReserved(false); screen.addPreference(accountCategory); final boolean isLoggedIn = !Utils.isEmpty(cookie) && Utils.getUserIdFromCookie(cookie) != null; - screen.addPreference(getPreference(isLoggedIn ? R.string.relogin : R.string.login, + screen.addPreference(getPreference( + isLoggedIn ? R.string.relogin : R.string.login, isLoggedIn ? R.string.relogin_summary : -1, -1, preference -> { @@ -48,15 +56,28 @@ public class MorePreferencesFragment extends BasePreferencesFragment { })); } - final PreferenceCategory defaultCategory = new PreferenceCategory(requireContext()); - screen.addPreference(defaultCategory); - defaultCategory.addPreference(getPreference(R.string.action_notif, R.drawable.ic_not_liked, preference -> false)); - defaultCategory.addPreference(getPreference(R.string.action_settings, R.drawable.ic_outline_settings_24, preference -> { + final PreferenceCategory generalCategory = new PreferenceCategory(requireContext()); + generalCategory.setTitle("General"); + generalCategory.setIconSpaceReserved(false); + screen.addPreference(generalCategory); + generalCategory.addPreference(getPreference(R.string.action_notif, R.drawable.ic_not_liked, preference -> false)); + generalCategory.addPreference(getPreference(R.string.action_settings, R.drawable.ic_outline_settings_24, preference -> { final NavDirections navDirections = MorePreferencesFragmentDirections.actionMorePreferencesFragmentToSettingsPreferencesFragment(); NavHostFragment.findNavController(this).navigate(navDirections); return true; })); - defaultCategory.addPreference(getPreference(R.string.action_about, R.drawable.ic_outline_info_24, preference -> false)); + final Preference aboutPreference = getPreference(R.string.action_about, R.drawable.ic_outline_info_24, preference -> false); + generalCategory.addPreference(aboutPreference); + + final Preference divider = new Preference(requireContext()); + divider.setLayoutResource(R.layout.item_pref_divider); + screen.addPreference(divider); + + final Preference versionPreference = getPreference(R.string.version, BuildConfig.VERSION_NAME, -1, preference -> { + FlavorTown.updateCheck((AppCompatActivity) requireActivity(), true); + return true; + }); + screen.addPreference(versionPreference); } @Override @@ -83,11 +104,27 @@ public class MorePreferencesFragment extends BasePreferencesFragment { final int summary, final int icon, final Preference.OnPreferenceClickListener clickListener) { + String string = null; + if (summary > 0) { + try { + string = getString(summary); + } catch (Resources.NotFoundException e) { + Log.e(TAG, "Error", e); + } + } + return getPreference(title, string, icon, clickListener); + } + + @NonNull + private Preference getPreference(final int title, + final String summary, + final int icon, + final Preference.OnPreferenceClickListener clickListener) { final Preference preference = new Preference(requireContext()); if (icon <= 0) preference.setIconSpaceReserved(false); if (icon > 0) preference.setIcon(icon); preference.setTitle(title); - if (summary > 0) { + if (!Utils.isEmpty(summary)) { preference.setSummary(summary); } preference.setOnPreferenceClickListener(clickListener); diff --git a/app/src/main/java/awais/instagrabber/utils/Constants.java b/app/src/main/java/awais/instagrabber/utils/Constants.java index 1fe142de..43732957 100755 --- a/app/src/main/java/awais/instagrabber/utils/Constants.java +++ b/app/src/main/java/awais/instagrabber/utils/Constants.java @@ -68,4 +68,6 @@ public final class Constants { public static final String SIGNATURE_KEY = "9193488027538fd3450b83b7d05286d4ca9599a0f7eeed90d8c85925698a05dc"; public static final String BREADCRUMB_KEY = "iN4$aGr0m"; public static final int LOGIN_RESULT_CODE = 5000; + public static final String FDROID_SHA1_FINGERPRINT = "C1661EB8FD09F618307E687786D5E5056F65084D"; + public static final String SKIPPED_VERSION = "skipped_version"; } \ No newline at end of file diff --git a/app/src/main/java/awais/instagrabber/utils/FlavorTown.java b/app/src/main/java/awais/instagrabber/utils/FlavorTown.java index bd641684..1559afcd 100755 --- a/app/src/main/java/awais/instagrabber/utils/FlavorTown.java +++ b/app/src/main/java/awais/instagrabber/utils/FlavorTown.java @@ -1,48 +1,102 @@ package awais.instagrabber.utils; +import android.annotation.SuppressLint; import android.content.ActivityNotFoundException; import android.content.Context; +import android.content.DialogInterface; import android.content.Intent; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.content.pm.Signature; import android.content.res.Resources; import android.net.Uri; import android.os.AsyncTask; +import android.util.Log; import android.widget.Toast; import androidx.annotation.NonNull; import androidx.appcompat.app.AlertDialog; +import androidx.appcompat.app.AppCompatActivity; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +import javax.security.cert.CertificateException; +import javax.security.cert.X509Certificate; import awais.instagrabber.BuildConfig; import awais.instagrabber.R; +import awais.instagrabber.databinding.DialogUpdateBinding; import static awais.instagrabber.utils.Utils.settingsHelper; public final class FlavorTown { - public static void updateCheck(@NonNull final Context context) { + private static final String TAG = "FlavorTown"; + private static final char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray(); + private static AlertDialog dialog; + + public static void updateCheck(@NonNull final AppCompatActivity context) { + updateCheck(context, false); + } + + @SuppressLint("PackageManagerGetSignatures") + public static void updateCheck(@NonNull final AppCompatActivity context, final boolean force) { + boolean isInstalledFromFdroid = false; + final PackageInfo packageInfo; + try { + packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), PackageManager.GET_SIGNATURES); + for (Signature signature : packageInfo.signatures) { + final X509Certificate cert = X509Certificate.getInstance(signature.toByteArray()); + final String fingerprint = bytesToHex(MessageDigest.getInstance("SHA-1").digest(cert.getEncoded())); + isInstalledFromFdroid = fingerprint.equals(Constants.FDROID_SHA1_FINGERPRINT); + // Log.d(TAG, "fingerprint:" + fingerprint); + } + } catch (PackageManager.NameNotFoundException | NoSuchAlgorithmException | CertificateException e) { + Log.e(TAG, "Error", e); + } + if (isInstalledFromFdroid) return; + final DialogUpdateBinding binding = DialogUpdateBinding.inflate(context.getLayoutInflater(), null, false); + binding.skipUpdate.setOnCheckedChangeListener((buttonView, isChecked) -> { + if (dialog == null) return; + dialog.getButton(DialogInterface.BUTTON_POSITIVE).setEnabled(!isChecked); + }); Resources res = context.getResources(); new UpdateChecker(version -> { - if (!version.equals(BuildConfig.VERSION_NAME) && !BuildConfig.DEBUG) { - new AlertDialog.Builder(context) - .setTitle(res.getString(R.string.update_available, version)) - .setMessage(R.string.update_notice) - .setNeutralButton(R.string.cancel, null) - .setNegativeButton(R.string.action_github, (dialog, which) -> { - try { - context.startActivity(new Intent(Intent.ACTION_VIEW).setData( - Uri.parse("https://github.com/austinhuang0131/instagrabber/releases/latest"))); - } catch (final ActivityNotFoundException e) { - // do nothing - } - }) - .setPositiveButton(R.string.action_fdroid, (dialog, which) -> { - try { - context.startActivity(new Intent(Intent.ACTION_VIEW).setData( - Uri.parse("https://f-droid.org/packages/me.austinhuang.instagrabber/"))); - } catch (final ActivityNotFoundException e) { - // do nothing - } - }) - .show(); + if (force && version.equals(BuildConfig.VERSION_NAME)) { + Toast.makeText(context, "You're already on the latest version", Toast.LENGTH_SHORT).show(); + return; } + final String skippedVersion = settingsHelper.getString(Constants.SKIPPED_VERSION); + final boolean shouldShowDialog = force || (!version.equals(BuildConfig.VERSION_NAME) && !BuildConfig.DEBUG && !skippedVersion + .equals(version)); + if (!shouldShowDialog) return; + dialog = new AlertDialog.Builder(context) + .setTitle(res.getString(R.string.update_available, version)) + .setView(binding.getRoot()) + .setNeutralButton(R.string.cancel, (dialog, which) -> { + if (binding.skipUpdate.isChecked()) { + settingsHelper.putString(Constants.SKIPPED_VERSION, version); + } + dialog.dismiss(); + }) + .setPositiveButton(R.string.action_github, (dialog1, which) -> { + try { + context.startActivity(new Intent(Intent.ACTION_VIEW).setData( + Uri.parse("https://github.com/austinhuang0131/instagrabber/releases/latest"))); + } catch (final ActivityNotFoundException e) { + // do nothing + } + }) + // if we don't show dialog for fdroid users, is the below required? + .setNegativeButton(R.string.action_fdroid, (dialog, which) -> { + try { + context.startActivity(new Intent(Intent.ACTION_VIEW).setData( + Uri.parse("https://f-droid.org/packages/me.austinhuang.instagrabber/"))); + } catch (final ActivityNotFoundException e) { + // do nothing + } + }) + .show(); }).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } @@ -52,4 +106,14 @@ public final class FlavorTown { settingsHelper.putInteger(Constants.PREV_INSTALL_VERSION, BuildConfig.VERSION_CODE); } } + + public static String bytesToHex(byte[] bytes) { + char[] hexChars = new char[bytes.length * 2]; + for (int j = 0; j < bytes.length; j++) { + int v = bytes[j] & 0xFF; + hexChars[j * 2] = HEX_ARRAY[v >>> 4]; + hexChars[j * 2 + 1] = HEX_ARRAY[v & 0x0F]; + } + return new String(hexChars); + } } \ No newline at end of file diff --git a/app/src/main/java/awais/instagrabber/utils/SettingsHelper.java b/app/src/main/java/awais/instagrabber/utils/SettingsHelper.java index e73c2992..967f675b 100755 --- a/app/src/main/java/awais/instagrabber/utils/SettingsHelper.java +++ b/app/src/main/java/awais/instagrabber/utils/SettingsHelper.java @@ -1,6 +1,5 @@ package awais.instagrabber.utils; -import android.annotation.SuppressLint; import android.content.Context; import android.content.SharedPreferences; import android.os.Build; @@ -32,6 +31,7 @@ import static awais.instagrabber.utils.Constants.MARK_AS_SEEN; import static awais.instagrabber.utils.Constants.MUTED_VIDEOS; import static awais.instagrabber.utils.Constants.PREV_INSTALL_VERSION; import static awais.instagrabber.utils.Constants.SHOW_QUICK_ACCESS_DIALOG; +import static awais.instagrabber.utils.Constants.SKIPPED_VERSION; import static awais.instagrabber.utils.Constants.STORIESIG; public final class SettingsHelper { @@ -119,12 +119,13 @@ public final class SettingsHelper { if (sharedPreferences != null) sharedPreferences.edit().putBoolean(key, val).apply(); } - @StringDef({APP_LANGUAGE, APP_THEME, COOKIE, FOLDER_PATH, DATE_TIME_FORMAT, DATE_TIME_SELECTION, CUSTOM_DATE_TIME_FORMAT, DEVICE_UUID}) + @StringDef( + {APP_LANGUAGE, APP_THEME, COOKIE, FOLDER_PATH, DATE_TIME_FORMAT, DATE_TIME_SELECTION, CUSTOM_DATE_TIME_FORMAT, DEVICE_UUID, SKIPPED_VERSION}) public @interface StringSettings {} @StringDef({DOWNLOAD_USER_FOLDER, BOTTOM_TOOLBAR, FOLDER_SAVE_TO, AUTOPLAY_VIDEOS, SHOW_QUICK_ACCESS_DIALOG, MUTED_VIDEOS, - AUTOLOAD_POSTS, CUSTOM_DATE_TIME_FORMAT_ENABLED, MARK_AS_SEEN, DM_MARK_AS_SEEN, - INSTADP, STORIESIG, AMOLED_THEME, CHECK_ACTIVITY, CHECK_UPDATES}) + AUTOLOAD_POSTS, CUSTOM_DATE_TIME_FORMAT_ENABLED, MARK_AS_SEEN, DM_MARK_AS_SEEN, + INSTADP, STORIESIG, AMOLED_THEME, CHECK_ACTIVITY, CHECK_UPDATES}) public @interface BooleanSettings {} @StringDef({PREV_INSTALL_VERSION}) diff --git a/app/src/main/java/awais/instagrabber/utils/UpdateChecker.java b/app/src/main/java/awais/instagrabber/utils/UpdateChecker.java index 87e26e63..a6585aac 100755 --- a/app/src/main/java/awais/instagrabber/utils/UpdateChecker.java +++ b/app/src/main/java/awais/instagrabber/utils/UpdateChecker.java @@ -3,15 +3,15 @@ package awais.instagrabber.utils; import android.os.AsyncTask; import android.util.Log; -import androidx.annotation.NonNull; - import java.net.HttpURLConnection; import java.net.URL; import awais.instagrabber.BuildConfig; import awais.instagrabber.interfaces.FetchListener; -public final class UpdateChecker extends AsyncTask { +public final class UpdateChecker extends AsyncTask { + private static final String TAG = "UpdateChecker"; + private final FetchListener fetchListener; private String version; @@ -19,14 +19,11 @@ public final class UpdateChecker extends AsyncTask { this.fetchListener = fetchListener; } - @NonNull @Override - protected Boolean doInBackground(final Void... voids) { + protected String doInBackground(final Void... voids) { + HttpURLConnection conn = null; try { - version = ""; - - HttpURLConnection conn = - (HttpURLConnection) new URL("https://github.com/austinhuang0131/instagrabber/releases/latest").openConnection(); + conn = (HttpURLConnection) new URL("https://github.com/austinhuang0131/instagrabber/releases/latest").openConnection(); conn.setInstanceFollowRedirects(false); conn.setUseCaches(false); conn.setRequestProperty("User-Agent", Constants.A_USER_AGENT); @@ -35,20 +32,25 @@ public final class UpdateChecker extends AsyncTask { final int responseCode = conn.getResponseCode(); if (responseCode == HttpURLConnection.HTTP_MOVED_TEMP) { version = conn.getHeaderField("Location").split("/v")[1]; - return !version.equals(BuildConfig.VERSION_NAME); + return version; } conn.disconnect(); } catch (final Exception e) { - if (BuildConfig.DEBUG) Log.e("AWAISKING_APP", "", e); + if (BuildConfig.DEBUG) Log.e(TAG, "", e); + } finally { + if (conn != null) { + conn.disconnect(); + } } - - return false; + return null; } @Override - protected void onPostExecute(final Boolean result) { - if (result != null && result && fetchListener != null) - fetchListener.onResult("v"+version); + protected void onPostExecute(final String result) { + if (result == null || fetchListener == null) { + return; + } + fetchListener.onResult(version); } } \ No newline at end of file diff --git a/app/src/main/res/drawable/preference_list_divider_material.xml b/app/src/main/res/drawable/preference_list_divider_material.xml new file mode 100644 index 00000000..23eff349 --- /dev/null +++ b/app/src/main/res/drawable/preference_list_divider_material.xml @@ -0,0 +1,18 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_update.xml b/app/src/main/res/layout/dialog_update.xml new file mode 100644 index 00000000..39d4def5 --- /dev/null +++ b/app/src/main/res/layout/dialog_update.xml @@ -0,0 +1,20 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_pref_divider.xml b/app/src/main/res/layout/item_pref_divider.xml new file mode 100644 index 00000000..45ae1d2c --- /dev/null +++ b/app/src/main/res/layout/item_pref_divider.xml @@ -0,0 +1,5 @@ + + \ 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 82373257..c852be1d 100755 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -251,4 +251,6 @@ Successfully logged out! Info Mark as seen + Do not show again until next update + Version \ No newline at end of file