parent
1cd81e1cad
commit
88da4ba372
@ -0,0 +1,104 @@
|
||||
package com.fox2code.mmm;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import com.fox2code.mmm.utils.Http;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
// See https://docs.github.com/en/rest/reference/repos#releases
|
||||
public class AppUpdateManager {
|
||||
private static final String TAG = "AppUpdateManager";
|
||||
private static final AppUpdateManager INSTANCE = new AppUpdateManager();
|
||||
private static final String RELEASES_API_URL =
|
||||
"https://api.github.com/repos/Fox2Code/FoxMagiskModuleManager/releases";
|
||||
|
||||
public static AppUpdateManager getAppUpdateManager() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
private final Object updateLock = new Object();
|
||||
private String latestRelease;
|
||||
private String latestPreRelease;
|
||||
private long lastChecked;
|
||||
private boolean preReleaseNewer;
|
||||
|
||||
private AppUpdateManager() {
|
||||
this.latestRelease = MainApplication.getBootSharedPreferences()
|
||||
.getString("updater_latest_release", BuildConfig.VERSION_NAME);
|
||||
this.latestPreRelease = MainApplication.getBootSharedPreferences()
|
||||
.getString("updater_latest_pre_release", BuildConfig.VERSION_NAME);
|
||||
this.lastChecked = 0;
|
||||
this.preReleaseNewer = true;
|
||||
}
|
||||
|
||||
// Return true if should show a notification
|
||||
public boolean checkUpdate(boolean force) {
|
||||
if (this.peekShouldUpdate())
|
||||
return true;
|
||||
long lastChecked = this.lastChecked;
|
||||
if (!force && lastChecked != 0 &&
|
||||
// Avoid spam calls by putting a 10 seconds timer
|
||||
lastChecked < System.currentTimeMillis() - 10000L)
|
||||
return false;
|
||||
synchronized (this.updateLock) {
|
||||
if (lastChecked != this.lastChecked)
|
||||
return this.peekShouldUpdate();
|
||||
boolean preReleaseNewer = true;
|
||||
try {
|
||||
JSONArray releases = new JSONArray(new String(Http.doHttpGet(
|
||||
RELEASES_API_URL, false), StandardCharsets.UTF_8));
|
||||
String latestRelease = null, latestPreRelease = null;
|
||||
for (int i = releases.length() - 1; i > 0; i--) {
|
||||
JSONObject release = releases.getJSONObject(i);
|
||||
// Skip invalid entries
|
||||
if (release.getBoolean("draft")) continue;
|
||||
boolean preRelease = release.getBoolean("prerelease");
|
||||
String version = release.getString("tag_name");
|
||||
if (version.startsWith("v"))
|
||||
version = version.substring(1);
|
||||
if (preRelease) {
|
||||
latestPreRelease = version;
|
||||
} else {
|
||||
latestRelease = version;
|
||||
if (latestPreRelease == null)
|
||||
preReleaseNewer = false;
|
||||
}
|
||||
if (latestRelease != null && latestPreRelease != null) {
|
||||
break; // We read everything we needed to read.
|
||||
}
|
||||
}
|
||||
if (latestRelease != null)
|
||||
this.latestRelease = latestRelease;
|
||||
if (latestPreRelease != null) {
|
||||
this.latestPreRelease = latestPreRelease;
|
||||
this.preReleaseNewer = preReleaseNewer;
|
||||
} else if (!preReleaseNewer) {
|
||||
this.latestPreRelease = "";
|
||||
this.preReleaseNewer = false;
|
||||
}
|
||||
Log.d(TAG, "Latest release: " + latestRelease);
|
||||
Log.d(TAG, "Latest pre-release: " + latestPreRelease);
|
||||
Log.d(TAG, "Latest pre-release newer: " + preReleaseNewer);
|
||||
this.lastChecked = System.currentTimeMillis();
|
||||
} catch (Exception ioe) {
|
||||
Log.e("AppUpdateManager", "Failed to check releases", ioe);
|
||||
}
|
||||
}
|
||||
return this.peekShouldUpdate();
|
||||
}
|
||||
|
||||
public boolean peekShouldUpdate() {
|
||||
return !(BuildConfig.VERSION_NAME.equals(this.latestRelease) ||
|
||||
(this.preReleaseNewer &&
|
||||
BuildConfig.VERSION_NAME.equals(this.latestPreRelease)));
|
||||
}
|
||||
|
||||
public boolean peekHasUpdate() {
|
||||
return !BuildConfig.VERSION_NAME.equals(this.preReleaseNewer ?
|
||||
this.latestPreRelease : this.latestRelease);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,76 @@
|
||||
package com.fox2code.mmm.compat;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Configuration;
|
||||
import android.content.res.Resources;
|
||||
import android.os.Build;
|
||||
import android.os.LocaleList;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* I will probably outsource this to a separate library later
|
||||
*/
|
||||
final class CompatConfigHelper {
|
||||
// ENGLISH like this is an unnatural local, as it doesn't precise the country
|
||||
// All english locales settable by the user precise the country (Ex: en-US)
|
||||
private static final Locale english = Locale.ENGLISH;
|
||||
|
||||
private final Context context;
|
||||
private Locale userLocale;
|
||||
|
||||
CompatConfigHelper(Context context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
void checkResourcesOverrides(boolean forceEnglish,
|
||||
Boolean nightModeOverride) {
|
||||
this.checkResourcesOverrides(
|
||||
this.context.getTheme(),
|
||||
forceEnglish, nightModeOverride);
|
||||
}
|
||||
|
||||
void checkResourcesOverrides(Resources.Theme theme, boolean forceEnglish,
|
||||
Boolean nightModeOverride) {
|
||||
final Resources res = theme.getResources();
|
||||
final Configuration conf = res.getConfiguration();
|
||||
Locale current = conf.locale;
|
||||
boolean didChange = false;
|
||||
if (forceEnglish != current.equals(english)) {
|
||||
didChange = true;
|
||||
if (forceEnglish) {
|
||||
this.userLocale = conf.locale;
|
||||
conf.locale = english;
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
conf.setLocales(LocaleList.getEmptyLocaleList());
|
||||
}
|
||||
} else {
|
||||
conf.locale = this.userLocale;
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
conf.setLocales(LocaleList.getAdjustedDefault());
|
||||
}
|
||||
}
|
||||
}
|
||||
int nightMode = conf.uiMode & Configuration.UI_MODE_NIGHT_MASK;
|
||||
int sysNightMode = Resources.getSystem()
|
||||
.getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
|
||||
if (nightModeOverride == null ? sysNightMode != nightMode :
|
||||
nightMode != (nightModeOverride ?
|
||||
Configuration.UI_MODE_NIGHT_YES : Configuration.UI_MODE_NIGHT_NO)) {
|
||||
didChange = true;
|
||||
nightMode = nightModeOverride == null ? sysNightMode : nightModeOverride ?
|
||||
Configuration.UI_MODE_NIGHT_YES : Configuration.UI_MODE_NIGHT_NO;
|
||||
conf.uiMode = nightMode | (conf.uiMode & ~Configuration.UI_MODE_NIGHT_MASK);
|
||||
}
|
||||
if (didChange) {
|
||||
res.updateConfiguration(conf, null);
|
||||
if (!forceEnglish) this.userLocale = null;
|
||||
}
|
||||
}
|
||||
|
||||
public Locale getUserLocale() {
|
||||
// Only use cached value if force english
|
||||
Locale locale = this.context.getResources().getConfiguration().locale;
|
||||
return english.equals(locale) ? this.userLocale : locale;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,56 @@
|
||||
package com.fox2code.mmm.compat;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
|
||||
import androidx.annotation.StyleRes;
|
||||
import androidx.appcompat.view.ContextThemeWrapper;
|
||||
|
||||
/**
|
||||
* I will probably outsource this to a separate library later
|
||||
*/
|
||||
public class CompatThemeWrapper extends ContextThemeWrapper {
|
||||
private final CompatConfigHelper compatConfigHelper = new CompatConfigHelper(this);
|
||||
private boolean canReload;
|
||||
// CompatConfigHelper
|
||||
private boolean forceEnglish;
|
||||
private Boolean nightModeOverride;
|
||||
|
||||
public CompatThemeWrapper(Context base, @StyleRes int themeResId) {
|
||||
super(base, themeResId);
|
||||
this.canReload = true;
|
||||
this.checkResourcesOverrides(
|
||||
this.forceEnglish, this.nightModeOverride);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onApplyThemeResource(Resources.Theme theme, int resid, boolean first) {
|
||||
boolean couldReload = this.canReload;
|
||||
if (couldReload) this.canReload = false;
|
||||
this.compatConfigHelper.checkResourcesOverrides(theme,
|
||||
this.forceEnglish, this.nightModeOverride);
|
||||
super.onApplyThemeResource(theme, resid, first);
|
||||
if (couldReload) this.canReload = true;
|
||||
// In case value change while reload, should have no effect
|
||||
this.compatConfigHelper.checkResourcesOverrides(theme,
|
||||
this.forceEnglish, this.nightModeOverride);
|
||||
}
|
||||
|
||||
public void setForceEnglish(boolean forceEnglish) {
|
||||
if (this.forceEnglish == forceEnglish) return;
|
||||
this.forceEnglish = forceEnglish;
|
||||
this.checkResourcesOverrides(forceEnglish, this.nightModeOverride);
|
||||
}
|
||||
|
||||
public void setNightModeOverride(Boolean nightModeOverride) {
|
||||
if (this.nightModeOverride == nightModeOverride) return;
|
||||
this.nightModeOverride = nightModeOverride;
|
||||
this.checkResourcesOverrides(this.forceEnglish, nightModeOverride);
|
||||
}
|
||||
|
||||
private void checkResourcesOverrides(boolean forceEnglish,Boolean nightModeOverride) {
|
||||
if (!this.canReload) return; // Do not reload during theme reload
|
||||
this.compatConfigHelper.checkResourcesOverrides(forceEnglish, nightModeOverride);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,10 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M11.99,2C6.47,2 2,6.48 2,12s4.47,10 9.99,10C17.52,22 22,17.52 22,12S17.52,2 11.99,2zM18.92,8h-2.95c-0.32,-1.25 -0.78,-2.45 -1.38,-3.56 1.84,0.63 3.37,1.91 4.33,3.56zM12,4.04c0.83,1.2 1.48,2.53 1.91,3.96h-3.82c0.43,-1.43 1.08,-2.76 1.91,-3.96zM4.26,14C4.1,13.36 4,12.69 4,12s0.1,-1.36 0.26,-2h3.38c-0.08,0.66 -0.14,1.32 -0.14,2 0,0.68 0.06,1.34 0.14,2L4.26,14zM5.08,16h2.95c0.32,1.25 0.78,2.45 1.38,3.56 -1.84,-0.63 -3.37,-1.9 -4.33,-3.56zM8.03,8L5.08,8c0.96,-1.66 2.49,-2.93 4.33,-3.56C8.81,5.55 8.35,6.75 8.03,8zM12,19.96c-0.83,-1.2 -1.48,-2.53 -1.91,-3.96h3.82c-0.43,1.43 -1.08,2.76 -1.91,3.96zM14.34,14L9.66,14c-0.09,-0.66 -0.16,-1.32 -0.16,-2 0,-0.68 0.07,-1.35 0.16,-2h4.68c0.09,0.65 0.16,1.32 0.16,2 0,0.68 -0.07,1.34 -0.16,2zM14.59,19.56c0.6,-1.11 1.06,-2.31 1.38,-3.56h2.95c-0.96,1.65 -2.49,2.93 -4.33,3.56zM16.36,14c0.08,-0.66 0.14,-1.32 0.14,-2 0,-0.68 -0.06,-1.34 -0.14,-2h3.38c0.16,0.64 0.26,1.31 0.26,2s-0.1,1.36 -0.26,2h-3.38z"/>
|
||||
</vector>
|
||||
@ -0,0 +1,10 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M17,1.01L7,1c-1.1,0 -2,0.9 -2,2v18c0,1.1 0.9,2 2,2h10c1.1,0 2,-0.9 2,-2L19,3c0,-1.1 -0.9,-1.99 -2,-1.99zM17,19L7,19L7,5h10v14zM16,13h-3L13,8h-2v5L8,13l4,4 4,-4z"/>
|
||||
</vector>
|
||||
Loading…
Reference in New Issue