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).
This commit is contained in:
Ammar Githam 2020-09-06 22:27:41 +09:00
parent 00800590ba
commit c9d342471b
10 changed files with 204 additions and 50 deletions

View File

@ -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() {

View File

@ -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);

View File

@ -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";
}

View File

@ -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);
}
}

View File

@ -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})

View File

@ -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<Void, Void, Boolean> {
public final class UpdateChecker extends AsyncTask<Void, Void, String> {
private static final String TAG = "UpdateChecker";
private final FetchListener<String> fetchListener;
private String version;
@ -19,14 +19,11 @@ public final class UpdateChecker extends AsyncTask<Void, Void, Boolean> {
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<Void, Void, Boolean> {
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);
}
}

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?><!--
Copyright (C) 2015 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#1f000000" />
<size
android:width="1dp"
android:height="1dp" />
</shape>

View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="16dp">
<androidx.appcompat.widget.AppCompatTextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/update_notice"
android:textAppearance="?attr/textAppearanceBody1" />
<CheckBox
android:id="@+id/skip_update"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/skip_update_checkbox" />
</LinearLayout>

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<View xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@drawable/preference_list_divider_material" />

View File

@ -251,4 +251,6 @@
<string name="logout_success">Successfully logged out!</string>
<string name="dm_thread_info">Info</string>
<string name="mark_as_seen">Mark as seen</string>
<string name="skip_update_checkbox">Do not show again until next update</string>
<string name="version">Version</string>
</resources>