Rewrite FoxCompat to support Notch and remove unused stuff.

pull/27/head
Fox2Code 3 years ago
parent afc91645aa
commit a92d752160

@ -4,6 +4,9 @@ import androidx.annotation.Keep;
import com.topjohnwu.superuser.ShellUtils; import com.topjohnwu.superuser.ShellUtils;
/**
* I will probably outsource this to a separate library later
*/
@Keep @Keep
public class SystemProperties { public class SystemProperties {
@Keep @Keep
@ -13,4 +16,15 @@ public class SystemProperties {
prop = prop.substring(0, prop.length() - 1).trim(); prop = prop.substring(0, prop.length() - 1).trim();
return prop; return prop;
} }
@Keep
public static int getInt(String key, int def) {
try {
String value = get(key);
if (value.isEmpty()) return def;
return Integer.parseInt(value);
} catch (Exception e) {
return def;
}
}
} }

@ -1,6 +1,7 @@
package com.fox2code.mmm; package com.fox2code.mmm;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.content.ComponentName;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.content.res.Configuration; import android.content.res.Configuration;
@ -78,6 +79,13 @@ public class MainApplication extends CompatApplication {
} }
public static void addSecret(Intent intent) { public static void addSecret(Intent intent) {
ComponentName componentName = intent.getComponent();
String packageName = componentName != null ?
componentName.getPackageName() : intent.getPackage();
if (!BuildConfig.APPLICATION_ID.equalsIgnoreCase(packageName)) {
// Code safeguard, we should never reach here.
throw new IllegalArgumentException("Can't add secret to outbound Intent");
}
intent.putExtra("secret", secret); intent.putExtra("secret", secret);
} }
@ -101,10 +109,6 @@ public class MainApplication extends CompatApplication {
return getSharedPreferences().getBoolean("pref_show_incompatible", false); return getSharedPreferences().getBoolean("pref_show_incompatible", false);
} }
public static boolean isForceEnglish() {
return getSharedPreferences().getBoolean("pref_force_english", false);
}
public static boolean isForceDarkTerminal() { public static boolean isForceDarkTerminal() {
return getSharedPreferences().getBoolean("pref_force_dark_terminal", false); return getSharedPreferences().getBoolean("pref_force_dark_terminal", false);
} }
@ -190,7 +194,6 @@ public class MainApplication extends CompatApplication {
if (contextThemeWrapper == null) { if (contextThemeWrapper == null) {
contextThemeWrapper = this.markwonThemeContext = contextThemeWrapper = this.markwonThemeContext =
new CompatThemeWrapper(this, this.managerThemeResId); new CompatThemeWrapper(this, this.managerThemeResId);
contextThemeWrapper.setForceEnglish(isForceEnglish());
} }
Markwon markwon = Markwon.builder(contextThemeWrapper).usePlugin(HtmlPlugin.create()) Markwon markwon = Markwon.builder(contextThemeWrapper).usePlugin(HtmlPlugin.create())
.usePlugin(SyntaxHighlightPlugin.create( .usePlugin(SyntaxHighlightPlugin.create(
@ -327,14 +330,12 @@ public class MainApplication extends CompatApplication {
@Override @Override
public void onCreateCompatActivity(CompatActivity compatActivity) { public void onCreateCompatActivity(CompatActivity compatActivity) {
this.setForceEnglish(isForceEnglish());
super.onCreateCompatActivity(compatActivity); super.onCreateCompatActivity(compatActivity);
compatActivity.setTheme(this.managerThemeResId); compatActivity.setTheme(this.managerThemeResId);
} }
@Override @Override
public void onRefreshUI(CompatActivity compatActivity) { public void onRefreshUI(CompatActivity compatActivity) {
this.setForceEnglish(isForceEnglish());
super.onRefreshUI(compatActivity); super.onRefreshUI(compatActivity);
compatActivity.setThemeRecreate(this.managerThemeResId); compatActivity.setThemeRecreate(this.managerThemeResId);
} }

@ -12,16 +12,16 @@ import android.graphics.drawable.Drawable;
import android.os.Build; import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.os.SystemProperties; import android.os.SystemProperties;
import android.util.AttributeSet;
import android.util.Log; import android.util.Log;
import android.util.TypedValue; import android.util.TypedValue;
import android.view.Display;
import android.view.KeyCharacterMap; import android.view.KeyCharacterMap;
import android.view.KeyEvent; import android.view.KeyEvent;
import android.view.Menu; import android.view.Menu;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.Surface;
import android.view.View; import android.view.View;
import android.view.ViewConfiguration; import android.view.ViewConfiguration;
import android.widget.ScrollView;
import androidx.annotation.AttrRes; import androidx.annotation.AttrRes;
import androidx.annotation.CallSuper; import androidx.annotation.CallSuper;
@ -29,6 +29,7 @@ import androidx.annotation.ColorInt;
import androidx.annotation.ColorRes; import androidx.annotation.ColorRes;
import androidx.annotation.Dimension; import androidx.annotation.Dimension;
import androidx.annotation.DrawableRes; import androidx.annotation.DrawableRes;
import androidx.annotation.IntDef;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.annotation.Px; import androidx.annotation.Px;
@ -37,6 +38,7 @@ import androidx.annotation.StyleRes;
import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.ContextCompat; import androidx.core.content.ContextCompat;
import androidx.core.graphics.ColorUtils; import androidx.core.graphics.ColorUtils;
import androidx.core.graphics.Insets;
import androidx.core.view.WindowInsetsCompat; import androidx.core.view.WindowInsetsCompat;
import androidx.core.widget.NestedScrollView; import androidx.core.widget.NestedScrollView;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
@ -44,12 +46,12 @@ import androidx.recyclerview.widget.RecyclerView;
import com.fox2code.mmm.Constants; import com.fox2code.mmm.Constants;
import com.fox2code.mmm.R; import com.fox2code.mmm.R;
import com.kieronquinn.monetcompat.app.MonetCompatActivity;
import com.kieronquinn.monetcompat.extensions.views.ViewExtensions_RecyclerViewKt; import com.kieronquinn.monetcompat.extensions.views.ViewExtensions_RecyclerViewKt;
import com.kieronquinn.monetcompat.extensions.views.ViewExtensions_ScrollViewKt; import com.kieronquinn.monetcompat.extensions.views.ViewExtensions_ScrollViewKt;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
import java.util.Locale;
import java.util.Objects; import java.util.Objects;
import rikka.insets.WindowInsetsHelper; import rikka.insets.WindowInsetsHelper;
@ -71,13 +73,13 @@ public class CompatActivity extends AppCompatActivity {
}; };
final WeakReference<CompatActivity> selfReference; final WeakReference<CompatActivity> selfReference;
private final CompatConfigHelper compatConfigHelper = new CompatConfigHelper(this);
private CompatActivity.OnActivityResultCallback onActivityResultCallback; private CompatActivity.OnActivityResultCallback onActivityResultCallback;
private CompatActivity.OnBackPressedCallback onBackPressedCallback; private CompatActivity.OnBackPressedCallback onBackPressedCallback;
private MenuItem.OnMenuItemClickListener menuClickListener; private MenuItem.OnMenuItemClickListener menuClickListener;
private CharSequence menuContentDescription; private CharSequence menuContentDescription;
@StyleRes private int displayCutoutHeight = 0;
private int setThemeDynamic = 0; @Rotation private int cachedRotation = 0;
@StyleRes private int setThemeDynamic = 0;
private boolean onCreateCalledOnce = false; private boolean onCreateCalledOnce = false;
private boolean onCreateCalled = false; private boolean onCreateCalled = false;
private boolean isRefreshUi = false; private boolean isRefreshUi = false;
@ -107,6 +109,8 @@ public class CompatActivity extends AppCompatActivity {
} }
})); }));
this.hasHardwareNavBar = this.hasHardwareNavBar0(); this.hasHardwareNavBar = this.hasHardwareNavBar0();
this.displayCutoutHeight = CompatNotch.getNotchHeight(this);
this.cachedRotation = this.getRotation();
this.onCreateCalledOnce = true; this.onCreateCalledOnce = true;
} }
Application application = this.getApplication(); Application application = this.getApplication();
@ -115,17 +119,28 @@ public class CompatActivity extends AppCompatActivity {
} }
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
this.onCreateCalled = true; this.onCreateCalled = true;
this.checkResourcesOverrides(
this.forceEnglish, this.nightModeOverride);
} }
@Override @Override
protected void onResume() { protected void onResume() {
this.hasHardwareNavBar = this.hasHardwareNavBar0(); this.hasHardwareNavBar = this.hasHardwareNavBar0();
this.displayCutoutHeight = CompatNotch.getNotchHeight(this);
this.cachedRotation = this.getRotation();
super.onResume(); super.onResume();
this.refreshUI(); this.refreshUI();
} }
@Override
public void onConfigurationChanged(@NonNull Configuration newConfig) {
super.onConfigurationChanged(newConfig);
if (this.cachedRotation != this.getRotation() &&
this.onCreateCalledOnce) {
this.cachedRotation = this.getRotation();
this.displayCutoutHeight = CompatNotch.getNotchHeight(this);
}
}
@Override @Override
public void finish() { public void finish() {
this.onActivityResultCallback = null; this.onActivityResultCallback = null;
@ -151,8 +166,6 @@ public class CompatActivity extends AppCompatActivity {
} finally { } finally {
this.isRefreshUi = false; this.isRefreshUi = false;
} }
this.checkResourcesOverrides(
this.forceEnglish, this.nightModeOverride);
} }
} }
@ -239,8 +252,7 @@ public class CompatActivity extends AppCompatActivity {
} }
} }
@Dimension @Dimension @Px
@Px
public int getActionBarHeight() { public int getActionBarHeight() {
androidx.appcompat.app.ActionBar compatActionBar; androidx.appcompat.app.ActionBar compatActionBar;
try { try {
@ -266,15 +278,6 @@ public class CompatActivity extends AppCompatActivity {
} }
} }
public int getActionBarHeight(Activity activity) {
TypedValue tv = new TypedValue();
int actionBarHeight = 0;
if (activity.getTheme().resolveAttribute(R.attr.actionBarSize, tv, true)) {
actionBarHeight = TypedValue.complexToDimensionPixelSize(tv.data, getResources().getDisplayMetrics());
}
return actionBarHeight;
}
public void setActionBarBackground(Drawable drawable) { public void setActionBarBackground(Drawable drawable) {
androidx.appcompat.app.ActionBar compatActionBar; androidx.appcompat.app.ActionBar compatActionBar;
try { try {
@ -295,8 +298,17 @@ public class CompatActivity extends AppCompatActivity {
@Dimension @Px @Dimension @Px
@SuppressLint("InternalInsetResource") @SuppressLint("InternalInsetResource")
public int getStatusBarHeight() { public int getStatusBarHeight() {
int height = WindowInsetsCompat.CONSUMED.getInsets( // Check display cutout height
WindowInsetsCompat.Type.statusBars()).top; int height = this.getRotation() == 0 ?
this.displayCutoutHeight : 0;
// Check consumed insets
if (WindowInsetsCompat.CONSUMED.isConsumed()) {
Insets insets = WindowInsetsCompat.CONSUMED.getInsets(
WindowInsetsCompat.Type.statusBars());
if (insets.top == 0) {
height = Math.max(height, insets.bottom);
}
}
// Check system resources // Check system resources
int id = Resources.getSystem().getIdentifier( int id = Resources.getSystem().getIdentifier(
"status_bar_height", "dimen", "android"); "status_bar_height", "dimen", "android");
@ -307,8 +319,16 @@ public class CompatActivity extends AppCompatActivity {
@Dimension @Px @Dimension @Px
@SuppressLint("InternalInsetResource") @SuppressLint("InternalInsetResource")
public int getNavigationBarHeight() { public int getNavigationBarHeight() {
int height = WindowInsetsCompat.CONSUMED.getInsets( int height = 0;
WindowInsetsCompat.Type.navigationBars()).bottom; // Check consumed insets
if (WindowInsetsCompat.CONSUMED.isConsumed()) {
Insets insets = WindowInsetsCompat.CONSUMED.getInsets(
WindowInsetsCompat.Type.statusBars());
if (insets.top != 0) {
height = Math.max(height,
insets.bottom - insets.top);
}
}
// Check system resources // Check system resources
int id = Resources.getSystem().getIdentifier( int id = Resources.getSystem().getIdentifier(
"config_showNavigationBar", "bool", "android"); "config_showNavigationBar", "bool", "android");
@ -408,19 +428,10 @@ public class CompatActivity extends AppCompatActivity {
super.overridePendingTransition( super.overridePendingTransition(
android.R.anim.fade_in, android.R.anim.fade_out); android.R.anim.fade_in, android.R.anim.fade_out);
} else { } else {
this.compatConfigHelper.checkResourcesOverrides(theme,
this.forceEnglish, this.nightModeOverride);
super.onApplyThemeResource(theme, resid, first); super.onApplyThemeResource(theme, resid, first);
} }
} }
@Override
public void onConfigurationChanged(@NonNull Configuration newConfig) {
this.compatConfigHelper.checkResourcesOverrides(newConfig,
this.forceEnglish, this.nightModeOverride);
super.onConfigurationChanged(newConfig);
}
public void setOnBackPressedCallback(OnBackPressedCallback onBackPressedCallback) { public void setOnBackPressedCallback(OnBackPressedCallback onBackPressedCallback) {
this.onBackPressedCallback = onBackPressedCallback; this.onBackPressedCallback = onBackPressedCallback;
} }
@ -487,31 +498,6 @@ public class CompatActivity extends AppCompatActivity {
} }
} }
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);
}
void propagateResourcesOverride(boolean forceEnglish, Boolean nightModeOverride) {
if (this.forceEnglish == forceEnglish &&
this.nightModeOverride == nightModeOverride) return;
this.forceEnglish = forceEnglish;
this.nightModeOverride = nightModeOverride;
this.checkResourcesOverrides(forceEnglish, nightModeOverride);
}
private void checkResourcesOverrides(boolean forceEnglish, Boolean nightModeOverride) {
if (this.isRefreshUi || !this.onCreateCalled) return; // Wait before reload
this.compatConfigHelper.checkResourcesOverrides(forceEnglish, nightModeOverride);
}
public boolean isLightTheme() { public boolean isLightTheme() {
Resources.Theme theme = this.getTheme(); Resources.Theme theme = this.getTheme();
TypedValue typedValue = new TypedValue(); TypedValue typedValue = new TypedValue();
@ -544,8 +530,34 @@ public class CompatActivity extends AppCompatActivity {
return ContextCompat.getColor(this, color); return ContextCompat.getColor(this, color);
} }
public Locale getUserLocale() { /**
return this.compatConfigHelper.getUserLocale(); * Note: This value can change at runtime on some devices,
* and return true if DisplayCutout is simulated.
* */
public boolean hasNotch() {
if (!this.onCreateCalledOnce) {
Log.w(TAG, "hasNotch() called before onCreate()");
return CompatNotch.getNotchHeight(this) != 0;
}
return this.displayCutoutHeight != 0;
}
@SuppressWarnings("deprecation")
@Nullable @Override
public Display getDisplay() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
return super.getDisplay();
}
return this.getWindowManager().getDefaultDisplay();
}
@Rotation
public int getRotation() {
Display display = this.getDisplay();
return display != null ? display.getRotation() :
this.getResources().getConfiguration().orientation ==
Configuration.ORIENTATION_LANDSCAPE ?
Surface.ROTATION_90 : Surface.ROTATION_0;
} }
public static CompatActivity getCompatActivity(View view) { public static CompatActivity getCompatActivity(View view) {
@ -584,4 +596,13 @@ public class CompatActivity extends AppCompatActivity {
void onRefreshUI(CompatActivity compatActivity); void onRefreshUI(CompatActivity compatActivity);
} }
@IntDef(open = true, value = {
Surface.ROTATION_0,
Surface.ROTATION_90,
Surface.ROTATION_180,
Surface.ROTATION_270
})
@Retention(RetentionPolicy.SOURCE)
private @interface Rotation {}
} }

@ -1,17 +1,15 @@
package com.fox2code.mmm.compat; package com.fox2code.mmm.compat;
import android.app.Application; import android.app.Application;
import android.content.res.Configuration;
import android.content.res.Resources; import android.content.res.Resources;
import android.os.Build; import android.os.Build;
import android.util.Log;
import android.util.TypedValue; import android.util.TypedValue;
import androidx.annotation.AttrRes; import androidx.annotation.AttrRes;
import androidx.annotation.CallSuper; import androidx.annotation.CallSuper;
import androidx.annotation.ColorInt; import androidx.annotation.ColorInt;
import androidx.annotation.ColorRes; import androidx.annotation.ColorRes;
import androidx.annotation.NonNull; import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat; import androidx.core.content.ContextCompat;
import androidx.core.graphics.ColorUtils; import androidx.core.graphics.ColorUtils;
@ -24,69 +22,10 @@ import java.lang.ref.WeakReference;
*/ */
public class CompatApplication extends Application implements CompatActivity.ApplicationCallbacks { public class CompatApplication extends Application implements CompatActivity.ApplicationCallbacks {
private static final String TAG = "CompatApplication"; private static final String TAG = "CompatApplication";
private final CompatConfigHelper compatConfigHelper = new CompatConfigHelper(this);
private WeakReference<CompatActivity> lastCompatActivity; private WeakReference<CompatActivity> lastCompatActivity;
// CompatConfigHelper
private boolean forceEnglish;
private Boolean nightModeOverride;
private boolean propagateOverrides;
public CompatApplication() {} public CompatApplication() {}
@Override
public void onConfigurationChanged(@NonNull Configuration newConfig) {
this.compatConfigHelper.checkResourcesOverrides(newConfig,
this.forceEnglish, this.nightModeOverride);
super.onConfigurationChanged(newConfig);
}
public void setForceEnglish(boolean forceEnglish) {
if (this.forceEnglish != forceEnglish) {
this.forceEnglish = forceEnglish;
this.checkResourcesOverrides(forceEnglish, this.nightModeOverride);
}
// Propagate even if local value didn't changed
if (this.propagateOverrides && this.lastCompatActivity != null) {
CompatActivity compatActivity = this.lastCompatActivity.get();
if (compatActivity != null)
compatActivity.setForceEnglish(forceEnglish);
}
}
public void setNightModeOverride(Boolean nightModeOverride) {
if (this.nightModeOverride != nightModeOverride) {
this.nightModeOverride = nightModeOverride;
this.checkResourcesOverrides(this.forceEnglish, nightModeOverride);
}
// Propagate even if local value didn't changed
if (this.propagateOverrides && this.lastCompatActivity != null) {
CompatActivity compatActivity = this.lastCompatActivity.get();
if (compatActivity != null)
compatActivity.setNightModeOverride(nightModeOverride);
}
}
public boolean isPropagateOverrides() {
return propagateOverrides;
}
public void setPropagateOverrides(boolean propagateOverrides) {
this.propagateOverrides = propagateOverrides;
WeakReference<CompatActivity> lastCompatActivity = this.lastCompatActivity;
if (lastCompatActivity != null) {
Log.d(TAG, "setPropagateOverrides(" + // This should be avoided
propagateOverrides + ") called after first activity created!");
CompatActivity compatActivity = lastCompatActivity.get();
if (compatActivity != null && propagateOverrides) {
this.propagateOverrides(compatActivity);
}
}
}
private void checkResourcesOverrides(boolean forceEnglish, Boolean nightModeOverride) {
this.compatConfigHelper.checkResourcesOverrides(forceEnglish, nightModeOverride);
}
public boolean isLightTheme() { public boolean isLightTheme() {
Resources.Theme theme = this.getTheme(); Resources.Theme theme = this.getTheme();
TypedValue typedValue = new TypedValue(); TypedValue typedValue = new TypedValue();
@ -123,22 +62,17 @@ public class CompatApplication extends Application implements CompatActivity.App
@CallSuper @CallSuper
public void onCreateCompatActivity(CompatActivity compatActivity) { public void onCreateCompatActivity(CompatActivity compatActivity) {
this.lastCompatActivity = compatActivity.selfReference; this.lastCompatActivity = compatActivity.selfReference;
if (this.propagateOverrides) {
this.propagateOverrides(compatActivity);
}
} }
@Override @Override
@CallSuper @CallSuper
public void onRefreshUI(CompatActivity compatActivity) { public void onRefreshUI(CompatActivity compatActivity) {
this.lastCompatActivity = compatActivity.selfReference; this.lastCompatActivity = compatActivity.selfReference;
if (this.propagateOverrides) {
this.propagateOverrides(compatActivity);
}
} }
private void propagateOverrides(CompatActivity compatActivity) { @Nullable
compatActivity.propagateResourcesOverride( public CompatActivity getLastCompatActivity() {
this.forceEnglish, this.nightModeOverride); return this.lastCompatActivity == null ?
null : this.lastCompatActivity.get();
} }
} }

@ -1,94 +0,0 @@
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 englishLocale = Locale.ENGLISH;
private static final Object englishLocales =
Build.VERSION.SDK_INT >= Build.VERSION_CODES.N ?
new LocaleList(englishLocale) : null;
private final Context context;
private Object userLocales;
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) {
Resources res = theme.getResources();
if (this.checkResourcesOverrides(res.getConfiguration(),
forceEnglish, nightModeOverride)) {
res.updateConfiguration(
res.getConfiguration(),
res.getDisplayMetrics());
}
}
boolean checkResourcesOverrides(Configuration conf, boolean forceEnglish,
Boolean nightModeOverride) {
Locale current = conf.locale;
boolean didChange = false;
boolean wasForceEnglish = englishLocale.equals(current);
if (forceEnglish != wasForceEnglish) {
didChange = true;
if (forceEnglish) {
this.userLocale = conf.locale;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
this.userLocales = conf.getLocales();
}
conf.locale = englishLocale;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
conf.setLocales((LocaleList) englishLocales);
}
} else {
conf.locale = this.userLocale;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
conf.setLocales((LocaleList) this.userLocales);
}
}
}
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 (!forceEnglish && !wasForceEnglish) {
this.userLocale = null;
this.userLocales = null;
}
return didChange;
}
public Locale getUserLocale() {
// Only use cached value if force english
Locale locale = this.context.getResources().getConfiguration().locale;
return englishLocale.equals(locale) ? this.userLocale : locale;
}
}

@ -0,0 +1,93 @@
package com.fox2code.mmm.compat;
import android.annotation.SuppressLint;
import android.content.res.Resources;
import android.os.Build;
import android.os.SystemProperties;
import android.util.Log;
import android.view.Display;
import android.view.DisplayCutout;
import androidx.annotation.RequiresApi;
import androidx.core.view.DisplayCutoutCompat;
import androidx.core.view.WindowInsetsCompat;
import java.lang.reflect.Method;
import java.util.Objects;
/**
* Get notch information from any Android devices.
*/
final class CompatNotch {
private static final String TAG = "CompatNotch";
static int getNotchHeight(CompatActivity compatActivity) {
// Android 9.0 still need legacy check for notch detection.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
return getNotchHeightModern(compatActivity);
} else {
int notch = getNotchHeightLegacy(compatActivity);
DisplayCutoutCompat displayCutoutCompat =
WindowInsetsCompat.CONSUMED.getDisplayCutout();
return displayCutoutCompat == null ? notch :
Math.max(displayCutoutCompat.getSafeInsetTop(), notch);
}
}
@RequiresApi(Build.VERSION_CODES.Q)
private static int getNotchHeightModern(CompatActivity compatActivity) {
Display display = compatActivity.getDisplay();
DisplayCutout displayCutout = display == null ? null : display.getCutout();
if (displayCutout != null) return Math.max(displayCutout.getSafeInsetTop(), 1);
DisplayCutoutCompat displayCutoutCompat = WindowInsetsCompat.CONSUMED.getDisplayCutout();
return displayCutoutCompat == null ? 0 : Math.max(displayCutoutCompat.getSafeInsetTop(), 1);
}
private static final int VIVO_NOTCH = 0x00000020;
@SuppressLint({"InternalInsetResource", "PrivateApi"})
private static int getNotchHeightLegacy(CompatActivity compatActivity) {
ClassLoader classLoader = compatActivity.getClassLoader();
int id = Resources.getSystem().getIdentifier("status_bar_height", "dimen", "android");
int height = id <= 0 ? 1 : Resources.getSystem().getDimensionPixelSize(id);
try { // Huawei Notch
Class<?> HwNotchSizeUtil = classLoader.loadClass("com.huawei.android.util.HwNotchSizeUtil");
Method get = HwNotchSizeUtil.getMethod("hasNotchInScreen");
if ((boolean) Objects.requireNonNull(
get.invoke(HwNotchSizeUtil))) {
try {
get = HwNotchSizeUtil.getMethod("getNotchSize");
return Math.max(((int[]) Objects.requireNonNull(
get.invoke(HwNotchSizeUtil)))[1], height);
} catch (Exception e) {
Log.e(TAG, "Failed to get Huawei notch on Huawei device", e);
return height;
}
}
} catch (Exception e) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O &&
"Huawei".equalsIgnoreCase(Build.MANUFACTURER)) {
Log.e(TAG, "Failed to get Huawei notch on Huawei device", e);
}
}
if (compatActivity.getPackageManager() // Oppo & MIUI Notch
.hasSystemFeature("com.oppo.feature.screen.heteromorphism") ||
SystemProperties.getInt("ro.miui.notch", -1) == 1) {
return height;
}
try { // Vivo Notch
Class<?> FtFeature = classLoader.loadClass("android.util.FtFeature");
Method method = FtFeature.getMethod("isFeatureSupport", int.class);
if ((boolean) Objects.requireNonNull(
method.invoke(FtFeature, VIVO_NOTCH))) {
return height;
}
} catch (Exception e) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O &&
"Vivo".equalsIgnoreCase(Build.MANUFACTURER)) {
Log.e(TAG, "Failed to get Vivo notch on Vivo device", e);
}
}
return 0;
}
}

@ -19,47 +19,19 @@ import com.fox2code.mmm.R;
* I will probably outsource this to a separate library later * I will probably outsource this to a separate library later
*/ */
public class CompatThemeWrapper extends ContextThemeWrapper { public class CompatThemeWrapper extends ContextThemeWrapper {
private final CompatConfigHelper compatConfigHelper = new CompatConfigHelper(this);
private boolean canReload; private boolean canReload;
// CompatConfigHelper
private boolean forceEnglish;
private Boolean nightModeOverride;
public CompatThemeWrapper(Context base, @StyleRes int themeResId) { public CompatThemeWrapper(Context base, @StyleRes int themeResId) {
super(base, themeResId); super(base, themeResId);
this.canReload = true; this.canReload = true;
this.checkResourcesOverrides(
this.forceEnglish, this.nightModeOverride);
} }
@Override @Override
protected void onApplyThemeResource(Resources.Theme theme, int resid, boolean first) { protected void onApplyThemeResource(Resources.Theme theme, int resid, boolean first) {
boolean couldReload = this.canReload; boolean couldReload = this.canReload;
if (couldReload) this.canReload = false; if (couldReload) this.canReload = false;
this.compatConfigHelper.checkResourcesOverrides(theme,
this.forceEnglish, this.nightModeOverride);
super.onApplyThemeResource(theme, resid, first); super.onApplyThemeResource(theme, resid, first);
if (couldReload) this.canReload = true; 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);
} }
public boolean isLightTheme() { public boolean isLightTheme() {

@ -267,8 +267,8 @@ public class InstallerActivity extends CompatActivity {
} }
installerMonitor = new InstallerMonitor(installScript); installerMonitor = new InstallerMonitor(installScript);
installJob = Shell.cmd("export MMM_EXT_SUPPORT=1", installJob = Shell.cmd("export MMM_EXT_SUPPORT=1",
"export MMM_USER_LANGUAGE=" + (MainApplication.isForceEnglish() ? "en-US" : "export MMM_USER_LANGUAGE=" + this.getResources()
Resources.getSystem().getConfiguration().locale.toLanguageTag()), .getConfiguration().locale.toLanguageTag(),
"export MMM_APP_VERSION=" + BuildConfig.VERSION_NAME, "export MMM_APP_VERSION=" + BuildConfig.VERSION_NAME,
"export MMM_TEXT_WRAP=" + (this.textWrap ? "1" : "0"), "export MMM_TEXT_WRAP=" + (this.textWrap ? "1" : "0"),
AnsiConstants.ANSI_CMD_SUPPORT, AnsiConstants.ANSI_CMD_SUPPORT,
@ -406,8 +406,8 @@ public class InstallerActivity extends CompatActivity {
this.installerTerminal.disableAnsi(); this.installerTerminal.disableAnsi();
else this.installerTerminal.enableAnsi(); else this.installerTerminal.enableAnsi();
installJob = Shell.cmd(arch32, "export MMM_EXT_SUPPORT=1", installJob = Shell.cmd(arch32, "export MMM_EXT_SUPPORT=1",
"export MMM_USER_LANGUAGE=" + (MainApplication.isForceEnglish() ? "en-US" : "export MMM_USER_LANGUAGE=" + this.getResources()
Resources.getSystem().getConfiguration().locale.toLanguageTag()), .getConfiguration().locale.toLanguageTag(),
"export MMM_APP_VERSION=" + BuildConfig.VERSION_NAME, "export MMM_APP_VERSION=" + BuildConfig.VERSION_NAME,
"export MMM_TEXT_WRAP=" + (this.textWrap ? "1" : "0"), "export MMM_TEXT_WRAP=" + (this.textWrap ? "1" : "0"),
this.installerTerminal.isAnsiEnabled() ? this.installerTerminal.isAnsiEnabled() ?

Loading…
Cancel
Save