Post-AOD cleanup checkpoint
This commit is contained in:
@@ -1,9 +1,12 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
||||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
||||||
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
|
<uses-permission
|
||||||
|
android:name="android.permission.QUERY_ALL_PACKAGES"
|
||||||
|
tools:ignore="QueryAllPackagesPermission" />
|
||||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||||
|
|
||||||
<application
|
<application
|
||||||
@@ -34,7 +37,8 @@
|
|||||||
<provider
|
<provider
|
||||||
android:name=".shell.settings.SbtSettingsProvider"
|
android:name=".shell.settings.SbtSettingsProvider"
|
||||||
android:authorities="se.ajpanton.statusbartweak.settings"
|
android:authorities="se.ajpanton.statusbartweak.settings"
|
||||||
android:exported="true" />
|
android:exported="true"
|
||||||
|
tools:ignore="ExportedContentProvider" />
|
||||||
|
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,102 @@
|
|||||||
|
package se.ajpanton.statusbartweak.runtime;
|
||||||
|
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
|
import se.ajpanton.statusbartweak.runtime.hooks.ReflectionSupport;
|
||||||
|
import se.ajpanton.statusbartweak.shell.settings.AppIconRules;
|
||||||
|
|
||||||
|
public final class NotificationKeyReflection {
|
||||||
|
private static final String[] ENTRY_KEY_FIELD_NAMES = {
|
||||||
|
"mKey",
|
||||||
|
"key",
|
||||||
|
"notificationKey",
|
||||||
|
"mNotificationKey"
|
||||||
|
};
|
||||||
|
private static final String[] ICON_VIEW_KEY_FIELD_NAMES = {
|
||||||
|
"mNotificationKey",
|
||||||
|
"notificationKey",
|
||||||
|
"mKey",
|
||||||
|
"key"
|
||||||
|
};
|
||||||
|
|
||||||
|
private NotificationKeyReflection() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String rowFilterKey(Object target) {
|
||||||
|
String key = nonEmptyStringFromMethod(target, "getKey");
|
||||||
|
if (key != null) {
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
key = nonEmptyStringFromMethod(target, "getNotificationKey");
|
||||||
|
if (key != null) {
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
return nonEmptyStringFromFields(target, "mKey", "key");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String keyForEntry(Object entry) {
|
||||||
|
if (entry == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String key = nonEmptyStringFromMethod(entry, "getKey");
|
||||||
|
if (key != null) {
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
return nonEmptyStringFromFields(entry, ENTRY_KEY_FIELD_NAMES);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String keyForIconView(View view) {
|
||||||
|
if (view == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String key = nonEmptyStringFromMethod(view, "getNotificationKey");
|
||||||
|
if (key != null) {
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
return nonEmptyStringFromFields(view, ICON_VIEW_KEY_FIELD_NAMES);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Object entryForRow(View row) {
|
||||||
|
Object value = primaryEntryForRow(row);
|
||||||
|
return value != null ? value : ReflectionSupport.getFieldValue(row, "entry");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Object primaryEntryForRow(View row) {
|
||||||
|
Object value = ReflectionSupport.invokeMethod(row, "getEntry");
|
||||||
|
if (value != null) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
return ReflectionSupport.getFieldValue(row, "mEntry");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String packageFromNotificationKey(String key) {
|
||||||
|
if (key == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String normalized = key.trim();
|
||||||
|
int suffix = normalized.indexOf('@');
|
||||||
|
if (suffix >= 0) {
|
||||||
|
normalized = normalized.substring(0, suffix);
|
||||||
|
}
|
||||||
|
int slash = normalized.indexOf('/');
|
||||||
|
if (slash >= 0) {
|
||||||
|
normalized = normalized.substring(0, slash);
|
||||||
|
}
|
||||||
|
return AppIconRules.isValidPackageName(normalized) ? normalized : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String nonEmptyStringFromMethod(Object target, String methodName) {
|
||||||
|
Object value = ReflectionSupport.invokeMethod(target, methodName);
|
||||||
|
return value instanceof String string && !string.isEmpty() ? string : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String nonEmptyStringFromFields(Object target, String... fieldNames) {
|
||||||
|
for (String fieldName : fieldNames) {
|
||||||
|
Object value = ReflectionSupport.getFieldValue(target, fieldName);
|
||||||
|
if (value instanceof String string && !string.isEmpty()) {
|
||||||
|
return string;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package se.ajpanton.statusbartweak.runtime;
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
|
import android.content.Context;
|
||||||
|
|
||||||
|
import se.ajpanton.statusbartweak.runtime.hooks.ReflectionSupport;
|
||||||
|
|
||||||
|
public final class SystemContextProvider {
|
||||||
|
private SystemContextProvider() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("PrivateApi")
|
||||||
|
public static Context currentApplication() {
|
||||||
|
try {
|
||||||
|
Class<?> activityThreadClass = Class.forName("android.app.ActivityThread");
|
||||||
|
Object app = ReflectionSupport.invokeStaticMethod(
|
||||||
|
activityThreadClass,
|
||||||
|
"currentApplication");
|
||||||
|
return app instanceof Context context ? context : null;
|
||||||
|
} catch (Throwable ignored) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package se.ajpanton.statusbartweak.runtime;
|
||||||
|
|
||||||
|
import android.content.res.Resources;
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
|
public final class ViewIdNames {
|
||||||
|
private ViewIdNames() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String idName(View view) {
|
||||||
|
if (view == null || view.getId() == View.NO_ID) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return view.getResources().getResourceEntryName(view.getId());
|
||||||
|
} catch (Resources.NotFoundException ignored) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean hasIdName(View view, String expectedIdName) {
|
||||||
|
return expectedIdName != null && expectedIdName.equals(idName(view));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -41,10 +41,6 @@ public final class RuntimeContext {
|
|||||||
return RuntimeLogGate.isEnabled();
|
return RuntimeLogGate.isEnabled();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void logInfo(String message) {
|
|
||||||
logSplit(Log.INFO, message, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void logWarning(String message, Throwable throwable) {
|
public void logWarning(String message, Throwable throwable) {
|
||||||
logSplit(Log.WARN, message, throwable);
|
logSplit(Log.WARN, message, throwable);
|
||||||
}
|
}
|
||||||
@@ -54,7 +50,7 @@ public final class RuntimeContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void logSplit(int priority, String message, Throwable throwable) {
|
private void logSplit(int priority, String message, Throwable throwable) {
|
||||||
if (!RuntimeLogGate.isEnabled()) {
|
if (!isLogEnabled()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
String safeMessage = message != null ? message : "";
|
String safeMessage = message != null ? message : "";
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package se.ajpanton.statusbartweak.runtime.features;
|
package se.ajpanton.statusbartweak.runtime.features;
|
||||||
|
|
||||||
import io.github.libxposed.api.XposedModuleInterface;
|
import io.github.libxposed.api.XposedModuleInterface;
|
||||||
|
import se.ajpanton.statusbartweak.shell.settings.SbtSettings;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Small independent runtime slice.
|
* Small independent runtime slice.
|
||||||
@@ -13,6 +14,10 @@ public interface RuntimeFeature {
|
|||||||
|
|
||||||
String getName();
|
String getName();
|
||||||
|
|
||||||
|
static boolean isSystemUiPackage(XposedModuleInterface.PackageReadyParam param) {
|
||||||
|
return param != null && SbtSettings.PACKAGE_SYSTEMUI.equals(param.getPackageName());
|
||||||
|
}
|
||||||
|
|
||||||
default void onModuleLoaded(
|
default void onModuleLoaded(
|
||||||
RuntimeContext context,
|
RuntimeContext context,
|
||||||
XposedModuleInterface.ModuleLoadedParam param
|
XposedModuleInterface.ModuleLoadedParam param
|
||||||
|
|||||||
@@ -1,12 +1,9 @@
|
|||||||
package se.ajpanton.statusbartweak.runtime.features;
|
package se.ajpanton.statusbartweak.runtime.features;
|
||||||
|
|
||||||
import android.content.BroadcastReceiver;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
|
||||||
import android.content.IntentFilter;
|
|
||||||
import android.os.Build;
|
|
||||||
|
|
||||||
import se.ajpanton.statusbartweak.runtime.hooks.ReflectionSupport;
|
import se.ajpanton.statusbartweak.runtime.SystemContextProvider;
|
||||||
|
import se.ajpanton.statusbartweak.runtime.settings.BroadcastReceiverSupport;
|
||||||
import se.ajpanton.statusbartweak.shell.settings.SbtDefaults;
|
import se.ajpanton.statusbartweak.shell.settings.SbtDefaults;
|
||||||
import se.ajpanton.statusbartweak.shell.settings.SbtSettings;
|
import se.ajpanton.statusbartweak.shell.settings.SbtSettings;
|
||||||
|
|
||||||
@@ -25,7 +22,7 @@ final class RuntimeLogGate {
|
|||||||
if (enabled != null) {
|
if (enabled != null) {
|
||||||
return enabled;
|
return enabled;
|
||||||
}
|
}
|
||||||
Context context = getSystemContext();
|
Context context = SystemContextProvider.currentApplication();
|
||||||
if (context == null) {
|
if (context == null) {
|
||||||
return SbtDefaults.DEBUG_WRITE_LOGS_DEFAULT;
|
return SbtDefaults.DEBUG_WRITE_LOGS_DEFAULT;
|
||||||
}
|
}
|
||||||
@@ -34,7 +31,7 @@ final class RuntimeLogGate {
|
|||||||
if (cachedEnabled == null) {
|
if (cachedEnabled == null) {
|
||||||
cachedEnabled = SbtSettings.isDebugLogWritingEnabled(context);
|
cachedEnabled = SbtSettings.isDebugLogWritingEnabled(context);
|
||||||
}
|
}
|
||||||
return cachedEnabled != null ? cachedEnabled : SbtDefaults.DEBUG_WRITE_LOGS_DEFAULT;
|
return cachedEnabled;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,37 +49,12 @@ final class RuntimeLogGate {
|
|||||||
if (receiverRegistered) {
|
if (receiverRegistered) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Context appContext = context.getApplicationContext();
|
BroadcastReceiverSupport.registerInvalidatingReceiver(
|
||||||
if (appContext == null) {
|
context,
|
||||||
appContext = context;
|
RuntimeLogGate::invalidate,
|
||||||
}
|
BroadcastReceiverSupport.filter(SbtSettings.ACTION_SETTINGS_CHANGED));
|
||||||
BroadcastReceiver receiver = new BroadcastReceiver() {
|
|
||||||
@Override
|
|
||||||
public void onReceive(Context context, Intent intent) {
|
|
||||||
invalidate();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
IntentFilter filter = new IntentFilter(SbtSettings.ACTION_SETTINGS_CHANGED);
|
|
||||||
if (Build.VERSION.SDK_INT >= 33) {
|
|
||||||
appContext.registerReceiver(receiver, filter, Context.RECEIVER_EXPORTED);
|
|
||||||
} else {
|
|
||||||
appContext.registerReceiver(receiver, filter);
|
|
||||||
}
|
|
||||||
receiverRegistered = true;
|
receiverRegistered = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Context getSystemContext() {
|
|
||||||
try {
|
|
||||||
Class<?> activityThreadClass = Class.forName("android.app.ActivityThread");
|
|
||||||
Object app = ReflectionSupport.invokeStaticMethod(
|
|
||||||
activityThreadClass,
|
|
||||||
"currentApplication",
|
|
||||||
new Class<?>[0]
|
|
||||||
);
|
|
||||||
return app instanceof Context context ? context : null;
|
|
||||||
} catch (Throwable ignored) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-27
@@ -3,14 +3,11 @@ package se.ajpanton.statusbartweak.runtime.features.battery;
|
|||||||
import android.content.BroadcastReceiver;
|
import android.content.BroadcastReceiver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.IntentFilter;
|
|
||||||
import android.content.res.Resources;
|
|
||||||
import android.graphics.Canvas;
|
import android.graphics.Canvas;
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
import android.graphics.Paint;
|
import android.graphics.Paint;
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.os.BatteryManager;
|
import android.os.BatteryManager;
|
||||||
import android.os.Build;
|
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.view.ViewParent;
|
import android.view.ViewParent;
|
||||||
@@ -24,9 +21,11 @@ import java.util.Set;
|
|||||||
import java.util.WeakHashMap;
|
import java.util.WeakHashMap;
|
||||||
|
|
||||||
import io.github.libxposed.api.XposedInterface;
|
import io.github.libxposed.api.XposedInterface;
|
||||||
|
import se.ajpanton.statusbartweak.runtime.ViewIdNames;
|
||||||
import se.ajpanton.statusbartweak.runtime.features.RuntimeContext;
|
import se.ajpanton.statusbartweak.runtime.features.RuntimeContext;
|
||||||
import se.ajpanton.statusbartweak.runtime.hooks.ReflectionSupport;
|
import se.ajpanton.statusbartweak.runtime.hooks.ReflectionSupport;
|
||||||
import se.ajpanton.statusbartweak.runtime.hooks.XposedHookSupport;
|
import se.ajpanton.statusbartweak.runtime.hooks.XposedHookSupport;
|
||||||
|
import se.ajpanton.statusbartweak.runtime.settings.BroadcastReceiverSupport;
|
||||||
import se.ajpanton.statusbartweak.runtime.settings.RuntimeSettingsCache;
|
import se.ajpanton.statusbartweak.runtime.settings.RuntimeSettingsCache;
|
||||||
import se.ajpanton.statusbartweak.shell.settings.BatteryBarStyle;
|
import se.ajpanton.statusbartweak.shell.settings.BatteryBarStyle;
|
||||||
import se.ajpanton.statusbartweak.shell.settings.SbtSettings;
|
import se.ajpanton.statusbartweak.shell.settings.SbtSettings;
|
||||||
@@ -116,7 +115,6 @@ final class BatteryBarController {
|
|||||||
root.removeOnLayoutChangeListener(listener);
|
root.removeOnLayoutChangeListener(listener);
|
||||||
}
|
}
|
||||||
roots.remove(root);
|
roots.remove(root);
|
||||||
lastSignatures.remove(root);
|
|
||||||
removeBatteryBarView(root);
|
removeBatteryBarView(root);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -124,10 +122,6 @@ final class BatteryBarController {
|
|||||||
if (context == null || receiverRegistered) {
|
if (context == null || receiverRegistered) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Context appContext = context.getApplicationContext();
|
|
||||||
if (appContext == null) {
|
|
||||||
appContext = context;
|
|
||||||
}
|
|
||||||
BroadcastReceiver receiver = new BroadcastReceiver() {
|
BroadcastReceiver receiver = new BroadcastReceiver() {
|
||||||
@Override
|
@Override
|
||||||
public void onReceive(Context ctx, Intent intent) {
|
public void onReceive(Context ctx, Intent intent) {
|
||||||
@@ -141,16 +135,12 @@ final class BatteryBarController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
IntentFilter filter = new IntentFilter();
|
Intent sticky = BroadcastReceiverSupport.registerExportedOnApplicationContext(
|
||||||
filter.addAction(Intent.ACTION_BATTERY_CHANGED);
|
context,
|
||||||
filter.addAction(Intent.ACTION_USER_UNLOCKED);
|
receiver,
|
||||||
filter.addAction(SbtSettings.ACTION_SETTINGS_CHANGED);
|
BroadcastReceiverSupport.filter(
|
||||||
Intent sticky;
|
Intent.ACTION_BATTERY_CHANGED,
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
SbtSettings.ACTION_SETTINGS_CHANGED));
|
||||||
sticky = appContext.registerReceiver(receiver, filter, Context.RECEIVER_EXPORTED);
|
|
||||||
} else {
|
|
||||||
sticky = appContext.registerReceiver(receiver, filter);
|
|
||||||
}
|
|
||||||
receiverRegistered = true;
|
receiverRegistered = true;
|
||||||
if (sticky != null) {
|
if (sticky != null) {
|
||||||
updateBatteryState(sticky);
|
updateBatteryState(sticky);
|
||||||
@@ -353,15 +343,7 @@ final class BatteryBarController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static boolean matchesClockId(View view) {
|
private static boolean matchesClockId(View view) {
|
||||||
int id = view.getId();
|
return ViewIdNames.hasIdName(view, "clock");
|
||||||
if (id == View.NO_ID) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
return "clock".equals(view.getResources().getResourceEntryName(id));
|
|
||||||
} catch (Resources.NotFoundException ignored) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int dpToPx(Context context, int dp) {
|
private static int dpToPx(Context context, int dp) {
|
||||||
|
|||||||
+1
-1
@@ -25,7 +25,7 @@ public final class BatteryBarFeature implements RuntimeFeature {
|
|||||||
RuntimeContext context,
|
RuntimeContext context,
|
||||||
XposedModuleInterface.PackageReadyParam param
|
XposedModuleInterface.PackageReadyParam param
|
||||||
) {
|
) {
|
||||||
if (param == null || !"com.android.systemui".equals(param.getPackageName())) {
|
if (!RuntimeFeature.isSystemUiPackage(param)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
installController(context, param.getClassLoader());
|
installController(context, param.getClassLoader());
|
||||||
|
|||||||
+33
-71
@@ -3,8 +3,6 @@ package se.ajpanton.statusbartweak.runtime.features.chips;
|
|||||||
import android.app.KeyguardManager;
|
import android.app.KeyguardManager;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.IntentFilter;
|
|
||||||
import android.os.Build;
|
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.view.ViewParent;
|
import android.view.ViewParent;
|
||||||
@@ -12,13 +10,17 @@ import android.widget.TextView;
|
|||||||
|
|
||||||
import java.util.ArrayDeque;
|
import java.util.ArrayDeque;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.Locale;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.WeakHashMap;
|
import java.util.WeakHashMap;
|
||||||
|
|
||||||
|
import se.ajpanton.statusbartweak.runtime.SystemContextProvider;
|
||||||
|
import se.ajpanton.statusbartweak.runtime.ViewIdNames;
|
||||||
import se.ajpanton.statusbartweak.runtime.features.RuntimeContext;
|
import se.ajpanton.statusbartweak.runtime.features.RuntimeContext;
|
||||||
import se.ajpanton.statusbartweak.runtime.hooks.InstanceStateStore;
|
import se.ajpanton.statusbartweak.runtime.hooks.InstanceStateStore;
|
||||||
import se.ajpanton.statusbartweak.runtime.hooks.ReflectionSupport;
|
import se.ajpanton.statusbartweak.runtime.hooks.ReflectionSupport;
|
||||||
import se.ajpanton.statusbartweak.runtime.hooks.XposedHookSupport;
|
import se.ajpanton.statusbartweak.runtime.hooks.XposedHookSupport;
|
||||||
|
import se.ajpanton.statusbartweak.runtime.settings.BroadcastReceiverSupport;
|
||||||
import se.ajpanton.statusbartweak.runtime.settings.RuntimeSettingsCache;
|
import se.ajpanton.statusbartweak.runtime.settings.RuntimeSettingsCache;
|
||||||
import se.ajpanton.statusbartweak.shell.settings.SbtSettings;
|
import se.ajpanton.statusbartweak.shell.settings.SbtSettings;
|
||||||
|
|
||||||
@@ -64,7 +66,7 @@ final class StatusChipHider {
|
|||||||
if (hooksInstalled) {
|
if (hooksInstalled) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
installBroadcastReceiver(getSystemContext());
|
installBroadcastReceiver(SystemContextProvider.currentApplication());
|
||||||
refreshSettings();
|
refreshSettings();
|
||||||
installOngoingActivityHooks(classLoader);
|
installOngoingActivityHooks(classLoader);
|
||||||
installTouchInterceptHooks(classLoader);
|
installTouchInterceptHooks(classLoader);
|
||||||
@@ -148,7 +150,7 @@ final class StatusChipHider {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
if (scannedRoots.add(root)) {
|
if (scannedRoots.add(root)) {
|
||||||
applyToViewTree(root, false);
|
applyToViewTree(root);
|
||||||
} else {
|
} else {
|
||||||
keepForcedHiddenViewsHidden();
|
keepForcedHiddenViewsHidden();
|
||||||
}
|
}
|
||||||
@@ -173,7 +175,7 @@ final class StatusChipHider {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
if (view.getWidth() > 0 && view.getHeight() > 0) {
|
if (view.getWidth() > 0 && view.getHeight() > 0) {
|
||||||
applySourceDecision(view, false);
|
applySourceDecision(view);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
});
|
});
|
||||||
@@ -206,7 +208,7 @@ final class StatusChipHider {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
if (view.getWidth() > 0 && view.getHeight() > 0) {
|
if (view.getWidth() > 0 && view.getHeight() > 0) {
|
||||||
applySourceDecision(view, false);
|
applySourceDecision(view);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
});
|
});
|
||||||
@@ -219,12 +221,6 @@ final class StatusChipHider {
|
|||||||
if (context == null) {
|
if (context == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Context appContext = context.getApplicationContext();
|
|
||||||
if (appContext == null) {
|
|
||||||
appContext = context;
|
|
||||||
}
|
|
||||||
IntentFilter filter = new IntentFilter(SbtSettings.ACTION_SETTINGS_CHANGED);
|
|
||||||
filter.addAction(Intent.ACTION_USER_UNLOCKED);
|
|
||||||
android.content.BroadcastReceiver receiver = new android.content.BroadcastReceiver() {
|
android.content.BroadcastReceiver receiver = new android.content.BroadcastReceiver() {
|
||||||
@Override
|
@Override
|
||||||
public void onReceive(Context context, Intent intent) {
|
public void onReceive(Context context, Intent intent) {
|
||||||
@@ -235,16 +231,17 @@ final class StatusChipHider {
|
|||||||
rescanTrackedRoots();
|
rescanTrackedRoots();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if (Build.VERSION.SDK_INT >= 33) {
|
BroadcastReceiverSupport.registerExportedOnApplicationContext(
|
||||||
appContext.registerReceiver(receiver, filter, Context.RECEIVER_EXPORTED);
|
context,
|
||||||
} else {
|
receiver,
|
||||||
appContext.registerReceiver(receiver, filter);
|
BroadcastReceiverSupport.filter(
|
||||||
}
|
SbtSettings.ACTION_SETTINGS_CHANGED,
|
||||||
|
Intent.ACTION_USER_UNLOCKED));
|
||||||
broadcastInstalled = true;
|
broadcastInstalled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void refreshSettings() {
|
private void refreshSettings() {
|
||||||
Context context = getSystemContext();
|
Context context = SystemContextProvider.currentApplication();
|
||||||
if (context == null) {
|
if (context == null) {
|
||||||
hideAll = false;
|
hideAll = false;
|
||||||
hideMediaUnlocked = false;
|
hideMediaUnlocked = false;
|
||||||
@@ -271,7 +268,7 @@ final class StatusChipHider {
|
|||||||
for (View root : trackedRoots) {
|
for (View root : trackedRoots) {
|
||||||
if (root != null) {
|
if (root != null) {
|
||||||
scannedRoots.add(root);
|
scannedRoots.add(root);
|
||||||
applyToViewTree(root, false);
|
applyToViewTree(root);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -302,7 +299,7 @@ final class StatusChipHider {
|
|||||||
userManager
|
userManager
|
||||||
);
|
);
|
||||||
ReflectionSupport.invokeMethod(controller, "updateParentViewVisibility", new Class<?>[]{boolean.class}, false);
|
ReflectionSupport.invokeMethod(controller, "updateParentViewVisibility", new Class<?>[]{boolean.class}, false);
|
||||||
ReflectionSupport.invokeMethod(controller, "updateAdapter", new Class<?>[0]);
|
ReflectionSupport.invokeMethod(controller, "updateAdapter");
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean shouldSuppressTopOngoingController() {
|
private boolean shouldSuppressTopOngoingController() {
|
||||||
@@ -325,7 +322,7 @@ final class StatusChipHider {
|
|||||||
return sawItem;
|
return sawItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void applyToViewTree(View root, boolean restoreOnly) {
|
private void applyToViewTree(View root) {
|
||||||
ArrayDeque<View> stack = new ArrayDeque<>();
|
ArrayDeque<View> stack = new ArrayDeque<>();
|
||||||
stack.push(root);
|
stack.push(root);
|
||||||
while (!stack.isEmpty()) {
|
while (!stack.isEmpty()) {
|
||||||
@@ -338,18 +335,14 @@ final class StatusChipHider {
|
|||||||
stack.push(group.getChildAt(index));
|
stack.push(group.getChildAt(index));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
applySourceDecision(source, restoreOnly);
|
applySourceDecision(source);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean applySourceDecision(View source, boolean restoreOnly) {
|
private boolean applySourceDecision(View source) {
|
||||||
if (source == null) {
|
if (source == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (restoreOnly) {
|
|
||||||
restoreIfForcedHidden(source);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
int zone = detectZone(source);
|
int zone = detectZone(source);
|
||||||
if (zone == ZONE_NONE || !isSourceCandidate(source)) {
|
if (zone == ZONE_NONE || !isSourceCandidate(source)) {
|
||||||
restoreIfForcedHidden(source);
|
restoreIfForcedHidden(source);
|
||||||
@@ -371,7 +364,7 @@ final class StatusChipHider {
|
|||||||
String classNames = target == source
|
String classNames = target == source
|
||||||
? collectClassNames(source)
|
? collectClassNames(source)
|
||||||
: collectClassNames(source) + " " + collectClassNames(target);
|
: collectClassNames(source) + " " + collectClassNames(target);
|
||||||
String lowerText = kindText.toLowerCase();
|
String lowerText = kindText.toLowerCase(Locale.ROOT);
|
||||||
if (looksLikePrivacy(target, kindText) || isDefinitelyNotChipText(lowerText)) {
|
if (looksLikePrivacy(target, kindText) || isDefinitelyNotChipText(lowerText)) {
|
||||||
restoreIfForcedHidden(target);
|
restoreIfForcedHidden(target);
|
||||||
return false;
|
return false;
|
||||||
@@ -415,7 +408,7 @@ final class StatusChipHider {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
String sourceText = collectText(source);
|
String sourceText = collectText(source);
|
||||||
String lowerText = sourceText.toLowerCase();
|
String lowerText = sourceText.toLowerCase(Locale.ROOT);
|
||||||
if (looksLikePrivacy(source, sourceText) || isDefinitelyNotChipText(lowerText)) {
|
if (looksLikePrivacy(source, sourceText) || isDefinitelyNotChipText(lowerText)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -427,17 +420,7 @@ final class StatusChipHider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean isSourceCandidate(View view) {
|
private boolean isSourceCandidate(View view) {
|
||||||
if (isOngoingActivityCapsule(view)) {
|
return isTransitionSourceCandidate(view) && looksLikeChipGeometry(view);
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!isSystemUiView(view) || !looksLikeChipGeometry(view)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
String className = className(view).toLowerCase();
|
|
||||||
if (className.contains("privacy") || isDefinitelyNotChipClass(className)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return isChipClassName(className);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isTransitionSourceCandidate(View view) {
|
private boolean isTransitionSourceCandidate(View view) {
|
||||||
@@ -447,7 +430,7 @@ final class StatusChipHider {
|
|||||||
if (!isSystemUiView(view)) {
|
if (!isSystemUiView(view)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
String className = className(view).toLowerCase();
|
String className = className(view).toLowerCase(Locale.ROOT);
|
||||||
if (className.contains("privacy") || isDefinitelyNotChipClass(className)) {
|
if (className.contains("privacy") || isDefinitelyNotChipClass(className)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -455,7 +438,7 @@ final class StatusChipHider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private View resolveHideTarget(View source, int sourceZone) {
|
private View resolveHideTarget(View source, int sourceZone) {
|
||||||
String sourceClass = className(source).toLowerCase();
|
String sourceClass = className(source).toLowerCase(Locale.ROOT);
|
||||||
if (sourceClass.contains("touchinterceptframelayout")) {
|
if (sourceClass.contains("touchinterceptframelayout")) {
|
||||||
return source;
|
return source;
|
||||||
}
|
}
|
||||||
@@ -484,7 +467,7 @@ final class StatusChipHider {
|
|||||||
if (!looksLikeChipGeometry(candidate)) {
|
if (!looksLikeChipGeometry(candidate)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
String className = className(candidate).toLowerCase();
|
String className = className(candidate).toLowerCase(Locale.ROOT);
|
||||||
if (className.contains("privacy") || isDefinitelyNotChipClass(className)) {
|
if (className.contains("privacy") || isDefinitelyNotChipClass(className)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -546,10 +529,10 @@ final class StatusChipHider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private int classifyKind(View view, String text, String classNames) {
|
private int classifyKind(View view, String text, String classNames) {
|
||||||
String lowerText = text != null ? text.toLowerCase() : "";
|
String lowerText = text != null ? text.toLowerCase(Locale.ROOT) : "";
|
||||||
String lowerClass = classNames != null && !classNames.isEmpty()
|
String lowerClass = classNames != null && !classNames.isEmpty()
|
||||||
? classNames.toLowerCase()
|
? classNames.toLowerCase(Locale.ROOT)
|
||||||
: (view != null ? className(view).toLowerCase() : "");
|
: (view != null ? className(view).toLowerCase(Locale.ROOT) : "");
|
||||||
if (containsToken(lowerText, "call")
|
if (containsToken(lowerText, "call")
|
||||||
|| containsPhrase(lowerText, "ongoing call")
|
|| containsPhrase(lowerText, "ongoing call")
|
||||||
|| lowerClass.contains("call")) {
|
|| lowerClass.contains("call")) {
|
||||||
@@ -598,8 +581,8 @@ final class StatusChipHider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean looksLikePrivacy(View view, String text) {
|
private boolean looksLikePrivacy(View view, String text) {
|
||||||
String lowerClass = className(view).toLowerCase();
|
String lowerClass = className(view).toLowerCase(Locale.ROOT);
|
||||||
String lowerText = text != null ? text.toLowerCase() : "";
|
String lowerText = text != null ? text.toLowerCase(Locale.ROOT) : "";
|
||||||
return lowerClass.contains("privacy")
|
return lowerClass.contains("privacy")
|
||||||
|| containsToken(lowerText, "camera")
|
|| containsToken(lowerText, "camera")
|
||||||
|| containsToken(lowerText, "microphone")
|
|| containsToken(lowerText, "microphone")
|
||||||
@@ -784,14 +767,7 @@ final class StatusChipHider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean isOngoingActivityCapsule(View view) {
|
private boolean isOngoingActivityCapsule(View view) {
|
||||||
if (view == null || view.getId() == View.NO_ID) {
|
return ViewIdNames.hasIdName(view, "ongoing_activity_capsule");
|
||||||
return false;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
return "ongoing_activity_capsule".equals(view.getResources().getResourceEntryName(view.getId()));
|
|
||||||
} catch (Throwable ignored) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void appendText(StringBuilder out, CharSequence value) {
|
private void appendText(StringBuilder out, CharSequence value) {
|
||||||
@@ -878,23 +854,9 @@ final class StatusChipHider {
|
|||||||
return Math.round(dp * view.getResources().getDisplayMetrics().density);
|
return Math.round(dp * view.getResources().getDisplayMetrics().density);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Context getSystemContext() {
|
|
||||||
try {
|
|
||||||
Class<?> activityThreadClass = Class.forName("android.app.ActivityThread");
|
|
||||||
Object app = ReflectionSupport.invokeStaticMethod(
|
|
||||||
activityThreadClass,
|
|
||||||
"currentApplication",
|
|
||||||
new Class<?>[0]
|
|
||||||
);
|
|
||||||
return app instanceof Context context ? context : null;
|
|
||||||
} catch (Throwable ignored) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isKeyguardLocked() {
|
private boolean isKeyguardLocked() {
|
||||||
try {
|
try {
|
||||||
Context context = getSystemContext();
|
Context context = SystemContextProvider.currentApplication();
|
||||||
if (context == null) {
|
if (context == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -25,7 +25,7 @@ public final class StatusChipsFeature implements RuntimeFeature {
|
|||||||
RuntimeContext context,
|
RuntimeContext context,
|
||||||
XposedModuleInterface.PackageReadyParam param
|
XposedModuleInterface.PackageReadyParam param
|
||||||
) {
|
) {
|
||||||
if (param == null || !"com.android.systemui".equals(param.getPackageName())) {
|
if (!RuntimeFeature.isSystemUiPackage(param)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
installController(context, param.getClassLoader());
|
installController(context, param.getClassLoader());
|
||||||
|
|||||||
+1
-1
@@ -25,7 +25,7 @@ public final class ClockFeature implements RuntimeFeature {
|
|||||||
RuntimeContext context,
|
RuntimeContext context,
|
||||||
XposedModuleInterface.PackageReadyParam param
|
XposedModuleInterface.PackageReadyParam param
|
||||||
) {
|
) {
|
||||||
if (param == null || !"com.android.systemui".equals(param.getPackageName())) {
|
if (!RuntimeFeature.isSystemUiPackage(param)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
installController(context, param.getClassLoader());
|
installController(context, param.getClassLoader());
|
||||||
|
|||||||
+3
-2
@@ -6,6 +6,8 @@ import java.util.ArrayList;
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
final class ClockMarkupSupport {
|
final class ClockMarkupSupport {
|
||||||
|
|
||||||
@@ -207,8 +209,7 @@ final class ClockMarkupSupport {
|
|||||||
"$1").toLowerCase(Locale.ROOT);
|
"$1").toLowerCase(Locale.ROOT);
|
||||||
return new ParsedTag(false, true, name, trimmed, TagCategory.OTHER);
|
return new ParsedTag(false, true, name, trimmed, TagCategory.OTHER);
|
||||||
}
|
}
|
||||||
java.util.regex.Matcher matcher = java.util.regex.Pattern
|
Matcher matcher = Pattern.compile("(?i)<\\s*([a-z0-9_-]+)([^>]*)>")
|
||||||
.compile("(?i)<\\s*([a-z0-9_-]+)([^>]*)>")
|
|
||||||
.matcher(trimmed);
|
.matcher(trimmed);
|
||||||
if (!matcher.matches()) {
|
if (!matcher.matches()) {
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
+5
-3
@@ -3,6 +3,8 @@ package se.ajpanton.statusbartweak.runtime.features.clock;
|
|||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
final class ClockPatternParser {
|
final class ClockPatternParser {
|
||||||
|
|
||||||
@@ -112,7 +114,7 @@ final class ClockPatternParser {
|
|||||||
if (TextUtils.isEmpty(markup)) {
|
if (TextUtils.isEmpty(markup)) {
|
||||||
return ClockParsedPattern.ClockParsedRow.plain("", gapBeforePx);
|
return ClockParsedPattern.ClockParsedRow.plain("", gapBeforePx);
|
||||||
}
|
}
|
||||||
java.util.List<Integer> pipePositions = ClockMarkupSupport.findPipePositions(markup);
|
List<Integer> pipePositions = ClockMarkupSupport.findPipePositions(markup);
|
||||||
if (pipePositions.size() > 2) {
|
if (pipePositions.size() > 2) {
|
||||||
return ClockParsedPattern.ClockParsedRow.syntaxError(gapBeforePx);
|
return ClockParsedPattern.ClockParsedRow.syntaxError(gapBeforePx);
|
||||||
}
|
}
|
||||||
@@ -169,7 +171,7 @@ final class ClockPatternParser {
|
|||||||
new ClockMarkupSupport.ParsedTag(
|
new ClockMarkupSupport.ParsedTag(
|
||||||
true,
|
true,
|
||||||
false,
|
false,
|
||||||
name.toLowerCase(java.util.Locale.ROOT),
|
name.toLowerCase(Locale.ROOT),
|
||||||
"</" + name + ">",
|
"</" + name + ">",
|
||||||
ClockMarkupSupport.TagCategory.OTHER));
|
ClockMarkupSupport.TagCategory.OTHER));
|
||||||
continue;
|
continue;
|
||||||
@@ -210,7 +212,7 @@ final class ClockPatternParser {
|
|||||||
new ClockMarkupSupport.ParsedTag(
|
new ClockMarkupSupport.ParsedTag(
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
token.toLowerCase(java.util.Locale.ROOT),
|
token.toLowerCase(Locale.ROOT),
|
||||||
literal,
|
literal,
|
||||||
ClockMarkupSupport.TagCategory.OTHER));
|
ClockMarkupSupport.TagCategory.OTHER));
|
||||||
}
|
}
|
||||||
|
|||||||
+27
-41
@@ -4,8 +4,6 @@ import android.app.KeyguardManager;
|
|||||||
import android.content.BroadcastReceiver;
|
import android.content.BroadcastReceiver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.IntentFilter;
|
|
||||||
import android.os.Build;
|
|
||||||
import android.text.Spanned;
|
import android.text.Spanned;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.text.style.ForegroundColorSpan;
|
import android.text.style.ForegroundColorSpan;
|
||||||
@@ -24,6 +22,7 @@ import java.util.ArrayList;
|
|||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.WeakHashMap;
|
import java.util.WeakHashMap;
|
||||||
@@ -33,6 +32,7 @@ import se.ajpanton.statusbartweak.runtime.features.RuntimeContext;
|
|||||||
import se.ajpanton.statusbartweak.runtime.hooks.ReflectionSupport;
|
import se.ajpanton.statusbartweak.runtime.hooks.ReflectionSupport;
|
||||||
import se.ajpanton.statusbartweak.runtime.hooks.XposedHookSupport;
|
import se.ajpanton.statusbartweak.runtime.hooks.XposedHookSupport;
|
||||||
import se.ajpanton.statusbartweak.runtime.mode.SceneKey;
|
import se.ajpanton.statusbartweak.runtime.mode.SceneKey;
|
||||||
|
import se.ajpanton.statusbartweak.runtime.settings.BroadcastReceiverSupport;
|
||||||
import se.ajpanton.statusbartweak.runtime.settings.RuntimeSettingsCache;
|
import se.ajpanton.statusbartweak.runtime.settings.RuntimeSettingsCache;
|
||||||
import se.ajpanton.statusbartweak.shell.settings.SbtSettings;
|
import se.ajpanton.statusbartweak.shell.settings.SbtSettings;
|
||||||
|
|
||||||
@@ -111,7 +111,7 @@ final class StockClockController {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
TextView clockView = (TextView) target;
|
TextView clockView = (TextView) target;
|
||||||
java.util.List<Object> args = chain.getArgs();
|
List<Object> args = chain.getArgs();
|
||||||
Object bellSound = args != null && !args.isEmpty()
|
Object bellSound = args != null && !args.isEmpty()
|
||||||
? args.get(0)
|
? args.get(0)
|
||||||
: null;
|
: null;
|
||||||
@@ -125,31 +125,28 @@ final class StockClockController {
|
|||||||
});
|
});
|
||||||
XposedHookSupport.hookAllMethodsIfExists(framework, clockClass, "setTextColor", chain -> {
|
XposedHookSupport.hookAllMethodsIfExists(framework, clockClass, "setTextColor", chain -> {
|
||||||
Object result = chain.proceed();
|
Object result = chain.proceed();
|
||||||
Object target = chain.getThisObject();
|
if (chain.getThisObject() instanceof TextView clockView) {
|
||||||
if (target instanceof TextView) {
|
reapplyClockIfCustomOrOwned(clockView);
|
||||||
TextView clockView = (TextView) target;
|
|
||||||
if (hasCustomClockTextEnabled(RuntimeSettingsCache.get(clockView.getContext()))
|
|
||||||
|| ownedClocks.contains(clockView)) {
|
|
||||||
applyClockText(clockView);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
});
|
});
|
||||||
XposedHookSupport.hookAllMethodsIfExists(framework, clockClass, "onDarkChanged", chain -> {
|
XposedHookSupport.hookAllMethodsIfExists(framework, clockClass, "onDarkChanged", chain -> {
|
||||||
Object result = chain.proceed();
|
Object result = chain.proceed();
|
||||||
Object target = chain.getThisObject();
|
if (chain.getThisObject() instanceof TextView clockView) {
|
||||||
if (target instanceof TextView) {
|
reapplyClockIfCustomOrOwned(clockView);
|
||||||
TextView clockView = (TextView) target;
|
|
||||||
if (hasCustomClockTextEnabled(RuntimeSettingsCache.get(clockView.getContext()))
|
|
||||||
|| ownedClocks.contains(clockView)) {
|
|
||||||
applyClockText(clockView);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
});
|
});
|
||||||
hooksInstalled = true;
|
hooksInstalled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void reapplyClockIfCustomOrOwned(TextView clockView) {
|
||||||
|
if (hasCustomClockTextEnabled(RuntimeSettingsCache.get(clockView.getContext()))
|
||||||
|
|| ownedClocks.contains(clockView)) {
|
||||||
|
applyClockText(clockView);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void registerLayoutModeListenerIfNeeded() {
|
private void registerLayoutModeListenerIfNeeded() {
|
||||||
if (layoutModeListenerRegistered) {
|
if (layoutModeListenerRegistered) {
|
||||||
return;
|
return;
|
||||||
@@ -188,30 +185,24 @@ final class StockClockController {
|
|||||||
if (context == null || receiverRegistered) {
|
if (context == null || receiverRegistered) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Context appContext = context.getApplicationContext();
|
|
||||||
if (appContext == null) {
|
|
||||||
appContext = context;
|
|
||||||
}
|
|
||||||
BroadcastReceiver receiver = new BroadcastReceiver() {
|
BroadcastReceiver receiver = new BroadcastReceiver() {
|
||||||
@Override
|
@Override
|
||||||
public void onReceive(Context ctx, Intent intent) {
|
public void onReceive(Context ctx, Intent intent) {
|
||||||
refreshAllClocks();
|
refreshAllClocks();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
IntentFilter filter = new IntentFilter();
|
BroadcastReceiverSupport.registerExportedOnApplicationContext(
|
||||||
filter.addAction(SbtSettings.ACTION_SETTINGS_CHANGED);
|
context,
|
||||||
filter.addAction(Intent.ACTION_USER_UNLOCKED);
|
receiver,
|
||||||
filter.addAction(Intent.ACTION_BATTERY_CHANGED);
|
BroadcastReceiverSupport.filter(
|
||||||
filter.addAction(Intent.ACTION_TIME_TICK);
|
SbtSettings.ACTION_SETTINGS_CHANGED,
|
||||||
filter.addAction(Intent.ACTION_TIME_CHANGED);
|
Intent.ACTION_USER_UNLOCKED,
|
||||||
filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
|
Intent.ACTION_BATTERY_CHANGED,
|
||||||
filter.addAction(Intent.ACTION_LOCALE_CHANGED);
|
Intent.ACTION_TIME_TICK,
|
||||||
filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
|
Intent.ACTION_TIME_CHANGED,
|
||||||
if (Build.VERSION.SDK_INT >= 33) {
|
Intent.ACTION_TIMEZONE_CHANGED,
|
||||||
appContext.registerReceiver(receiver, filter, Context.RECEIVER_EXPORTED);
|
Intent.ACTION_LOCALE_CHANGED,
|
||||||
} else {
|
Intent.ACTION_CONFIGURATION_CHANGED));
|
||||||
appContext.registerReceiver(receiver, filter);
|
|
||||||
}
|
|
||||||
receiverRegistered = true;
|
receiverRegistered = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -322,9 +313,6 @@ final class StockClockController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean hasCustomClockTextEnabled(SbtSettings settings) {
|
private boolean hasCustomClockTextEnabled(SbtSettings settings) {
|
||||||
if (settings == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
String pattern = settings.clockCustomFormat != null ? settings.clockCustomFormat : "";
|
String pattern = settings.clockCustomFormat != null ? settings.clockCustomFormat : "";
|
||||||
return settings.clockShowSeconds
|
return settings.clockShowSeconds
|
||||||
|| settings.clockShowDatePrefix
|
|| settings.clockShowDatePrefix
|
||||||
@@ -477,7 +465,7 @@ final class StockClockController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void stopTicker(TextView clockView) {
|
private void stopTicker(TextView clockView) {
|
||||||
Runnable ticker = tickers.get(clockView);
|
Runnable ticker = tickers.remove(clockView);
|
||||||
if (ticker != null) {
|
if (ticker != null) {
|
||||||
clockView.removeCallbacks(ticker);
|
clockView.removeCallbacks(ticker);
|
||||||
}
|
}
|
||||||
@@ -715,10 +703,8 @@ final class StockClockController {
|
|||||||
source.getPaddingTop(),
|
source.getPaddingTop(),
|
||||||
source.getPaddingRight(),
|
source.getPaddingRight(),
|
||||||
source.getPaddingBottom());
|
source.getPaddingBottom());
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
|
||||||
target.setLetterSpacing(source.getLetterSpacing());
|
target.setLetterSpacing(source.getLetterSpacing());
|
||||||
target.setFontFeatureSettings(source.getFontFeatureSettings());
|
target.setFontFeatureSettings(source.getFontFeatureSettings());
|
||||||
}
|
|
||||||
VisualState visualState = resolveVisualState(source);
|
VisualState visualState = resolveVisualState(source);
|
||||||
target.setVisibility(visualState.visible ? View.VISIBLE : View.INVISIBLE);
|
target.setVisibility(visualState.visible ? View.VISIBLE : View.INVISIBLE);
|
||||||
target.setAlpha(visualState.alpha);
|
target.setAlpha(visualState.alpha);
|
||||||
|
|||||||
+6
-15
@@ -111,24 +111,18 @@ final class DebugNotificationAutoGroupController {
|
|||||||
packageName = candidatePackage;
|
packageName = candidatePackage;
|
||||||
}
|
}
|
||||||
if (arg != null && arg.getClass().getName().contains("NotificationRecord")) {
|
if (arg != null && arg.getClass().getName().contains("NotificationRecord")) {
|
||||||
Object sbnObj = ReflectionSupport.invokeMethod(arg, "getSbn", new Class<?>[0]);
|
Object sbnObj = ReflectionSupport.invokeMethod(arg, "getSbn");
|
||||||
if (sbnObj instanceof StatusBarNotification statusBarNotification) {
|
if (sbnObj instanceof StatusBarNotification statusBarNotification) {
|
||||||
sbn = statusBarNotification;
|
sbn = statusBarNotification;
|
||||||
packageName = sbn.getPackageName();
|
packageName = sbn.getPackageName();
|
||||||
notification = sbn.getNotification();
|
notification = sbn.getNotification();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
Object packageObj = ReflectionSupport.invokeMethod(
|
Object packageObj = ReflectionSupport.invokeMethod(arg, "getPackageName");
|
||||||
arg,
|
|
||||||
"getPackageName",
|
|
||||||
new Class<?>[0]);
|
|
||||||
if (packageObj instanceof String stringPackage) {
|
if (packageObj instanceof String stringPackage) {
|
||||||
packageName = stringPackage;
|
packageName = stringPackage;
|
||||||
}
|
}
|
||||||
Object notificationObj = ReflectionSupport.invokeMethod(
|
Object notificationObj = ReflectionSupport.invokeMethod(arg, "getNotification");
|
||||||
arg,
|
|
||||||
"getNotification",
|
|
||||||
new Class<?>[0]);
|
|
||||||
if (notificationObj instanceof Notification candidateNotification) {
|
if (notificationObj instanceof Notification candidateNotification) {
|
||||||
notification = candidateNotification;
|
notification = candidateNotification;
|
||||||
}
|
}
|
||||||
@@ -150,20 +144,17 @@ final class DebugNotificationAutoGroupController {
|
|||||||
if (record == null) {
|
if (record == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
Object sbnObj = ReflectionSupport.invokeMethod(record, "getSbn", new Class<?>[0]);
|
Object sbnObj = ReflectionSupport.invokeMethod(record, "getSbn");
|
||||||
if (sbnObj instanceof StatusBarNotification sbn) {
|
if (sbnObj instanceof StatusBarNotification sbn) {
|
||||||
return SbtSettings.MODULE_PACKAGE.equals(sbn.getPackageName());
|
return SbtSettings.MODULE_PACKAGE.equals(sbn.getPackageName());
|
||||||
}
|
}
|
||||||
if (sbnObj != null) {
|
if (sbnObj != null) {
|
||||||
Object packageObj = ReflectionSupport.invokeMethod(
|
Object packageObj = ReflectionSupport.invokeMethod(sbnObj, "getPackageName");
|
||||||
sbnObj,
|
|
||||||
"getPackageName",
|
|
||||||
new Class<?>[0]);
|
|
||||||
if (packageObj instanceof String packageName) {
|
if (packageObj instanceof String packageName) {
|
||||||
return SbtSettings.MODULE_PACKAGE.equals(packageName);
|
return SbtSettings.MODULE_PACKAGE.equals(packageName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Object packageObj = ReflectionSupport.invokeMethod(record, "getPackageName", new Class<?>[0]);
|
Object packageObj = ReflectionSupport.invokeMethod(record, "getPackageName");
|
||||||
return packageObj instanceof String packageName
|
return packageObj instanceof String packageName
|
||||||
&& SbtSettings.MODULE_PACKAGE.equals(packageName);
|
&& SbtSettings.MODULE_PACKAGE.equals(packageName);
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-3
@@ -327,11 +327,11 @@ final class AodBottomBatteryFallbackController {
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
Object panelLazy = ReflectionSupport.getFieldValue(manager, "mPanelViewControllerLazy");
|
Object panelLazy = ReflectionSupport.getFieldValue(manager, "mPanelViewControllerLazy");
|
||||||
Object panel = ReflectionSupport.invokeMethod(panelLazy, "get", new Class<?>[0]);
|
Object panel = ReflectionSupport.invokeMethod(panelLazy, "get");
|
||||||
Object bottomController = ReflectionSupport.getFieldValue(panel, "mKeyguardSecBottomAreaViewController");
|
Object bottomController = ReflectionSupport.getFieldValue(panel, "mKeyguardSecBottomAreaViewController");
|
||||||
Object bottomView = ReflectionSupport.invokeMethod(bottomController, "getView", new Class<?>[0]);
|
Object bottomView = ReflectionSupport.invokeMethod(bottomController, "getView");
|
||||||
Object delegate = ReflectionSupport.getFieldValue(bottomView, "bottomDozeArea$delegate");
|
Object delegate = ReflectionSupport.getFieldValue(bottomView, "bottomDozeArea$delegate");
|
||||||
Object host = ReflectionSupport.invokeMethod(delegate, "getValue", new Class<?>[0]);
|
Object host = ReflectionSupport.invokeMethod(delegate, "getValue");
|
||||||
return host instanceof FrameLayout frameLayout ? frameLayout : null;
|
return host instanceof FrameLayout frameLayout ? frameLayout : null;
|
||||||
} catch (Throwable ignored) {
|
} catch (Throwable ignored) {
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
+13
-32
@@ -1,11 +1,15 @@
|
|||||||
package se.ajpanton.statusbartweak.runtime.features.misc;
|
package se.ajpanton.statusbartweak.runtime.features.misc;
|
||||||
|
|
||||||
|
import android.Manifest;
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
import android.media.AudioManager;
|
import android.media.AudioManager;
|
||||||
import android.telecom.TelecomManager;
|
import android.telecom.TelecomManager;
|
||||||
import android.telephony.TelephonyManager;
|
import android.telephony.TelephonyManager;
|
||||||
|
|
||||||
import io.github.libxposed.api.XposedInterface;
|
import io.github.libxposed.api.XposedInterface;
|
||||||
|
import se.ajpanton.statusbartweak.runtime.SystemContextProvider;
|
||||||
import se.ajpanton.statusbartweak.runtime.features.RuntimeContext;
|
import se.ajpanton.statusbartweak.runtime.features.RuntimeContext;
|
||||||
import se.ajpanton.statusbartweak.runtime.hooks.ReflectionSupport;
|
import se.ajpanton.statusbartweak.runtime.hooks.ReflectionSupport;
|
||||||
import se.ajpanton.statusbartweak.runtime.hooks.XposedHookSupport;
|
import se.ajpanton.statusbartweak.runtime.hooks.XposedHookSupport;
|
||||||
@@ -68,15 +72,12 @@ final class AodCallVisibilityController {
|
|||||||
"com.android.systemui.doze.DozeMachine",
|
"com.android.systemui.doze.DozeMachine",
|
||||||
classLoader
|
classLoader
|
||||||
);
|
);
|
||||||
Class<?> stateClass = ReflectionSupport.findClassIfExists(
|
if (dozeMachineClass == null) {
|
||||||
"com.android.systemui.doze.DozeMachine$State",
|
|
||||||
classLoader
|
|
||||||
);
|
|
||||||
if (dozeMachineClass == null || stateClass == null) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
XposedInterface framework = runtimeContext.getFramework();
|
XposedInterface framework = runtimeContext.getFramework();
|
||||||
XposedHookSupport.hookAllMethods(framework, dozeMachineClass, "requestState", chain -> {
|
for (String methodName : new String[]{"requestState", "transitionTo"}) {
|
||||||
|
XposedHookSupport.hookAllMethods(framework, dozeMachineClass, methodName, chain -> {
|
||||||
Object state = chain.getArgs().isEmpty() ? null : chain.getArg(0);
|
Object state = chain.getArgs().isEmpty() ? null : chain.getArg(0);
|
||||||
if (!(state instanceof Enum<?> target) || !shouldForceAodForCall()) {
|
if (!(state instanceof Enum<?> target) || !shouldForceAodForCall()) {
|
||||||
return chain.proceed();
|
return chain.proceed();
|
||||||
@@ -89,19 +90,7 @@ final class AodCallVisibilityController {
|
|||||||
args[0] = replacement;
|
args[0] = replacement;
|
||||||
return chain.proceed(args);
|
return chain.proceed(args);
|
||||||
});
|
});
|
||||||
XposedHookSupport.hookAllMethods(framework, dozeMachineClass, "transitionTo", chain -> {
|
|
||||||
Object state = chain.getArgs().isEmpty() ? null : chain.getArg(0);
|
|
||||||
if (!(state instanceof Enum<?> target) || !shouldForceAodForCall()) {
|
|
||||||
return chain.proceed();
|
|
||||||
}
|
}
|
||||||
Enum<?> replacement = overrideDozeState(target);
|
|
||||||
if (replacement == null) {
|
|
||||||
return chain.proceed();
|
|
||||||
}
|
|
||||||
Object[] args = chain.getArgs().toArray();
|
|
||||||
args[0] = replacement;
|
|
||||||
return chain.proceed(args);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void hookPluginPhoneStateReadOverride(ClassLoader classLoader) {
|
private void hookPluginPhoneStateReadOverride(ClassLoader classLoader) {
|
||||||
@@ -164,7 +153,7 @@ final class AodCallVisibilityController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean shouldForceAodForCall() {
|
private boolean shouldForceAodForCall() {
|
||||||
Context context = getSystemContext();
|
Context context = SystemContextProvider.currentApplication();
|
||||||
if (context == null) {
|
if (context == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -174,7 +163,11 @@ final class AodCallVisibilityController {
|
|||||||
return isInCallLikeState(context);
|
return isInCallLikeState(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressLint("MissingPermission")
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
private boolean isInCallLikeState(Context context) {
|
private boolean isInCallLikeState(Context context) {
|
||||||
|
if (context.checkSelfPermission(Manifest.permission.READ_PHONE_STATE)
|
||||||
|
== PackageManager.PERMISSION_GRANTED) {
|
||||||
try {
|
try {
|
||||||
TelecomManager telecomManager = context.getSystemService(TelecomManager.class);
|
TelecomManager telecomManager = context.getSystemService(TelecomManager.class);
|
||||||
if (telecomManager != null && telecomManager.isInCall()) {
|
if (telecomManager != null && telecomManager.isInCall()) {
|
||||||
@@ -190,6 +183,7 @@ final class AodCallVisibilityController {
|
|||||||
}
|
}
|
||||||
} catch (Throwable ignored) {
|
} catch (Throwable ignored) {
|
||||||
}
|
}
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
AudioManager audioManager = context.getSystemService(AudioManager.class);
|
AudioManager audioManager = context.getSystemService(AudioManager.class);
|
||||||
if (audioManager == null) {
|
if (audioManager == null) {
|
||||||
@@ -202,17 +196,4 @@ final class AodCallVisibilityController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Context getSystemContext() {
|
|
||||||
try {
|
|
||||||
Class<?> activityThreadClass = Class.forName("android.app.ActivityThread");
|
|
||||||
Object app = ReflectionSupport.invokeStaticMethod(
|
|
||||||
activityThreadClass,
|
|
||||||
"currentApplication",
|
|
||||||
new Class<?>[0]
|
|
||||||
);
|
|
||||||
return app instanceof Context context ? context : null;
|
|
||||||
} catch (Throwable ignored) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-9
@@ -2,10 +2,10 @@ package se.ajpanton.statusbartweak.runtime.features.misc;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.IntentFilter;
|
|
||||||
import android.os.BatteryManager;
|
import android.os.BatteryManager;
|
||||||
|
|
||||||
import se.ajpanton.statusbartweak.runtime.hooks.ReflectionSupport;
|
import se.ajpanton.statusbartweak.runtime.hooks.ReflectionSupport;
|
||||||
|
import se.ajpanton.statusbartweak.runtime.settings.BroadcastReceiverSupport;
|
||||||
|
|
||||||
final class BatteryStatusAccess {
|
final class BatteryStatusAccess {
|
||||||
|
|
||||||
@@ -16,9 +16,9 @@ final class BatteryStatusAccess {
|
|||||||
if (context == null) {
|
if (context == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
Intent batteryIntent = context.registerReceiver(
|
Intent batteryIntent = BroadcastReceiverSupport.readExportedSticky(
|
||||||
null,
|
context,
|
||||||
new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
|
BroadcastReceiverSupport.filter(Intent.ACTION_BATTERY_CHANGED));
|
||||||
if (batteryIntent == null) {
|
if (batteryIntent == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -41,11 +41,6 @@ final class BatteryStatusAccess {
|
|||||||
return value instanceof Context context ? context : null;
|
return value instanceof Context context ? context : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int getIntField(Object target, String fieldName, int fallback) {
|
|
||||||
Object value = ReflectionSupport.getFieldValue(target, fieldName);
|
|
||||||
return value instanceof Integer integer ? integer : fallback;
|
|
||||||
}
|
|
||||||
|
|
||||||
static boolean getBooleanField(Object target, String fieldName, boolean fallback) {
|
static boolean getBooleanField(Object target, String fieldName, boolean fallback) {
|
||||||
Object value = ReflectionSupport.getFieldValue(target, fieldName);
|
Object value = ReflectionSupport.getFieldValue(target, fieldName);
|
||||||
return value instanceof Boolean bool ? bool : fallback;
|
return value instanceof Boolean bool ? bool : fallback;
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ public final class MiscFeature implements RuntimeFeature {
|
|||||||
RuntimeContext context,
|
RuntimeContext context,
|
||||||
XposedModuleInterface.PackageReadyParam param
|
XposedModuleInterface.PackageReadyParam param
|
||||||
) {
|
) {
|
||||||
if (param == null || !"com.android.systemui".equals(param.getPackageName())) {
|
if (!RuntimeFeature.isSystemUiPackage(param)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
installControllers(context, param.getClassLoader());
|
installControllers(context, param.getClassLoader());
|
||||||
|
|||||||
+14
-30
@@ -3,9 +3,6 @@ package se.ajpanton.statusbartweak.runtime.features.notifications;
|
|||||||
import android.content.BroadcastReceiver;
|
import android.content.BroadcastReceiver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.IntentFilter;
|
|
||||||
import android.content.res.Resources;
|
|
||||||
import android.os.Build;
|
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.view.ViewParent;
|
import android.view.ViewParent;
|
||||||
@@ -14,10 +11,12 @@ import java.util.Collections;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.WeakHashMap;
|
import java.util.WeakHashMap;
|
||||||
|
|
||||||
|
import se.ajpanton.statusbartweak.runtime.ViewIdNames;
|
||||||
import se.ajpanton.statusbartweak.runtime.features.RuntimeContext;
|
import se.ajpanton.statusbartweak.runtime.features.RuntimeContext;
|
||||||
import se.ajpanton.statusbartweak.runtime.hooks.ReflectionSupport;
|
import se.ajpanton.statusbartweak.runtime.hooks.ReflectionSupport;
|
||||||
import se.ajpanton.statusbartweak.runtime.hooks.XposedHookSupport;
|
import se.ajpanton.statusbartweak.runtime.hooks.XposedHookSupport;
|
||||||
import se.ajpanton.statusbartweak.runtime.mode.SceneKey;
|
import se.ajpanton.statusbartweak.runtime.mode.SceneKey;
|
||||||
|
import se.ajpanton.statusbartweak.runtime.settings.BroadcastReceiverSupport;
|
||||||
import se.ajpanton.statusbartweak.runtime.settings.RuntimeSettingsCache;
|
import se.ajpanton.statusbartweak.runtime.settings.RuntimeSettingsCache;
|
||||||
import se.ajpanton.statusbartweak.shell.settings.SbtDefaults;
|
import se.ajpanton.statusbartweak.shell.settings.SbtDefaults;
|
||||||
import se.ajpanton.statusbartweak.shell.settings.SbtSettings;
|
import se.ajpanton.statusbartweak.shell.settings.SbtSettings;
|
||||||
@@ -121,23 +120,18 @@ final class StockUnlockedNotificationIconsController {
|
|||||||
if (receiverRegistered || context == null) {
|
if (receiverRegistered || context == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Context appContext = context.getApplicationContext();
|
|
||||||
if (appContext == null) {
|
|
||||||
appContext = context;
|
|
||||||
}
|
|
||||||
BroadcastReceiver receiver = new BroadcastReceiver() {
|
BroadcastReceiver receiver = new BroadcastReceiver() {
|
||||||
@Override
|
@Override
|
||||||
public void onReceive(Context context, Intent intent) {
|
public void onReceive(Context context, Intent intent) {
|
||||||
refreshTrackedContainers();
|
refreshTrackedContainers();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
IntentFilter filter = new IntentFilter(SbtSettings.ACTION_SETTINGS_CHANGED);
|
BroadcastReceiverSupport.registerExportedOnApplicationContext(
|
||||||
filter.addAction(Intent.ACTION_USER_UNLOCKED);
|
context,
|
||||||
if (Build.VERSION.SDK_INT >= 33) {
|
receiver,
|
||||||
appContext.registerReceiver(receiver, filter, Context.RECEIVER_EXPORTED);
|
BroadcastReceiverSupport.filter(
|
||||||
} else {
|
SbtSettings.ACTION_SETTINGS_CHANGED,
|
||||||
appContext.registerReceiver(receiver, filter);
|
Intent.ACTION_USER_UNLOCKED));
|
||||||
}
|
|
||||||
receiverRegistered = true;
|
receiverRegistered = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -213,19 +207,19 @@ final class StockUnlockedNotificationIconsController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void tryRecalculateIcons(View view) {
|
private void tryRecalculateIcons(View view) {
|
||||||
ReflectionSupport.invokeMethod(view, "calculateIconXTranslations", new Class<?>[0]);
|
ReflectionSupport.invokeMethod(view, "calculateIconXTranslations");
|
||||||
ReflectionSupport.invokeMethod(view, "applyIconStates", new Class<?>[0]);
|
ReflectionSupport.invokeMethod(view, "applyIconStates");
|
||||||
ReflectionSupport.invokeMethod(view, "onNotificationInfoUpdated", new Class<?>[0]);
|
ReflectionSupport.invokeMethod(view, "onNotificationInfoUpdated");
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isFeatureEnabled(Context context) {
|
private boolean isFeatureEnabled(Context context) {
|
||||||
SbtSettings settings = RuntimeSettingsCache.get(context);
|
SbtSettings settings = RuntimeSettingsCache.get(context);
|
||||||
return settings != null && !settings.clockEnabled;
|
return !settings.clockEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int resolveUnlockedLimit(Context context) {
|
private int resolveUnlockedLimit(Context context) {
|
||||||
SbtSettings settings = RuntimeSettingsCache.get(context);
|
SbtSettings settings = RuntimeSettingsCache.get(context);
|
||||||
if (settings == null || settings.clockEnabled) {
|
if (settings.clockEnabled) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
int value = settings.unlockedMaxIconsPerRow;
|
int value = settings.unlockedMaxIconsPerRow;
|
||||||
@@ -253,7 +247,7 @@ final class StockUnlockedNotificationIconsController {
|
|||||||
boolean inUnlockedStatusBarIconArea = false;
|
boolean inUnlockedStatusBarIconArea = false;
|
||||||
int depth = 0;
|
int depth = 0;
|
||||||
while (parent instanceof View parentView && depth < 8) {
|
while (parent instanceof View parentView && depth < 8) {
|
||||||
String idName = resolveIdName(parentView);
|
String idName = ViewIdNames.idName(parentView);
|
||||||
if (idName.equals("notification_icon_area")
|
if (idName.equals("notification_icon_area")
|
||||||
|| idName.equals("notification_icon_area_inner")) {
|
|| idName.equals("notification_icon_area_inner")) {
|
||||||
inUnlockedStatusBarIconArea = true;
|
inUnlockedStatusBarIconArea = true;
|
||||||
@@ -275,14 +269,4 @@ final class StockUnlockedNotificationIconsController {
|
|||||||
return scene != null && scene.isUnlocked();
|
return scene != null && scene.isUnlocked();
|
||||||
}
|
}
|
||||||
|
|
||||||
private String resolveIdName(View view) {
|
|
||||||
if (view == null || view.getId() == View.NO_ID) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
return view.getResources().getResourceEntryName(view.getId());
|
|
||||||
} catch (Resources.NotFoundException ignored) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -19,7 +19,7 @@ public final class StockUnlockedNotificationIconsFeature implements RuntimeFeatu
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPackageReady(RuntimeContext context, XposedModuleInterface.PackageReadyParam param) {
|
public void onPackageReady(RuntimeContext context, XposedModuleInterface.PackageReadyParam param) {
|
||||||
if (param == null || !"com.android.systemui".equals(param.getPackageName())) {
|
if (!RuntimeFeature.isSystemUiPackage(param)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
installController(context, param.getClassLoader());
|
installController(context, param.getClassLoader());
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ import java.lang.reflect.Method;
|
|||||||
* Small reflection helpers used by rebuilt runtime slices.
|
* Small reflection helpers used by rebuilt runtime slices.
|
||||||
*/
|
*/
|
||||||
public final class ReflectionSupport {
|
public final class ReflectionSupport {
|
||||||
|
private static final Class<?>[] NO_ARGS = new Class<?>[0];
|
||||||
|
|
||||||
private ReflectionSupport() {
|
private ReflectionSupport() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -120,6 +122,10 @@ public final class ReflectionSupport {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Object invokeMethod(Object target, String methodName) {
|
||||||
|
return invokeMethod(target, methodName, NO_ARGS);
|
||||||
|
}
|
||||||
|
|
||||||
public static Object invokeStaticMethod(
|
public static Object invokeStaticMethod(
|
||||||
Class<?> type,
|
Class<?> type,
|
||||||
String methodName,
|
String methodName,
|
||||||
@@ -140,6 +146,10 @@ public final class ReflectionSupport {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Object invokeStaticMethod(Class<?> type, String methodName) {
|
||||||
|
return invokeStaticMethod(type, methodName, NO_ARGS);
|
||||||
|
}
|
||||||
|
|
||||||
private static Field requireField(Class<?> type, String fieldName) {
|
private static Field requireField(Class<?> type, String fieldName) {
|
||||||
if (fieldName == null || fieldName.isEmpty()) {
|
if (fieldName == null || fieldName.isEmpty()) {
|
||||||
throw new IllegalArgumentException("Field name is empty");
|
throw new IllegalArgumentException("Field name is empty");
|
||||||
|
|||||||
+141
@@ -0,0 +1,141 @@
|
|||||||
|
package se.ajpanton.statusbartweak.runtime.layout;
|
||||||
|
|
||||||
|
import android.graphics.Color;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.WeakHashMap;
|
||||||
|
import java.util.function.BooleanSupplier;
|
||||||
|
|
||||||
|
import se.ajpanton.statusbartweak.runtime.features.RuntimeContext;
|
||||||
|
import se.ajpanton.statusbartweak.runtime.hooks.ReflectionSupport;
|
||||||
|
import se.ajpanton.statusbartweak.runtime.hooks.XposedHookSupport;
|
||||||
|
|
||||||
|
final class DarkIconDispatcherGuard {
|
||||||
|
private final RuntimeContext runtimeContext;
|
||||||
|
private final BooleanSupplier lockscreenSceneSupplier;
|
||||||
|
private final Runnable refreshAllRoots;
|
||||||
|
private final Set<Object> dispatchers =
|
||||||
|
Collections.newSetFromMap(new WeakHashMap<>());
|
||||||
|
private final Map<Object, State> forcedStates = new WeakHashMap<>();
|
||||||
|
|
||||||
|
DarkIconDispatcherGuard(
|
||||||
|
RuntimeContext runtimeContext,
|
||||||
|
BooleanSupplier lockscreenSceneSupplier,
|
||||||
|
Runnable refreshAllRoots
|
||||||
|
) {
|
||||||
|
this.runtimeContext = runtimeContext;
|
||||||
|
this.lockscreenSceneSupplier = lockscreenSceneSupplier;
|
||||||
|
this.refreshAllRoots = refreshAllRoots;
|
||||||
|
}
|
||||||
|
|
||||||
|
void install(Class<?> darkIconDispatcherClass) {
|
||||||
|
XposedHookSupport.hookAllConstructors(
|
||||||
|
runtimeContext.getFramework(),
|
||||||
|
darkIconDispatcherClass,
|
||||||
|
chain -> {
|
||||||
|
Object result = chain.proceed();
|
||||||
|
track(chain.getThisObject());
|
||||||
|
return result;
|
||||||
|
});
|
||||||
|
XposedHookSupport.hookAllMethodsIfExists(
|
||||||
|
runtimeContext.getFramework(),
|
||||||
|
darkIconDispatcherClass,
|
||||||
|
"applyIconTint",
|
||||||
|
chain -> {
|
||||||
|
Object dispatcher = chain.getThisObject();
|
||||||
|
track(dispatcher);
|
||||||
|
if (isLockscreenScene()) {
|
||||||
|
forceLightState(dispatcher);
|
||||||
|
}
|
||||||
|
Object result = chain.proceed();
|
||||||
|
refreshAllRoots.run();
|
||||||
|
return result;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void forceLightStateForAll() {
|
||||||
|
if (!isLockscreenScene()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (Object dispatcher : new ArrayList<>(dispatchers)) {
|
||||||
|
forceLightState(dispatcher);
|
||||||
|
ReflectionSupport.invokeMethod(dispatcher, "applyIconTint");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void restoreForcedStates() {
|
||||||
|
if (forcedStates.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (Map.Entry<Object, State> entry : new ArrayList<>(forcedStates.entrySet())) {
|
||||||
|
Object dispatcher = entry.getKey();
|
||||||
|
State state = entry.getValue();
|
||||||
|
restoreState(dispatcher, state);
|
||||||
|
ReflectionSupport.invokeMethod(dispatcher, "applyIconTint");
|
||||||
|
}
|
||||||
|
forcedStates.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isLockscreenScene() {
|
||||||
|
return lockscreenSceneSupplier.getAsBoolean();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void track(Object dispatcher) {
|
||||||
|
if (dispatcher != null) {
|
||||||
|
dispatchers.add(dispatcher);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private State captureState(Object dispatcher) {
|
||||||
|
return dispatcher != null
|
||||||
|
? new State(
|
||||||
|
ReflectionSupport.getFieldValue(dispatcher, "mDarkIntensity"),
|
||||||
|
ReflectionSupport.getFieldValue(dispatcher, "mIconTint"),
|
||||||
|
ReflectionSupport.getFieldValue(dispatcher, "mTint"),
|
||||||
|
ReflectionSupport.getFieldValue(dispatcher, "mDarkAreas"),
|
||||||
|
ReflectionSupport.getFieldValue(dispatcher, "mTintAreas"))
|
||||||
|
: null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void forceLightState(Object dispatcher) {
|
||||||
|
if (dispatcher == null || !isLockscreenScene()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
forcedStates.computeIfAbsent(dispatcher, this::captureState);
|
||||||
|
setLightState(dispatcher);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setLightState(Object dispatcher) {
|
||||||
|
if (dispatcher == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ReflectionSupport.setFieldValue(dispatcher, "mDarkIntensity", 0f);
|
||||||
|
ReflectionSupport.setFieldValue(dispatcher, "mIconTint", Color.WHITE);
|
||||||
|
ReflectionSupport.setFieldValue(dispatcher, "mTint", Color.WHITE);
|
||||||
|
ReflectionSupport.setFieldValue(dispatcher, "mDarkAreas", new ArrayList<>());
|
||||||
|
ReflectionSupport.setFieldValue(dispatcher, "mTintAreas", new ArrayList<>());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void restoreState(Object dispatcher, State state) {
|
||||||
|
if (dispatcher == null || state == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ReflectionSupport.setFieldValue(dispatcher, "mDarkIntensity", state.darkIntensity);
|
||||||
|
ReflectionSupport.setFieldValue(dispatcher, "mIconTint", state.iconTint);
|
||||||
|
ReflectionSupport.setFieldValue(dispatcher, "mTint", state.tint);
|
||||||
|
ReflectionSupport.setFieldValue(dispatcher, "mDarkAreas", state.darkAreas);
|
||||||
|
ReflectionSupport.setFieldValue(dispatcher, "mTintAreas", state.tintAreas);
|
||||||
|
}
|
||||||
|
|
||||||
|
private record State(
|
||||||
|
Object darkIntensity,
|
||||||
|
Object iconTint,
|
||||||
|
Object tint,
|
||||||
|
Object darkAreas,
|
||||||
|
Object tintAreas
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
}
|
||||||
+15
-79
@@ -15,6 +15,7 @@ import java.util.WeakHashMap;
|
|||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
import java.util.regex.PatternSyntaxException;
|
import java.util.regex.PatternSyntaxException;
|
||||||
|
|
||||||
|
import se.ajpanton.statusbartweak.runtime.NotificationKeyReflection;
|
||||||
import se.ajpanton.statusbartweak.runtime.hooks.ReflectionSupport;
|
import se.ajpanton.statusbartweak.runtime.hooks.ReflectionSupport;
|
||||||
import se.ajpanton.statusbartweak.runtime.mode.NotificationDisplayStyle;
|
import se.ajpanton.statusbartweak.runtime.mode.NotificationDisplayStyle;
|
||||||
import se.ajpanton.statusbartweak.runtime.mode.SystemNotificationDisplayStyleDetector;
|
import se.ajpanton.statusbartweak.runtime.mode.SystemNotificationDisplayStyleDetector;
|
||||||
@@ -27,10 +28,6 @@ final class LockscreenCardsNotificationRowFilter {
|
|||||||
|
|
||||||
private final Map<View, HiddenRowState> hiddenRows = new WeakHashMap<>();
|
private final Map<View, HiddenRowState> hiddenRows = new WeakHashMap<>();
|
||||||
|
|
||||||
boolean apply(ViewGroup stack) {
|
|
||||||
return apply(stack, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean apply(ViewGroup stack, boolean allowAfterKeyguardUnlock) {
|
boolean apply(ViewGroup stack, boolean allowAfterKeyguardUnlock) {
|
||||||
if (stack == null) {
|
if (stack == null) {
|
||||||
return false;
|
return false;
|
||||||
@@ -80,16 +77,12 @@ final class LockscreenCardsNotificationRowFilter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean isActive(Context context) {
|
|
||||||
return isActive(context, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isActive(Context context, boolean allowAfterKeyguardUnlock) {
|
private boolean isActive(Context context, boolean allowAfterKeyguardUnlock) {
|
||||||
if (context == null) {
|
if (context == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
SbtSettings settings = RuntimeSettingsCache.get(context);
|
SbtSettings settings = RuntimeSettingsCache.get(context);
|
||||||
if (settings == null || !settings.clockEnabled) {
|
if (!settings.clockEnabled) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (settings.appIconBlockedModes.isEmpty() && settings.appIconExceptionRules.isEmpty()) {
|
if (settings.appIconBlockedModes.isEmpty() && settings.appIconExceptionRules.isEmpty()) {
|
||||||
@@ -127,7 +120,7 @@ final class LockscreenCardsNotificationRowFilter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean shouldHideRow(Context context, View row, boolean allowAfterKeyguardUnlock) {
|
private boolean shouldHideRow(Context context, View row, boolean allowAfterKeyguardUnlock) {
|
||||||
Object entry = entryForRow(row);
|
Object entry = NotificationKeyReflection.entryForRow(row);
|
||||||
if (shouldHideEntry(context, entry, allowAfterKeyguardUnlock)) {
|
if (shouldHideEntry(context, entry, allowAfterKeyguardUnlock)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -226,29 +219,20 @@ final class LockscreenCardsNotificationRowFilter {
|
|||||||
return view != null && view.getClass().getName().contains("ExpandableNotificationRow");
|
return view != null && view.getClass().getName().contains("ExpandableNotificationRow");
|
||||||
}
|
}
|
||||||
|
|
||||||
private Object entryForRow(View row) {
|
|
||||||
Object value = ReflectionSupport.invokeMethod(row, "getEntry", new Class<?>[0]);
|
|
||||||
if (value != null) {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
value = ReflectionSupport.getFieldValue(row, "mEntry");
|
|
||||||
return value != null ? value : ReflectionSupport.getFieldValue(row, "entry");
|
|
||||||
}
|
|
||||||
|
|
||||||
private String packageFor(Object target) {
|
private String packageFor(Object target) {
|
||||||
if (target == null) {
|
if (target == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
StatusBarNotification sbn = statusBarNotification(target);
|
StatusBarNotification sbn = NotificationReflection.statusBarNotification(target);
|
||||||
if (sbn != null && AppIconRules.isValidPackageName(sbn.getPackageName())) {
|
if (sbn != null && AppIconRules.isValidPackageName(sbn.getPackageName())) {
|
||||||
return sbn.getPackageName();
|
return sbn.getPackageName();
|
||||||
}
|
}
|
||||||
String key = notificationKey(target);
|
String key = NotificationKeyReflection.rowFilterKey(target);
|
||||||
String fromKey = packageFromNotificationKey(key);
|
String fromKey = NotificationKeyReflection.packageFromNotificationKey(key);
|
||||||
if (AppIconRules.isValidPackageName(fromKey)) {
|
if (AppIconRules.isValidPackageName(fromKey)) {
|
||||||
return fromKey;
|
return fromKey;
|
||||||
}
|
}
|
||||||
Object packageName = ReflectionSupport.invokeMethod(target, "getPackageName", new Class<?>[0]);
|
Object packageName = ReflectionSupport.invokeMethod(target, "getPackageName");
|
||||||
if (packageName instanceof String string && AppIconRules.isValidPackageName(string)) {
|
if (packageName instanceof String string && AppIconRules.isValidPackageName(string)) {
|
||||||
return string;
|
return string;
|
||||||
}
|
}
|
||||||
@@ -261,14 +245,15 @@ final class LockscreenCardsNotificationRowFilter {
|
|||||||
return string;
|
return string;
|
||||||
}
|
}
|
||||||
if (target instanceof View view) {
|
if (target instanceof View view) {
|
||||||
Object entry = entryForRow(view);
|
Object entry = NotificationKeyReflection.entryForRow(view);
|
||||||
String fromEntry = packageFor(entry);
|
String fromEntry = packageFor(entry);
|
||||||
if (AppIconRules.isValidPackageName(fromEntry)) {
|
if (AppIconRules.isValidPackageName(fromEntry)) {
|
||||||
return fromEntry;
|
return fromEntry;
|
||||||
}
|
}
|
||||||
CharSequence description = view.getContentDescription();
|
CharSequence description = view.getContentDescription();
|
||||||
if (description != null) {
|
if (description != null) {
|
||||||
String fromDescription = packageFromNotificationKey(description.toString());
|
String fromDescription = NotificationKeyReflection.packageFromNotificationKey(
|
||||||
|
description.toString());
|
||||||
if (AppIconRules.isValidPackageName(fromDescription)) {
|
if (AppIconRules.isValidPackageName(fromDescription)) {
|
||||||
return fromDescription;
|
return fromDescription;
|
||||||
}
|
}
|
||||||
@@ -277,68 +262,19 @@ final class LockscreenCardsNotificationRowFilter {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String notificationKey(Object target) {
|
|
||||||
Object key = ReflectionSupport.invokeMethod(target, "getKey", new Class<?>[0]);
|
|
||||||
if (key instanceof String string && !string.isEmpty()) {
|
|
||||||
return string;
|
|
||||||
}
|
|
||||||
key = ReflectionSupport.invokeMethod(target, "getNotificationKey", new Class<?>[0]);
|
|
||||||
if (key instanceof String string && !string.isEmpty()) {
|
|
||||||
return string;
|
|
||||||
}
|
|
||||||
key = ReflectionSupport.getFieldValue(target, "mKey");
|
|
||||||
if (key instanceof String string && !string.isEmpty()) {
|
|
||||||
return string;
|
|
||||||
}
|
|
||||||
key = ReflectionSupport.getFieldValue(target, "key");
|
|
||||||
return key instanceof String string && !string.isEmpty() ? string : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private StatusBarNotification statusBarNotification(Object target) {
|
|
||||||
if (target instanceof StatusBarNotification sbn) {
|
|
||||||
return sbn;
|
|
||||||
}
|
|
||||||
Object value = ReflectionSupport.invokeMethod(target, "getSbn", new Class<?>[0]);
|
|
||||||
if (value instanceof StatusBarNotification sbn) {
|
|
||||||
return sbn;
|
|
||||||
}
|
|
||||||
for (String field : new String[]{"mSbn", "sbn", "mStatusBarNotification", "statusBarNotification"}) {
|
|
||||||
value = ReflectionSupport.getFieldValue(target, field);
|
|
||||||
if (value instanceof StatusBarNotification sbn) {
|
|
||||||
return sbn;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String packageFromNotificationKey(String key) {
|
|
||||||
if (key == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
String normalized = key.trim();
|
|
||||||
int suffix = normalized.indexOf('@');
|
|
||||||
if (suffix >= 0) {
|
|
||||||
normalized = normalized.substring(0, suffix);
|
|
||||||
}
|
|
||||||
int slash = normalized.indexOf('/');
|
|
||||||
if (slash >= 0) {
|
|
||||||
normalized = normalized.substring(0, slash);
|
|
||||||
}
|
|
||||||
return AppIconRules.isValidPackageName(normalized) ? normalized : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String matchText(View row, Object entry) {
|
private String matchText(View row, Object entry) {
|
||||||
StringBuilder out = new StringBuilder();
|
StringBuilder out = new StringBuilder();
|
||||||
append(out, notificationKey(entry));
|
append(out, NotificationKeyReflection.rowFilterKey(entry));
|
||||||
append(out, notificationKey(row));
|
append(out, NotificationKeyReflection.rowFilterKey(row));
|
||||||
appendNotification(out, statusBarNotification(entry));
|
appendNotification(out, NotificationReflection.statusBarNotification(entry));
|
||||||
appendNotification(out, statusBarNotification(row));
|
appendNotification(out, NotificationReflection.statusBarNotification(row));
|
||||||
if (row != null) {
|
if (row != null) {
|
||||||
append(out, row.getContentDescription());
|
append(out, row.getContentDescription());
|
||||||
}
|
}
|
||||||
return out.toString();
|
return out.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
private void appendNotification(StringBuilder out, StatusBarNotification sbn) {
|
private void appendNotification(StringBuilder out, StatusBarNotification sbn) {
|
||||||
if (sbn == null) {
|
if (sbn == null) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
+52
@@ -0,0 +1,52 @@
|
|||||||
|
package se.ajpanton.statusbartweak.runtime.layout;
|
||||||
|
|
||||||
|
import android.service.notification.StatusBarNotification;
|
||||||
|
|
||||||
|
import se.ajpanton.statusbartweak.runtime.hooks.ReflectionSupport;
|
||||||
|
|
||||||
|
final class NotificationReflection {
|
||||||
|
private static final String[] SBN_FIELD_NAMES = {
|
||||||
|
"mSbn",
|
||||||
|
"sbn",
|
||||||
|
"mStatusBarNotification",
|
||||||
|
"statusBarNotification"
|
||||||
|
};
|
||||||
|
|
||||||
|
private NotificationReflection() {
|
||||||
|
}
|
||||||
|
|
||||||
|
static StatusBarNotification statusBarNotification(Object target) {
|
||||||
|
StatusBarNotification sbn = directStatusBarNotification(target);
|
||||||
|
if (sbn != null) {
|
||||||
|
return sbn;
|
||||||
|
}
|
||||||
|
return statusBarNotificationField(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
static StatusBarNotification statusBarNotificationEntry(Object target) {
|
||||||
|
StatusBarNotification sbn = directStatusBarNotification(target);
|
||||||
|
if (sbn != null) {
|
||||||
|
return sbn;
|
||||||
|
}
|
||||||
|
Object value = ReflectionSupport.invokeMethod(target, "getStatusBarNotification");
|
||||||
|
return value instanceof StatusBarNotification found ? found : statusBarNotificationField(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static StatusBarNotification directStatusBarNotification(Object target) {
|
||||||
|
if (target instanceof StatusBarNotification sbn) {
|
||||||
|
return sbn;
|
||||||
|
}
|
||||||
|
Object value = ReflectionSupport.invokeMethod(target, "getSbn");
|
||||||
|
return value instanceof StatusBarNotification sbn ? sbn : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static StatusBarNotification statusBarNotificationField(Object target) {
|
||||||
|
for (String field : SBN_FIELD_NAMES) {
|
||||||
|
Object value = ReflectionSupport.getFieldValue(target, field);
|
||||||
|
if (value instanceof StatusBarNotification sbn) {
|
||||||
|
return sbn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
+297
@@ -0,0 +1,297 @@
|
|||||||
|
package se.ajpanton.statusbartweak.runtime.layout;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.WeakHashMap;
|
||||||
|
|
||||||
|
import se.ajpanton.statusbartweak.runtime.features.RuntimeContext;
|
||||||
|
import se.ajpanton.statusbartweak.runtime.hooks.ReflectionSupport;
|
||||||
|
import se.ajpanton.statusbartweak.runtime.hooks.XposedHookSupport;
|
||||||
|
import se.ajpanton.statusbartweak.runtime.mode.SceneKey;
|
||||||
|
import se.ajpanton.statusbartweak.runtime.render.StatusIconSlotVisibilityStore;
|
||||||
|
|
||||||
|
final class StatusIconModelTracker {
|
||||||
|
private static final String[] CONTROLLER_CLASS_NAMES = {
|
||||||
|
"com.android.systemui.statusbar.phone.StatusBarIconControllerImpl",
|
||||||
|
"com.android.systemui.statusbar.phone.ui.StatusBarIconControllerImpl"
|
||||||
|
};
|
||||||
|
private static final String[] LIST_CLASS_NAMES = {
|
||||||
|
"com.android.systemui.statusbar.phone.StatusBarIconList",
|
||||||
|
"com.android.systemui.statusbar.phone.ui.StatusBarIconList"
|
||||||
|
};
|
||||||
|
private static final String[] ICON_MANAGER_CLASS_NAMES = {
|
||||||
|
"com.android.systemui.statusbar.phone.StatusBarIconController$IconManager",
|
||||||
|
"com.android.systemui.statusbar.phone.ui.StatusBarIconController$IconManager",
|
||||||
|
"com.android.systemui.statusbar.phone.StatusBarIconControllerImpl$IconManager",
|
||||||
|
"com.android.systemui.statusbar.phone.ui.StatusBarIconControllerImpl$IconManager"
|
||||||
|
};
|
||||||
|
private static final String[] CONTROLLER_METHOD_NAMES = {
|
||||||
|
"setIcon",
|
||||||
|
"setIconVisibility",
|
||||||
|
"removeIcon",
|
||||||
|
"addIconGroup",
|
||||||
|
"removeIconGroup",
|
||||||
|
"refreshIconGroup"
|
||||||
|
};
|
||||||
|
private static final String[] LIST_METHOD_NAMES = {
|
||||||
|
"setIcon",
|
||||||
|
"removeIcon"
|
||||||
|
};
|
||||||
|
private static final String[] ICON_MANAGER_METHOD_NAMES = {
|
||||||
|
"onIconAdded",
|
||||||
|
"onSetIcon",
|
||||||
|
"onRemoveIcon",
|
||||||
|
"onIconExternal"
|
||||||
|
};
|
||||||
|
private static final String[] MODEL_FIELD_NAMES = {
|
||||||
|
"mStatusBarIconList",
|
||||||
|
"mIconList",
|
||||||
|
"mIconGroups",
|
||||||
|
"mIconGroup",
|
||||||
|
"mSlots",
|
||||||
|
"mStatusIcons"
|
||||||
|
};
|
||||||
|
|
||||||
|
private final RuntimeContext runtimeContext;
|
||||||
|
private final Set<Object> knownObjects =
|
||||||
|
Collections.newSetFromMap(new WeakHashMap<>());
|
||||||
|
|
||||||
|
private boolean dirty = true;
|
||||||
|
private SceneKey lastScene;
|
||||||
|
private boolean lastLayoutEnabled;
|
||||||
|
|
||||||
|
StatusIconModelTracker(RuntimeContext runtimeContext) {
|
||||||
|
this.runtimeContext = runtimeContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
void installHooks(ClassLoader classLoader) {
|
||||||
|
for (String className : CONTROLLER_CLASS_NAMES) {
|
||||||
|
hookClass(className, classLoader, CONTROLLER_METHOD_NAMES);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (String className : LIST_CLASS_NAMES) {
|
||||||
|
hookClass(className, classLoader, LIST_METHOD_NAMES);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (String className : ICON_MANAGER_CLASS_NAMES) {
|
||||||
|
hookClass(className, classLoader, ICON_MANAGER_METHOD_NAMES);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void hookClass(String className, ClassLoader classLoader, String[] methodNames) {
|
||||||
|
Class<?> type = ReflectionSupport.findClassIfExists(className, classLoader);
|
||||||
|
if (type == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
hookConstructors(type);
|
||||||
|
for (String methodName : methodNames) {
|
||||||
|
hookMethod(type, methodName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean updateActiveSlots(boolean layoutEnabled, SceneKey scene) {
|
||||||
|
if (!dirty
|
||||||
|
&& layoutEnabled == lastLayoutEnabled
|
||||||
|
&& Objects.equals(scene, lastScene)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
lastLayoutEnabled = layoutEnabled;
|
||||||
|
lastScene = scene;
|
||||||
|
if (!layoutEnabled || scene == null || scene.isAod()) {
|
||||||
|
dirty = false;
|
||||||
|
return StatusIconSlotVisibilityStore.setActiveSlots(new ArrayList<>());
|
||||||
|
}
|
||||||
|
if (knownObjects.isEmpty()) {
|
||||||
|
dirty = false;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
LinkedHashSet<String> mergedSlots = new LinkedHashSet<>();
|
||||||
|
for (Object object : new ArrayList<>(knownObjects)) {
|
||||||
|
rememberObject(object);
|
||||||
|
Object iconList = ReflectionSupport.getFieldValue(object, "mStatusBarIconList");
|
||||||
|
if (iconList == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Set<String> hiddenSlots = copyStringSet(
|
||||||
|
ReflectionSupport.getFieldValue(object, "mIconHideList"));
|
||||||
|
mergedSlots.addAll(activeSlots(iconList, hiddenSlots));
|
||||||
|
}
|
||||||
|
boolean changed = StatusIconSlotVisibilityStore.setActiveSlots(new ArrayList<>(mergedSlots));
|
||||||
|
dirty = false;
|
||||||
|
return changed;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void hookConstructors(Class<?> type) {
|
||||||
|
try {
|
||||||
|
XposedHookSupport.hookAllConstructors(
|
||||||
|
runtimeContext.getFramework(),
|
||||||
|
type,
|
||||||
|
chain -> {
|
||||||
|
Object result = chain.proceed();
|
||||||
|
rememberObject(chain.getThisObject());
|
||||||
|
return result;
|
||||||
|
});
|
||||||
|
} catch (Throwable throwable) {
|
||||||
|
runtimeContext.logWarning(
|
||||||
|
"Status icon model constructor hook failed for " + type.getName(),
|
||||||
|
throwable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void hookMethod(Class<?> type, String methodName) {
|
||||||
|
XposedHookSupport.hookAllMethodsIfExists(
|
||||||
|
runtimeContext.getFramework(),
|
||||||
|
type,
|
||||||
|
methodName,
|
||||||
|
chain -> {
|
||||||
|
rememberObject(chain.getThisObject());
|
||||||
|
Object result = chain.proceed();
|
||||||
|
rememberObject(chain.getThisObject());
|
||||||
|
return result;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void rememberObject(Object object) {
|
||||||
|
if (object == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
knownObjects.add(object);
|
||||||
|
for (String fieldName : MODEL_FIELD_NAMES) {
|
||||||
|
rememberField(object, fieldName);
|
||||||
|
}
|
||||||
|
dirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void rememberField(Object target, String fieldName) {
|
||||||
|
Object value = ReflectionSupport.getFieldValue(target, fieldName);
|
||||||
|
if (value == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
knownObjects.add(value);
|
||||||
|
if (value instanceof Iterable<?> iterable) {
|
||||||
|
for (Object item : iterable) {
|
||||||
|
if (item != null) {
|
||||||
|
knownObjects.add(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private LinkedHashSet<String> activeSlots(Object iconList, Set<String> hiddenSlots) {
|
||||||
|
LinkedHashSet<String> result = new LinkedHashSet<>();
|
||||||
|
addActiveSlots(
|
||||||
|
result,
|
||||||
|
ReflectionSupport.getFieldValue(iconList, "mSlots"),
|
||||||
|
hiddenSlots);
|
||||||
|
addActiveSlots(
|
||||||
|
result,
|
||||||
|
ReflectionSupport.getFieldValue(iconList, "mViewOnlySlots"),
|
||||||
|
hiddenSlots);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addActiveSlots(
|
||||||
|
LinkedHashSet<String> out,
|
||||||
|
Object slotsObj,
|
||||||
|
Set<String> hiddenSlots
|
||||||
|
) {
|
||||||
|
if (!(slotsObj instanceof Iterable<?> slots)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (Object slotObj : slots) {
|
||||||
|
String name = firstNonEmpty(
|
||||||
|
reflectiveFieldString(slotObj, "mName"),
|
||||||
|
reflectiveFieldString(slotObj, "name"),
|
||||||
|
reflectiveString(slotObj, "getName"));
|
||||||
|
if (name.isEmpty()
|
||||||
|
|| (hiddenSlots != null && hiddenSlots.contains(name))) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Object holder = firstNonNull(
|
||||||
|
ReflectionSupport.getFieldValue(slotObj, "mHolder"),
|
||||||
|
ReflectionSupport.getFieldValue(slotObj, "holder"));
|
||||||
|
Object subSlots = ReflectionSupport.getFieldValue(slotObj, "mSubSlots");
|
||||||
|
boolean hasSubSlots = subSlots instanceof Iterable<?> iterable && iterable.iterator().hasNext();
|
||||||
|
if ((holder != null && isHolderVisible(holder)) || hasSubSlots) {
|
||||||
|
out.add(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isHolderVisible(Object holder) {
|
||||||
|
if (holder == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Object methodVisible = ReflectionSupport.invokeMethod(holder, "isVisible");
|
||||||
|
if (methodVisible instanceof Boolean visible) {
|
||||||
|
return visible;
|
||||||
|
}
|
||||||
|
Object visibleField = firstNonNull(
|
||||||
|
ReflectionSupport.getFieldValue(holder, "mVisible"),
|
||||||
|
ReflectionSupport.getFieldValue(holder, "visible"));
|
||||||
|
if (visibleField instanceof Boolean visible) {
|
||||||
|
return visible;
|
||||||
|
}
|
||||||
|
Object icon = firstNonNull(
|
||||||
|
ReflectionSupport.getFieldValue(holder, "mIcon"),
|
||||||
|
ReflectionSupport.getFieldValue(holder, "icon"),
|
||||||
|
ReflectionSupport.invokeMethod(holder, "getIcon"));
|
||||||
|
Object iconVisible = firstNonNull(
|
||||||
|
ReflectionSupport.getFieldValue(icon, "visible"),
|
||||||
|
ReflectionSupport.getFieldValue(icon, "mVisible"));
|
||||||
|
return !(iconVisible instanceof Boolean) || (Boolean) iconVisible;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Set<String> copyStringSet(Object value) {
|
||||||
|
LinkedHashSet<String> result = new LinkedHashSet<>();
|
||||||
|
if (!(value instanceof Iterable<?> iterable)) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
for (Object item : iterable) {
|
||||||
|
if (item != null) {
|
||||||
|
String text = String.valueOf(item);
|
||||||
|
if (!text.isEmpty()) {
|
||||||
|
result.add(text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String reflectiveString(Object target, String methodName) {
|
||||||
|
Object value = ReflectionSupport.invokeMethod(target, methodName);
|
||||||
|
return value != null ? String.valueOf(value) : "";
|
||||||
|
}
|
||||||
|
|
||||||
|
private String reflectiveFieldString(Object target, String fieldName) {
|
||||||
|
Object value = ReflectionSupport.getFieldValue(target, fieldName);
|
||||||
|
return value != null ? String.valueOf(value) : "";
|
||||||
|
}
|
||||||
|
|
||||||
|
private Object firstNonNull(Object... values) {
|
||||||
|
if (values == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
for (Object value : values) {
|
||||||
|
if (value != null) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String firstNonEmpty(String... values) {
|
||||||
|
if (values == null) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
for (String value : values) {
|
||||||
|
if (value != null && !value.isEmpty() && !"null".equals(value)) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
+161
-621
File diff suppressed because it is too large
Load Diff
+2
-10
@@ -10,8 +10,6 @@ import se.ajpanton.statusbartweak.runtime.features.RuntimeFeature;
|
|||||||
*/
|
*/
|
||||||
public final class StockLayoutCanvasFeature implements RuntimeFeature {
|
public final class StockLayoutCanvasFeature implements RuntimeFeature {
|
||||||
|
|
||||||
private static final String PACKAGE_SYSTEM_UI = "com.android.systemui";
|
|
||||||
|
|
||||||
private StockLayoutCanvasController systemUiController;
|
private StockLayoutCanvasController systemUiController;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -21,18 +19,12 @@ public final class StockLayoutCanvasFeature implements RuntimeFeature {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPackageReady(RuntimeContext context, XposedModuleInterface.PackageReadyParam param) {
|
public void onPackageReady(RuntimeContext context, XposedModuleInterface.PackageReadyParam param) {
|
||||||
if (param == null) {
|
if (!RuntimeFeature.isSystemUiPackage(param)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
installForPackage(context, param.getPackageName(), param.getClassLoader());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void installForPackage(RuntimeContext context, String packageName, ClassLoader classLoader) {
|
|
||||||
if (PACKAGE_SYSTEM_UI.equals(packageName)) {
|
|
||||||
if (systemUiController == null) {
|
if (systemUiController == null) {
|
||||||
systemUiController = new StockLayoutCanvasController(context);
|
systemUiController = new StockLayoutCanvasController(context);
|
||||||
}
|
}
|
||||||
systemUiController.install(classLoader);
|
systemUiController.install(param.getClassLoader());
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-2
@@ -4,6 +4,7 @@ import java.util.ArrayList;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
public final class PackedStatusBarLayoutSolver {
|
public final class PackedStatusBarLayoutSolver {
|
||||||
private PackedStatusBarLayoutSolver() {
|
private PackedStatusBarLayoutSolver() {
|
||||||
@@ -181,7 +182,7 @@ public final class PackedStatusBarLayoutSolver {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (java.util.Map.Entry<Box, Double> entry : relaxedWallByEndBox.entrySet()) {
|
for (Map.Entry<Box, Double> entry : relaxedWallByEndBox.entrySet()) {
|
||||||
ArrayList<FinalConstraint> constraints = constraintsByEndBox.get(entry.getKey());
|
ArrayList<FinalConstraint> constraints = constraintsByEndBox.get(entry.getKey());
|
||||||
if (constraints == null) {
|
if (constraints == null) {
|
||||||
continue;
|
continue;
|
||||||
@@ -241,7 +242,7 @@ public final class PackedStatusBarLayoutSolver {
|
|||||||
LinkedHashMap<String, ArrayList<LayoutItem>> iconGroups = groupedIconItems(allItems);
|
LinkedHashMap<String, ArrayList<LayoutItem>> iconGroups = groupedIconItems(allItems);
|
||||||
HashMap<String, ArrayList<Integer>> remainingIconWidths = new HashMap<>();
|
HashMap<String, ArrayList<Integer>> remainingIconWidths = new HashMap<>();
|
||||||
HashMap<String, Integer> remainingIconStarts = new HashMap<>();
|
HashMap<String, Integer> remainingIconStarts = new HashMap<>();
|
||||||
for (java.util.Map.Entry<String, ArrayList<LayoutItem>> entry : iconGroups.entrySet()) {
|
for (Map.Entry<String, ArrayList<LayoutItem>> entry : iconGroups.entrySet()) {
|
||||||
remainingIconWidths.put(entry.getKey(), new ArrayList<>(entry.getValue().get(0).iconWidths()));
|
remainingIconWidths.put(entry.getKey(), new ArrayList<>(entry.getValue().get(0).iconWidths()));
|
||||||
remainingIconStarts.put(entry.getKey(), 0);
|
remainingIconStarts.put(entry.getKey(), 0);
|
||||||
}
|
}
|
||||||
|
|||||||
+9
@@ -717,6 +717,15 @@ public final class StatusBarLayoutSolver {
|
|||||||
int newTop = Math.min(top, other.top);
|
int newTop = Math.min(top, other.top);
|
||||||
return new Bounds(newLeft, newTop, right - newLeft, bottom - newTop);
|
return new Bounds(newLeft, newTop, right - newLeft, bottom - newTop);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int signature() {
|
||||||
|
int result = 17;
|
||||||
|
result = 31 * result + left;
|
||||||
|
result = 31 * result + top;
|
||||||
|
result = 31 * result + width;
|
||||||
|
result = 31 * result + height;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public record PlacedBand(
|
public record PlacedBand(
|
||||||
|
|||||||
+3
-12
@@ -3,6 +3,7 @@ package se.ajpanton.statusbartweak.runtime.mode;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
|
||||||
import io.github.libxposed.api.XposedModuleInterface;
|
import io.github.libxposed.api.XposedModuleInterface;
|
||||||
|
import se.ajpanton.statusbartweak.runtime.SystemContextProvider;
|
||||||
import se.ajpanton.statusbartweak.runtime.features.RuntimeContext;
|
import se.ajpanton.statusbartweak.runtime.features.RuntimeContext;
|
||||||
import se.ajpanton.statusbartweak.runtime.features.RuntimeFeature;
|
import se.ajpanton.statusbartweak.runtime.features.RuntimeFeature;
|
||||||
import se.ajpanton.statusbartweak.runtime.hooks.ReflectionSupport;
|
import se.ajpanton.statusbartweak.runtime.hooks.ReflectionSupport;
|
||||||
@@ -16,7 +17,6 @@ import se.ajpanton.statusbartweak.runtime.hooks.XposedHookSupport;
|
|||||||
*/
|
*/
|
||||||
public final class SystemUiStatusBarStateFeature implements RuntimeFeature {
|
public final class SystemUiStatusBarStateFeature implements RuntimeFeature {
|
||||||
|
|
||||||
private static final String PACKAGE_SYSTEM_UI = "com.android.systemui";
|
|
||||||
private static final String CLASS_STATUS_BAR_STATE_CONTROLLER =
|
private static final String CLASS_STATUS_BAR_STATE_CONTROLLER =
|
||||||
"com.android.systemui.statusbar.StatusBarStateControllerImpl";
|
"com.android.systemui.statusbar.StatusBarStateControllerImpl";
|
||||||
|
|
||||||
@@ -29,7 +29,7 @@ public final class SystemUiStatusBarStateFeature implements RuntimeFeature {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPackageReady(RuntimeContext context, XposedModuleInterface.PackageReadyParam param) {
|
public void onPackageReady(RuntimeContext context, XposedModuleInterface.PackageReadyParam param) {
|
||||||
if (param == null || installed || !PACKAGE_SYSTEM_UI.equals(param.getPackageName())) {
|
if (installed || !RuntimeFeature.isSystemUiPackage(param)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Class<?> controllerClass = ReflectionSupport.findClassIfExists(
|
Class<?> controllerClass = ReflectionSupport.findClassIfExists(
|
||||||
@@ -78,15 +78,6 @@ public final class SystemUiStatusBarStateFeature implements RuntimeFeature {
|
|||||||
if (context instanceof Context androidContext) {
|
if (context instanceof Context androidContext) {
|
||||||
return androidContext;
|
return androidContext;
|
||||||
}
|
}
|
||||||
try {
|
return SystemContextProvider.currentApplication();
|
||||||
Class<?> activityThreadClass = Class.forName("android.app.ActivityThread");
|
|
||||||
Object app = ReflectionSupport.invokeStaticMethod(
|
|
||||||
activityThreadClass,
|
|
||||||
"currentApplication",
|
|
||||||
new Class<?>[0]);
|
|
||||||
return app instanceof Context androidContext ? androidContext : null;
|
|
||||||
} catch (Throwable ignored) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-23
@@ -1,11 +1,11 @@
|
|||||||
package se.ajpanton.statusbartweak.runtime.render;
|
package se.ajpanton.statusbartweak.runtime.render;
|
||||||
|
|
||||||
import android.content.res.Resources;
|
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
import java.util.ArrayDeque;
|
import java.util.ArrayDeque;
|
||||||
|
|
||||||
|
import se.ajpanton.statusbartweak.runtime.ViewIdNames;
|
||||||
import se.ajpanton.statusbartweak.runtime.layoutsolver.StatusBarLayoutSolver.Bounds;
|
import se.ajpanton.statusbartweak.runtime.layoutsolver.StatusBarLayoutSolver.Bounds;
|
||||||
|
|
||||||
final class AodLiveStatusbarSource {
|
final class AodLiveStatusbarSource {
|
||||||
@@ -33,7 +33,7 @@ final class AodLiveStatusbarSource {
|
|||||||
if (childBounds == null) {
|
if (childBounds == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
union = union == null ? childBounds : union(union, childBounds);
|
union = union == null ? childBounds : union.union(childBounds);
|
||||||
}
|
}
|
||||||
return union != null ? union : sourceBounds;
|
return union != null ? union : sourceBounds;
|
||||||
}
|
}
|
||||||
@@ -71,7 +71,7 @@ final class AodLiveStatusbarSource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static int sourcePriority(View view, boolean movingOnly) {
|
private static int sourcePriority(View view, boolean movingOnly) {
|
||||||
String idName = resolveIdName(view);
|
String idName = ViewIdNames.idName(view);
|
||||||
if ("common_statusbar_battery_container_internal".equals(idName)
|
if ("common_statusbar_battery_container_internal".equals(idName)
|
||||||
&& view instanceof ViewGroup group
|
&& view instanceof ViewGroup group
|
||||||
&& group.getChildCount() > 0
|
&& group.getChildCount() > 0
|
||||||
@@ -106,14 +106,6 @@ final class AodLiveStatusbarSource {
|
|||||||
return className.contains("ImageView") || className.contains("StatusBarIcon");
|
return className.contains("ImageView") || className.contains("StatusBarIcon");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Bounds union(Bounds first, Bounds second) {
|
|
||||||
int left = Math.min(first.left, second.left);
|
|
||||||
int top = Math.min(first.top, second.top);
|
|
||||||
int right = Math.max(first.left + first.width, second.left + second.width);
|
|
||||||
int bottom = Math.max(first.top + first.height, second.top + second.height);
|
|
||||||
return new Bounds(left, top, right - left, bottom - top);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Bounds usableBounds(View root, View view) {
|
private static Bounds usableBounds(View root, View view) {
|
||||||
Bounds bounds = ViewGeometry.boundsRelativeTo(root, view);
|
Bounds bounds = ViewGeometry.boundsRelativeTo(root, view);
|
||||||
if (root == null || bounds == null || bounds.width <= 0 || bounds.height <= 0) {
|
if (root == null || bounds == null || bounds.width <= 0 || bounds.height <= 0) {
|
||||||
@@ -130,22 +122,11 @@ final class AodLiveStatusbarSource {
|
|||||||
private static boolean hasAncestorId(View view, String idName) {
|
private static boolean hasAncestorId(View view, String idName) {
|
||||||
Object parent = view != null ? view.getParent() : null;
|
Object parent = view != null ? view.getParent() : null;
|
||||||
while (parent instanceof View parentView) {
|
while (parent instanceof View parentView) {
|
||||||
if (idName.equals(resolveIdName(parentView))) {
|
if (idName.equals(ViewIdNames.idName(parentView))) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
parent = parentView.getParent();
|
parent = parentView.getParent();
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String resolveIdName(View view) {
|
|
||||||
if (view == null || view.getId() == View.NO_ID) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
return view.getResources().getResourceEntryName(view.getId());
|
|
||||||
} catch (Resources.NotFoundException ignored) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-90
@@ -21,17 +21,13 @@ public final class AodStatusbarSourceStore {
|
|||||||
private AodStatusbarSourceStore() {
|
private AodStatusbarSourceStore() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void putStatusContainer(View view) {
|
private static void putStatusSource(View view) {
|
||||||
putStatusSource(view);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void putStatusSource(View view) {
|
|
||||||
if (view != null) {
|
if (view != null) {
|
||||||
STATUS_SOURCES.put(view, StatusSourceRole.UNKNOWN);
|
STATUS_SOURCES.put(view, StatusSourceRole.UNKNOWN);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void putStatusSource(View view, StatusSourceRole role) {
|
private static void putStatusSource(View view, StatusSourceRole role) {
|
||||||
if (view != null) {
|
if (view != null) {
|
||||||
STATUS_SOURCES.put(view, role != null ? role : StatusSourceRole.UNKNOWN);
|
STATUS_SOURCES.put(view, role != null ? role : StatusSourceRole.UNKNOWN);
|
||||||
}
|
}
|
||||||
@@ -83,62 +79,28 @@ public final class AodStatusbarSourceStore {
|
|||||||
if (!isUsableRightAnchor(root, bounds)) {
|
if (!isUsableRightAnchor(root, bounds)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
union = union == null ? bounds : union(union, bounds);
|
union = union == null ? bounds : union.union(bounds);
|
||||||
}
|
}
|
||||||
return union;
|
return union;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ArrayList<Bounds> statusBoundsListForRoot(View root, View excludedContainer) {
|
|
||||||
ArrayList<Bounds> result = new ArrayList<>();
|
|
||||||
if (root == null) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
for (View source : STATUS_SOURCES.keySet()) {
|
|
||||||
if (!isUsableSource(root, source, excludedContainer)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!isStatusAnchorSource(STATUS_SOURCES.get(source))) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
Bounds bounds = boundsForRoot(root, source);
|
|
||||||
if (isUsableRightAnchor(root, bounds)) {
|
|
||||||
result.add(bounds);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean isStatusAnchorSource(StatusSourceRole role) {
|
private static boolean isStatusAnchorSource(StatusSourceRole role) {
|
||||||
return role != StatusSourceRole.SYSTEM_ICONS;
|
return role != StatusSourceRole.SYSTEM_ICONS;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Bounds union(Bounds first, Bounds second) {
|
|
||||||
if (first == null) {
|
|
||||||
return second;
|
|
||||||
}
|
|
||||||
if (second == null) {
|
|
||||||
return first;
|
|
||||||
}
|
|
||||||
int left = Math.min(first.left, second.left);
|
|
||||||
int top = Math.min(first.top, second.top);
|
|
||||||
int right = Math.max(right(first), right(second));
|
|
||||||
int bottom = Math.max(first.top + first.height, second.top + second.height);
|
|
||||||
return new Bounds(left, top, right - left, bottom - top);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean isUsableSource(View root, View source, View excludedContainer) {
|
private static boolean isUsableSource(View root, View source, View excludedContainer) {
|
||||||
return source != null
|
return source != null
|
||||||
&& source != excludedContainer
|
&& source != excludedContainer
|
||||||
&& !isRelated(source, excludedContainer)
|
&& !isRelated(source, excludedContainer)
|
||||||
&& !isNotificationContainer(source)
|
&& !isNotificationContainer(source)
|
||||||
&& !isOwnedRuntimeView(source)
|
&& !ViewGeometry.isOwnedRuntimeView(source)
|
||||||
&& source.isAttachedToWindow();
|
&& source.isAttachedToWindow();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Bounds boundsForRoot(View root, View view) {
|
private static Bounds boundsForRoot(View root, View view) {
|
||||||
Bounds localBounds = ViewGeometry.boundsRelativeTo(root, view);
|
Bounds localBounds = ViewGeometry.boundsRelativeTo(root, view);
|
||||||
if (localBounds != null) {
|
if (localBounds != null) {
|
||||||
return clampToRoot(root, localBounds);
|
return ViewGeometry.clampToRoot(root, localBounds);
|
||||||
}
|
}
|
||||||
return screenBoundsRelativeTo(root, view);
|
return screenBoundsRelativeTo(root, view);
|
||||||
}
|
}
|
||||||
@@ -158,21 +120,7 @@ public final class AodStatusbarSourceStore {
|
|||||||
view.getLocationOnScreen(viewLocation);
|
view.getLocationOnScreen(viewLocation);
|
||||||
int left = viewLocation[0] - rootLocation[0];
|
int left = viewLocation[0] - rootLocation[0];
|
||||||
int top = viewLocation[1] - rootLocation[1];
|
int top = viewLocation[1] - rootLocation[1];
|
||||||
return clampToRoot(root, new Bounds(left, top, width, height));
|
return ViewGeometry.clampToRoot(root, new Bounds(left, top, width, height));
|
||||||
}
|
|
||||||
|
|
||||||
private static Bounds clampToRoot(View root, Bounds bounds) {
|
|
||||||
if (root == null || bounds == null || root.getWidth() <= 0 || root.getHeight() <= 0) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
int left = Math.max(0, bounds.left);
|
|
||||||
int top = Math.max(0, bounds.top);
|
|
||||||
int right = Math.min(root.getWidth(), bounds.left + bounds.width);
|
|
||||||
int bottom = Math.min(root.getHeight(), bounds.top + bounds.height);
|
|
||||||
if (right <= left || bottom <= top) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return new Bounds(left, top, right - left, bottom - top);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isUsableRightAnchor(View root, Bounds bounds) {
|
private static boolean isUsableRightAnchor(View root, Bounds bounds) {
|
||||||
@@ -182,7 +130,7 @@ public final class AodStatusbarSourceStore {
|
|||||||
|| bounds.height <= 0) {
|
|| bounds.height <= 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
int right = right(bounds);
|
int right = bounds.left + bounds.width;
|
||||||
int bottom = bounds.top + bounds.height;
|
int bottom = bounds.top + bounds.height;
|
||||||
return bounds.left >= 0
|
return bounds.left >= 0
|
||||||
&& right <= root.getWidth()
|
&& right <= root.getWidth()
|
||||||
@@ -190,15 +138,11 @@ public final class AodStatusbarSourceStore {
|
|||||||
&& bottom <= root.getHeight();
|
&& bottom <= root.getHeight();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int right(Bounds bounds) {
|
|
||||||
return bounds.left + bounds.width;
|
|
||||||
}
|
|
||||||
|
|
||||||
static ArrayList<View> statusSourcesForRoot(View root, View excludedContainer) {
|
static ArrayList<View> statusSourcesForRoot(View root, View excludedContainer) {
|
||||||
ArrayList<View> result = new ArrayList<>();
|
ArrayList<View> result = new ArrayList<>();
|
||||||
for (View source : STATUS_SOURCES.keySet()) {
|
for (View source : STATUS_SOURCES.keySet()) {
|
||||||
if (!isUsableSource(root, source, excludedContainer)
|
if (!isUsableSource(root, source, excludedContainer)
|
||||||
|| !isDescendantOf(source, root)) {
|
|| !ViewGeometry.isDescendantOf(source, root)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!isStatusAnchorSource(STATUS_SOURCES.get(source))) {
|
if (!isStatusAnchorSource(STATUS_SOURCES.get(source))) {
|
||||||
@@ -209,22 +153,10 @@ public final class AodStatusbarSourceStore {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isDescendantOf(View view, View root) {
|
|
||||||
View current = view;
|
|
||||||
while (current != null) {
|
|
||||||
if (current == root) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
Object parent = current.getParent();
|
|
||||||
current = parent instanceof View ? (View) parent : null;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean isRelated(View view, View other) {
|
private static boolean isRelated(View view, View other) {
|
||||||
return view != null
|
return view != null
|
||||||
&& other != null
|
&& other != null
|
||||||
&& (isDescendantOf(view, other) || isDescendantOf(other, view));
|
&& (ViewGeometry.isDescendantOf(view, other) || ViewGeometry.isDescendantOf(other, view));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isNotificationContainer(View view) {
|
private static boolean isNotificationContainer(View view) {
|
||||||
@@ -233,17 +165,4 @@ public final class AodStatusbarSourceStore {
|
|||||||
|| className.contains("NotificationIconContainer");
|
|| className.contains("NotificationIconContainer");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isOwnedRuntimeView(View view) {
|
|
||||||
View current = view;
|
|
||||||
while (current != null) {
|
|
||||||
Object tag = current.getTag();
|
|
||||||
if (tag instanceof String value && value.startsWith("statusbartweak.")) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
Object parent = current.getParent();
|
|
||||||
current = parent instanceof View ? (View) parent : null;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import android.widget.FrameLayout;
|
|||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.WeakHashMap;
|
import java.util.WeakHashMap;
|
||||||
|
|
||||||
final class ClockProxyRenderer {
|
final class ClockProxyRenderer {
|
||||||
@@ -53,7 +54,7 @@ final class ClockProxyRenderer {
|
|||||||
view.setText(row.text);
|
view.setText(row.text);
|
||||||
hostChanged = true;
|
hostChanged = true;
|
||||||
}
|
}
|
||||||
if (!java.util.Objects.equals(view.getContentDescription(), placement.contentDescription)) {
|
if (!Objects.equals(view.getContentDescription(), placement.contentDescription)) {
|
||||||
view.setContentDescription(placement.contentDescription);
|
view.setContentDescription(placement.contentDescription);
|
||||||
hostChanged = true;
|
hostChanged = true;
|
||||||
}
|
}
|
||||||
@@ -145,7 +146,7 @@ final class ClockProxyRenderer {
|
|||||||
target.setTextSize(android.util.TypedValue.COMPLEX_UNIT_PX, source.getTextSize());
|
target.setTextSize(android.util.TypedValue.COMPLEX_UNIT_PX, source.getTextSize());
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
if (!java.util.Objects.equals(target.getTypeface(), source.getTypeface())) {
|
if (!Objects.equals(target.getTypeface(), source.getTypeface())) {
|
||||||
target.setTypeface(source.getTypeface());
|
target.setTypeface(source.getTypeface());
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
@@ -177,16 +178,14 @@ final class ClockProxyRenderer {
|
|||||||
source.getPaddingBottom());
|
source.getPaddingBottom());
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
|
|
||||||
if (target.getLetterSpacing() != source.getLetterSpacing()) {
|
if (target.getLetterSpacing() != source.getLetterSpacing()) {
|
||||||
target.setLetterSpacing(source.getLetterSpacing());
|
target.setLetterSpacing(source.getLetterSpacing());
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
if (!java.util.Objects.equals(target.getFontFeatureSettings(), source.getFontFeatureSettings())) {
|
if (!Objects.equals(target.getFontFeatureSettings(), source.getFontFeatureSettings())) {
|
||||||
target.setFontFeatureSettings(source.getFontFeatureSettings());
|
target.setFontFeatureSettings(source.getFontFeatureSettings());
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return changed;
|
return changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+21
-47
@@ -26,8 +26,6 @@ import se.ajpanton.statusbartweak.shell.settings.SbtSettings;
|
|||||||
public final class DebugBoundsOverlayController {
|
public final class DebugBoundsOverlayController {
|
||||||
|
|
||||||
private static final String TAG_OVERLAY_HOST = "statusbartweak.debug.bounds.host";
|
private static final String TAG_OVERLAY_HOST = "statusbartweak.debug.bounds.host";
|
||||||
private static final String TAG_CLOCK_HOST = "statusbartweak.unlocked.clock.host";
|
|
||||||
private static final String OVERFLOW_DOT_KEY = "statusbartweak:overflow_dot";
|
|
||||||
private static final int COLOR_NOTIFICATION = Color.argb(96, 0, 128, 255);
|
private static final int COLOR_NOTIFICATION = Color.argb(96, 0, 128, 255);
|
||||||
private static final int COLOR_STATUS = Color.argb(96, 255, 64, 64);
|
private static final int COLOR_STATUS = Color.argb(96, 255, 64, 64);
|
||||||
private static final int COLOR_CLOCK = Color.argb(96, 64, 220, 96);
|
private static final int COLOR_CLOCK = Color.argb(96, 64, 220, 96);
|
||||||
@@ -35,10 +33,6 @@ public final class DebugBoundsOverlayController {
|
|||||||
private static final int COLOR_CUTOUT = Color.argb(112, 255, 180, 0);
|
private static final int COLOR_CUTOUT = Color.argb(112, 255, 180, 0);
|
||||||
private static final int COLOR_AOD_DERIVED_STATUSBAR = Color.argb(80, 255, 220, 0);
|
private static final int COLOR_AOD_DERIVED_STATUSBAR = Color.argb(80, 255, 220, 0);
|
||||||
|
|
||||||
public boolean hasEnabledVisualizer(boolean layoutEnabled, SbtSettings settings) {
|
|
||||||
return hasEnabledVisualizer(layoutEnabled, settings, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean hasEnabledVisualizer(
|
public boolean hasEnabledVisualizer(
|
||||||
boolean layoutEnabled,
|
boolean layoutEnabled,
|
||||||
SbtSettings settings,
|
SbtSettings settings,
|
||||||
@@ -56,19 +50,6 @@ public final class DebugBoundsOverlayController {
|
|||||||
|| (aodStockVisualizersEnabled && settings.debugVisualizeAodStockContainers)));
|
|| (aodStockVisualizersEnabled && settings.debugVisualizeAodStockContainers)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void apply(View root, boolean layoutEnabled, SbtSettings settings) {
|
|
||||||
apply(root, layoutEnabled, settings, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void apply(
|
|
||||||
View root,
|
|
||||||
boolean layoutEnabled,
|
|
||||||
SbtSettings settings,
|
|
||||||
boolean aodStockVisualizersEnabled
|
|
||||||
) {
|
|
||||||
apply(root, layoutEnabled, settings, aodStockVisualizersEnabled, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void apply(
|
public void apply(
|
||||||
View root,
|
View root,
|
||||||
boolean layoutEnabled,
|
boolean layoutEnabled,
|
||||||
@@ -107,7 +88,12 @@ public final class DebugBoundsOverlayController {
|
|||||||
specs);
|
specs);
|
||||||
}
|
}
|
||||||
if (layoutEnabled && settings.debugVisualizeClockContainer) {
|
if (layoutEnabled && settings.debugVisualizeClockContainer) {
|
||||||
addHostChildSpecs(root, parent, TAG_CLOCK_HOST, COLOR_CLOCK, specs);
|
addHostChildSpecs(
|
||||||
|
root,
|
||||||
|
parent,
|
||||||
|
OwnedIconHostManager.TAG_UNLOCKED_CLOCK_HOST,
|
||||||
|
COLOR_CLOCK,
|
||||||
|
specs);
|
||||||
}
|
}
|
||||||
if (layoutEnabled && settings.debugVisualizeChipContainer) {
|
if (layoutEnabled && settings.debugVisualizeChipContainer) {
|
||||||
addHostContainerSpecs(
|
addHostContainerSpecs(
|
||||||
@@ -141,19 +127,6 @@ public final class DebugBoundsOverlayController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public int sourceSignature(View root, boolean layoutEnabled, SbtSettings settings) {
|
|
||||||
return sourceSignature(root, layoutEnabled, settings, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int sourceSignature(
|
|
||||||
View root,
|
|
||||||
boolean layoutEnabled,
|
|
||||||
SbtSettings settings,
|
|
||||||
boolean aodStockVisualizersEnabled
|
|
||||||
) {
|
|
||||||
return sourceSignature(root, layoutEnabled, settings, aodStockVisualizersEnabled, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int sourceSignature(
|
public int sourceSignature(
|
||||||
View root,
|
View root,
|
||||||
boolean layoutEnabled,
|
boolean layoutEnabled,
|
||||||
@@ -168,10 +141,10 @@ public final class DebugBoundsOverlayController {
|
|||||||
}
|
}
|
||||||
int result = 17;
|
int result = 17;
|
||||||
ViewGroup notificationContainer = aodNotificationContainer(root, scene);
|
ViewGroup notificationContainer = aodNotificationContainer(root, scene);
|
||||||
result = 31 * result + boundsSignature(
|
result = 31 * result + signature(
|
||||||
aodNotificationBounds(root, scene));
|
aodNotificationBounds(root, scene));
|
||||||
result = 31 * result + boundsSignature(liveAodStatusIconsBounds(root));
|
result = 31 * result + signature(liveAodStatusIconsBounds(root));
|
||||||
result = 31 * result + boundsSignature(
|
result = 31 * result + signature(
|
||||||
derivedAodStatusbarBounds(root, notificationContainer, settings, scene));
|
derivedAodStatusbarBounds(root, notificationContainer, settings, scene));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -289,16 +262,8 @@ public final class DebugBoundsOverlayController {
|
|||||||
&& bottom <= root.getHeight();
|
&& bottom <= root.getHeight();
|
||||||
}
|
}
|
||||||
|
|
||||||
private int boundsSignature(Bounds bounds) {
|
private int signature(Bounds bounds) {
|
||||||
if (bounds == null) {
|
return bounds != null ? bounds.signature() : 0;
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
int result = 17;
|
|
||||||
result = 31 * result + bounds.left;
|
|
||||||
result = 31 * result + bounds.top;
|
|
||||||
result = 31 * result + bounds.width;
|
|
||||||
result = 31 * result + bounds.height;
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Bounds overlayBounds(StatusBarLayoutSolver.Bounds bounds) {
|
private Bounds overlayBounds(StatusBarLayoutSolver.Bounds bounds) {
|
||||||
@@ -396,7 +361,7 @@ public final class DebugBoundsOverlayController {
|
|||||||
|
|
||||||
private boolean isOverflowDot(View view) {
|
private boolean isOverflowDot(View view) {
|
||||||
Object tag = view != null ? view.getTag() : null;
|
Object tag = view != null ? view.getTag() : null;
|
||||||
return tag instanceof String string && string.startsWith(OVERFLOW_DOT_KEY);
|
return tag instanceof String string && string.startsWith(SnapshotKeys.OVERFLOW_DOT);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Bounds overlayBoundsRelativeTo(View root, View child, boolean stableRegularIconSlots) {
|
private Bounds overlayBoundsRelativeTo(View root, View child, boolean stableRegularIconSlots) {
|
||||||
@@ -649,6 +614,15 @@ public final class DebugBoundsOverlayController {
|
|||||||
int newTop = Math.min(top, other.top);
|
int newTop = Math.min(top, other.top);
|
||||||
return new Bounds(newLeft, newTop, right - newLeft, bottom - newTop);
|
return new Bounds(newLeft, newTop, right - newLeft, bottom - newTop);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int signature() {
|
||||||
|
int result = 17;
|
||||||
|
result = 31 * result + left;
|
||||||
|
result = 31 * result + top;
|
||||||
|
result = 31 * result + width;
|
||||||
|
result = 31 * result + height;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final class OverlayView extends View {
|
private static final class OverlayView extends View {
|
||||||
|
|||||||
+16
-87
@@ -8,9 +8,12 @@ import java.util.ArrayList;
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.IdentityHashMap;
|
import java.util.IdentityHashMap;
|
||||||
|
import java.util.Locale;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.WeakHashMap;
|
import java.util.WeakHashMap;
|
||||||
|
|
||||||
|
import se.ajpanton.statusbartweak.runtime.NotificationKeyReflection;
|
||||||
|
import se.ajpanton.statusbartweak.runtime.ViewIdNames;
|
||||||
import se.ajpanton.statusbartweak.runtime.hooks.ReflectionSupport;
|
import se.ajpanton.statusbartweak.runtime.hooks.ReflectionSupport;
|
||||||
import se.ajpanton.statusbartweak.runtime.layoutsolver.StatusBarLayoutSolver.Bounds;
|
import se.ajpanton.statusbartweak.runtime.layoutsolver.StatusBarLayoutSolver.Bounds;
|
||||||
import se.ajpanton.statusbartweak.shell.settings.AppIconRules;
|
import se.ajpanton.statusbartweak.shell.settings.AppIconRules;
|
||||||
@@ -318,7 +321,7 @@ public final class LockscreenCardsNotificationIconSourceStore {
|
|||||||
|| bounds.height > 0) {
|
|| bounds.height > 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return "notification_dot_container".equals(resolveIdName(container));
|
return "notification_dot_container".equals(ViewIdNames.idName(container));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ViewGroup sourceContainerForRoot(
|
private static ViewGroup sourceContainerForRoot(
|
||||||
@@ -339,7 +342,7 @@ public final class LockscreenCardsNotificationIconSourceStore {
|
|||||||
for (ViewGroup container : containers) {
|
for (ViewGroup container : containers) {
|
||||||
if (container != null
|
if (container != null
|
||||||
&& container.isAttachedToWindow()
|
&& container.isAttachedToWindow()
|
||||||
&& isDescendantOf(container, root)
|
&& ViewGeometry.isDescendantOf(container, root)
|
||||||
&& (!iconOnlyContainerRequired || isAodIconOnlyContainer(container))) {
|
&& (!iconOnlyContainerRequired || isAodIconOnlyContainer(container))) {
|
||||||
return container;
|
return container;
|
||||||
}
|
}
|
||||||
@@ -351,24 +354,12 @@ public final class LockscreenCardsNotificationIconSourceStore {
|
|||||||
if (view == null) {
|
if (view == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
String idName = resolveIdName(view);
|
String idName = ViewIdNames.idName(view);
|
||||||
return "keyguard_icononly_container_view".equals(idName)
|
return "keyguard_icononly_container_view".equals(idName)
|
||||||
|| "notification_icononly_container".equals(idName)
|
|| "notification_icononly_container".equals(idName)
|
||||||
|| "notification_icononly_area".equals(idName);
|
|| "notification_icononly_area".equals(idName);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isDescendantOf(View view, View root) {
|
|
||||||
View current = view;
|
|
||||||
while (current != null) {
|
|
||||||
if (current == root) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
Object parent = current.getParent();
|
|
||||||
current = parent instanceof View ? (View) parent : null;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean hasSources(ViewGroup container) {
|
private static boolean hasSources(ViewGroup container) {
|
||||||
return SOURCES_BY_CONTAINER.containsKey(container)
|
return SOURCES_BY_CONTAINER.containsKey(container)
|
||||||
|| AOD_DRAWABLES_BY_CONTAINER.containsKey(container)
|
|| AOD_DRAWABLES_BY_CONTAINER.containsKey(container)
|
||||||
@@ -382,8 +373,7 @@ public final class LockscreenCardsNotificationIconSourceStore {
|
|||||||
}
|
}
|
||||||
int shelfTop = Integer.MAX_VALUE;
|
int shelfTop = Integer.MAX_VALUE;
|
||||||
if (shelf != null) {
|
if (shelf != null) {
|
||||||
se.ajpanton.statusbartweak.runtime.layoutsolver.StatusBarLayoutSolver.Bounds shelfBounds =
|
Bounds shelfBounds = ViewGeometry.boundsRelativeTo(root, shelf);
|
||||||
ViewGeometry.boundsRelativeTo(root, shelf);
|
|
||||||
if (shelfBounds != null) {
|
if (shelfBounds != null) {
|
||||||
shelfTop = shelfBounds.top;
|
shelfTop = shelfBounds.top;
|
||||||
}
|
}
|
||||||
@@ -393,8 +383,7 @@ public final class LockscreenCardsNotificationIconSourceStore {
|
|||||||
for (int i = 0; i < stack.size(); i++) {
|
for (int i = 0; i < stack.size(); i++) {
|
||||||
View view = stack.get(i);
|
View view = stack.get(i);
|
||||||
if (isNotificationRow(view) && isVisibleCardRow(view)) {
|
if (isNotificationRow(view) && isVisibleCardRow(view)) {
|
||||||
se.ajpanton.statusbartweak.runtime.layoutsolver.StatusBarLayoutSolver.Bounds rowBounds =
|
Bounds rowBounds = ViewGeometry.boundsRelativeTo(root, view);
|
||||||
ViewGeometry.boundsRelativeTo(root, view);
|
|
||||||
if (rowBounds != null && rowBounds.top < shelfTop) {
|
if (rowBounds != null && rowBounds.top < shelfTop) {
|
||||||
String key = keyForRow(view);
|
String key = keyForRow(view);
|
||||||
if (key != null && !key.isEmpty()) {
|
if (key != null && !key.isEmpty()) {
|
||||||
@@ -420,7 +409,7 @@ public final class LockscreenCardsNotificationIconSourceStore {
|
|||||||
}
|
}
|
||||||
ArrayList<View> visibleShelfIcons = visibleShelfIcons(container);
|
ArrayList<View> visibleShelfIcons = visibleShelfIcons(container);
|
||||||
for (View icon : visibleShelfIcons) {
|
for (View icon : visibleShelfIcons) {
|
||||||
String key = keyForIconView(icon);
|
String key = NotificationKeyReflection.keyForIconView(icon);
|
||||||
for (int i = 0; i < entries.size(); i++) {
|
for (int i = 0; i < entries.size(); i++) {
|
||||||
SourceEntry entry = entries.get(i);
|
SourceEntry entry = entries.get(i);
|
||||||
if (entry == null) {
|
if (entry == null) {
|
||||||
@@ -478,8 +467,8 @@ public final class LockscreenCardsNotificationIconSourceStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isOverflowDotCandidate(View view) {
|
private static boolean isOverflowDotCandidate(View view) {
|
||||||
String idName = resolveIdName(view).toLowerCase(java.util.Locale.ROOT);
|
String idName = ViewIdNames.idName(view).toLowerCase(Locale.ROOT);
|
||||||
String className = view.getClass().getName().toLowerCase(java.util.Locale.ROOT);
|
String className = view.getClass().getName().toLowerCase(Locale.ROOT);
|
||||||
return idName.contains("overflow")
|
return idName.contains("overflow")
|
||||||
|| idName.contains("dot")
|
|| idName.contains("dot")
|
||||||
|| className.contains("overflow")
|
|| className.contains("overflow")
|
||||||
@@ -490,52 +479,13 @@ public final class LockscreenCardsNotificationIconSourceStore {
|
|||||||
return new SourceEntry(view, key);
|
return new SourceEntry(view, key);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String keyForEntry(Object entry) {
|
|
||||||
if (entry == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
Object methodValue = ReflectionSupport.invokeMethod(entry, "getKey", new Class<?>[0]);
|
|
||||||
if (methodValue instanceof String string && !string.isEmpty()) {
|
|
||||||
return string;
|
|
||||||
}
|
|
||||||
for (String fieldName : new String[]{"mKey", "key", "notificationKey", "mNotificationKey"}) {
|
|
||||||
Object value = ReflectionSupport.getFieldValue(entry, fieldName);
|
|
||||||
if (value instanceof String string && !string.isEmpty()) {
|
|
||||||
return string;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String keyForIconView(View view) {
|
|
||||||
if (view == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
Object methodValue = ReflectionSupport.invokeMethod(view, "getNotificationKey", new Class<?>[0]);
|
|
||||||
if (methodValue instanceof String string && !string.isEmpty()) {
|
|
||||||
return string;
|
|
||||||
}
|
|
||||||
for (String fieldName : new String[]{"mNotificationKey", "notificationKey", "mKey", "key"}) {
|
|
||||||
Object value = ReflectionSupport.getFieldValue(view, fieldName);
|
|
||||||
if (value instanceof String string && !string.isEmpty()) {
|
|
||||||
return string;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String keyForRow(View view) {
|
private static String keyForRow(View view) {
|
||||||
Object entry = ReflectionSupport.invokeMethod(view, "getEntry", new Class<?>[0]);
|
Object entry = NotificationKeyReflection.primaryEntryForRow(view);
|
||||||
String key = keyForEntry(entry);
|
String key = NotificationKeyReflection.keyForEntry(entry);
|
||||||
if (key != null && !key.isEmpty()) {
|
if (key != null && !key.isEmpty()) {
|
||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
entry = ReflectionSupport.getFieldValue(view, "mEntry");
|
return NotificationKeyReflection.keyForIconView(view);
|
||||||
key = keyForEntry(entry);
|
|
||||||
if (key != null && !key.isEmpty()) {
|
|
||||||
return key;
|
|
||||||
}
|
|
||||||
return keyForIconView(view);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isNotificationRow(View view) {
|
private static boolean isNotificationRow(View view) {
|
||||||
@@ -546,22 +496,11 @@ public final class LockscreenCardsNotificationIconSourceStore {
|
|||||||
return className.contains("ExpandableNotificationRow");
|
return className.contains("ExpandableNotificationRow");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String resolveIdName(View view) {
|
|
||||||
if (view == null || view.getId() == View.NO_ID) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
return view.getResources().getResourceEntryName(view.getId());
|
|
||||||
} catch (Throwable ignored) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean isVisibleCardRow(View view) {
|
private static boolean isVisibleCardRow(View view) {
|
||||||
if (view == null || view.getVisibility() == View.GONE) {
|
if (view == null || view.getVisibility() == View.GONE) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!view.isShown() || effectiveAlpha(view) <= 0.05f) {
|
if (!view.isShown() || ViewGeometry.effectiveAlpha(view) <= 0.05f) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (ReflectionSupport.getBooleanField(view, "mInShelf", false)
|
if (ReflectionSupport.getBooleanField(view, "mInShelf", false)
|
||||||
@@ -580,7 +519,7 @@ public final class LockscreenCardsNotificationIconSourceStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static int actualHeight(View view, int fallback) {
|
private static int actualHeight(View view, int fallback) {
|
||||||
Object methodValue = ReflectionSupport.invokeMethod(view, "getActualHeight", new Class<?>[0]);
|
Object methodValue = ReflectionSupport.invokeMethod(view, "getActualHeight");
|
||||||
if (methodValue instanceof Integer integer && integer > 0) {
|
if (methodValue instanceof Integer integer && integer > 0) {
|
||||||
return integer;
|
return integer;
|
||||||
}
|
}
|
||||||
@@ -591,16 +530,6 @@ public final class LockscreenCardsNotificationIconSourceStore {
|
|||||||
return fallback;
|
return fallback;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static float effectiveAlpha(View view) {
|
|
||||||
float alpha = 1f;
|
|
||||||
Object current = view;
|
|
||||||
while (current instanceof View currentView) {
|
|
||||||
alpha *= currentView.getAlpha();
|
|
||||||
current = currentView.getParent();
|
|
||||||
}
|
|
||||||
return alpha;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final class SourceEntry {
|
public static final class SourceEntry {
|
||||||
final View view;
|
final View view;
|
||||||
final String key;
|
final String key;
|
||||||
|
|||||||
+8
-37
@@ -12,8 +12,10 @@ import android.widget.TextView;
|
|||||||
|
|
||||||
import java.util.ArrayDeque;
|
import java.util.ArrayDeque;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Locale;
|
||||||
import java.util.WeakHashMap;
|
import java.util.WeakHashMap;
|
||||||
|
|
||||||
|
import se.ajpanton.statusbartweak.runtime.ViewIdNames;
|
||||||
import se.ajpanton.statusbartweak.runtime.layoutsolver.StatusBarLayoutSolver.Bounds;
|
import se.ajpanton.statusbartweak.runtime.layoutsolver.StatusBarLayoutSolver.Bounds;
|
||||||
import se.ajpanton.statusbartweak.runtime.mode.NotificationDisplayStyle;
|
import se.ajpanton.statusbartweak.runtime.mode.NotificationDisplayStyle;
|
||||||
import se.ajpanton.statusbartweak.runtime.mode.SceneKey;
|
import se.ajpanton.statusbartweak.runtime.mode.SceneKey;
|
||||||
@@ -115,16 +117,6 @@ public final class LockscreenCardsNotificationStripRenderer {
|
|||||||
clearPills(host);
|
clearPills(host);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void clearAll() {
|
|
||||||
renderer.clearAll();
|
|
||||||
ArrayList<ViewGroup> hosts = new ArrayList<>(pillViewsByHost.keySet());
|
|
||||||
for (ViewGroup host : hosts) {
|
|
||||||
clearPills(host);
|
|
||||||
}
|
|
||||||
pillViewsByHost.clear();
|
|
||||||
aodInitialStatusbarHeightByRoot.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
private ViewGroup findSourceRoot(View root) {
|
private ViewGroup findSourceRoot(View root) {
|
||||||
if (!(root instanceof ViewGroup group)) {
|
if (!(root instanceof ViewGroup group)) {
|
||||||
return null;
|
return null;
|
||||||
@@ -170,22 +162,12 @@ public final class LockscreenCardsNotificationStripRenderer {
|
|||||||
if (host == null || sourceRoot == null) {
|
if (host == null || sourceRoot == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
float alpha = effectiveAncestorAlpha(sourceRoot);
|
float alpha = ViewGeometry.effectiveAncestorAlpha(sourceRoot);
|
||||||
if (host.getAlpha() != alpha) {
|
if (host.getAlpha() != alpha) {
|
||||||
host.setAlpha(alpha);
|
host.setAlpha(alpha);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private float effectiveAncestorAlpha(View view) {
|
|
||||||
float alpha = 1f;
|
|
||||||
Object current = view.getParent();
|
|
||||||
while (current instanceof View currentView) {
|
|
||||||
alpha *= currentView.getAlpha();
|
|
||||||
current = currentView.getParent();
|
|
||||||
}
|
|
||||||
return Math.max(0f, Math.min(1f, alpha));
|
|
||||||
}
|
|
||||||
|
|
||||||
private ArrayList<SnapshotSource> collectSources(ViewGroup sourceRoot) {
|
private ArrayList<SnapshotSource> collectSources(ViewGroup sourceRoot) {
|
||||||
ArrayList<SnapshotSource> result = new ArrayList<>();
|
ArrayList<SnapshotSource> result = new ArrayList<>();
|
||||||
ArrayDeque<View> queue = new ArrayDeque<>();
|
ArrayDeque<View> queue = new ArrayDeque<>();
|
||||||
@@ -448,9 +430,9 @@ public final class LockscreenCardsNotificationStripRenderer {
|
|||||||
while (!queue.isEmpty()) {
|
while (!queue.isEmpty()) {
|
||||||
View view = queue.removeFirst();
|
View view = queue.removeFirst();
|
||||||
String className = view.getClass().getName();
|
String className = view.getClass().getName();
|
||||||
String idName = resolveIdName(view);
|
String idName = ViewIdNames.idName(view);
|
||||||
if (className.contains("NotificationShelfBackground")
|
if (className.contains("NotificationShelfBackground")
|
||||||
|| idName.toLowerCase(java.util.Locale.ROOT).contains("background")) {
|
|| idName.toLowerCase(Locale.ROOT).contains("background")) {
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
if (view instanceof ViewGroup childGroup) {
|
if (view instanceof ViewGroup childGroup) {
|
||||||
@@ -580,7 +562,7 @@ public final class LockscreenCardsNotificationStripRenderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean isIconOnlyContainer(View view) {
|
private boolean isIconOnlyContainer(View view) {
|
||||||
String idName = resolveIdName(view);
|
String idName = ViewIdNames.idName(view);
|
||||||
return "keyguard_icononly_container_view".equals(idName)
|
return "keyguard_icononly_container_view".equals(idName)
|
||||||
|| "notification_icononly_container".equals(idName)
|
|| "notification_icononly_container".equals(idName)
|
||||||
|| "notification_icononly_area".equals(idName)
|
|| "notification_icononly_area".equals(idName)
|
||||||
@@ -603,25 +585,14 @@ public final class LockscreenCardsNotificationStripRenderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean isOverflowDotCandidate(View view) {
|
private boolean isOverflowDotCandidate(View view) {
|
||||||
String idName = resolveIdName(view).toLowerCase(java.util.Locale.ROOT);
|
String idName = ViewIdNames.idName(view).toLowerCase(Locale.ROOT);
|
||||||
String className = view.getClass().getName().toLowerCase(java.util.Locale.ROOT);
|
String className = view.getClass().getName().toLowerCase(Locale.ROOT);
|
||||||
return idName.contains("overflow")
|
return idName.contains("overflow")
|
||||||
|| idName.contains("dot")
|
|| idName.contains("dot")
|
||||||
|| className.contains("overflow")
|
|| className.contains("overflow")
|
||||||
|| className.contains("dot");
|
|| className.contains("dot");
|
||||||
}
|
}
|
||||||
|
|
||||||
private String resolveIdName(View view) {
|
|
||||||
if (view == null || view.getId() == View.NO_ID) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
return view.getResources().getResourceEntryName(view.getId());
|
|
||||||
} catch (Throwable ignored) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public record RenderResult(View sourceRoot, Bounds renderedBounds) {
|
public record RenderResult(View sourceRoot, Bounds renderedBounds) {
|
||||||
static RenderResult empty() {
|
static RenderResult empty() {
|
||||||
return new RenderResult(null, null);
|
return new RenderResult(null, null);
|
||||||
|
|||||||
+20
-16
@@ -30,6 +30,15 @@ public final class OwnedIconHostManager {
|
|||||||
"statusbartweak.lockscreen.cards.notification.host";
|
"statusbartweak.lockscreen.cards.notification.host";
|
||||||
public static final String TAG_AOD_CARDS_NOTIFICATION_HOST =
|
public static final String TAG_AOD_CARDS_NOTIFICATION_HOST =
|
||||||
"statusbartweak.aod.cards.notification.host";
|
"statusbartweak.aod.cards.notification.host";
|
||||||
|
private static final String[] OWNED_HOST_TAGS = {
|
||||||
|
TAG_UNLOCKED_STATUS_HOST,
|
||||||
|
TAG_UNLOCKED_NOTIFICATION_HOST,
|
||||||
|
TAG_UNLOCKED_CLOCK_HOST,
|
||||||
|
TAG_UNLOCKED_CARRIER_HOST,
|
||||||
|
TAG_UNLOCKED_CHIP_HOST,
|
||||||
|
TAG_LOCKSCREEN_CARDS_NOTIFICATION_HOST,
|
||||||
|
TAG_AOD_CARDS_NOTIFICATION_HOST
|
||||||
|
};
|
||||||
private static final String[] UNLOCKED_HOST_ORDER = {
|
private static final String[] UNLOCKED_HOST_ORDER = {
|
||||||
TAG_UNLOCKED_STATUS_HOST,
|
TAG_UNLOCKED_STATUS_HOST,
|
||||||
TAG_UNLOCKED_NOTIFICATION_HOST,
|
TAG_UNLOCKED_NOTIFICATION_HOST,
|
||||||
@@ -66,7 +75,7 @@ public final class OwnedIconHostManager {
|
|||||||
return ensureHost(root, TAG_AOD_CARDS_NOTIFICATION_HOST);
|
return ensureHost(root, TAG_AOD_CARDS_NOTIFICATION_HOST);
|
||||||
}
|
}
|
||||||
|
|
||||||
public FrameLayout ensureHost(View root, String tag) {
|
private FrameLayout ensureHost(View root, String tag) {
|
||||||
Objects.requireNonNull(tag, "tag");
|
Objects.requireNonNull(tag, "tag");
|
||||||
if (!(root instanceof ViewGroup parent)) {
|
if (!(root instanceof ViewGroup parent)) {
|
||||||
return null;
|
return null;
|
||||||
@@ -98,14 +107,10 @@ public final class OwnedIconHostManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removeUnlockedHosts(View root) {
|
public void removeOwnedHosts(View root) {
|
||||||
removeHost(root, TAG_UNLOCKED_STATUS_HOST);
|
for (String tag : OWNED_HOST_TAGS) {
|
||||||
removeHost(root, TAG_UNLOCKED_NOTIFICATION_HOST);
|
removeHost(root, tag);
|
||||||
removeHost(root, TAG_UNLOCKED_CLOCK_HOST);
|
}
|
||||||
removeHost(root, TAG_UNLOCKED_CARRIER_HOST);
|
|
||||||
removeHost(root, TAG_UNLOCKED_CHIP_HOST);
|
|
||||||
removeHost(root, TAG_LOCKSCREEN_CARDS_NOTIFICATION_HOST);
|
|
||||||
removeHost(root, TAG_AOD_CARDS_NOTIFICATION_HOST);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setUnlockedHostsVisible(View root, boolean visible) {
|
public void setUnlockedHostsVisible(View root, boolean visible) {
|
||||||
@@ -132,13 +137,12 @@ public final class OwnedIconHostManager {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
Object tag = view.getTag();
|
Object tag = view.getTag();
|
||||||
return TAG_UNLOCKED_STATUS_HOST.equals(tag)
|
for (String ownedTag : OWNED_HOST_TAGS) {
|
||||||
|| TAG_UNLOCKED_NOTIFICATION_HOST.equals(tag)
|
if (ownedTag.equals(tag)) {
|
||||||
|| TAG_UNLOCKED_CLOCK_HOST.equals(tag)
|
return true;
|
||||||
|| TAG_UNLOCKED_CARRIER_HOST.equals(tag)
|
}
|
||||||
|| TAG_UNLOCKED_CHIP_HOST.equals(tag)
|
}
|
||||||
|| TAG_LOCKSCREEN_CARDS_NOTIFICATION_HOST.equals(tag)
|
return false;
|
||||||
|| TAG_AOD_CARDS_NOTIFICATION_HOST.equals(tag);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private FrameLayout findDirectHost(ViewGroup parent, String tag) {
|
private FrameLayout findDirectHost(ViewGroup parent, String tag) {
|
||||||
|
|||||||
+4
-2
@@ -9,6 +9,8 @@ import android.view.View;
|
|||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
import se.ajpanton.statusbartweak.runtime.hooks.ReflectionSupport;
|
import se.ajpanton.statusbartweak.runtime.hooks.ReflectionSupport;
|
||||||
|
|
||||||
final class SnapshotAppearanceSignature {
|
final class SnapshotAppearanceSignature {
|
||||||
@@ -33,7 +35,7 @@ final class SnapshotAppearanceSignature {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
int result = 17;
|
int result = 17;
|
||||||
result = 31 * result + java.util.Arrays.hashCode(view.getDrawableState());
|
result = 31 * result + Arrays.hashCode(view.getDrawableState());
|
||||||
if (view instanceof TextView textView) {
|
if (view instanceof TextView textView) {
|
||||||
result = 31 * result + textView.getCurrentTextColor();
|
result = 31 * result + textView.getCurrentTextColor();
|
||||||
result = 31 * result + textView.getTextColors().hashCode();
|
result = 31 * result + textView.getTextColors().hashCode();
|
||||||
@@ -58,7 +60,7 @@ final class SnapshotAppearanceSignature {
|
|||||||
result = 31 * result + System.identityHashCode(drawable);
|
result = 31 * result + System.identityHashCode(drawable);
|
||||||
result = 31 * result + drawable.getLevel();
|
result = 31 * result + drawable.getLevel();
|
||||||
result = 31 * result + drawable.getAlpha();
|
result = 31 * result + drawable.getAlpha();
|
||||||
result = 31 * result + java.util.Arrays.hashCode(drawable.getState());
|
result = 31 * result + Arrays.hashCode(drawable.getState());
|
||||||
ColorFilter colorFilter = drawable.getColorFilter();
|
ColorFilter colorFilter = drawable.getColorFilter();
|
||||||
result = 31 * result + (colorFilter != null ? System.identityHashCode(colorFilter) : 0);
|
result = 31 * result + (colorFilter != null ? System.identityHashCode(colorFilter) : 0);
|
||||||
return result;
|
return result;
|
||||||
|
|||||||
+4
-25
@@ -1,6 +1,5 @@
|
|||||||
package se.ajpanton.statusbartweak.runtime.render;
|
package se.ajpanton.statusbartweak.runtime.render;
|
||||||
|
|
||||||
import android.content.res.Resources;
|
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -9,6 +8,8 @@ import java.util.Map;
|
|||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
import java.util.regex.PatternSyntaxException;
|
import java.util.regex.PatternSyntaxException;
|
||||||
|
|
||||||
|
import se.ajpanton.statusbartweak.runtime.NotificationKeyReflection;
|
||||||
|
import se.ajpanton.statusbartweak.runtime.ViewIdNames;
|
||||||
import se.ajpanton.statusbartweak.runtime.mode.SceneKey;
|
import se.ajpanton.statusbartweak.runtime.mode.SceneKey;
|
||||||
import se.ajpanton.statusbartweak.shell.settings.AppIconRules;
|
import se.ajpanton.statusbartweak.shell.settings.AppIconRules;
|
||||||
import se.ajpanton.statusbartweak.shell.settings.SbtSettings;
|
import se.ajpanton.statusbartweak.shell.settings.SbtSettings;
|
||||||
@@ -69,19 +70,7 @@ final class SnapshotIconFilter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static String notificationPackage(String key) {
|
static String notificationPackage(String key) {
|
||||||
if (key == null) {
|
return NotificationKeyReflection.packageFromNotificationKey(key);
|
||||||
return null;
|
|
||||||
}
|
|
||||||
String normalized = key.trim();
|
|
||||||
int suffix = normalized.indexOf('@');
|
|
||||||
if (suffix >= 0) {
|
|
||||||
normalized = normalized.substring(0, suffix);
|
|
||||||
}
|
|
||||||
int slash = normalized.indexOf('/');
|
|
||||||
if (slash >= 0) {
|
|
||||||
normalized = normalized.substring(0, slash);
|
|
||||||
}
|
|
||||||
return AppIconRules.isValidPackageName(normalized) ? normalized : null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static boolean isNotificationBlocked(
|
static boolean isNotificationBlocked(
|
||||||
@@ -165,7 +154,7 @@ final class SnapshotIconFilter {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
append(sb, view.getClass().getName());
|
append(sb, view.getClass().getName());
|
||||||
append(sb, resolveIdName(view));
|
append(sb, ViewIdNames.idName(view));
|
||||||
CharSequence contentDescription = view.getContentDescription();
|
CharSequence contentDescription = view.getContentDescription();
|
||||||
append(sb, contentDescription != null ? contentDescription.toString() : null);
|
append(sb, contentDescription != null ? contentDescription.toString() : null);
|
||||||
}
|
}
|
||||||
@@ -275,14 +264,4 @@ final class SnapshotIconFilter {
|
|||||||
sb.append(value);
|
sb.append(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String resolveIdName(View view) {
|
|
||||||
if (view == null || view.getId() == View.NO_ID) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
return view.getResources().getResourceEntryName(view.getId());
|
|
||||||
} catch (Resources.NotFoundException ignored) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import android.view.View;
|
|||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
import se.ajpanton.statusbartweak.runtime.layoutsolver.StatusBarLayoutSolver.Bounds;
|
import se.ajpanton.statusbartweak.runtime.layoutsolver.StatusBarLayoutSolver.Bounds;
|
||||||
|
|
||||||
@@ -353,7 +354,7 @@ final class LayoutInputSignature {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int stockSurfaceSignature() {
|
int stockSurfaceSignature() {
|
||||||
return java.util.Objects.hash(
|
return Objects.hash(
|
||||||
rootWidth,
|
rootWidth,
|
||||||
rootHeight,
|
rootHeight,
|
||||||
rootPaddingLeft,
|
rootPaddingLeft,
|
||||||
@@ -370,7 +371,7 @@ final class LayoutInputSignature {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int nonClockLayoutSignature() {
|
int nonClockLayoutSignature() {
|
||||||
return java.util.Objects.hash(
|
return Objects.hash(
|
||||||
scene,
|
scene,
|
||||||
rootWidth,
|
rootWidth,
|
||||||
rootHeight,
|
rootHeight,
|
||||||
@@ -421,12 +422,12 @@ final class LayoutInputSignature {
|
|||||||
&& statusSources == that.statusSources
|
&& statusSources == that.statusSources
|
||||||
&& notificationSources == that.notificationSources
|
&& notificationSources == that.notificationSources
|
||||||
&& chipSources == that.chipSources
|
&& chipSources == that.chipSources
|
||||||
&& java.util.Objects.equals(scene, that.scene);
|
&& Objects.equals(scene, that.scene);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return java.util.Objects.hash(
|
return Objects.hash(
|
||||||
scene,
|
scene,
|
||||||
rootWidth,
|
rootWidth,
|
||||||
rootHeight,
|
rootHeight,
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package se.ajpanton.statusbartweak.runtime.render;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.content.res.Resources;
|
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.graphics.Canvas;
|
import android.graphics.Canvas;
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
@@ -18,13 +17,19 @@ import android.widget.ImageView;
|
|||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.LinkedHashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.IdentityHashMap;
|
import java.util.IdentityHashMap;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.WeakHashMap;
|
import java.util.WeakHashMap;
|
||||||
|
|
||||||
|
import se.ajpanton.statusbartweak.runtime.NotificationKeyReflection;
|
||||||
|
import se.ajpanton.statusbartweak.runtime.ViewIdNames;
|
||||||
import se.ajpanton.statusbartweak.runtime.hooks.ReflectionSupport;
|
import se.ajpanton.statusbartweak.runtime.hooks.ReflectionSupport;
|
||||||
import se.ajpanton.statusbartweak.runtime.layoutsolver.StatusBarLayoutSolver.Bounds;
|
import se.ajpanton.statusbartweak.runtime.layoutsolver.StatusBarLayoutSolver.Bounds;
|
||||||
|
|
||||||
@@ -180,7 +185,7 @@ final class SnapshotRenderer {
|
|||||||
structureChanged = true;
|
structureChanged = true;
|
||||||
proxyChanged = true;
|
proxyChanged = true;
|
||||||
}
|
}
|
||||||
if (!java.util.Objects.equals(proxy.getTag(), key)) {
|
if (!Objects.equals(proxy.getTag(), key)) {
|
||||||
proxy.setTag(key);
|
proxy.setTag(key);
|
||||||
proxyChanged = true;
|
proxyChanged = true;
|
||||||
}
|
}
|
||||||
@@ -372,14 +377,14 @@ final class SnapshotRenderer {
|
|||||||
return keyHint;
|
return keyHint;
|
||||||
}
|
}
|
||||||
if (view == null) {
|
if (view == null) {
|
||||||
return source.mode().name().toLowerCase(java.util.Locale.ROOT) + "#" + order;
|
return source.mode().name().toLowerCase(Locale.ROOT) + "#" + order;
|
||||||
}
|
}
|
||||||
String slot = reflectString(view, "getSlot", "mSlot", "slot");
|
String slot = reflectString(view, "getSlot", "mSlot", "slot");
|
||||||
if (!slot.isEmpty()) {
|
if (!slot.isEmpty()) {
|
||||||
return slot;
|
return slot;
|
||||||
}
|
}
|
||||||
String key = reflectString(view, "getNotificationKey", "mNotificationKey", "notificationKey", "mKey", "key");
|
String key = NotificationKeyReflection.keyForIconView(view);
|
||||||
if (!key.isEmpty()) {
|
if (key != null && !key.isEmpty()) {
|
||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
return view.getClass().getName() + "#" + order;
|
return view.getClass().getName() + "#" + order;
|
||||||
@@ -389,15 +394,15 @@ final class SnapshotRenderer {
|
|||||||
if (view == null || key == null) {
|
if (view == null || key == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
String lowerKey = key.toLowerCase(java.util.Locale.ROOT);
|
String lowerKey = key.toLowerCase(Locale.ROOT);
|
||||||
if (lowerKey.contains("wifi")) {
|
if (lowerKey.contains("wifi")) {
|
||||||
return "wifi";
|
return "wifi";
|
||||||
}
|
}
|
||||||
if (lowerKey.contains("mobile")) {
|
if (lowerKey.contains("mobile")) {
|
||||||
return "mobile";
|
return "mobile";
|
||||||
}
|
}
|
||||||
String idName = resolveIdName(view).toLowerCase(java.util.Locale.ROOT);
|
String idName = ViewIdNames.idName(view).toLowerCase(Locale.ROOT);
|
||||||
String className = view.getClass().getName().toLowerCase(java.util.Locale.ROOT);
|
String className = view.getClass().getName().toLowerCase(Locale.ROOT);
|
||||||
if (idName.contains("wifi") || className.contains("wifi")) {
|
if (idName.contains("wifi") || className.contains("wifi")) {
|
||||||
return "wifi";
|
return "wifi";
|
||||||
}
|
}
|
||||||
@@ -448,37 +453,36 @@ final class SnapshotRenderer {
|
|||||||
liveSignalKeys.add(placement.key());
|
liveSignalKeys.add(placement.key());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ArrayList<String> staleKeys = new ArrayList<>();
|
Iterator<Map.Entry<String, HeldSignal>> iterator = heldSignals.entrySet().iterator();
|
||||||
for (String key : heldSignals.keySet()) {
|
while (iterator.hasNext()) {
|
||||||
if (!liveSignalKeys.contains(key)) {
|
Map.Entry<String, HeldSignal> entry = iterator.next();
|
||||||
staleKeys.add(key);
|
if (!liveSignalKeys.contains(entry.getKey())) {
|
||||||
}
|
HeldSignal stale = entry.getValue();
|
||||||
}
|
iterator.remove();
|
||||||
for (String key : staleKeys) {
|
|
||||||
HeldSignal stale = heldSignals.remove(key);
|
|
||||||
if (stale != null) {
|
if (stale != null) {
|
||||||
stale.recycle();
|
stale.recycle();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private int removeMissing(
|
private int removeMissing(
|
||||||
LinkedHashMap<String, ImageView> proxies,
|
LinkedHashMap<String, ImageView> proxies,
|
||||||
HashSet<String> desiredKeys
|
HashSet<String> desiredKeys
|
||||||
) {
|
) {
|
||||||
ArrayList<String> staleKeys = new ArrayList<>();
|
int removed = 0;
|
||||||
for (Map.Entry<String, ImageView> entry : proxies.entrySet()) {
|
Iterator<Map.Entry<String, ImageView>> iterator = proxies.entrySet().iterator();
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
Map.Entry<String, ImageView> entry = iterator.next();
|
||||||
if (!desiredKeys.contains(entry.getKey())) {
|
if (!desiredKeys.contains(entry.getKey())) {
|
||||||
ImageView proxy = entry.getValue();
|
ImageView proxy = entry.getValue();
|
||||||
detachFromParent(proxy);
|
detachFromParent(proxy);
|
||||||
statesByProxy.remove(proxy);
|
statesByProxy.remove(proxy);
|
||||||
staleKeys.add(entry.getKey());
|
iterator.remove();
|
||||||
|
removed++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (String key : staleKeys) {
|
return removed;
|
||||||
proxies.remove(key);
|
|
||||||
}
|
|
||||||
return staleKeys.size();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private BitmapResult bitmapFor(ImageView proxy, Bounds bounds) {
|
private BitmapResult bitmapFor(ImageView proxy, Bounds bounds) {
|
||||||
@@ -499,6 +503,7 @@ final class SnapshotRenderer {
|
|||||||
|
|
||||||
private SnapshotRenderState renderStateFor(SnapshotPlacement placement) {
|
private SnapshotRenderState renderStateFor(SnapshotPlacement placement) {
|
||||||
Bounds bounds = placement.bounds();
|
Bounds bounds = placement.bounds();
|
||||||
|
Bounds sourceRenderBounds = placement.sourceRenderBounds();
|
||||||
return new SnapshotRenderState(
|
return new SnapshotRenderState(
|
||||||
placement.key(),
|
placement.key(),
|
||||||
bounds.width,
|
bounds.width,
|
||||||
@@ -507,7 +512,7 @@ final class SnapshotRenderer {
|
|||||||
placement.overflowDot(),
|
placement.overflowDot(),
|
||||||
placement.overflowDotColor(),
|
placement.overflowDotColor(),
|
||||||
placement.sourceOffsetX(),
|
placement.sourceOffsetX(),
|
||||||
boundsSignature(placement.sourceRenderBounds()),
|
sourceRenderBounds != null ? sourceRenderBounds.signature() : 0,
|
||||||
placement.heldSignal() != null ? placement.heldSignal().key : "",
|
placement.heldSignal() != null ? placement.heldSignal().key : "",
|
||||||
placement.heldSignal() != null ? System.identityHashCode(placement.heldSignal().bitmap) : 0,
|
placement.heldSignal() != null ? System.identityHashCode(placement.heldSignal().bitmap) : 0,
|
||||||
placement.source() != null ? placement.source().mode() : null,
|
placement.source() != null ? placement.source().mode() : null,
|
||||||
@@ -520,19 +525,8 @@ final class SnapshotRenderer {
|
|||||||
}
|
}
|
||||||
int result = 17;
|
int result = 17;
|
||||||
result = 31 * result + sourceTreeSignature(source.view());
|
result = 31 * result + sourceTreeSignature(source.view());
|
||||||
result = 31 * result + boundsSignature(source.boundsOverride());
|
Bounds boundsOverride = source.boundsOverride();
|
||||||
return result;
|
result = 31 * result + (boundsOverride != null ? boundsOverride.signature() : 0);
|
||||||
}
|
|
||||||
|
|
||||||
private int boundsSignature(Bounds bounds) {
|
|
||||||
if (bounds == null) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
int result = 17;
|
|
||||||
result = 31 * result + bounds.left;
|
|
||||||
result = 31 * result + bounds.top;
|
|
||||||
result = 31 * result + bounds.width;
|
|
||||||
result = 31 * result + bounds.height;
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -565,7 +559,7 @@ final class SnapshotRenderer {
|
|||||||
result = 31 * result + view.getScrollY();
|
result = 31 * result + view.getScrollY();
|
||||||
CharSequence contentDescription = view.getContentDescription();
|
CharSequence contentDescription = view.getContentDescription();
|
||||||
result = 31 * result + (contentDescription != null ? contentDescription.toString().hashCode() : 0);
|
result = 31 * result + (contentDescription != null ? contentDescription.toString().hashCode() : 0);
|
||||||
result = 31 * result + java.util.Arrays.hashCode(view.getDrawableState());
|
result = 31 * result + Arrays.hashCode(view.getDrawableState());
|
||||||
result = 31 * result + SnapshotAppearanceSignature.view(view);
|
result = 31 * result + SnapshotAppearanceSignature.view(view);
|
||||||
if (view instanceof TextView textView) {
|
if (view instanceof TextView textView) {
|
||||||
CharSequence text = textView.getText();
|
CharSequence text = textView.getText();
|
||||||
@@ -597,7 +591,7 @@ final class SnapshotRenderer {
|
|||||||
result = 31 * result + view.getHeight();
|
result = 31 * result + view.getHeight();
|
||||||
result = 31 * result + view.getScrollX();
|
result = 31 * result + view.getScrollX();
|
||||||
result = 31 * result + view.getScrollY();
|
result = 31 * result + view.getScrollY();
|
||||||
result = 31 * result + java.util.Arrays.hashCode(view.getDrawableState());
|
result = 31 * result + Arrays.hashCode(view.getDrawableState());
|
||||||
result = 31 * result + SnapshotAppearanceSignature.view(view);
|
result = 31 * result + SnapshotAppearanceSignature.view(view);
|
||||||
if (view instanceof TextView textView) {
|
if (view instanceof TextView textView) {
|
||||||
CharSequence text = textView.getText();
|
CharSequence text = textView.getText();
|
||||||
@@ -611,7 +605,7 @@ final class SnapshotRenderer {
|
|||||||
if (drawable != null) {
|
if (drawable != null) {
|
||||||
result = 31 * result + drawable.getLevel();
|
result = 31 * result + drawable.getLevel();
|
||||||
result = 31 * result + drawable.getAlpha();
|
result = 31 * result + drawable.getAlpha();
|
||||||
result = 31 * result + java.util.Arrays.hashCode(drawable.getState());
|
result = 31 * result + Arrays.hashCode(drawable.getState());
|
||||||
}
|
}
|
||||||
result = 31 * result + (imageView.getImageTintList() != null
|
result = 31 * result + (imageView.getImageTintList() != null
|
||||||
? imageView.getImageTintList().hashCode()
|
? imageView.getImageTintList().hashCode()
|
||||||
@@ -632,20 +626,6 @@ final class SnapshotRenderer {
|
|||||||
private record SourceSignatureCache(int stamp, int signature) {
|
private record SourceSignatureCache(int stamp, int signature) {
|
||||||
}
|
}
|
||||||
|
|
||||||
private int drawableSignature(Drawable drawable) {
|
|
||||||
if (drawable == null) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
int result = 17;
|
|
||||||
result = 31 * result + SnapshotAppearanceSignature.drawable(drawable);
|
|
||||||
Rect bounds = drawable.getBounds();
|
|
||||||
result = 31 * result + bounds.left;
|
|
||||||
result = 31 * result + bounds.top;
|
|
||||||
result = 31 * result + bounds.right;
|
|
||||||
result = 31 * result + bounds.bottom;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void drawSnapshot(SnapshotSource source, Bitmap bitmap) {
|
private void drawSnapshot(SnapshotSource source, Bitmap bitmap) {
|
||||||
drawSnapshot(source, bitmap, 0);
|
drawSnapshot(source, bitmap, 0);
|
||||||
}
|
}
|
||||||
@@ -1094,19 +1074,8 @@ final class SnapshotRenderer {
|
|||||||
return new Bounds(left, top, Math.max(0, width), Math.max(0, height));
|
return new Bounds(left, top, Math.max(0, width), Math.max(0, height));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String resolveIdName(View view) {
|
|
||||||
if (view.getId() == View.NO_ID) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
return view.getResources().getResourceEntryName(view.getId());
|
|
||||||
} catch (Resources.NotFoundException ignored) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String reflectString(Object target, String methodName, String... fieldNames) {
|
private static String reflectString(Object target, String methodName, String... fieldNames) {
|
||||||
Object methodValue = ReflectionSupport.invokeMethod(target, methodName, new Class<?>[0]);
|
Object methodValue = ReflectionSupport.invokeMethod(target, methodName);
|
||||||
if (methodValue instanceof String string && !string.isEmpty()) {
|
if (methodValue instanceof String string && !string.isEmpty()) {
|
||||||
return string;
|
return string;
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-6
@@ -1,6 +1,8 @@
|
|||||||
package se.ajpanton.statusbartweak.runtime.render;
|
package se.ajpanton.statusbartweak.runtime.render;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public final class StatusIconSlotVisibilityStore {
|
public final class StatusIconSlotVisibilityStore {
|
||||||
private static final Object LOCK = new Object();
|
private static final Object LOCK = new Object();
|
||||||
@@ -9,7 +11,7 @@ public final class StatusIconSlotVisibilityStore {
|
|||||||
private StatusIconSlotVisibilityStore() {
|
private StatusIconSlotVisibilityStore() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean setActiveSlots(ArrayList<String> slots) {
|
public static boolean setActiveSlots(List<String> slots) {
|
||||||
ArrayList<String> normalized = normalize(slots);
|
ArrayList<String> normalized = normalize(slots);
|
||||||
synchronized (LOCK) {
|
synchronized (LOCK) {
|
||||||
if (activeSlots.equals(normalized)) {
|
if (activeSlots.equals(normalized)) {
|
||||||
@@ -26,17 +28,17 @@ public final class StatusIconSlotVisibilityStore {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ArrayList<String> normalize(ArrayList<String> slots) {
|
private static ArrayList<String> normalize(List<String> slots) {
|
||||||
ArrayList<String> normalized = new ArrayList<>();
|
|
||||||
if (slots == null) {
|
if (slots == null) {
|
||||||
return normalized;
|
return new ArrayList<>();
|
||||||
}
|
}
|
||||||
|
LinkedHashSet<String> normalized = new LinkedHashSet<>();
|
||||||
for (String slot : slots) {
|
for (String slot : slots) {
|
||||||
if (slot == null || slot.isEmpty() || normalized.contains(slot)) {
|
if (slot == null || slot.isEmpty()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
normalized.add(slot);
|
normalized.add(slot);
|
||||||
}
|
}
|
||||||
return normalized;
|
return new ArrayList<>(normalized);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+12
-26
@@ -1,11 +1,11 @@
|
|||||||
package se.ajpanton.statusbartweak.runtime.render;
|
package se.ajpanton.statusbartweak.runtime.render;
|
||||||
|
|
||||||
import android.content.res.Resources;
|
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
import java.util.ArrayDeque;
|
import java.util.ArrayDeque;
|
||||||
|
|
||||||
|
import se.ajpanton.statusbartweak.runtime.ViewIdNames;
|
||||||
import se.ajpanton.statusbartweak.runtime.layoutsolver.StatusBarLayoutSolver.Bounds;
|
import se.ajpanton.statusbartweak.runtime.layoutsolver.StatusBarLayoutSolver.Bounds;
|
||||||
import se.ajpanton.statusbartweak.runtime.mode.SceneKey;
|
import se.ajpanton.statusbartweak.runtime.mode.SceneKey;
|
||||||
|
|
||||||
@@ -41,31 +41,28 @@ final class StatusbarHeightSource {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int height(View root, SceneKey scene, RootAnchors anchors, Bounds fallbackBounds) {
|
|
||||||
Bounds bounds = bounds(root, scene, anchors);
|
|
||||||
if (isUsable(root, bounds)) {
|
|
||||||
return bounds.top + bounds.height;
|
|
||||||
}
|
|
||||||
if (isUsable(root, fallbackBounds)) {
|
|
||||||
return fallbackBounds.top + fallbackBounds.height;
|
|
||||||
}
|
|
||||||
return Math.max(1, root != null ? root.getHeight() : 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Bounds firstBoundsForIds(View root, String... idNames) {
|
private static Bounds firstBoundsForIds(View root, String... idNames) {
|
||||||
if (!(root instanceof ViewGroup rootGroup) || idNames == null || idNames.length == 0) {
|
if (!(root instanceof ViewGroup rootGroup) || idNames == null || idNames.length == 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
for (String candidateId : idNames) {
|
Bounds bestMatch = null;
|
||||||
|
int bestIndex = idNames.length;
|
||||||
ArrayDeque<View> queue = new ArrayDeque<>();
|
ArrayDeque<View> queue = new ArrayDeque<>();
|
||||||
queue.add(rootGroup);
|
queue.add(rootGroup);
|
||||||
while (!queue.isEmpty()) {
|
while (!queue.isEmpty()) {
|
||||||
View view = queue.removeFirst();
|
View view = queue.removeFirst();
|
||||||
if (candidateId.equals(resolveIdName(view))) {
|
String idName = ViewIdNames.idName(view);
|
||||||
|
for (int i = 0; i < bestIndex; i++) {
|
||||||
|
if (idNames[i].equals(idName)) {
|
||||||
Bounds bounds = ViewGeometry.boundsRelativeTo(root, view);
|
Bounds bounds = ViewGeometry.boundsRelativeTo(root, view);
|
||||||
if (isUsable(root, bounds)) {
|
if (isUsable(root, bounds)) {
|
||||||
|
if (i == 0) {
|
||||||
return bounds;
|
return bounds;
|
||||||
}
|
}
|
||||||
|
bestMatch = bounds;
|
||||||
|
bestIndex = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (view instanceof ViewGroup group) {
|
if (view instanceof ViewGroup group) {
|
||||||
for (int i = 0; i < group.getChildCount(); i++) {
|
for (int i = 0; i < group.getChildCount(); i++) {
|
||||||
@@ -76,8 +73,7 @@ final class StatusbarHeightSource {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
return bestMatch;
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isUsable(View root, Bounds bounds) {
|
private static boolean isUsable(View root, Bounds bounds) {
|
||||||
@@ -92,14 +88,4 @@ final class StatusbarHeightSource {
|
|||||||
&& bottom <= root.getHeight();
|
&& bottom <= root.getHeight();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String resolveIdName(View view) {
|
|
||||||
if (view == null || view.getId() == View.NO_ID) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
return view.getResources().getResourceEntryName(view.getId());
|
|
||||||
} catch (Resources.NotFoundException ignored) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
+18
@@ -0,0 +1,18 @@
|
|||||||
|
package se.ajpanton.statusbartweak.runtime.render;
|
||||||
|
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
final class TextVerticalOffsetScaler {
|
||||||
|
private float baselineTextSizePx;
|
||||||
|
|
||||||
|
int scale(int offsetPx, TextView source) {
|
||||||
|
if (offsetPx == 0 || source == null || source.getTextSize() <= 0f) {
|
||||||
|
return offsetPx;
|
||||||
|
}
|
||||||
|
float textSize = source.getTextSize();
|
||||||
|
if (baselineTextSizePx <= 0f || textSize < baselineTextSizePx) {
|
||||||
|
baselineTextSizePx = textSize;
|
||||||
|
}
|
||||||
|
return Math.round(offsetPx * textSize / baselineTextSizePx);
|
||||||
|
}
|
||||||
|
}
|
||||||
+18
-28
@@ -7,9 +7,9 @@ import android.widget.TextView;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.WeakHashMap;
|
import java.util.WeakHashMap;
|
||||||
|
|
||||||
import se.ajpanton.statusbartweak.runtime.features.RuntimeContext;
|
|
||||||
import se.ajpanton.statusbartweak.runtime.features.clock.ClockLayoutTextFactory;
|
import se.ajpanton.statusbartweak.runtime.features.clock.ClockLayoutTextFactory;
|
||||||
import se.ajpanton.statusbartweak.runtime.layoutsolver.StatusBarLayoutSolver.Bounds;
|
import se.ajpanton.statusbartweak.runtime.layoutsolver.StatusBarLayoutSolver.Bounds;
|
||||||
import se.ajpanton.statusbartweak.runtime.mode.NotificationDisplayStyle;
|
import se.ajpanton.statusbartweak.runtime.mode.NotificationDisplayStyle;
|
||||||
@@ -24,14 +24,13 @@ import se.ajpanton.statusbartweak.shell.settings.SbtSettings;
|
|||||||
* into owned unlocked rows instead of copying each stock X position.
|
* into owned unlocked rows instead of copying each stock X position.
|
||||||
*/
|
*/
|
||||||
public final class UnlockedIconSnapshotRenderController {
|
public final class UnlockedIconSnapshotRenderController {
|
||||||
private final RuntimeContext runtimeContext;
|
|
||||||
private final SnapshotRenderer statusRenderer;
|
private final SnapshotRenderer statusRenderer;
|
||||||
private final SnapshotRenderer notificationRenderer;
|
private final SnapshotRenderer notificationRenderer;
|
||||||
private final SnapshotRenderer chipRenderer;
|
private final SnapshotRenderer chipRenderer;
|
||||||
private final ClockProxyRenderer clockRenderer = new ClockProxyRenderer();
|
private final ClockProxyRenderer clockRenderer = new ClockProxyRenderer();
|
||||||
private final ClockProxyRenderer carrierRenderer = new ClockProxyRenderer();
|
private final ClockProxyRenderer carrierRenderer = new ClockProxyRenderer();
|
||||||
private final UnlockedStockSourceCollector sourceCollector;
|
private final UnlockedStockSourceCollector sourceCollector;
|
||||||
private final UnlockedVerticalOffsetScaler offsetScaler = new UnlockedVerticalOffsetScaler();
|
private final TextVerticalOffsetScaler textOffsetScaler = new TextVerticalOffsetScaler();
|
||||||
private final UnlockedChipPlacementController chipPlacementController;
|
private final UnlockedChipPlacementController chipPlacementController;
|
||||||
private final UnlockedLayoutPlanner layoutPlanner;
|
private final UnlockedLayoutPlanner layoutPlanner;
|
||||||
private final WeakHashMap<View, Integer> clockBaselineDeltaByRoot = new WeakHashMap<>();
|
private final WeakHashMap<View, Integer> clockBaselineDeltaByRoot = new WeakHashMap<>();
|
||||||
@@ -45,12 +44,7 @@ public final class UnlockedIconSnapshotRenderController {
|
|||||||
private final WeakHashMap<View, Boolean> forcedChipRefreshByRoot = new WeakHashMap<>();
|
private final WeakHashMap<View, Boolean> forcedChipRefreshByRoot = new WeakHashMap<>();
|
||||||
|
|
||||||
public UnlockedIconSnapshotRenderController() {
|
public UnlockedIconSnapshotRenderController() {
|
||||||
this(null);
|
sourceCollector = new UnlockedStockSourceCollector();
|
||||||
}
|
|
||||||
|
|
||||||
public UnlockedIconSnapshotRenderController(RuntimeContext runtimeContext) {
|
|
||||||
this.runtimeContext = runtimeContext;
|
|
||||||
sourceCollector = new UnlockedStockSourceCollector(runtimeContext);
|
|
||||||
statusRenderer = new SnapshotRenderer(true, true, false);
|
statusRenderer = new SnapshotRenderer(true, true, false);
|
||||||
notificationRenderer = new SnapshotRenderer(false, false, false);
|
notificationRenderer = new SnapshotRenderer(false, false, false);
|
||||||
chipRenderer = new SnapshotRenderer(false, false, true);
|
chipRenderer = new SnapshotRenderer(false, false, true);
|
||||||
@@ -60,8 +54,7 @@ public final class UnlockedIconSnapshotRenderController {
|
|||||||
notificationRenderer,
|
notificationRenderer,
|
||||||
chipRenderer,
|
chipRenderer,
|
||||||
chipPlacementController,
|
chipPlacementController,
|
||||||
offsetScaler,
|
textOffsetScaler);
|
||||||
runtimeContext);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public RenderResult renderUnlocked(
|
public RenderResult renderUnlocked(
|
||||||
@@ -110,7 +103,7 @@ public final class UnlockedIconSnapshotRenderController {
|
|||||||
LayoutInputSignature previousSignature = lastLayoutSignatureByRoot.get(root);
|
LayoutInputSignature previousSignature = lastLayoutSignatureByRoot.get(root);
|
||||||
boolean forceChipRefresh = Boolean.TRUE.equals(forcedChipRefreshByRoot.remove(root));
|
boolean forceChipRefresh = Boolean.TRUE.equals(forcedChipRefreshByRoot.remove(root));
|
||||||
boolean sceneChanged = previousSignature != null
|
boolean sceneChanged = previousSignature != null
|
||||||
&& !java.util.Objects.equals(signature.scene, previousSignature.scene);
|
&& !Objects.equals(signature.scene, previousSignature.scene);
|
||||||
boolean stockSourcesChanged = previousSignature == null
|
boolean stockSourcesChanged = previousSignature == null
|
||||||
|| signature.stockSurfaceSignature() != previousSignature.stockSurfaceSignature();
|
|| signature.stockSurfaceSignature() != previousSignature.stockSurfaceSignature();
|
||||||
boolean chipSourcesChanged = previousSignature == null
|
boolean chipSourcesChanged = previousSignature == null
|
||||||
@@ -134,7 +127,7 @@ public final class UnlockedIconSnapshotRenderController {
|
|||||||
&& previousIcons != null) {
|
&& previousIcons != null) {
|
||||||
LayoutPlan previousPlan = lastLayoutPlanByRoot.get(root);
|
LayoutPlan previousPlan = lastLayoutPlanByRoot.get(root);
|
||||||
if (previousPlan != null
|
if (previousPlan != null
|
||||||
&& java.util.Objects.equals(
|
&& Objects.equals(
|
||||||
lastClockSourceGeometryByRoot.get(root),
|
lastClockSourceGeometryByRoot.get(root),
|
||||||
currentClockSourceGeometry)) {
|
currentClockSourceGeometry)) {
|
||||||
ClockPlacement updatedClock = clockPlacementWithTextFromModel(
|
ClockPlacement updatedClock = clockPlacementWithTextFromModel(
|
||||||
@@ -165,12 +158,11 @@ public final class UnlockedIconSnapshotRenderController {
|
|||||||
previousPlan != null ? previousPlan.clockPlacement : null,
|
previousPlan != null ? previousPlan.clockPlacement : null,
|
||||||
textPlacement);
|
textPlacement);
|
||||||
Integer previousClockGeometry = lastClockGeometryByRoot.get(root);
|
Integer previousClockGeometry = lastClockGeometryByRoot.get(root);
|
||||||
String missReason = clockFastPathMissReason(
|
if (canReuseClockFastPath(
|
||||||
previousPlan,
|
previousPlan,
|
||||||
previousClockGeometry,
|
previousClockGeometry,
|
||||||
currentClockGeometry,
|
currentClockGeometry,
|
||||||
updatedClock);
|
updatedClock)) {
|
||||||
if (missReason == null) {
|
|
||||||
LayoutPlan updatedPlan = previousPlan.withClockPlacement(updatedClock);
|
LayoutPlan updatedPlan = previousPlan.withClockPlacement(updatedClock);
|
||||||
lastLayoutPlanByRoot.put(root, updatedPlan);
|
lastLayoutPlanByRoot.put(root, updatedPlan);
|
||||||
clockRenderer.render(clockHost, updatedClock);
|
clockRenderer.render(clockHost, updatedClock);
|
||||||
@@ -308,7 +300,7 @@ public final class UnlockedIconSnapshotRenderController {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
SbtSettings settings = RuntimeSettingsCache.get(root.getContext());
|
SbtSettings settings = RuntimeSettingsCache.get(root.getContext());
|
||||||
if (settings == null || !settings.layoutChipEnabledUnlocked) {
|
if (!settings.layoutChipEnabledUnlocked) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
chipRenderer.renderPlacements(chipHost, layoutPlan.chipPlacements);
|
chipRenderer.renderPlacements(chipHost, layoutPlan.chipPlacements);
|
||||||
@@ -332,7 +324,7 @@ public final class UnlockedIconSnapshotRenderController {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
SbtSettings settings = RuntimeSettingsCache.get(root.getContext());
|
SbtSettings settings = RuntimeSettingsCache.get(root.getContext());
|
||||||
if (settings == null || !clockEnabledForScene(settings, scene)) {
|
if (!clockEnabledForScene(settings, scene)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
CollectedIcons collectedIcons = lastCollectedIconsByRoot.get(root);
|
CollectedIcons collectedIcons = lastCollectedIconsByRoot.get(root);
|
||||||
@@ -600,7 +592,7 @@ public final class UnlockedIconSnapshotRenderController {
|
|||||||
if (settings == null) {
|
if (settings == null) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return java.util.Objects.hash(
|
return Objects.hash(
|
||||||
settings.clockShowSeconds,
|
settings.clockShowSeconds,
|
||||||
settings.clockShowDatePrefix,
|
settings.clockShowDatePrefix,
|
||||||
settings.clockCustomFormatEnabled,
|
settings.clockCustomFormatEnabled,
|
||||||
@@ -704,7 +696,7 @@ public final class UnlockedIconSnapshotRenderController {
|
|||||||
source,
|
source,
|
||||||
model,
|
model,
|
||||||
UnlockedLayoutPlanner.positionFor(settings.clockPosition),
|
UnlockedLayoutPlanner.positionFor(settings.clockPosition),
|
||||||
baselineY - offsetScaler.clock(settings.clockVerticalOffsetPx, source),
|
baselineY - textOffsetScaler.scale(settings.clockVerticalOffsetPx, source),
|
||||||
root.getWidth(),
|
root.getWidth(),
|
||||||
cutoutBounds,
|
cutoutBounds,
|
||||||
settings.clockMiddleAutoNearestSide,
|
settings.clockMiddleAutoNearestSide,
|
||||||
@@ -871,11 +863,9 @@ public final class UnlockedIconSnapshotRenderController {
|
|||||||
result = 31 * result + source.getPaddingTop();
|
result = 31 * result + source.getPaddingTop();
|
||||||
result = 31 * result + source.getPaddingRight();
|
result = 31 * result + source.getPaddingRight();
|
||||||
result = 31 * result + source.getPaddingBottom();
|
result = 31 * result + source.getPaddingBottom();
|
||||||
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
|
|
||||||
result = 31 * result + Float.floatToIntBits(source.getLetterSpacing());
|
result = 31 * result + Float.floatToIntBits(source.getLetterSpacing());
|
||||||
String fontFeatures = source.getFontFeatureSettings();
|
String fontFeatures = source.getFontFeatureSettings();
|
||||||
result = 31 * result + (fontFeatures != null ? fontFeatures.hashCode() : 0);
|
result = 31 * result + (fontFeatures != null ? fontFeatures.hashCode() : 0);
|
||||||
}
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -918,25 +908,25 @@ public final class UnlockedIconSnapshotRenderController {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String clockFastPathMissReason(
|
private boolean canReuseClockFastPath(
|
||||||
LayoutPlan previousPlan,
|
LayoutPlan previousPlan,
|
||||||
Integer previousGeometry,
|
Integer previousGeometry,
|
||||||
Integer currentGeometry,
|
Integer currentGeometry,
|
||||||
ClockPlacement updatedClock
|
ClockPlacement updatedClock
|
||||||
) {
|
) {
|
||||||
if (previousPlan == null) {
|
if (previousPlan == null) {
|
||||||
return "noPlan";
|
return false;
|
||||||
}
|
}
|
||||||
if (currentGeometry == null) {
|
if (currentGeometry == null) {
|
||||||
return "noGeometry";
|
return false;
|
||||||
}
|
}
|
||||||
if (!currentGeometry.equals(previousGeometry)) {
|
if (!currentGeometry.equals(previousGeometry)) {
|
||||||
return "geometryChanged";
|
return false;
|
||||||
}
|
}
|
||||||
if (previousPlan.clockPlacement != null && updatedClock == null) {
|
if (previousPlan.clockPlacement != null && updatedClock == null) {
|
||||||
return "rowMismatch";
|
return false;
|
||||||
}
|
}
|
||||||
return null;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int boundsGeometrySignature(Bounds bounds) {
|
private static int boundsGeometrySignature(Bounds bounds) {
|
||||||
|
|||||||
+3
-15
@@ -4,6 +4,7 @@ import android.view.ViewGroup;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
import se.ajpanton.statusbartweak.runtime.layoutsolver.StatusBarLayoutSolver;
|
import se.ajpanton.statusbartweak.runtime.layoutsolver.StatusBarLayoutSolver;
|
||||||
import se.ajpanton.statusbartweak.runtime.layoutsolver.StatusBarLayoutSolver.AnchorSide;
|
import se.ajpanton.statusbartweak.runtime.layoutsolver.StatusBarLayoutSolver.AnchorSide;
|
||||||
@@ -611,19 +612,6 @@ final class UnlockedLayoutBand extends StatusBarLayoutSolver.LayoutBand {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int shrinkableIconCount(ArrayList<SnapshotPlacement> icons) {
|
|
||||||
int count = 0;
|
|
||||||
if (icons == null) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
for (SnapshotPlacement icon : icons) {
|
|
||||||
if (isShrinkableIcon(icon)) {
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean hasOverflowDot(ArrayList<SnapshotPlacement> icons) {
|
private boolean hasOverflowDot(ArrayList<SnapshotPlacement> icons) {
|
||||||
for (SnapshotPlacement icon : icons) {
|
for (SnapshotPlacement icon : icons) {
|
||||||
if (icon.overflowDot) {
|
if (icon.overflowDot) {
|
||||||
@@ -709,7 +697,7 @@ final class UnlockedLayoutBand extends StatusBarLayoutSolver.LayoutBand {
|
|||||||
return new SnapshotPlacement(
|
return new SnapshotPlacement(
|
||||||
null,
|
null,
|
||||||
new Bounds(0, rowTop, safeWidth, safeHeight),
|
new Bounds(0, rowTop, safeWidth, safeHeight),
|
||||||
SnapshotKeys.OVERFLOW_DOT + ":" + kind.name().toLowerCase(java.util.Locale.ROOT),
|
SnapshotKeys.OVERFLOW_DOT + ":" + kind.name().toLowerCase(Locale.ROOT),
|
||||||
false,
|
false,
|
||||||
true,
|
true,
|
||||||
dotColor(),
|
dotColor(),
|
||||||
@@ -762,7 +750,7 @@ final class UnlockedLayoutBand extends StatusBarLayoutSolver.LayoutBand {
|
|||||||
return new SnapshotPlacement(
|
return new SnapshotPlacement(
|
||||||
null,
|
null,
|
||||||
new Bounds(0, rowTop(activePlacements()), 1, height),
|
new Bounds(0, rowTop(activePlacements()), 1, height),
|
||||||
SnapshotKeys.EMPTY_ICON_CONTAINER + ":" + kind.name().toLowerCase(java.util.Locale.ROOT),
|
SnapshotKeys.EMPTY_ICON_CONTAINER + ":" + kind.name().toLowerCase(Locale.ROOT),
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
null,
|
null,
|
||||||
|
|||||||
+16
-18
@@ -5,12 +5,13 @@ import android.view.View;
|
|||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.IdentityHashMap;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.WeakHashMap;
|
import java.util.WeakHashMap;
|
||||||
|
|
||||||
import se.ajpanton.statusbartweak.R;
|
import se.ajpanton.statusbartweak.R;
|
||||||
import se.ajpanton.statusbartweak.runtime.features.RuntimeContext;
|
|
||||||
import se.ajpanton.statusbartweak.runtime.layoutsolver.StatusBarLayoutSolver;
|
import se.ajpanton.statusbartweak.runtime.layoutsolver.StatusBarLayoutSolver;
|
||||||
import se.ajpanton.statusbartweak.runtime.layoutsolver.StatusBarLayoutSolver.AnchorSide;
|
import se.ajpanton.statusbartweak.runtime.layoutsolver.StatusBarLayoutSolver.AnchorSide;
|
||||||
import se.ajpanton.statusbartweak.runtime.layoutsolver.StatusBarLayoutSolver.Bounds;
|
import se.ajpanton.statusbartweak.runtime.layoutsolver.StatusBarLayoutSolver.Bounds;
|
||||||
@@ -28,7 +29,7 @@ final class UnlockedLayoutPlanner {
|
|||||||
private final SnapshotRenderer notificationRenderer;
|
private final SnapshotRenderer notificationRenderer;
|
||||||
private final SnapshotRenderer chipRenderer;
|
private final SnapshotRenderer chipRenderer;
|
||||||
private final UnlockedChipPlacementController chipPlacementController;
|
private final UnlockedChipPlacementController chipPlacementController;
|
||||||
private final UnlockedVerticalOffsetScaler offsetScaler;
|
private final TextVerticalOffsetScaler textOffsetScaler;
|
||||||
private final NotificationSeenAppReporter notificationSeenAppReporter =
|
private final NotificationSeenAppReporter notificationSeenAppReporter =
|
||||||
new NotificationSeenAppReporter();
|
new NotificationSeenAppReporter();
|
||||||
private final WeakHashMap<View, Integer> aodStatusRightInsetByRoot = new WeakHashMap<>();
|
private final WeakHashMap<View, Integer> aodStatusRightInsetByRoot = new WeakHashMap<>();
|
||||||
@@ -40,14 +41,13 @@ final class UnlockedLayoutPlanner {
|
|||||||
SnapshotRenderer notificationRenderer,
|
SnapshotRenderer notificationRenderer,
|
||||||
SnapshotRenderer chipRenderer,
|
SnapshotRenderer chipRenderer,
|
||||||
UnlockedChipPlacementController chipPlacementController,
|
UnlockedChipPlacementController chipPlacementController,
|
||||||
UnlockedVerticalOffsetScaler offsetScaler,
|
TextVerticalOffsetScaler textOffsetScaler
|
||||||
RuntimeContext runtimeContext
|
|
||||||
) {
|
) {
|
||||||
this.statusRenderer = statusRenderer;
|
this.statusRenderer = statusRenderer;
|
||||||
this.notificationRenderer = notificationRenderer;
|
this.notificationRenderer = notificationRenderer;
|
||||||
this.chipRenderer = chipRenderer;
|
this.chipRenderer = chipRenderer;
|
||||||
this.chipPlacementController = chipPlacementController;
|
this.chipPlacementController = chipPlacementController;
|
||||||
this.offsetScaler = offsetScaler;
|
this.textOffsetScaler = textOffsetScaler;
|
||||||
}
|
}
|
||||||
|
|
||||||
LayoutPlan solve(
|
LayoutPlan solve(
|
||||||
@@ -307,7 +307,10 @@ final class UnlockedLayoutPlanner {
|
|||||||
if (bands == null || bands.size() < 2 || itemOrder == null || itemOrder.isEmpty()) {
|
if (bands == null || bands.size() < 2 || itemOrder == null || itemOrder.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ArrayList<UnlockedLayoutBand> originalOrder = new ArrayList<>(bands);
|
IdentityHashMap<UnlockedLayoutBand, Integer> originalOrder = new IdentityHashMap<>();
|
||||||
|
for (int i = 0; i < bands.size(); i++) {
|
||||||
|
originalOrder.put(bands.get(i), i);
|
||||||
|
}
|
||||||
bands.sort((left, right) -> {
|
bands.sort((left, right) -> {
|
||||||
int orderComparison = Integer.compare(
|
int orderComparison = Integer.compare(
|
||||||
orderIndex(itemOrder, left != null ? left.kind : null),
|
orderIndex(itemOrder, left != null ? left.kind : null),
|
||||||
@@ -315,7 +318,9 @@ final class UnlockedLayoutPlanner {
|
|||||||
if (orderComparison != 0) {
|
if (orderComparison != 0) {
|
||||||
return orderComparison;
|
return orderComparison;
|
||||||
}
|
}
|
||||||
return Integer.compare(originalOrder.indexOf(left), originalOrder.indexOf(right));
|
return Integer.compare(
|
||||||
|
originalOrder.getOrDefault(left, Integer.MAX_VALUE),
|
||||||
|
originalOrder.getOrDefault(right, Integer.MAX_VALUE));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -440,7 +445,7 @@ final class UnlockedLayoutPlanner {
|
|||||||
boxes);
|
boxes);
|
||||||
if ((band.kind == LayoutItemKind.NOTIFICATIONS || band.kind == LayoutItemKind.STATUS)
|
if ((band.kind == LayoutItemKind.NOTIFICATIONS || band.kind == LayoutItemKind.STATUS)
|
||||||
&& !isFixedDotBand(band)) {
|
&& !isFixedDotBand(band)) {
|
||||||
item.iconGroup = packedKind(band.kind).toLowerCase(java.util.Locale.ROOT);
|
item.iconGroup = packedKind(band.kind).toLowerCase(Locale.ROOT);
|
||||||
item.iconCount = band.forceOverflowDotOnly
|
item.iconCount = band.forceOverflowDotOnly
|
||||||
? 1
|
? 1
|
||||||
: band.rawPlacements != null ? band.rawPlacements.size() : 0;
|
: band.rawPlacements != null ? band.rawPlacements.size() : 0;
|
||||||
@@ -544,8 +549,8 @@ final class UnlockedLayoutPlanner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void configurePackedIconGroups(ArrayList<PackedStatusBarLayoutSolver.LayoutItem> items) {
|
private void configurePackedIconGroups(ArrayList<PackedStatusBarLayoutSolver.LayoutItem> items) {
|
||||||
java.util.LinkedHashMap<String, ArrayList<PackedStatusBarLayoutSolver.LayoutItem>> groups =
|
LinkedHashMap<String, ArrayList<PackedStatusBarLayoutSolver.LayoutItem>> groups =
|
||||||
new java.util.LinkedHashMap<>();
|
new LinkedHashMap<>();
|
||||||
for (PackedStatusBarLayoutSolver.LayoutItem item : items) {
|
for (PackedStatusBarLayoutSolver.LayoutItem item : items) {
|
||||||
if (item.iconGroup != null) {
|
if (item.iconGroup != null) {
|
||||||
groups.computeIfAbsent(item.iconGroup, ignored -> new ArrayList<>()).add(item);
|
groups.computeIfAbsent(item.iconGroup, ignored -> new ArrayList<>()).add(item);
|
||||||
@@ -672,7 +677,7 @@ final class UnlockedLayoutPlanner {
|
|||||||
: ClockLayout.centeredTextBaseline(
|
: ClockLayout.centeredTextBaseline(
|
||||||
collectedIcons.carrierView,
|
collectedIcons.carrierView,
|
||||||
sourceHeight > 0 ? sourceHeight : anchorBounds.height);
|
sourceHeight > 0 ? sourceHeight : anchorBounds.height);
|
||||||
int verticalOffset = offsetScaler.clock(
|
int verticalOffset = textOffsetScaler.scale(
|
||||||
settings.layoutCarrierVerticalOffsetPx,
|
settings.layoutCarrierVerticalOffsetPx,
|
||||||
collectedIcons.carrierView);
|
collectedIcons.carrierView);
|
||||||
return ClockLayout.simpleText(
|
return ClockLayout.simpleText(
|
||||||
@@ -1183,13 +1188,6 @@ final class UnlockedLayoutPlanner {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int representativeHeight(ArrayList<SnapshotPlacement> placements) {
|
|
||||||
if (placements == null || placements.isEmpty()) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return Math.max(0, placements.get(0).bounds.height);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void splitClockIfNeeded(
|
private void splitClockIfNeeded(
|
||||||
View root,
|
View root,
|
||||||
ArrayList<UnlockedLayoutBand> bands,
|
ArrayList<UnlockedLayoutBand> bands,
|
||||||
|
|||||||
+56
-128
@@ -1,6 +1,5 @@
|
|||||||
package se.ajpanton.statusbartweak.runtime.render;
|
package se.ajpanton.statusbartweak.runtime.render;
|
||||||
|
|
||||||
import android.content.res.Resources;
|
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
@@ -10,10 +9,13 @@ import android.widget.TextView;
|
|||||||
|
|
||||||
import java.util.ArrayDeque;
|
import java.util.ArrayDeque;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.WeakHashMap;
|
import java.util.WeakHashMap;
|
||||||
|
|
||||||
import se.ajpanton.statusbartweak.runtime.features.RuntimeContext;
|
import se.ajpanton.statusbartweak.runtime.ViewIdNames;
|
||||||
import se.ajpanton.statusbartweak.runtime.hooks.ReflectionSupport;
|
import se.ajpanton.statusbartweak.runtime.hooks.ReflectionSupport;
|
||||||
import se.ajpanton.statusbartweak.runtime.layoutsolver.StatusBarLayoutSolver.Bounds;
|
import se.ajpanton.statusbartweak.runtime.layoutsolver.StatusBarLayoutSolver.Bounds;
|
||||||
import se.ajpanton.statusbartweak.runtime.mode.NotificationDisplayStyle;
|
import se.ajpanton.statusbartweak.runtime.mode.NotificationDisplayStyle;
|
||||||
@@ -23,13 +25,6 @@ import se.ajpanton.statusbartweak.shell.settings.SbtSettings;
|
|||||||
final class UnlockedStockSourceCollector {
|
final class UnlockedStockSourceCollector {
|
||||||
private final WeakHashMap<View, RootAnchors> anchorsByRoot = new WeakHashMap<>();
|
private final WeakHashMap<View, RootAnchors> anchorsByRoot = new WeakHashMap<>();
|
||||||
|
|
||||||
UnlockedStockSourceCollector() {
|
|
||||||
this(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
UnlockedStockSourceCollector(RuntimeContext runtimeContext) {
|
|
||||||
}
|
|
||||||
|
|
||||||
void clear() {
|
void clear() {
|
||||||
anchorsByRoot.clear();
|
anchorsByRoot.clear();
|
||||||
}
|
}
|
||||||
@@ -72,7 +67,7 @@ final class UnlockedStockSourceCollector {
|
|||||||
if (scene == null || !scene.isAod()) {
|
if (scene == null || !scene.isAod()) {
|
||||||
mergeActiveHiddenStatusSources(root, anchors.statusIcons, statusIcons);
|
mergeActiveHiddenStatusSources(root, anchors.statusIcons, statusIcons);
|
||||||
}
|
}
|
||||||
if (anchors.battery != null && !isDescendantOf(anchors.battery, anchors.statusRoot)) {
|
if (anchors.battery != null && !ViewGeometry.isDescendantOf(anchors.battery, anchors.statusRoot)) {
|
||||||
collectStatusSnapshotViews(anchors.battery, statusIcons);
|
collectStatusSnapshotViews(anchors.battery, statusIcons);
|
||||||
}
|
}
|
||||||
normalizeStatusIconSourceBounds(root, statusIcons);
|
normalizeStatusIconSourceBounds(root, statusIcons);
|
||||||
@@ -119,7 +114,7 @@ final class UnlockedStockSourceCollector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private String reflectString(View view, String methodName, String... fieldNames) {
|
private String reflectString(View view, String methodName, String... fieldNames) {
|
||||||
Object methodValue = ReflectionSupport.invokeMethod(view, methodName, new Class<?>[0]);
|
Object methodValue = ReflectionSupport.invokeMethod(view, methodName);
|
||||||
if (methodValue != null) {
|
if (methodValue != null) {
|
||||||
return safeText(String.valueOf(methodValue));
|
return safeText(String.valueOf(methodValue));
|
||||||
}
|
}
|
||||||
@@ -196,7 +191,7 @@ final class UnlockedStockSourceCollector {
|
|||||||
loggingAwareSettingsSignature(root, settings),
|
loggingAwareSettingsSignature(root, settings),
|
||||||
clockTimeSignature(settings),
|
clockTimeSignature(settings),
|
||||||
viewSignatureOrZero(anchors != null ? anchors.clockView : null),
|
viewSignatureOrZero(anchors != null ? anchors.clockView : null),
|
||||||
shallowTreeSignature(anchors != null ? anchors.clockContainer : null),
|
shallowTreeSignatureExcluding(anchors != null ? anchors.clockContainer : null, null),
|
||||||
shallowTreeSignatureExcluding(
|
shallowTreeSignatureExcluding(
|
||||||
anchors != null ? anchors.statusRoot : null,
|
anchors != null ? anchors.statusRoot : null,
|
||||||
anchors != null ? anchors.clockContainer : null),
|
anchors != null ? anchors.clockContainer : null),
|
||||||
@@ -236,8 +231,8 @@ final class UnlockedStockSourceCollector {
|
|||||||
}
|
}
|
||||||
Bounds statusBounds = AodStatusbarSourceStore.statusBoundsForRoot(root, notificationContainer);
|
Bounds statusBounds = AodStatusbarSourceStore.statusBoundsForRoot(root, notificationContainer);
|
||||||
int result = 17;
|
int result = 17;
|
||||||
result = 31 * result + boundsSignature(notificationBounds);
|
result = 31 * result + (notificationBounds != null ? notificationBounds.signature() : 0);
|
||||||
result = 31 * result + boundsSignature(statusBounds);
|
result = 31 * result + (statusBounds != null ? statusBounds.signature() : 0);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -289,7 +284,7 @@ final class UnlockedStockSourceCollector {
|
|||||||
queue.add(root);
|
queue.add(root);
|
||||||
while (!queue.isEmpty()) {
|
while (!queue.isEmpty()) {
|
||||||
View view = queue.removeFirst();
|
View view = queue.removeFirst();
|
||||||
String idName = resolveIdName(view);
|
String idName = ViewIdNames.idName(view);
|
||||||
if (clockContainer == null && idName.equals("left_clock_container")) {
|
if (clockContainer == null && idName.equals("left_clock_container")) {
|
||||||
clockContainer = view;
|
clockContainer = view;
|
||||||
}
|
}
|
||||||
@@ -352,8 +347,8 @@ final class UnlockedStockSourceCollector {
|
|||||||
if (view == null) {
|
if (view == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
String idName = resolveIdName(view).toLowerCase(java.util.Locale.ROOT);
|
String idName = ViewIdNames.idName(view).toLowerCase(Locale.ROOT);
|
||||||
String className = view.getClass().getName().toLowerCase(java.util.Locale.ROOT);
|
String className = view.getClass().getName().toLowerCase(Locale.ROOT);
|
||||||
CharSequence text = view.getText();
|
CharSequence text = view.getText();
|
||||||
return (idName.contains("carrier") || className.contains("carrier"))
|
return (idName.contains("carrier") || className.contains("carrier"))
|
||||||
&& text != null
|
&& text != null
|
||||||
@@ -395,10 +390,10 @@ final class UnlockedStockSourceCollector {
|
|||||||
ArrayList<SnapshotSource> out,
|
ArrayList<SnapshotSource> out,
|
||||||
boolean includeHidden
|
boolean includeHidden
|
||||||
) {
|
) {
|
||||||
if (isOwnedRuntimeView(source)) {
|
if (ViewGeometry.isOwnedRuntimeView(source)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
boolean candidate = isStatusSnapshotCandidate(source);
|
boolean candidate = isStatusSnapshotCandidate(source, false);
|
||||||
if (includeHidden) {
|
if (includeHidden) {
|
||||||
candidate = isStatusSnapshotCandidate(source, true);
|
candidate = isStatusSnapshotCandidate(source, true);
|
||||||
}
|
}
|
||||||
@@ -435,7 +430,7 @@ final class UnlockedStockSourceCollector {
|
|||||||
}
|
}
|
||||||
LinkedHashMap<String, SnapshotSource> existingBySlot = new LinkedHashMap<>();
|
LinkedHashMap<String, SnapshotSource> existingBySlot = new LinkedHashMap<>();
|
||||||
for (SnapshotSource source : out) {
|
for (SnapshotSource source : out) {
|
||||||
if (source != null && isDescendantOf(source.view(), statusIcons)) {
|
if (source != null && ViewGeometry.isDescendantOf(source.view(), statusIcons)) {
|
||||||
String slot = reflectString(source.view(), "getSlot", "mSlot", "slot");
|
String slot = reflectString(source.view(), "getSlot", "mSlot", "slot");
|
||||||
if (!slot.isEmpty()) {
|
if (!slot.isEmpty()) {
|
||||||
existingBySlot.put(slot, source);
|
existingBySlot.put(slot, source);
|
||||||
@@ -486,7 +481,7 @@ final class UnlockedStockSourceCollector {
|
|||||||
ArrayList<SnapshotSource> merged = new ArrayList<>();
|
ArrayList<SnapshotSource> merged = new ArrayList<>();
|
||||||
boolean inserted = false;
|
boolean inserted = false;
|
||||||
for (SnapshotSource source : out) {
|
for (SnapshotSource source : out) {
|
||||||
if (source != null && isDescendantOf(source.view(), statusIcons)) {
|
if (source != null && ViewGeometry.isDescendantOf(source.view(), statusIcons)) {
|
||||||
if (!inserted) {
|
if (!inserted) {
|
||||||
merged.addAll(mergedStatusIcons);
|
merged.addAll(mergedStatusIcons);
|
||||||
inserted = true;
|
inserted = true;
|
||||||
@@ -653,7 +648,7 @@ final class UnlockedStockSourceCollector {
|
|||||||
) {
|
) {
|
||||||
if (sources != null) {
|
if (sources != null) {
|
||||||
for (SnapshotSource source : sources) {
|
for (SnapshotSource source : sources) {
|
||||||
if (source == null || !isDescendantOf(source.view(), statusIcons)) {
|
if (source == null || !ViewGeometry.isDescendantOf(source.view(), statusIcons)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
Bounds bounds = ViewGeometry.boundsRelativeTo(root, source.view());
|
Bounds bounds = ViewGeometry.boundsRelativeTo(root, source.view());
|
||||||
@@ -709,13 +704,13 @@ final class UnlockedStockSourceCollector {
|
|||||||
queue.add(root);
|
queue.add(root);
|
||||||
while (!queue.isEmpty()) {
|
while (!queue.isEmpty()) {
|
||||||
View view = queue.removeFirst();
|
View view = queue.removeFirst();
|
||||||
if (isStatusChipSnapshotCandidate(root, view)) {
|
if (isStatusChipSnapshotCandidate(root, view, false)) {
|
||||||
SnapshotSource source = statusChipSource(root, view);
|
SnapshotSource source = statusChipSource(root, view);
|
||||||
visibleOut.add(source);
|
visibleOut.add(source);
|
||||||
metricOut.add(source);
|
metricOut.add(source);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (metricOut.isEmpty() && isStatusChipMetricCandidate(root, view)) {
|
if (metricOut.isEmpty() && isStatusChipMetricCandidate(root, view, false)) {
|
||||||
metricOut.add(statusChipSource(root, view));
|
metricOut.add(statusChipSource(root, view));
|
||||||
}
|
}
|
||||||
if (view instanceof ViewGroup group) {
|
if (view instanceof ViewGroup group) {
|
||||||
@@ -726,10 +721,6 @@ final class UnlockedStockSourceCollector {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isStatusChipSnapshotCandidate(View root, View view) {
|
|
||||||
return isStatusChipSnapshotCandidate(root, view, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
private SnapshotSource statusChipSource(View root, View view) {
|
private SnapshotSource statusChipSource(View root, View view) {
|
||||||
Bounds bounds = ViewGeometry.boundsRelativeTo(root, view);
|
Bounds bounds = ViewGeometry.boundsRelativeTo(root, view);
|
||||||
if (bounds == null || bounds.width <= 0 || bounds.height <= 0) {
|
if (bounds == null || bounds.width <= 0 || bounds.height <= 0) {
|
||||||
@@ -755,7 +746,7 @@ final class UnlockedStockSourceCollector {
|
|||||||
if (view == null
|
if (view == null
|
||||||
|| view == root
|
|| view == root
|
||||||
|| !view.isAttachedToWindow()
|
|| !view.isAttachedToWindow()
|
||||||
|| !isDescendantOf(view, root)
|
|| !ViewGeometry.isDescendantOf(view, root)
|
||||||
|| ReflectionSupport.getBooleanField(view, "sbtStatusChipForcedHidden", false)
|
|| ReflectionSupport.getBooleanField(view, "sbtStatusChipForcedHidden", false)
|
||||||
|| !isStatusChipCandidate(view)
|
|| !isStatusChipCandidate(view)
|
||||||
|| !hasVisibleStatusChipContent(view)) {
|
|| !hasVisibleStatusChipContent(view)) {
|
||||||
@@ -833,10 +824,6 @@ final class UnlockedStockSourceCollector {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isStatusChipMetricCandidate(View root, View view) {
|
|
||||||
return isStatusChipMetricCandidate(root, view, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isStatusChipMetricCandidate(View root, View view, boolean allowHidden) {
|
private boolean isStatusChipMetricCandidate(View root, View view, boolean allowHidden) {
|
||||||
if (view == null || view == root || root == null) {
|
if (view == null || view == root || root == null) {
|
||||||
return false;
|
return false;
|
||||||
@@ -867,8 +854,8 @@ final class UnlockedStockSourceCollector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean isStatusChipCandidate(View view) {
|
private boolean isStatusChipCandidate(View view) {
|
||||||
String className = view.getClass().getName().toLowerCase(java.util.Locale.ROOT);
|
String className = view.getClass().getName().toLowerCase(Locale.ROOT);
|
||||||
String idName = resolveIdName(view).toLowerCase(java.util.Locale.ROOT);
|
String idName = ViewIdNames.idName(view).toLowerCase(Locale.ROOT);
|
||||||
if (className.contains("privacy") || idName.contains("privacy")) {
|
if (className.contains("privacy") || idName.contains("privacy")) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -877,12 +864,8 @@ final class UnlockedStockSourceCollector {
|
|||||||
|| "ongoing_activity_capsule".equals(idName);
|
|| "ongoing_activity_capsule".equals(idName);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isStatusSnapshotCandidate(View view) {
|
|
||||||
return isStatusSnapshotCandidate(view, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isStatusSnapshotCandidate(View view, boolean includeHidden) {
|
private boolean isStatusSnapshotCandidate(View view, boolean includeHidden) {
|
||||||
if (isOwnedRuntimeView(view)) {
|
if (ViewGeometry.isOwnedRuntimeView(view)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!includeHidden && view.getVisibility() != View.VISIBLE) {
|
if (!includeHidden && view.getVisibility() != View.VISIBLE) {
|
||||||
@@ -893,7 +876,7 @@ final class UnlockedStockSourceCollector {
|
|||||||
if (width <= 0 || height <= 0) {
|
if (width <= 0 || height <= 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
String idName = resolveIdName(view);
|
String idName = ViewIdNames.idName(view);
|
||||||
if (idName.equals("battery") || containsAny(idName, "wifi", "mobile", "signal")) {
|
if (idName.equals("battery") || containsAny(idName, "wifi", "mobile", "signal")) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -912,7 +895,7 @@ final class UnlockedStockSourceCollector {
|
|||||||
if (view instanceof ImageView) {
|
if (view instanceof ImageView) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
String idName = resolveIdName(view);
|
String idName = ViewIdNames.idName(view);
|
||||||
String className = view.getClass().getName();
|
String className = view.getClass().getName();
|
||||||
return idName.equals("battery")
|
return idName.equals("battery")
|
||||||
|| containsAny(idName, "wifi", "mobile", "signal")
|
|| containsAny(idName, "wifi", "mobile", "signal")
|
||||||
@@ -923,7 +906,7 @@ final class UnlockedStockSourceCollector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean isNotificationSnapshotCandidate(View view) {
|
private boolean isNotificationSnapshotCandidate(View view) {
|
||||||
if (isOwnedRuntimeView(view)) {
|
if (ViewGeometry.isOwnedRuntimeView(view)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (view instanceof TextView) {
|
if (view instanceof TextView) {
|
||||||
@@ -934,7 +917,7 @@ final class UnlockedStockSourceCollector {
|
|||||||
}
|
}
|
||||||
int width = view.getWidth() > 0 ? view.getWidth() : view.getMeasuredWidth();
|
int width = view.getWidth() > 0 ? view.getWidth() : view.getMeasuredWidth();
|
||||||
int height = view.getHeight() > 0 ? view.getHeight() : view.getMeasuredHeight();
|
int height = view.getHeight() > 0 ? view.getHeight() : view.getMeasuredHeight();
|
||||||
if (width <= 0 || height <= 0 || resolveIdName(view).equals("status_bar_dot")) {
|
if (width <= 0 || height <= 0 || ViewIdNames.idName(view).equals("status_bar_dot")) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
String className = view.getClass().getName();
|
String className = view.getClass().getName();
|
||||||
@@ -944,7 +927,7 @@ final class UnlockedStockSourceCollector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean containsAny(String value, String... needles) {
|
private boolean containsAny(String value, String... needles) {
|
||||||
String lowerValue = value.toLowerCase(java.util.Locale.ROOT);
|
String lowerValue = value.toLowerCase(Locale.ROOT);
|
||||||
for (String needle : needles) {
|
for (String needle : needles) {
|
||||||
if (lowerValue.contains(needle)) {
|
if (lowerValue.contains(needle)) {
|
||||||
return true;
|
return true;
|
||||||
@@ -953,42 +936,10 @@ final class UnlockedStockSourceCollector {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isDescendantOf(View child, View ancestor) {
|
|
||||||
if (child == null || ancestor == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
View current = child;
|
|
||||||
while (current != null) {
|
|
||||||
if (current == ancestor) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
Object parent = current.getParent();
|
|
||||||
current = parent instanceof View ? (View) parent : null;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isOwnedRuntimeView(View view) {
|
|
||||||
View current = view;
|
|
||||||
while (current != null) {
|
|
||||||
Object tag = current.getTag();
|
|
||||||
if (tag instanceof String value && value.startsWith("statusbartweak.")) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
Object parent = current.getParent();
|
|
||||||
current = parent instanceof View ? (View) parent : null;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int viewSignatureOrZero(View view) {
|
private static int viewSignatureOrZero(View view) {
|
||||||
return view != null ? viewSignature(view) : 0;
|
return view != null ? viewSignature(view) : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int shallowTreeSignature(View view) {
|
|
||||||
return shallowTreeSignatureExcluding(view, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int shallowTreeSignatureExcluding(View view, View excluded) {
|
private static int shallowTreeSignatureExcluding(View view, View excluded) {
|
||||||
if (view == null) {
|
if (view == null) {
|
||||||
return 0;
|
return 0;
|
||||||
@@ -1174,7 +1125,7 @@ final class UnlockedStockSourceCollector {
|
|||||||
result = 31 * result + view.getPaddingBottom();
|
result = 31 * result + view.getPaddingBottom();
|
||||||
CharSequence contentDescription = view.getContentDescription();
|
CharSequence contentDescription = view.getContentDescription();
|
||||||
result = 31 * result + (contentDescription != null ? contentDescription.toString().hashCode() : 0);
|
result = 31 * result + (contentDescription != null ? contentDescription.toString().hashCode() : 0);
|
||||||
result = 31 * result + java.util.Arrays.hashCode(view.getDrawableState());
|
result = 31 * result + Arrays.hashCode(view.getDrawableState());
|
||||||
if (view instanceof TextView textView) {
|
if (view instanceof TextView textView) {
|
||||||
CharSequence text = textView.getText();
|
CharSequence text = textView.getText();
|
||||||
result = 31 * result + (text != null ? text.toString().hashCode() : 0);
|
result = 31 * result + (text != null ? text.toString().hashCode() : 0);
|
||||||
@@ -1192,26 +1143,14 @@ final class UnlockedStockSourceCollector {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int boundsSignature(Bounds bounds) {
|
private static int drawableLayoutSignature(Drawable drawable) {
|
||||||
if (bounds == null) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
int result = 17;
|
|
||||||
result = 31 * result + bounds.left;
|
|
||||||
result = 31 * result + bounds.top;
|
|
||||||
result = 31 * result + bounds.width;
|
|
||||||
result = 31 * result + bounds.height;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int drawableLayoutSignature(android.graphics.drawable.Drawable drawable) {
|
|
||||||
if (drawable == null) {
|
if (drawable == null) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
int result = 17;
|
int result = 17;
|
||||||
result = 31 * result + System.identityHashCode(drawable);
|
result = 31 * result + System.identityHashCode(drawable);
|
||||||
result = 31 * result + drawable.getLevel();
|
result = 31 * result + drawable.getLevel();
|
||||||
result = 31 * result + java.util.Arrays.hashCode(drawable.getState());
|
result = 31 * result + Arrays.hashCode(drawable.getState());
|
||||||
Rect bounds = drawable.getBounds();
|
Rect bounds = drawable.getBounds();
|
||||||
result = 31 * result + bounds.left;
|
result = 31 * result + bounds.left;
|
||||||
result = 31 * result + bounds.top;
|
result = 31 * result + bounds.top;
|
||||||
@@ -1220,17 +1159,6 @@ final class UnlockedStockSourceCollector {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String resolveIdName(View view) {
|
|
||||||
if (view.getId() == View.NO_ID) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
return view.getResources().getResourceEntryName(view.getId());
|
|
||||||
} catch (Resources.NotFoundException ignored) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private int clockTimeSignature(SbtSettings settings) {
|
private int clockTimeSignature(SbtSettings settings) {
|
||||||
if (settings == null || !settings.clockEnabledUnlocked) {
|
if (settings == null || !settings.clockEnabledUnlocked) {
|
||||||
return 0;
|
return 0;
|
||||||
@@ -1253,7 +1181,7 @@ final class UnlockedStockSourceCollector {
|
|||||||
if (settings == null) {
|
if (settings == null) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return java.util.Objects.hash(
|
return Objects.hash(
|
||||||
settings.clockEnabled,
|
settings.clockEnabled,
|
||||||
settings.clockEnabledUnlocked,
|
settings.clockEnabledUnlocked,
|
||||||
settings.clockPosition,
|
settings.clockPosition,
|
||||||
@@ -1291,44 +1219,44 @@ final class UnlockedStockSourceCollector {
|
|||||||
settings.layoutNotifSortOrder,
|
settings.layoutNotifSortOrder,
|
||||||
settings.layoutNotifEnabledUnlocked,
|
settings.layoutNotifEnabledUnlocked,
|
||||||
settings.layoutNotifUnlockedCount,
|
settings.layoutNotifUnlockedCount,
|
||||||
java.util.Arrays.hashCode(settings.layoutNotifPositions),
|
Arrays.hashCode(settings.layoutNotifPositions),
|
||||||
java.util.Arrays.hashCode(settings.layoutNotifMiddleSides),
|
Arrays.hashCode(settings.layoutNotifMiddleSides),
|
||||||
java.util.Arrays.hashCode(settings.layoutNotifMiddleAutoNearestSides),
|
Arrays.hashCode(settings.layoutNotifMiddleAutoNearestSides),
|
||||||
java.util.Arrays.hashCode(settings.layoutNotifVerticalOffsetsPx),
|
Arrays.hashCode(settings.layoutNotifVerticalOffsetsPx),
|
||||||
settings.layoutNotifEnabledLockscreen,
|
settings.layoutNotifEnabledLockscreen,
|
||||||
settings.layoutNotifLockCount,
|
settings.layoutNotifLockCount,
|
||||||
java.util.Arrays.hashCode(settings.layoutNotifLockPositions),
|
Arrays.hashCode(settings.layoutNotifLockPositions),
|
||||||
java.util.Arrays.hashCode(settings.layoutNotifLockMiddleSides),
|
Arrays.hashCode(settings.layoutNotifLockMiddleSides),
|
||||||
java.util.Arrays.hashCode(settings.layoutNotifLockMiddleAutoNearestSides),
|
Arrays.hashCode(settings.layoutNotifLockMiddleAutoNearestSides),
|
||||||
java.util.Arrays.hashCode(settings.layoutNotifLockVerticalOffsetsPx),
|
Arrays.hashCode(settings.layoutNotifLockVerticalOffsetsPx),
|
||||||
settings.layoutNotifEnabledAod,
|
settings.layoutNotifEnabledAod,
|
||||||
settings.layoutNotifAodCount,
|
settings.layoutNotifAodCount,
|
||||||
java.util.Arrays.hashCode(settings.layoutNotifAodPositions),
|
Arrays.hashCode(settings.layoutNotifAodPositions),
|
||||||
java.util.Arrays.hashCode(settings.layoutNotifAodMiddleSides),
|
Arrays.hashCode(settings.layoutNotifAodMiddleSides),
|
||||||
java.util.Arrays.hashCode(settings.layoutNotifAodMiddleAutoNearestSides),
|
Arrays.hashCode(settings.layoutNotifAodMiddleAutoNearestSides),
|
||||||
java.util.Arrays.hashCode(settings.layoutNotifAodVerticalOffsetsPx),
|
Arrays.hashCode(settings.layoutNotifAodVerticalOffsetsPx),
|
||||||
settings.layoutNotifMiddleSide,
|
settings.layoutNotifMiddleSide,
|
||||||
settings.layoutNotifMiddleAutoNearestSide,
|
settings.layoutNotifMiddleAutoNearestSide,
|
||||||
settings.layoutNotifVerticalOffsetPx,
|
settings.layoutNotifVerticalOffsetPx,
|
||||||
settings.layoutStatusPosition,
|
settings.layoutStatusPosition,
|
||||||
settings.layoutStatusEnabledUnlocked,
|
settings.layoutStatusEnabledUnlocked,
|
||||||
settings.layoutStatusUnlockedCount,
|
settings.layoutStatusUnlockedCount,
|
||||||
java.util.Arrays.hashCode(settings.layoutStatusPositions),
|
Arrays.hashCode(settings.layoutStatusPositions),
|
||||||
java.util.Arrays.hashCode(settings.layoutStatusMiddleSides),
|
Arrays.hashCode(settings.layoutStatusMiddleSides),
|
||||||
java.util.Arrays.hashCode(settings.layoutStatusMiddleAutoNearestSides),
|
Arrays.hashCode(settings.layoutStatusMiddleAutoNearestSides),
|
||||||
java.util.Arrays.hashCode(settings.layoutStatusVerticalOffsetsPx),
|
Arrays.hashCode(settings.layoutStatusVerticalOffsetsPx),
|
||||||
settings.layoutStatusEnabledLockscreen,
|
settings.layoutStatusEnabledLockscreen,
|
||||||
settings.layoutStatusLockCount,
|
settings.layoutStatusLockCount,
|
||||||
java.util.Arrays.hashCode(settings.layoutStatusLockPositions),
|
Arrays.hashCode(settings.layoutStatusLockPositions),
|
||||||
java.util.Arrays.hashCode(settings.layoutStatusLockMiddleSides),
|
Arrays.hashCode(settings.layoutStatusLockMiddleSides),
|
||||||
java.util.Arrays.hashCode(settings.layoutStatusLockMiddleAutoNearestSides),
|
Arrays.hashCode(settings.layoutStatusLockMiddleAutoNearestSides),
|
||||||
java.util.Arrays.hashCode(settings.layoutStatusLockVerticalOffsetsPx),
|
Arrays.hashCode(settings.layoutStatusLockVerticalOffsetsPx),
|
||||||
settings.layoutStatusEnabledAod,
|
settings.layoutStatusEnabledAod,
|
||||||
settings.layoutStatusAodCount,
|
settings.layoutStatusAodCount,
|
||||||
java.util.Arrays.hashCode(settings.layoutStatusAodPositions),
|
Arrays.hashCode(settings.layoutStatusAodPositions),
|
||||||
java.util.Arrays.hashCode(settings.layoutStatusAodMiddleSides),
|
Arrays.hashCode(settings.layoutStatusAodMiddleSides),
|
||||||
java.util.Arrays.hashCode(settings.layoutStatusAodMiddleAutoNearestSides),
|
Arrays.hashCode(settings.layoutStatusAodMiddleAutoNearestSides),
|
||||||
java.util.Arrays.hashCode(settings.layoutStatusAodVerticalOffsetsPx),
|
Arrays.hashCode(settings.layoutStatusAodVerticalOffsetsPx),
|
||||||
settings.layoutStatusMiddleSide,
|
settings.layoutStatusMiddleSide,
|
||||||
settings.layoutStatusMiddleAutoNearestSide,
|
settings.layoutStatusMiddleAutoNearestSide,
|
||||||
settings.layoutStatusVerticalOffsetPx,
|
settings.layoutStatusVerticalOffsetPx,
|
||||||
|
|||||||
-48
@@ -1,48 +0,0 @@
|
|||||||
package se.ajpanton.statusbartweak.runtime.render;
|
|
||||||
|
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
final class UnlockedVerticalOffsetScaler {
|
|
||||||
private int baselineNotificationIconSizePx;
|
|
||||||
private int baselineStatusIconHeightPx;
|
|
||||||
private float baselineClockTextSizePx;
|
|
||||||
|
|
||||||
int notification(int offsetPx, int currentIconHeightPx) {
|
|
||||||
baselineNotificationIconSizePx = updateBaseline(
|
|
||||||
baselineNotificationIconSizePx,
|
|
||||||
currentIconHeightPx);
|
|
||||||
return scaledOffset(offsetPx, currentIconHeightPx, baselineNotificationIconSizePx);
|
|
||||||
}
|
|
||||||
|
|
||||||
int status(int offsetPx, int currentIconHeightPx) {
|
|
||||||
baselineStatusIconHeightPx = updateBaseline(
|
|
||||||
baselineStatusIconHeightPx,
|
|
||||||
currentIconHeightPx);
|
|
||||||
return scaledOffset(offsetPx, currentIconHeightPx, baselineStatusIconHeightPx);
|
|
||||||
}
|
|
||||||
|
|
||||||
int clock(int offsetPx, TextView source) {
|
|
||||||
if (offsetPx == 0 || source == null || source.getTextSize() <= 0f) {
|
|
||||||
return offsetPx;
|
|
||||||
}
|
|
||||||
float textSize = source.getTextSize();
|
|
||||||
if (baselineClockTextSizePx <= 0f || textSize < baselineClockTextSizePx) {
|
|
||||||
baselineClockTextSizePx = textSize;
|
|
||||||
}
|
|
||||||
return Math.round(offsetPx * textSize / baselineClockTextSizePx);
|
|
||||||
}
|
|
||||||
|
|
||||||
private int updateBaseline(int baselinePx, int currentPx) {
|
|
||||||
if (currentPx <= 0) {
|
|
||||||
return baselinePx;
|
|
||||||
}
|
|
||||||
return baselinePx <= 0 || currentPx < baselinePx ? currentPx : baselinePx;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int scaledOffset(int offsetPx, int currentPx, int baselinePx) {
|
|
||||||
if (offsetPx == 0 || currentPx <= 0 || baselinePx <= 0) {
|
|
||||||
return offsetPx;
|
|
||||||
}
|
|
||||||
return Math.round((float) offsetPx * currentPx / baselinePx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -10,6 +10,8 @@ import java.util.List;
|
|||||||
import se.ajpanton.statusbartweak.runtime.layoutsolver.StatusBarLayoutSolver.Bounds;
|
import se.ajpanton.statusbartweak.runtime.layoutsolver.StatusBarLayoutSolver.Bounds;
|
||||||
|
|
||||||
final class ViewGeometry {
|
final class ViewGeometry {
|
||||||
|
private static final String OWNED_RUNTIME_TAG_PREFIX = "statusbartweak.";
|
||||||
|
|
||||||
private ViewGeometry() {
|
private ViewGeometry() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -34,6 +36,72 @@ final class ViewGeometry {
|
|||||||
return new Bounds(left, top, Math.max(0, width), Math.max(0, height));
|
return new Bounds(left, top, Math.max(0, width), Math.max(0, height));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static boolean isDescendantOf(View child, View ancestor) {
|
||||||
|
if (child == null || ancestor == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
View current = child;
|
||||||
|
while (current != null) {
|
||||||
|
if (current == ancestor) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
Object parent = current.getParent();
|
||||||
|
current = parent instanceof View ? (View) parent : null;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static boolean hasAncestorTagPrefix(View view, String prefix) {
|
||||||
|
if (view == null || prefix == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
View current = view;
|
||||||
|
while (current != null) {
|
||||||
|
Object tag = current.getTag();
|
||||||
|
if (tag instanceof String value && value.startsWith(prefix)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
Object parent = current.getParent();
|
||||||
|
current = parent instanceof View ? (View) parent : null;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static boolean isOwnedRuntimeView(View view) {
|
||||||
|
return hasAncestorTagPrefix(view, OWNED_RUNTIME_TAG_PREFIX);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Bounds clampToRoot(View root, Bounds bounds) {
|
||||||
|
if (root == null || bounds == null || root.getWidth() <= 0 || root.getHeight() <= 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
int left = Math.max(0, bounds.left);
|
||||||
|
int top = Math.max(0, bounds.top);
|
||||||
|
int right = Math.min(root.getWidth(), bounds.left + bounds.width);
|
||||||
|
int bottom = Math.min(root.getHeight(), bounds.top + bounds.height);
|
||||||
|
if (right <= left || bottom <= top) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return new Bounds(left, top, right - left, bottom - top);
|
||||||
|
}
|
||||||
|
|
||||||
|
static float effectiveAlpha(View view) {
|
||||||
|
return effectiveAlphaFrom(view);
|
||||||
|
}
|
||||||
|
|
||||||
|
static float effectiveAncestorAlpha(View view) {
|
||||||
|
return view != null ? effectiveAlphaFrom(view.getParent()) : 1f;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static float effectiveAlphaFrom(Object current) {
|
||||||
|
float alpha = 1f;
|
||||||
|
while (current instanceof View currentView) {
|
||||||
|
alpha *= currentView.getAlpha();
|
||||||
|
current = currentView.getParent();
|
||||||
|
}
|
||||||
|
return Math.max(0f, Math.min(1f, alpha));
|
||||||
|
}
|
||||||
|
|
||||||
static Rect middleCutout(View root) {
|
static Rect middleCutout(View root) {
|
||||||
if (root == null || root.getWidth() <= 0) {
|
if (root == null || root.getWidth() <= 0) {
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
+58
@@ -0,0 +1,58 @@
|
|||||||
|
package se.ajpanton.statusbartweak.runtime.settings;
|
||||||
|
|
||||||
|
import android.content.BroadcastReceiver;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.IntentFilter;
|
||||||
|
|
||||||
|
public final class BroadcastReceiverSupport {
|
||||||
|
private BroadcastReceiverSupport() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IntentFilter filter(String firstAction, String... additionalActions) {
|
||||||
|
IntentFilter filter = new IntentFilter(firstAction);
|
||||||
|
if (additionalActions != null) {
|
||||||
|
for (String action : additionalActions) {
|
||||||
|
if (action != null) {
|
||||||
|
filter.addAction(action);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return filter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Intent registerExportedOnApplicationContext(
|
||||||
|
Context context,
|
||||||
|
BroadcastReceiver receiver,
|
||||||
|
IntentFilter filter
|
||||||
|
) {
|
||||||
|
return applicationContext(context)
|
||||||
|
.registerReceiver(receiver, filter, Context.RECEIVER_EXPORTED);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Intent registerInvalidatingReceiver(
|
||||||
|
Context context,
|
||||||
|
Runnable invalidator,
|
||||||
|
IntentFilter filter
|
||||||
|
) {
|
||||||
|
BroadcastReceiver receiver = new BroadcastReceiver() {
|
||||||
|
@Override
|
||||||
|
public void onReceive(Context context, Intent intent) {
|
||||||
|
if (invalidator != null) {
|
||||||
|
invalidator.run();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return registerExportedOnApplicationContext(context, receiver, filter);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Intent readExportedSticky(Context context, IntentFilter filter) {
|
||||||
|
return applicationContext(context)
|
||||||
|
.registerReceiver(null, filter, Context.RECEIVER_EXPORTED);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Context applicationContext(Context context) {
|
||||||
|
Context appContext = context.getApplicationContext();
|
||||||
|
return appContext != null ? appContext : context;
|
||||||
|
}
|
||||||
|
}
|
||||||
+7
-21
@@ -1,10 +1,7 @@
|
|||||||
package se.ajpanton.statusbartweak.runtime.settings;
|
package se.ajpanton.statusbartweak.runtime.settings;
|
||||||
|
|
||||||
import android.content.BroadcastReceiver;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.IntentFilter;
|
|
||||||
import android.os.Build;
|
|
||||||
|
|
||||||
import se.ajpanton.statusbartweak.shell.settings.SbtSettings;
|
import se.ajpanton.statusbartweak.shell.settings.SbtSettings;
|
||||||
|
|
||||||
@@ -38,7 +35,7 @@ public final class RuntimeSettingsCache {
|
|||||||
if (cachedSettings == null) {
|
if (cachedSettings == null) {
|
||||||
cachedSettings = SbtSettings.from(context);
|
cachedSettings = SbtSettings.from(context);
|
||||||
}
|
}
|
||||||
return cachedSettings != null ? cachedSettings : SbtSettings.defaults();
|
return cachedSettings;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,23 +53,12 @@ public final class RuntimeSettingsCache {
|
|||||||
if (receiverRegistered) {
|
if (receiverRegistered) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Context appContext = context.getApplicationContext();
|
BroadcastReceiverSupport.registerInvalidatingReceiver(
|
||||||
if (appContext == null) {
|
context,
|
||||||
appContext = context;
|
RuntimeSettingsCache::invalidate,
|
||||||
}
|
BroadcastReceiverSupport.filter(
|
||||||
BroadcastReceiver receiver = new BroadcastReceiver() {
|
SbtSettings.ACTION_SETTINGS_CHANGED,
|
||||||
@Override
|
Intent.ACTION_USER_UNLOCKED));
|
||||||
public void onReceive(Context context, Intent intent) {
|
|
||||||
invalidate();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
IntentFilter filter = new IntentFilter(SbtSettings.ACTION_SETTINGS_CHANGED);
|
|
||||||
filter.addAction(Intent.ACTION_USER_UNLOCKED);
|
|
||||||
if (Build.VERSION.SDK_INT >= 33) {
|
|
||||||
appContext.registerReceiver(receiver, filter, Context.RECEIVER_EXPORTED);
|
|
||||||
} else {
|
|
||||||
appContext.registerReceiver(receiver, filter);
|
|
||||||
}
|
|
||||||
receiverRegistered = true;
|
receiverRegistered = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package se.ajpanton.statusbartweak.shell.debug;
|
package se.ajpanton.statusbartweak.shell.debug;
|
||||||
|
|
||||||
import android.Manifest;
|
import android.Manifest;
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
import android.app.Notification;
|
import android.app.Notification;
|
||||||
import android.app.NotificationChannel;
|
import android.app.NotificationChannel;
|
||||||
import android.app.NotificationManager;
|
import android.app.NotificationManager;
|
||||||
@@ -111,9 +112,7 @@ public final class DebugNotifications {
|
|||||||
cancelDebugNotificationsAbove(appContext, nm, desired);
|
cancelDebugNotificationsAbove(appContext, nm, desired);
|
||||||
cleanupAutoGroupSummaries(appContext, nm);
|
cleanupAutoGroupSummaries(appContext, nm);
|
||||||
|
|
||||||
for (int i = 1; i <= desired; i++) {
|
postDebugNotifications(appContext, nm, desired);
|
||||||
nm.notify(DEBUG_ID_BASE + i, buildDebugNotification(appContext, i));
|
|
||||||
}
|
|
||||||
if (desired > 0) {
|
if (desired > 0) {
|
||||||
scheduleAutoGroupRecovery(appContext);
|
scheduleAutoGroupRecovery(appContext);
|
||||||
} else {
|
} else {
|
||||||
@@ -194,7 +193,7 @@ public final class DebugNotifications {
|
|||||||
int desired
|
int desired
|
||||||
) {
|
) {
|
||||||
for (StatusBarNotification sbn : nm.getActiveNotifications()) {
|
for (StatusBarNotification sbn : nm.getActiveNotifications()) {
|
||||||
if (!context.getPackageName().equals(sbn.getPackageName())) {
|
if (!isOwnNotification(context, sbn)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
int debugNumber = sbn.getId() - DEBUG_ID_BASE;
|
int debugNumber = sbn.getId() - DEBUG_ID_BASE;
|
||||||
@@ -206,15 +205,7 @@ public final class DebugNotifications {
|
|||||||
|
|
||||||
private static void cleanupAutoGroupSummaries(Context context, NotificationManager nm) {
|
private static void cleanupAutoGroupSummaries(Context context, NotificationManager nm) {
|
||||||
for (StatusBarNotification sbn : nm.getActiveNotifications()) {
|
for (StatusBarNotification sbn : nm.getActiveNotifications()) {
|
||||||
if (!context.getPackageName().equals(sbn.getPackageName()) || isDebugId(sbn.getId())) {
|
if (isDebugAutoGroupSummary(context, sbn)) {
|
||||||
continue;
|
|
||||||
}
|
|
||||||
Notification notification = sbn.getNotification();
|
|
||||||
if (notification == null || isDebugNotification(notification)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
String group = notification.getGroup();
|
|
||||||
if (group == null || !group.startsWith(GROUP_PREFIX)) {
|
|
||||||
cancel(nm, sbn);
|
cancel(nm, sbn);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -254,14 +245,22 @@ public final class DebugNotifications {
|
|||||||
try {
|
try {
|
||||||
prefs.edit().putBoolean(KEY_RECOVERY_USED, true).apply();
|
prefs.edit().putBoolean(KEY_RECOVERY_USED, true).apply();
|
||||||
cancelDebugNotificationsAndSummaries(appContext, nm);
|
cancelDebugNotificationsAndSummaries(appContext, nm);
|
||||||
for (int i = 1; i <= desired; i++) {
|
postDebugNotifications(appContext, nm, desired);
|
||||||
nm.notify(DEBUG_ID_BASE + i, buildDebugNotification(appContext, i));
|
|
||||||
}
|
|
||||||
} finally {
|
} finally {
|
||||||
recoveryInProgress = false;
|
recoveryInProgress = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void postDebugNotifications(
|
||||||
|
Context context,
|
||||||
|
NotificationManager nm,
|
||||||
|
int desired
|
||||||
|
) {
|
||||||
|
for (int i = 1; i <= desired; i++) {
|
||||||
|
nm.notify(DEBUG_ID_BASE + i, buildDebugNotification(context, i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static void cancelAutoGroupRecovery() {
|
private static void cancelAutoGroupRecovery() {
|
||||||
if (recoveryRunnable != null) {
|
if (recoveryRunnable != null) {
|
||||||
RECOVERY_HANDLER.removeCallbacks(recoveryRunnable);
|
RECOVERY_HANDLER.removeCallbacks(recoveryRunnable);
|
||||||
@@ -271,15 +270,7 @@ public final class DebugNotifications {
|
|||||||
|
|
||||||
private static boolean hasAutoGroupSummary(Context context, NotificationManager nm) {
|
private static boolean hasAutoGroupSummary(Context context, NotificationManager nm) {
|
||||||
for (StatusBarNotification sbn : nm.getActiveNotifications()) {
|
for (StatusBarNotification sbn : nm.getActiveNotifications()) {
|
||||||
if (!context.getPackageName().equals(sbn.getPackageName()) || isDebugId(sbn.getId())) {
|
if (isDebugAutoGroupSummary(context, sbn)) {
|
||||||
continue;
|
|
||||||
}
|
|
||||||
Notification notification = sbn.getNotification();
|
|
||||||
if (notification == null || isDebugNotification(notification)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
String group = notification.getGroup();
|
|
||||||
if (group == null || !group.startsWith(GROUP_PREFIX)) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -288,15 +279,10 @@ public final class DebugNotifications {
|
|||||||
|
|
||||||
private static void cancelDebugNotificationsAndSummaries(Context context, NotificationManager nm) {
|
private static void cancelDebugNotificationsAndSummaries(Context context, NotificationManager nm) {
|
||||||
for (StatusBarNotification sbn : nm.getActiveNotifications()) {
|
for (StatusBarNotification sbn : nm.getActiveNotifications()) {
|
||||||
if (!context.getPackageName().equals(sbn.getPackageName())) {
|
if (!isOwnNotification(context, sbn)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
Notification notification = sbn.getNotification();
|
if (isDebugId(sbn.getId()) || isDebugAutoGroupSummary(context, sbn)) {
|
||||||
boolean debugSummary = notification != null
|
|
||||||
&& !isDebugNotification(notification)
|
|
||||||
&& (notification.getGroup() == null
|
|
||||||
|| !notification.getGroup().startsWith(GROUP_PREFIX));
|
|
||||||
if (isDebugId(sbn.getId()) || debugSummary) {
|
|
||||||
cancel(nm, sbn);
|
cancel(nm, sbn);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -323,6 +309,22 @@ public final class DebugNotifications {
|
|||||||
return debugNumber >= 1 && debugNumber <= MAX_COUNT;
|
return debugNumber >= 1 && debugNumber <= MAX_COUNT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static boolean isDebugAutoGroupSummary(Context context, StatusBarNotification sbn) {
|
||||||
|
if (!isOwnNotification(context, sbn) || isDebugId(sbn.getId())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Notification notification = sbn.getNotification();
|
||||||
|
if (notification == null || isDebugNotification(notification)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
String group = notification.getGroup();
|
||||||
|
return group == null || !group.startsWith(GROUP_PREFIX);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isOwnNotification(Context context, StatusBarNotification sbn) {
|
||||||
|
return context.getPackageName().equals(sbn.getPackageName());
|
||||||
|
}
|
||||||
|
|
||||||
private static void cancel(NotificationManager nm, StatusBarNotification sbn) {
|
private static void cancel(NotificationManager nm, StatusBarNotification sbn) {
|
||||||
if (sbn.getTag() != null) {
|
if (sbn.getTag() != null) {
|
||||||
nm.cancel(sbn.getTag(), sbn.getId());
|
nm.cancel(sbn.getTag(), sbn.getId());
|
||||||
@@ -416,6 +418,7 @@ public final class DebugNotifications {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressLint("WakelockTimeout")
|
||||||
private static void acquireCycleWakeLock(Context context) {
|
private static void acquireCycleWakeLock(Context context) {
|
||||||
if (cycleWakeLock == null) {
|
if (cycleWakeLock == null) {
|
||||||
PowerManager pm = context.getSystemService(PowerManager.class);
|
PowerManager pm = context.getSystemService(PowerManager.class);
|
||||||
|
|||||||
+7
-2
@@ -5,6 +5,8 @@ import android.content.Context;
|
|||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
public final class NotificationDisplayStyleSettings {
|
public final class NotificationDisplayStyleSettings {
|
||||||
private static final String KEY_LOCKSCREEN_MINIMIZING_NOTIFICATION =
|
private static final String KEY_LOCKSCREEN_MINIMIZING_NOTIFICATION =
|
||||||
"lockscreen_minimizing_notification";
|
"lockscreen_minimizing_notification";
|
||||||
@@ -53,7 +55,7 @@ public final class NotificationDisplayStyleSettings {
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
return Settings.System.getInt(resolver, key);
|
return Settings.System.getInt(resolver, key);
|
||||||
} catch (Throwable ignored) {
|
} catch (Settings.SettingNotFoundException ignored) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -67,7 +69,10 @@ public final class NotificationDisplayStyleSettings {
|
|||||||
.redirectErrorStream(true)
|
.redirectErrorStream(true)
|
||||||
.start();
|
.start();
|
||||||
return process.waitFor() == 0;
|
return process.waitFor() == 0;
|
||||||
} catch (Throwable ignored) {
|
} catch (InterruptedException ignored) {
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
return false;
|
||||||
|
} catch (IOException | SecurityException ignored) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ public final class AppIconRules {
|
|||||||
public static final int MODE_AOD = 1;
|
public static final int MODE_AOD = 1;
|
||||||
public static final int MODE_LOCK = 1 << 1;
|
public static final int MODE_LOCK = 1 << 1;
|
||||||
public static final int MODE_UNLOCK = 1 << 2;
|
public static final int MODE_UNLOCK = 1 << 2;
|
||||||
|
private static final int ALL_MODES = MODE_AOD | MODE_LOCK | MODE_UNLOCK;
|
||||||
private static final String MODE_NAME_AOD = "AOD";
|
private static final String MODE_NAME_AOD = "AOD";
|
||||||
private static final String MODE_NAME_LOCK = "LOCK";
|
private static final String MODE_NAME_LOCK = "LOCK";
|
||||||
private static final String MODE_NAME_UNLOCK = "UNLOCK";
|
private static final String MODE_NAME_UNLOCK = "UNLOCK";
|
||||||
@@ -62,51 +63,27 @@ public final class AppIconRules {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static Map<String, Integer> loadBlockedModes(SharedPreferences prefs) {
|
public static Map<String, Integer> loadBlockedModes(SharedPreferences prefs) {
|
||||||
if (prefs == null) {
|
return parseBlockedModes(readStringSet(prefs, PREF_KEY_BLOCKED_MODES));
|
||||||
return new HashMap<>();
|
|
||||||
}
|
|
||||||
Set<String> raw = prefs.getStringSet(PREF_KEY_BLOCKED_MODES, Collections.emptySet());
|
|
||||||
return parseBlockedModes(raw);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void saveBlockedModes(SharedPreferences prefs, Map<String, Integer> map) {
|
public static void saveBlockedModes(SharedPreferences prefs, Map<String, Integer> map) {
|
||||||
if (prefs == null) {
|
writeStringSet(prefs, PREF_KEY_BLOCKED_MODES, encodeBlockedModes(map));
|
||||||
return;
|
|
||||||
}
|
|
||||||
Set<String> encoded = encodeBlockedModes(map);
|
|
||||||
prefs.edit().putStringSet(PREF_KEY_BLOCKED_MODES, encoded).apply();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Map<String, SeenApp> loadSeenSession(SharedPreferences prefs) {
|
public static Map<String, SeenApp> loadSeenSession(SharedPreferences prefs) {
|
||||||
if (prefs == null) {
|
return parseSeenSession(readStringSet(prefs, PREF_KEY_SEEN_SESSION));
|
||||||
return new HashMap<>();
|
|
||||||
}
|
|
||||||
Set<String> raw = prefs.getStringSet(PREF_KEY_SEEN_SESSION, Collections.emptySet());
|
|
||||||
return parseSeenSession(raw);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Map<String, ArrayList<ExceptionRule>> loadExceptionRules(SharedPreferences prefs) {
|
public static Map<String, ArrayList<ExceptionRule>> loadExceptionRules(SharedPreferences prefs) {
|
||||||
if (prefs == null) {
|
return parseExceptionRules(readStringSet(prefs, PREF_KEY_EXCEPTION_RULES));
|
||||||
return new HashMap<>();
|
|
||||||
}
|
|
||||||
Set<String> raw = prefs.getStringSet(PREF_KEY_EXCEPTION_RULES, Collections.emptySet());
|
|
||||||
return parseExceptionRules(raw);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void saveExceptionRules(SharedPreferences prefs, Map<String, ArrayList<ExceptionRule>> map) {
|
public static void saveExceptionRules(SharedPreferences prefs, Map<String, ArrayList<ExceptionRule>> map) {
|
||||||
if (prefs == null) {
|
writeStringSet(prefs, PREF_KEY_EXCEPTION_RULES, encodeExceptionRules(map));
|
||||||
return;
|
|
||||||
}
|
|
||||||
Set<String> encoded = encodeExceptionRules(map);
|
|
||||||
prefs.edit().putStringSet(PREF_KEY_EXCEPTION_RULES, encoded).apply();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void saveSeenSession(SharedPreferences prefs, Map<String, SeenApp> map) {
|
public static void saveSeenSession(SharedPreferences prefs, Map<String, SeenApp> map) {
|
||||||
if (prefs == null) {
|
writeStringSet(prefs, PREF_KEY_SEEN_SESSION, encodeSeenSession(map));
|
||||||
return;
|
|
||||||
}
|
|
||||||
Set<String> encoded = encodeSeenSession(map);
|
|
||||||
prefs.edit().putStringSet(PREF_KEY_SEEN_SESSION, encoded).apply();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void clearSeenSession(SharedPreferences prefs) {
|
public static void clearSeenSession(SharedPreferences prefs) {
|
||||||
@@ -116,6 +93,20 @@ public final class AppIconRules {
|
|||||||
prefs.edit().remove(PREF_KEY_SEEN_SESSION).apply();
|
prefs.edit().remove(PREF_KEY_SEEN_SESSION).apply();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Set<String> readStringSet(SharedPreferences prefs, String key) {
|
||||||
|
if (prefs == null) {
|
||||||
|
return Collections.emptySet();
|
||||||
|
}
|
||||||
|
return prefs.getStringSet(key, Collections.emptySet());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void writeStringSet(SharedPreferences prefs, String key, Set<String> value) {
|
||||||
|
if (prefs == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
prefs.edit().putStringSet(key, value).apply();
|
||||||
|
}
|
||||||
|
|
||||||
public static boolean noteSeen(Map<String, SeenApp> seen,
|
public static boolean noteSeen(Map<String, SeenApp> seen,
|
||||||
String pkg,
|
String pkg,
|
||||||
long seenMs,
|
long seenMs,
|
||||||
@@ -226,7 +217,7 @@ public final class AppIconRules {
|
|||||||
if (rawSet == null || rawSet.isEmpty()) {
|
if (rawSet == null || rawSet.isEmpty()) {
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
for (String entry : new HashSet<>(rawSet)) {
|
for (String entry : snapshot(rawSet)) {
|
||||||
if (entry == null || entry.isEmpty()) {
|
if (entry == null || entry.isEmpty()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -284,7 +275,7 @@ public final class AppIconRules {
|
|||||||
if (rawSet == null || rawSet.isEmpty()) {
|
if (rawSet == null || rawSet.isEmpty()) {
|
||||||
return new HashMap<>();
|
return new HashMap<>();
|
||||||
}
|
}
|
||||||
for (String entry : new HashSet<>(rawSet)) {
|
for (String entry : snapshot(rawSet)) {
|
||||||
if (entry == null || entry.isEmpty()) {
|
if (entry == null || entry.isEmpty()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -312,7 +303,7 @@ public final class AppIconRules {
|
|||||||
try {
|
try {
|
||||||
byte[] decoded = Base64.decode(parts[3], Base64.NO_WRAP);
|
byte[] decoded = Base64.decode(parts[3], Base64.NO_WRAP);
|
||||||
regex = new String(decoded, StandardCharsets.UTF_8).trim();
|
regex = new String(decoded, StandardCharsets.UTF_8).trim();
|
||||||
} catch (Throwable ignored) {
|
} catch (IllegalArgumentException ignored) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (regex.isEmpty()) {
|
if (regex.isEmpty()) {
|
||||||
@@ -366,8 +357,11 @@ public final class AppIconRules {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static int sanitizeModeMask(int mask) {
|
private static int sanitizeModeMask(int mask) {
|
||||||
int allowed = MODE_AOD | MODE_LOCK | MODE_UNLOCK;
|
return mask & ALL_MODES;
|
||||||
return mask & allowed;
|
}
|
||||||
|
|
||||||
|
private static HashSet<String> snapshot(Set<String> rawSet) {
|
||||||
|
return new HashSet<>(rawSet);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String normalizeModeName(String mode) {
|
private static String normalizeModeName(String mode) {
|
||||||
@@ -395,7 +389,7 @@ public final class AppIconRules {
|
|||||||
if (rawSet == null || rawSet.isEmpty()) {
|
if (rawSet == null || rawSet.isEmpty()) {
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
for (String entry : new HashSet<>(rawSet)) {
|
for (String entry : snapshot(rawSet)) {
|
||||||
if (entry == null || entry.isEmpty()) {
|
if (entry == null || entry.isEmpty()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,10 +3,10 @@ package se.ajpanton.statusbartweak.shell.settings;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.IntentFilter;
|
import android.content.IntentFilter;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.BatteryManager;
|
import android.os.BatteryManager;
|
||||||
import android.os.Build;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
@@ -104,6 +104,13 @@ public final class BatteryBarStyle {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static ArrayList<Threshold> loadThresholds(SharedPreferences prefs, String key) {
|
||||||
|
if (prefs == null || key == null || key.isEmpty()) {
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
return decodeThresholds(prefs.getStringSet(key, Collections.emptySet()));
|
||||||
|
}
|
||||||
|
|
||||||
public static ArrayList<String> encodeThresholds(List<Threshold> thresholds) {
|
public static ArrayList<String> encodeThresholds(List<Threshold> thresholds) {
|
||||||
ArrayList<String> result = new ArrayList<>();
|
ArrayList<String> result = new ArrayList<>();
|
||||||
if (thresholds == null) {
|
if (thresholds == null) {
|
||||||
@@ -196,11 +203,7 @@ public final class BatteryBarStyle {
|
|||||||
IntentFilter filter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
|
IntentFilter filter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
|
||||||
Intent sticky = null;
|
Intent sticky = null;
|
||||||
try {
|
try {
|
||||||
if (Build.VERSION.SDK_INT >= 33) {
|
|
||||||
sticky = context.registerReceiver(null, filter, Context.RECEIVER_EXPORTED);
|
sticky = context.registerReceiver(null, filter, Context.RECEIVER_EXPORTED);
|
||||||
} else {
|
|
||||||
sticky = context.registerReceiver(null, filter);
|
|
||||||
}
|
|
||||||
} catch (Throwable ignored) {
|
} catch (Throwable ignored) {
|
||||||
}
|
}
|
||||||
if (sticky != null) {
|
if (sticky != null) {
|
||||||
|
|||||||
+7
@@ -147,6 +147,13 @@ public final class ClockCameraTypeSupport {
|
|||||||
return out.isEmpty() ? Collections.emptyMap() : out;
|
return out.isEmpty() ? Collections.emptyMap() : out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Map<String, String> loadOverrides(SharedPreferences prefs, String key) {
|
||||||
|
if (prefs == null || TextUtils.isEmpty(key)) {
|
||||||
|
return Collections.emptyMap();
|
||||||
|
}
|
||||||
|
return parseOverrides(prefs.getStringSet(key, Collections.emptySet()));
|
||||||
|
}
|
||||||
|
|
||||||
public static Set<String> encodeOverrides(Map<String, String> overrides) {
|
public static Set<String> encodeOverrides(Map<String, String> overrides) {
|
||||||
if (overrides == null || overrides.isEmpty()) {
|
if (overrides == null || overrides.isEmpty()) {
|
||||||
return Collections.emptySet();
|
return Collections.emptySet();
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import java.util.Map;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
public final class SbtSettings {
|
public final class SbtSettings {
|
||||||
private interface IndexedKey {
|
public interface IndexedKey {
|
||||||
String key(int index);
|
String key(int index);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -21,6 +21,8 @@ public final class SbtSettings {
|
|||||||
public static final String ACTION_SETTINGS_CHANGED =
|
public static final String ACTION_SETTINGS_CHANGED =
|
||||||
"se.ajpanton.statusbartweak.action.SETTINGS_CHANGED";
|
"se.ajpanton.statusbartweak.action.SETTINGS_CHANGED";
|
||||||
public static final String PACKAGE_SYSTEMUI = "com.android.systemui";
|
public static final String PACKAGE_SYSTEMUI = "com.android.systemui";
|
||||||
|
private static final String SETTINGS_PROVIDER_BASE_URI =
|
||||||
|
"content://" + SbtSettingsProvider.AUTHORITY;
|
||||||
public static final String KEY_DEBUG_CURRENT_CAMERA_ID = "debug_current_camera_id";
|
public static final String KEY_DEBUG_CURRENT_CAMERA_ID = "debug_current_camera_id";
|
||||||
public static final String KEY_DEBUG_CURRENT_CAMERA_AUTO_TYPE = "debug_current_camera_auto_type";
|
public static final String KEY_DEBUG_CURRENT_CAMERA_AUTO_TYPE = "debug_current_camera_auto_type";
|
||||||
public static final String KEY_DEBUG_CURRENT_CAMERA_EFFECTIVE_TYPE = "debug_current_camera_effective_type";
|
public static final String KEY_DEBUG_CURRENT_CAMERA_EFFECTIVE_TYPE = "debug_current_camera_effective_type";
|
||||||
@@ -117,6 +119,24 @@ public final class SbtSettings {
|
|||||||
public static final String KEY_LAYOUT_NOTIF_ENABLED_LOCKSCREEN = "layout_notif_enabled_lockscreen";
|
public static final String KEY_LAYOUT_NOTIF_ENABLED_LOCKSCREEN = "layout_notif_enabled_lockscreen";
|
||||||
public static final String KEY_LAYOUT_NOTIF_ENABLED_UNLOCKED = "layout_notif_enabled_unlocked";
|
public static final String KEY_LAYOUT_NOTIF_ENABLED_UNLOCKED = "layout_notif_enabled_unlocked";
|
||||||
public static final String KEY_LAYOUT_NOTIF_UNLOCKED_COUNT = "layout_notif_unlocked_count";
|
public static final String KEY_LAYOUT_NOTIF_UNLOCKED_COUNT = "layout_notif_unlocked_count";
|
||||||
|
public static final String KEY_LAYOUT_NOTIF_LOCK_COUNT = "layout_lock_notifications_count";
|
||||||
|
public static final String KEY_LAYOUT_NOTIF_AOD_COUNT = "layout_aod_notifications_count";
|
||||||
|
public static final String KEY_LAYOUT_NOTIF_LOCK_POSITION = "layout_lock_notifications_position";
|
||||||
|
public static final String KEY_LAYOUT_NOTIF_LOCK_MIDDLE_SIDE = "layout_lock_notifications_middle_side";
|
||||||
|
public static final String KEY_LAYOUT_NOTIF_LOCK_MIDDLE_AUTO_NEAREST_SIDE =
|
||||||
|
"layout_lock_notifications_middle_auto_nearest_side";
|
||||||
|
public static final String KEY_LAYOUT_NOTIF_LOCK_VERTICAL_OFFSET_PX =
|
||||||
|
"layout_lock_notifications_vertical_offset_px";
|
||||||
|
public static final String KEY_LAYOUT_NOTIF_LOCK_ICON_HEIGHT_STEPS =
|
||||||
|
"layout_lock_notifications_icon_height_steps";
|
||||||
|
public static final String KEY_LAYOUT_NOTIF_AOD_POSITION = "layout_aod_notifications_position";
|
||||||
|
public static final String KEY_LAYOUT_NOTIF_AOD_MIDDLE_SIDE = "layout_aod_notifications_middle_side";
|
||||||
|
public static final String KEY_LAYOUT_NOTIF_AOD_MIDDLE_AUTO_NEAREST_SIDE =
|
||||||
|
"layout_aod_notifications_middle_auto_nearest_side";
|
||||||
|
public static final String KEY_LAYOUT_NOTIF_AOD_VERTICAL_OFFSET_PX =
|
||||||
|
"layout_aod_notifications_vertical_offset_px";
|
||||||
|
public static final String KEY_LAYOUT_NOTIF_AOD_ICON_HEIGHT_STEPS =
|
||||||
|
"layout_aod_notifications_icon_height_steps";
|
||||||
public static final String KEY_LAYOUT_NOTIF_MIDDLE_SIDE = "layout_notif_middle_side";
|
public static final String KEY_LAYOUT_NOTIF_MIDDLE_SIDE = "layout_notif_middle_side";
|
||||||
public static final String KEY_LAYOUT_NOTIF_MIDDLE_AUTO_NEAREST_SIDE = "layout_notif_middle_auto_nearest_side";
|
public static final String KEY_LAYOUT_NOTIF_MIDDLE_AUTO_NEAREST_SIDE = "layout_notif_middle_auto_nearest_side";
|
||||||
public static final String KEY_LAYOUT_NOTIF_VERTICAL_OFFSET_PX = "layout_notif_vertical_offset_px";
|
public static final String KEY_LAYOUT_NOTIF_VERTICAL_OFFSET_PX = "layout_notif_vertical_offset_px";
|
||||||
@@ -126,6 +146,24 @@ public final class SbtSettings {
|
|||||||
public static final String KEY_LAYOUT_STATUS_ENABLED_LOCKSCREEN = "layout_status_enabled_lockscreen";
|
public static final String KEY_LAYOUT_STATUS_ENABLED_LOCKSCREEN = "layout_status_enabled_lockscreen";
|
||||||
public static final String KEY_LAYOUT_STATUS_ENABLED_UNLOCKED = "layout_status_enabled_unlocked";
|
public static final String KEY_LAYOUT_STATUS_ENABLED_UNLOCKED = "layout_status_enabled_unlocked";
|
||||||
public static final String KEY_LAYOUT_STATUS_UNLOCKED_COUNT = "layout_status_unlocked_count";
|
public static final String KEY_LAYOUT_STATUS_UNLOCKED_COUNT = "layout_status_unlocked_count";
|
||||||
|
public static final String KEY_LAYOUT_STATUS_LOCK_COUNT = "layout_lock_status_count";
|
||||||
|
public static final String KEY_LAYOUT_STATUS_AOD_COUNT = "layout_aod_status_count";
|
||||||
|
public static final String KEY_LAYOUT_STATUS_LOCK_POSITION = "layout_lock_status_position";
|
||||||
|
public static final String KEY_LAYOUT_STATUS_LOCK_MIDDLE_SIDE = "layout_lock_status_middle_side";
|
||||||
|
public static final String KEY_LAYOUT_STATUS_LOCK_MIDDLE_AUTO_NEAREST_SIDE =
|
||||||
|
"layout_lock_status_middle_auto_nearest_side";
|
||||||
|
public static final String KEY_LAYOUT_STATUS_LOCK_VERTICAL_OFFSET_PX =
|
||||||
|
"layout_lock_status_vertical_offset_px";
|
||||||
|
public static final String KEY_LAYOUT_STATUS_LOCK_ICON_HEIGHT_STEPS =
|
||||||
|
"layout_lock_status_icon_height_steps";
|
||||||
|
public static final String KEY_LAYOUT_STATUS_AOD_POSITION = "layout_aod_status_position";
|
||||||
|
public static final String KEY_LAYOUT_STATUS_AOD_MIDDLE_SIDE = "layout_aod_status_middle_side";
|
||||||
|
public static final String KEY_LAYOUT_STATUS_AOD_MIDDLE_AUTO_NEAREST_SIDE =
|
||||||
|
"layout_aod_status_middle_auto_nearest_side";
|
||||||
|
public static final String KEY_LAYOUT_STATUS_AOD_VERTICAL_OFFSET_PX =
|
||||||
|
"layout_aod_status_vertical_offset_px";
|
||||||
|
public static final String KEY_LAYOUT_STATUS_AOD_ICON_HEIGHT_STEPS =
|
||||||
|
"layout_aod_status_icon_height_steps";
|
||||||
public static final String KEY_LAYOUT_STATUS_SHOW_DOT_IF_TRUNCATED = "layout_status_show_dot_if_truncated";
|
public static final String KEY_LAYOUT_STATUS_SHOW_DOT_IF_TRUNCATED = "layout_status_show_dot_if_truncated";
|
||||||
public static final String KEY_LAYOUT_STATUS_MIDDLE_SIDE = "layout_status_middle_side";
|
public static final String KEY_LAYOUT_STATUS_MIDDLE_SIDE = "layout_status_middle_side";
|
||||||
public static final String KEY_LAYOUT_STATUS_MIDDLE_AUTO_NEAREST_SIDE = "layout_status_middle_auto_nearest_side";
|
public static final String KEY_LAYOUT_STATUS_MIDDLE_AUTO_NEAREST_SIDE = "layout_status_middle_auto_nearest_side";
|
||||||
@@ -169,87 +207,91 @@ public final class SbtSettings {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static String layoutLockNotifPositionKey(int index) {
|
public static String layoutLockNotifPositionKey(int index) {
|
||||||
return suffixedKey("layout_lock_notifications_position", index);
|
return suffixedKey(KEY_LAYOUT_NOTIF_LOCK_POSITION, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String layoutLockNotifMiddleSideKey(int index) {
|
public static String layoutLockNotifMiddleSideKey(int index) {
|
||||||
return suffixedKey("layout_lock_notifications_middle_side", index);
|
return suffixedKey(KEY_LAYOUT_NOTIF_LOCK_MIDDLE_SIDE, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String layoutLockNotifMiddleAutoNearestSideKey(int index) {
|
public static String layoutLockNotifMiddleAutoNearestSideKey(int index) {
|
||||||
return suffixedKey("layout_lock_notifications_middle_auto_nearest_side", index);
|
return suffixedKey(KEY_LAYOUT_NOTIF_LOCK_MIDDLE_AUTO_NEAREST_SIDE, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String layoutLockNotifVerticalOffsetKey(int index) {
|
public static String layoutLockNotifVerticalOffsetKey(int index) {
|
||||||
return suffixedKey("layout_lock_notifications_vertical_offset_px", index);
|
return suffixedKey(KEY_LAYOUT_NOTIF_LOCK_VERTICAL_OFFSET_PX, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String layoutLockNotifIconHeightKey() {
|
public static String layoutLockNotifIconHeightKey() {
|
||||||
return "layout_lock_notifications_icon_height_steps";
|
return KEY_LAYOUT_NOTIF_LOCK_ICON_HEIGHT_STEPS;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String layoutAodNotifPositionKey(int index) {
|
public static String layoutAodNotifPositionKey(int index) {
|
||||||
return suffixedKey("layout_aod_notifications_position", index);
|
return suffixedKey(KEY_LAYOUT_NOTIF_AOD_POSITION, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String layoutAodNotifMiddleSideKey(int index) {
|
public static String layoutAodNotifMiddleSideKey(int index) {
|
||||||
return suffixedKey("layout_aod_notifications_middle_side", index);
|
return suffixedKey(KEY_LAYOUT_NOTIF_AOD_MIDDLE_SIDE, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String layoutAodNotifMiddleAutoNearestSideKey(int index) {
|
public static String layoutAodNotifMiddleAutoNearestSideKey(int index) {
|
||||||
return suffixedKey("layout_aod_notifications_middle_auto_nearest_side", index);
|
return suffixedKey(KEY_LAYOUT_NOTIF_AOD_MIDDLE_AUTO_NEAREST_SIDE, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String layoutAodNotifVerticalOffsetKey(int index) {
|
public static String layoutAodNotifVerticalOffsetKey(int index) {
|
||||||
return suffixedKey("layout_aod_notifications_vertical_offset_px", index);
|
return suffixedKey(KEY_LAYOUT_NOTIF_AOD_VERTICAL_OFFSET_PX, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String layoutAodNotifIconHeightKey() {
|
public static String layoutAodNotifIconHeightKey() {
|
||||||
return "layout_aod_notifications_icon_height_steps";
|
return KEY_LAYOUT_NOTIF_AOD_ICON_HEIGHT_STEPS;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String layoutLockStatusPositionKey(int index) {
|
public static String layoutLockStatusPositionKey(int index) {
|
||||||
return suffixedKey("layout_lock_status_position", index);
|
return suffixedKey(KEY_LAYOUT_STATUS_LOCK_POSITION, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String layoutLockStatusMiddleSideKey(int index) {
|
public static String layoutLockStatusMiddleSideKey(int index) {
|
||||||
return suffixedKey("layout_lock_status_middle_side", index);
|
return suffixedKey(KEY_LAYOUT_STATUS_LOCK_MIDDLE_SIDE, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String layoutLockStatusMiddleAutoNearestSideKey(int index) {
|
public static String layoutLockStatusMiddleAutoNearestSideKey(int index) {
|
||||||
return suffixedKey("layout_lock_status_middle_auto_nearest_side", index);
|
return suffixedKey(KEY_LAYOUT_STATUS_LOCK_MIDDLE_AUTO_NEAREST_SIDE, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String layoutLockStatusVerticalOffsetKey(int index) {
|
public static String layoutLockStatusVerticalOffsetKey(int index) {
|
||||||
return suffixedKey("layout_lock_status_vertical_offset_px", index);
|
return suffixedKey(KEY_LAYOUT_STATUS_LOCK_VERTICAL_OFFSET_PX, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String layoutLockStatusIconHeightKey() {
|
public static String layoutLockStatusIconHeightKey() {
|
||||||
return "layout_lock_status_icon_height_steps";
|
return KEY_LAYOUT_STATUS_LOCK_ICON_HEIGHT_STEPS;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String layoutAodStatusPositionKey(int index) {
|
public static String layoutAodStatusPositionKey(int index) {
|
||||||
return suffixedKey("layout_aod_status_position", index);
|
return suffixedKey(KEY_LAYOUT_STATUS_AOD_POSITION, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String layoutAodStatusMiddleSideKey(int index) {
|
public static String layoutAodStatusMiddleSideKey(int index) {
|
||||||
return suffixedKey("layout_aod_status_middle_side", index);
|
return suffixedKey(KEY_LAYOUT_STATUS_AOD_MIDDLE_SIDE, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String layoutAodStatusMiddleAutoNearestSideKey(int index) {
|
public static String layoutAodStatusMiddleAutoNearestSideKey(int index) {
|
||||||
return suffixedKey("layout_aod_status_middle_auto_nearest_side", index);
|
return suffixedKey(KEY_LAYOUT_STATUS_AOD_MIDDLE_AUTO_NEAREST_SIDE, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String layoutAodStatusVerticalOffsetKey(int index) {
|
public static String layoutAodStatusVerticalOffsetKey(int index) {
|
||||||
return suffixedKey("layout_aod_status_vertical_offset_px", index);
|
return suffixedKey(KEY_LAYOUT_STATUS_AOD_VERTICAL_OFFSET_PX, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String layoutAodStatusIconHeightKey() {
|
public static String layoutAodStatusIconHeightKey() {
|
||||||
return "layout_aod_status_icon_height_steps";
|
return KEY_LAYOUT_STATUS_AOD_ICON_HEIGHT_STEPS;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String indexedKey(String base, int index) {
|
||||||
|
return base == null || index <= 0 ? base : base + "_" + (index + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String suffixedKey(String base, int index) {
|
private static String suffixedKey(String base, int index) {
|
||||||
return index <= 0 ? base : base + "_" + (index + 1);
|
return indexedKey(base, index);
|
||||||
}
|
}
|
||||||
public final boolean enableAodCutoutLimit;
|
public final boolean enableAodCutoutLimit;
|
||||||
public final boolean enableLockCutoutLimit;
|
public final boolean enableLockCutoutLimit;
|
||||||
@@ -669,9 +711,7 @@ public final class SbtSettings {
|
|||||||
this.layoutNotifIconHeightSteps = clampIconHeightSteps(layoutNotifIconHeightSteps);
|
this.layoutNotifIconHeightSteps = clampIconHeightSteps(layoutNotifIconHeightSteps);
|
||||||
this.layoutNotifLockIconHeightSteps = clampIconHeightSteps(layoutNotifLockIconHeightSteps);
|
this.layoutNotifLockIconHeightSteps = clampIconHeightSteps(layoutNotifLockIconHeightSteps);
|
||||||
this.layoutNotifAodIconHeightSteps = clampIconHeightSteps(layoutNotifAodIconHeightSteps);
|
this.layoutNotifAodIconHeightSteps = clampIconHeightSteps(layoutNotifAodIconHeightSteps);
|
||||||
this.layoutNotifUnlockedCount = Math.max(
|
this.layoutNotifUnlockedCount = clampIconContainerCount(layoutNotifUnlockedCount);
|
||||||
SbtDefaults.LAYOUT_ICON_CONTAINER_COUNT_MIN,
|
|
||||||
Math.min(SbtDefaults.LAYOUT_ICON_CONTAINER_COUNT_MAX, layoutNotifUnlockedCount));
|
|
||||||
this.layoutNotifPositions = sanitizeStringArray(
|
this.layoutNotifPositions = sanitizeStringArray(
|
||||||
layoutNotifPositions,
|
layoutNotifPositions,
|
||||||
this.layoutNotifPosition,
|
this.layoutNotifPosition,
|
||||||
@@ -746,9 +786,7 @@ public final class SbtSettings {
|
|||||||
this.layoutStatusIconHeightSteps = clampIconHeightSteps(layoutStatusIconHeightSteps);
|
this.layoutStatusIconHeightSteps = clampIconHeightSteps(layoutStatusIconHeightSteps);
|
||||||
this.layoutStatusLockIconHeightSteps = clampIconHeightSteps(layoutStatusLockIconHeightSteps);
|
this.layoutStatusLockIconHeightSteps = clampIconHeightSteps(layoutStatusLockIconHeightSteps);
|
||||||
this.layoutStatusAodIconHeightSteps = clampIconHeightSteps(layoutStatusAodIconHeightSteps);
|
this.layoutStatusAodIconHeightSteps = clampIconHeightSteps(layoutStatusAodIconHeightSteps);
|
||||||
this.layoutStatusUnlockedCount = Math.max(
|
this.layoutStatusUnlockedCount = clampIconContainerCount(layoutStatusUnlockedCount);
|
||||||
SbtDefaults.LAYOUT_ICON_CONTAINER_COUNT_MIN,
|
|
||||||
Math.min(SbtDefaults.LAYOUT_ICON_CONTAINER_COUNT_MAX, layoutStatusUnlockedCount));
|
|
||||||
this.layoutStatusPositions = sanitizeStringArray(
|
this.layoutStatusPositions = sanitizeStringArray(
|
||||||
layoutStatusPositions,
|
layoutStatusPositions,
|
||||||
this.layoutStatusPosition,
|
this.layoutStatusPosition,
|
||||||
@@ -1002,9 +1040,8 @@ public final class SbtSettings {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static SbtSettings fromProvider(Context context) {
|
private static SbtSettings fromProvider(Context context) {
|
||||||
Uri uri = Uri.parse("content://" + SbtSettingsProvider.AUTHORITY);
|
|
||||||
Bundle out = context.getContentResolver()
|
Bundle out = context.getContentResolver()
|
||||||
.call(uri, SbtSettingsProvider.METHOD_GET_ALL, null, null);
|
.call(settingsProviderUri(), SbtSettingsProvider.METHOD_GET_ALL, null, null);
|
||||||
if (out == null) {
|
if (out == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -1017,9 +1054,8 @@ public final class SbtSettings {
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
if (!MODULE_PACKAGE.equals(context.getPackageName()) && hasSettingsProvider(context)) {
|
if (!MODULE_PACKAGE.equals(context.getPackageName()) && hasSettingsProvider(context)) {
|
||||||
Uri uri = Uri.parse("content://" + SbtSettingsProvider.AUTHORITY);
|
|
||||||
Bundle out = context.getContentResolver()
|
Bundle out = context.getContentResolver()
|
||||||
.call(uri, SbtSettingsProvider.METHOD_GET_ALL, null, null);
|
.call(settingsProviderUri(), SbtSettingsProvider.METHOD_GET_ALL, null, null);
|
||||||
if (out != null) {
|
if (out != null) {
|
||||||
return out.getBoolean(KEY_DEBUG_WRITE_LOGS, SbtDefaults.DEBUG_WRITE_LOGS_DEFAULT);
|
return out.getBoolean(KEY_DEBUG_WRITE_LOGS, SbtDefaults.DEBUG_WRITE_LOGS_DEFAULT);
|
||||||
}
|
}
|
||||||
@@ -1039,14 +1075,16 @@ public final class SbtSettings {
|
|||||||
int offsetMinutes = AppIconRules.currentTimezoneOffsetMinutes();
|
int offsetMinutes = AppIconRules.currentTimezoneOffsetMinutes();
|
||||||
try {
|
try {
|
||||||
if (!MODULE_PACKAGE.equals(context.getPackageName()) && hasSettingsProvider(context)) {
|
if (!MODULE_PACKAGE.equals(context.getPackageName()) && hasSettingsProvider(context)) {
|
||||||
Uri uri = Uri.parse("content://" + SbtSettingsProvider.AUTHORITY);
|
|
||||||
Bundle extras = new Bundle();
|
Bundle extras = new Bundle();
|
||||||
extras.putString(AppIconRules.EXTRA_PACKAGE, packageName);
|
extras.putString(AppIconRules.EXTRA_PACKAGE, packageName);
|
||||||
extras.putLong(AppIconRules.EXTRA_FIRST_SEEN_MS, seenMs);
|
extras.putLong(AppIconRules.EXTRA_FIRST_SEEN_MS, seenMs);
|
||||||
extras.putLong(AppIconRules.EXTRA_LAST_SEEN_MS, seenMs);
|
extras.putLong(AppIconRules.EXTRA_LAST_SEEN_MS, seenMs);
|
||||||
extras.putInt(AppIconRules.EXTRA_LAST_SEEN_TIMEZONE_OFFSET_MINUTES, offsetMinutes);
|
extras.putInt(AppIconRules.EXTRA_LAST_SEEN_TIMEZONE_OFFSET_MINUTES, offsetMinutes);
|
||||||
context.getContentResolver()
|
context.getContentResolver()
|
||||||
.call(uri, SbtSettingsProvider.METHOD_NOTE_SEEN_ICON_APP, null, extras);
|
.call(settingsProviderUri(),
|
||||||
|
SbtSettingsProvider.METHOD_NOTE_SEEN_ICON_APP,
|
||||||
|
null,
|
||||||
|
extras);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
SharedPreferences prefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
|
SharedPreferences prefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
|
||||||
@@ -1138,9 +1176,7 @@ public final class SbtSettings {
|
|||||||
SbtDefaults.BATTERY_BAR_DEFAULT_DISCHARGE_COLOR_DEFAULT),
|
SbtDefaults.BATTERY_BAR_DEFAULT_DISCHARGE_COLOR_DEFAULT),
|
||||||
prefs.getString(KEY_BATTERY_BAR_DEFAULT_CHARGE_COLOR,
|
prefs.getString(KEY_BATTERY_BAR_DEFAULT_CHARGE_COLOR,
|
||||||
SbtDefaults.BATTERY_BAR_DEFAULT_CHARGE_COLOR_DEFAULT),
|
SbtDefaults.BATTERY_BAR_DEFAULT_CHARGE_COLOR_DEFAULT),
|
||||||
BatteryBarStyle.decodeThresholds(prefs.getStringSet(
|
BatteryBarStyle.loadThresholds(prefs, KEY_BATTERY_BAR_THRESHOLDS),
|
||||||
KEY_BATTERY_BAR_THRESHOLDS,
|
|
||||||
Collections.emptySet())),
|
|
||||||
prefs.getBoolean(KEY_CLOCK_ENABLED, SbtDefaults.CLOCK_ENABLED_DEFAULT),
|
prefs.getBoolean(KEY_CLOCK_ENABLED, SbtDefaults.CLOCK_ENABLED_DEFAULT),
|
||||||
prefs.getBoolean(KEY_CLOCK_ENABLED_LOCKSCREEN, SbtDefaults.CLOCK_ENABLED_LOCKSCREEN_DEFAULT),
|
prefs.getBoolean(KEY_CLOCK_ENABLED_LOCKSCREEN, SbtDefaults.CLOCK_ENABLED_LOCKSCREEN_DEFAULT),
|
||||||
prefs.getBoolean(KEY_CLOCK_ENABLED_UNLOCKED, SbtDefaults.CLOCK_ENABLED_UNLOCKED_DEFAULT),
|
prefs.getBoolean(KEY_CLOCK_ENABLED_UNLOCKED, SbtDefaults.CLOCK_ENABLED_UNLOCKED_DEFAULT),
|
||||||
@@ -1233,7 +1269,7 @@ public final class SbtSettings {
|
|||||||
SbtDefaults.LAYOUT_NOTIF_VERTICAL_OFFSET_PX_DEFAULT),
|
SbtDefaults.LAYOUT_NOTIF_VERTICAL_OFFSET_PX_DEFAULT),
|
||||||
readIconContainerCount(
|
readIconContainerCount(
|
||||||
prefs,
|
prefs,
|
||||||
"layout_lock_notifications_count",
|
KEY_LAYOUT_NOTIF_LOCK_COUNT,
|
||||||
KEY_LAYOUT_NOTIF_ENABLED_LOCKSCREEN,
|
KEY_LAYOUT_NOTIF_ENABLED_LOCKSCREEN,
|
||||||
SbtDefaults.LAYOUT_NOTIF_UNLOCKED_COUNT_DEFAULT,
|
SbtDefaults.LAYOUT_NOTIF_UNLOCKED_COUNT_DEFAULT,
|
||||||
SbtDefaults.LAYOUT_NOTIF_ENABLED_LOCKSCREEN_DEFAULT),
|
SbtDefaults.LAYOUT_NOTIF_ENABLED_LOCKSCREEN_DEFAULT),
|
||||||
@@ -1255,7 +1291,7 @@ public final class SbtSettings {
|
|||||||
SbtDefaults.LAYOUT_NOTIF_VERTICAL_OFFSET_PX_DEFAULT),
|
SbtDefaults.LAYOUT_NOTIF_VERTICAL_OFFSET_PX_DEFAULT),
|
||||||
readIconContainerCount(
|
readIconContainerCount(
|
||||||
prefs,
|
prefs,
|
||||||
"layout_aod_notifications_count",
|
KEY_LAYOUT_NOTIF_AOD_COUNT,
|
||||||
KEY_LAYOUT_NOTIF_ENABLED_AOD,
|
KEY_LAYOUT_NOTIF_ENABLED_AOD,
|
||||||
SbtDefaults.LAYOUT_NOTIF_UNLOCKED_COUNT_DEFAULT,
|
SbtDefaults.LAYOUT_NOTIF_UNLOCKED_COUNT_DEFAULT,
|
||||||
SbtDefaults.LAYOUT_NOTIF_ENABLED_AOD_DEFAULT),
|
SbtDefaults.LAYOUT_NOTIF_ENABLED_AOD_DEFAULT),
|
||||||
@@ -1322,7 +1358,7 @@ public final class SbtSettings {
|
|||||||
SbtDefaults.LAYOUT_STATUS_VERTICAL_OFFSET_PX_DEFAULT),
|
SbtDefaults.LAYOUT_STATUS_VERTICAL_OFFSET_PX_DEFAULT),
|
||||||
readIconContainerCount(
|
readIconContainerCount(
|
||||||
prefs,
|
prefs,
|
||||||
"layout_lock_status_count",
|
KEY_LAYOUT_STATUS_LOCK_COUNT,
|
||||||
KEY_LAYOUT_STATUS_ENABLED_LOCKSCREEN,
|
KEY_LAYOUT_STATUS_ENABLED_LOCKSCREEN,
|
||||||
SbtDefaults.LAYOUT_STATUS_UNLOCKED_COUNT_DEFAULT,
|
SbtDefaults.LAYOUT_STATUS_UNLOCKED_COUNT_DEFAULT,
|
||||||
SbtDefaults.LAYOUT_STATUS_ENABLED_LOCKSCREEN_DEFAULT),
|
SbtDefaults.LAYOUT_STATUS_ENABLED_LOCKSCREEN_DEFAULT),
|
||||||
@@ -1344,7 +1380,7 @@ public final class SbtSettings {
|
|||||||
SbtDefaults.LAYOUT_STATUS_VERTICAL_OFFSET_PX_DEFAULT),
|
SbtDefaults.LAYOUT_STATUS_VERTICAL_OFFSET_PX_DEFAULT),
|
||||||
readIconContainerCount(
|
readIconContainerCount(
|
||||||
prefs,
|
prefs,
|
||||||
"layout_aod_status_count",
|
KEY_LAYOUT_STATUS_AOD_COUNT,
|
||||||
KEY_LAYOUT_STATUS_ENABLED_AOD,
|
KEY_LAYOUT_STATUS_ENABLED_AOD,
|
||||||
SbtDefaults.LAYOUT_STATUS_UNLOCKED_COUNT_DEFAULT,
|
SbtDefaults.LAYOUT_STATUS_UNLOCKED_COUNT_DEFAULT,
|
||||||
SbtDefaults.LAYOUT_STATUS_ENABLED_AOD_DEFAULT),
|
SbtDefaults.LAYOUT_STATUS_ENABLED_AOD_DEFAULT),
|
||||||
@@ -1364,17 +1400,18 @@ public final class SbtSettings {
|
|||||||
prefs,
|
prefs,
|
||||||
SbtSettings::layoutAodStatusVerticalOffsetKey,
|
SbtSettings::layoutAodStatusVerticalOffsetKey,
|
||||||
SbtDefaults.LAYOUT_STATUS_VERTICAL_OFFSET_PX_DEFAULT),
|
SbtDefaults.LAYOUT_STATUS_VERTICAL_OFFSET_PX_DEFAULT),
|
||||||
ClockCameraTypeSupport.parseOverrides(copyStringSet(
|
ClockCameraTypeSupport.loadOverrides(prefs, KEY_CLOCK_CAMERA_TYPE_OVERRIDES),
|
||||||
prefs.getStringSet(KEY_CLOCK_CAMERA_TYPE_OVERRIDES, Collections.emptySet()))),
|
|
||||||
systemIconBlockedModes,
|
systemIconBlockedModes,
|
||||||
prefs.getBoolean(KEY_STATUS_CHIPS_HIDE_ALL, false),
|
prefs.getBoolean(KEY_STATUS_CHIPS_HIDE_ALL, false),
|
||||||
prefs.getBoolean(KEY_STATUS_CHIPS_HIDE_MEDIA_UNLOCKED, false),
|
prefs.getBoolean(KEY_STATUS_CHIPS_HIDE_MEDIA_UNLOCKED, false),
|
||||||
prefs.getBoolean(KEY_STATUS_CHIPS_HIDE_NAV_UNLOCKED, false),
|
prefs.getBoolean(KEY_STATUS_CHIPS_HIDE_NAV_UNLOCKED, false),
|
||||||
prefs.getBoolean(KEY_STATUS_CHIPS_HIDE_CALL, false),
|
prefs.getBoolean(KEY_STATUS_CHIPS_HIDE_CALL, false),
|
||||||
AppIconRules.parseBlockedModes(copyStringSet(
|
AppIconRules.parseBlockedModes(readStringSetFromPrefs(
|
||||||
prefs.getStringSet(KEY_APP_ICON_BLOCKED_MODES, Collections.emptySet()))),
|
prefs,
|
||||||
AppIconRules.parseExceptionRules(copyStringSet(
|
KEY_APP_ICON_BLOCKED_MODES)),
|
||||||
prefs.getStringSet(KEY_APP_ICON_EXCEPTION_RULES, Collections.emptySet()))),
|
AppIconRules.parseExceptionRules(readStringSetFromPrefs(
|
||||||
|
prefs,
|
||||||
|
KEY_APP_ICON_EXCEPTION_RULES)),
|
||||||
prefs.getString(KEY_LOCKED_NOTIFICATION_MODE, "dot"),
|
prefs.getString(KEY_LOCKED_NOTIFICATION_MODE, "dot"),
|
||||||
prefs.getBoolean(
|
prefs.getBoolean(
|
||||||
KEY_DEBUG_VISUALIZE_NOTIFICATION_CONTAINER,
|
KEY_DEBUG_VISUALIZE_NOTIFICATION_CONTAINER,
|
||||||
@@ -1561,7 +1598,7 @@ public final class SbtSettings {
|
|||||||
SbtDefaults.LAYOUT_NOTIF_VERTICAL_OFFSET_PX_DEFAULT),
|
SbtDefaults.LAYOUT_NOTIF_VERTICAL_OFFSET_PX_DEFAULT),
|
||||||
readIconContainerCount(
|
readIconContainerCount(
|
||||||
bundle,
|
bundle,
|
||||||
"layout_lock_notifications_count",
|
KEY_LAYOUT_NOTIF_LOCK_COUNT,
|
||||||
KEY_LAYOUT_NOTIF_ENABLED_LOCKSCREEN,
|
KEY_LAYOUT_NOTIF_ENABLED_LOCKSCREEN,
|
||||||
SbtDefaults.LAYOUT_NOTIF_UNLOCKED_COUNT_DEFAULT,
|
SbtDefaults.LAYOUT_NOTIF_UNLOCKED_COUNT_DEFAULT,
|
||||||
SbtDefaults.LAYOUT_NOTIF_ENABLED_LOCKSCREEN_DEFAULT),
|
SbtDefaults.LAYOUT_NOTIF_ENABLED_LOCKSCREEN_DEFAULT),
|
||||||
@@ -1583,7 +1620,7 @@ public final class SbtSettings {
|
|||||||
SbtDefaults.LAYOUT_NOTIF_VERTICAL_OFFSET_PX_DEFAULT),
|
SbtDefaults.LAYOUT_NOTIF_VERTICAL_OFFSET_PX_DEFAULT),
|
||||||
readIconContainerCount(
|
readIconContainerCount(
|
||||||
bundle,
|
bundle,
|
||||||
"layout_aod_notifications_count",
|
KEY_LAYOUT_NOTIF_AOD_COUNT,
|
||||||
KEY_LAYOUT_NOTIF_ENABLED_AOD,
|
KEY_LAYOUT_NOTIF_ENABLED_AOD,
|
||||||
SbtDefaults.LAYOUT_NOTIF_UNLOCKED_COUNT_DEFAULT,
|
SbtDefaults.LAYOUT_NOTIF_UNLOCKED_COUNT_DEFAULT,
|
||||||
SbtDefaults.LAYOUT_NOTIF_ENABLED_AOD_DEFAULT),
|
SbtDefaults.LAYOUT_NOTIF_ENABLED_AOD_DEFAULT),
|
||||||
@@ -1650,7 +1687,7 @@ public final class SbtSettings {
|
|||||||
SbtDefaults.LAYOUT_STATUS_VERTICAL_OFFSET_PX_DEFAULT),
|
SbtDefaults.LAYOUT_STATUS_VERTICAL_OFFSET_PX_DEFAULT),
|
||||||
readIconContainerCount(
|
readIconContainerCount(
|
||||||
bundle,
|
bundle,
|
||||||
"layout_lock_status_count",
|
KEY_LAYOUT_STATUS_LOCK_COUNT,
|
||||||
KEY_LAYOUT_STATUS_ENABLED_LOCKSCREEN,
|
KEY_LAYOUT_STATUS_ENABLED_LOCKSCREEN,
|
||||||
SbtDefaults.LAYOUT_STATUS_UNLOCKED_COUNT_DEFAULT,
|
SbtDefaults.LAYOUT_STATUS_UNLOCKED_COUNT_DEFAULT,
|
||||||
SbtDefaults.LAYOUT_STATUS_ENABLED_LOCKSCREEN_DEFAULT),
|
SbtDefaults.LAYOUT_STATUS_ENABLED_LOCKSCREEN_DEFAULT),
|
||||||
@@ -1672,7 +1709,7 @@ public final class SbtSettings {
|
|||||||
SbtDefaults.LAYOUT_STATUS_VERTICAL_OFFSET_PX_DEFAULT),
|
SbtDefaults.LAYOUT_STATUS_VERTICAL_OFFSET_PX_DEFAULT),
|
||||||
readIconContainerCount(
|
readIconContainerCount(
|
||||||
bundle,
|
bundle,
|
||||||
"layout_aod_status_count",
|
KEY_LAYOUT_STATUS_AOD_COUNT,
|
||||||
KEY_LAYOUT_STATUS_ENABLED_AOD,
|
KEY_LAYOUT_STATUS_ENABLED_AOD,
|
||||||
SbtDefaults.LAYOUT_STATUS_UNLOCKED_COUNT_DEFAULT,
|
SbtDefaults.LAYOUT_STATUS_UNLOCKED_COUNT_DEFAULT,
|
||||||
SbtDefaults.LAYOUT_STATUS_ENABLED_AOD_DEFAULT),
|
SbtDefaults.LAYOUT_STATUS_ENABLED_AOD_DEFAULT),
|
||||||
@@ -1698,8 +1735,12 @@ public final class SbtSettings {
|
|||||||
bundle.getBoolean(KEY_STATUS_CHIPS_HIDE_MEDIA_UNLOCKED, false),
|
bundle.getBoolean(KEY_STATUS_CHIPS_HIDE_MEDIA_UNLOCKED, false),
|
||||||
bundle.getBoolean(KEY_STATUS_CHIPS_HIDE_NAV_UNLOCKED, false),
|
bundle.getBoolean(KEY_STATUS_CHIPS_HIDE_NAV_UNLOCKED, false),
|
||||||
bundle.getBoolean(KEY_STATUS_CHIPS_HIDE_CALL, false),
|
bundle.getBoolean(KEY_STATUS_CHIPS_HIDE_CALL, false),
|
||||||
AppIconRules.parseBlockedModes(readBlockedSetFromBundle(bundle)),
|
AppIconRules.parseBlockedModes(readStringSetFromBundle(
|
||||||
AppIconRules.parseExceptionRules(readRuleSetFromBundle(bundle)),
|
bundle,
|
||||||
|
KEY_APP_ICON_BLOCKED_MODES)),
|
||||||
|
AppIconRules.parseExceptionRules(readStringSetFromBundle(
|
||||||
|
bundle,
|
||||||
|
KEY_APP_ICON_EXCEPTION_RULES)),
|
||||||
bundle.getString(KEY_LOCKED_NOTIFICATION_MODE, "dot"),
|
bundle.getString(KEY_LOCKED_NOTIFICATION_MODE, "dot"),
|
||||||
bundle.getBoolean(
|
bundle.getBoolean(
|
||||||
KEY_DEBUG_VISUALIZE_NOTIFICATION_CONTAINER,
|
KEY_DEBUG_VISUALIZE_NOTIFICATION_CONTAINER,
|
||||||
@@ -1730,13 +1771,13 @@ public final class SbtSettings {
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int clampIconContainerCount(int value) {
|
public static int clampIconContainerCount(int value) {
|
||||||
return Math.max(
|
return Math.max(
|
||||||
SbtDefaults.LAYOUT_ICON_CONTAINER_COUNT_MIN,
|
SbtDefaults.LAYOUT_ICON_CONTAINER_COUNT_MIN,
|
||||||
Math.min(SbtDefaults.LAYOUT_ICON_CONTAINER_COUNT_MAX, value));
|
Math.min(SbtDefaults.LAYOUT_ICON_CONTAINER_COUNT_MAX, value));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int clampIconHeightSteps(int value) {
|
public static int clampIconHeightSteps(int value) {
|
||||||
return Math.max(
|
return Math.max(
|
||||||
SbtDefaults.LAYOUT_ICON_HEIGHT_STEPS_MIN,
|
SbtDefaults.LAYOUT_ICON_HEIGHT_STEPS_MIN,
|
||||||
Math.min(SbtDefaults.LAYOUT_ICON_HEIGHT_STEPS_MAX, value));
|
Math.min(SbtDefaults.LAYOUT_ICON_HEIGHT_STEPS_MAX, value));
|
||||||
@@ -1749,11 +1790,11 @@ public final class SbtSettings {
|
|||||||
int defaultCount,
|
int defaultCount,
|
||||||
boolean legacyEnabledDefault
|
boolean legacyEnabledDefault
|
||||||
) {
|
) {
|
||||||
int fallback = prefs.getBoolean(legacyEnabledKey, legacyEnabledDefault) ? defaultCount : 0;
|
int fallback = iconContainerCountFallback(
|
||||||
|
prefs.getBoolean(legacyEnabledKey, legacyEnabledDefault),
|
||||||
|
defaultCount);
|
||||||
int value = prefs.getInt(countKey, fallback);
|
int value = prefs.getInt(countKey, fallback);
|
||||||
return Math.max(
|
return clampIconContainerCount(value);
|
||||||
SbtDefaults.LAYOUT_ICON_CONTAINER_COUNT_MIN,
|
|
||||||
Math.min(SbtDefaults.LAYOUT_ICON_CONTAINER_COUNT_MAX, value));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int readIconContainerCount(
|
private static int readIconContainerCount(
|
||||||
@@ -1763,11 +1804,15 @@ public final class SbtSettings {
|
|||||||
int defaultCount,
|
int defaultCount,
|
||||||
boolean legacyEnabledDefault
|
boolean legacyEnabledDefault
|
||||||
) {
|
) {
|
||||||
int fallback = bundle.getBoolean(legacyEnabledKey, legacyEnabledDefault) ? defaultCount : 0;
|
int fallback = iconContainerCountFallback(
|
||||||
|
bundle.getBoolean(legacyEnabledKey, legacyEnabledDefault),
|
||||||
|
defaultCount);
|
||||||
int value = bundle.getInt(countKey, fallback);
|
int value = bundle.getInt(countKey, fallback);
|
||||||
return Math.max(
|
return clampIconContainerCount(value);
|
||||||
SbtDefaults.LAYOUT_ICON_CONTAINER_COUNT_MIN,
|
}
|
||||||
Math.min(SbtDefaults.LAYOUT_ICON_CONTAINER_COUNT_MAX, value));
|
|
||||||
|
private static int iconContainerCountFallback(boolean legacyEnabled, int defaultCount) {
|
||||||
|
return legacyEnabled ? defaultCount : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String[] readStringArrayFromPrefs(
|
private static String[] readStringArrayFromPrefs(
|
||||||
@@ -1864,24 +1909,17 @@ public final class SbtSettings {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Set<String> copyStringSet(Set<String> source) {
|
private static Set<String> readStringSetFromPrefs(SharedPreferences prefs, String key) {
|
||||||
|
if (prefs == null) {
|
||||||
|
return Collections.emptySet();
|
||||||
|
}
|
||||||
|
Set<String> source = prefs.getStringSet(key, Collections.emptySet());
|
||||||
if (source == null || source.isEmpty()) {
|
if (source == null || source.isEmpty()) {
|
||||||
return Collections.emptySet();
|
return Collections.emptySet();
|
||||||
}
|
}
|
||||||
return new HashSet<>(source);
|
return new HashSet<>(source);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Set<String> readBlockedSetFromBundle(Bundle bundle) {
|
|
||||||
if (bundle == null) {
|
|
||||||
return Collections.emptySet();
|
|
||||||
}
|
|
||||||
ArrayList<String> list = bundle.getStringArrayList(KEY_APP_ICON_BLOCKED_MODES);
|
|
||||||
if (list == null || list.isEmpty()) {
|
|
||||||
return Collections.emptySet();
|
|
||||||
}
|
|
||||||
return new HashSet<>(list);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Set<String> readStringSetFromBundle(Bundle bundle, String key) {
|
private static Set<String> readStringSetFromBundle(Bundle bundle, String key) {
|
||||||
if (bundle == null) {
|
if (bundle == null) {
|
||||||
return Collections.emptySet();
|
return Collections.emptySet();
|
||||||
@@ -1893,31 +1931,14 @@ public final class SbtSettings {
|
|||||||
return new HashSet<>(list);
|
return new HashSet<>(list);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Set<String> readRuleSetFromBundle(Bundle bundle) {
|
|
||||||
if (bundle == null) {
|
|
||||||
return Collections.emptySet();
|
|
||||||
}
|
|
||||||
ArrayList<String> list = bundle.getStringArrayList(KEY_APP_ICON_EXCEPTION_RULES);
|
|
||||||
if (list == null || list.isEmpty()) {
|
|
||||||
return Collections.emptySet();
|
|
||||||
}
|
|
||||||
return new HashSet<>(list);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Map<String, Integer> readSystemIconBlockedModesFromPrefs(SharedPreferences prefs) {
|
private static Map<String, Integer> readSystemIconBlockedModesFromPrefs(SharedPreferences prefs) {
|
||||||
if (prefs == null) {
|
if (prefs == null) {
|
||||||
return Collections.emptyMap();
|
return Collections.emptyMap();
|
||||||
}
|
}
|
||||||
Map<String, Integer> parsed = SystemIconRules.parseBlockedModes(copyStringSet(
|
Map<String, Integer> parsed = SystemIconRules.parseBlockedModes(
|
||||||
prefs.getStringSet(KEY_SYSTEM_ICON_BLOCKED_MODES, Collections.emptySet())));
|
readStringSetFromPrefs(prefs, KEY_SYSTEM_ICON_BLOCKED_MODES));
|
||||||
HashMap<String, Integer> merged = new HashMap<>(parsed);
|
HashMap<String, Integer> merged = new HashMap<>(parsed);
|
||||||
Set<String> legacyHidden = copyStringSet(
|
mergeLegacySystemIconHidden(merged, readStringSetFromPrefs(prefs, KEY_SYSTEM_ICON_HIDE_SLOTS));
|
||||||
prefs.getStringSet(KEY_SYSTEM_ICON_HIDE_SLOTS, Collections.emptySet()));
|
|
||||||
for (String slot : legacyHidden) {
|
|
||||||
SystemIconRules.setModeBlocked(merged, slot,
|
|
||||||
SystemIconRules.MODE_AOD | SystemIconRules.MODE_LOCK | SystemIconRules.MODE_UNLOCK,
|
|
||||||
true);
|
|
||||||
}
|
|
||||||
return merged.isEmpty() ? Collections.emptyMap() : merged;
|
return merged.isEmpty() ? Collections.emptyMap() : merged;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1928,23 +1949,36 @@ public final class SbtSettings {
|
|||||||
Map<String, Integer> parsed = SystemIconRules.parseBlockedModes(
|
Map<String, Integer> parsed = SystemIconRules.parseBlockedModes(
|
||||||
readStringSetFromBundle(bundle, KEY_SYSTEM_ICON_BLOCKED_MODES));
|
readStringSetFromBundle(bundle, KEY_SYSTEM_ICON_BLOCKED_MODES));
|
||||||
HashMap<String, Integer> merged = new HashMap<>(parsed);
|
HashMap<String, Integer> merged = new HashMap<>(parsed);
|
||||||
Set<String> legacyHidden = readStringSetFromBundle(bundle, KEY_SYSTEM_ICON_HIDE_SLOTS);
|
mergeLegacySystemIconHidden(merged, readStringSetFromBundle(bundle, KEY_SYSTEM_ICON_HIDE_SLOTS));
|
||||||
|
return merged.isEmpty() ? Collections.emptyMap() : merged;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void mergeLegacySystemIconHidden(HashMap<String, Integer> merged, Set<String> legacyHidden) {
|
||||||
|
if (merged == null || legacyHidden == null || legacyHidden.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
for (String slot : legacyHidden) {
|
for (String slot : legacyHidden) {
|
||||||
SystemIconRules.setModeBlocked(merged, slot,
|
SystemIconRules.setModeBlocked(merged, slot,
|
||||||
SystemIconRules.MODE_AOD | SystemIconRules.MODE_LOCK | SystemIconRules.MODE_UNLOCK,
|
SystemIconRules.MODE_AOD | SystemIconRules.MODE_LOCK | SystemIconRules.MODE_UNLOCK,
|
||||||
true);
|
true);
|
||||||
}
|
}
|
||||||
return merged.isEmpty() ? Collections.emptyMap() : merged;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void ensureReadable(Context context) {
|
public static void ensureReadable(Context context) {
|
||||||
if (context == null) {
|
if (context == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Uri uri = Uri.parse("content://" + SbtSettingsProvider.AUTHORITY + "/settings");
|
context.getContentResolver().notifyChange(settingsNotifyUri(), null);
|
||||||
context.getContentResolver().notifyChange(uri, null);
|
|
||||||
android.content.Intent intent = new android.content.Intent(ACTION_SETTINGS_CHANGED);
|
android.content.Intent intent = new android.content.Intent(ACTION_SETTINGS_CHANGED);
|
||||||
intent.setPackage(PACKAGE_SYSTEMUI);
|
intent.setPackage(PACKAGE_SYSTEMUI);
|
||||||
context.sendBroadcast(intent);
|
context.sendBroadcast(intent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Uri settingsProviderUri() {
|
||||||
|
return Uri.parse(SETTINGS_PROVIDER_BASE_URI);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Uri settingsNotifyUri() {
|
||||||
|
return Uri.parse(SETTINGS_PROVIDER_BASE_URI + "/settings");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+37
-40
@@ -9,13 +9,11 @@ import android.net.Uri;
|
|||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
public class SbtSettingsProvider extends ContentProvider {
|
public class SbtSettingsProvider extends ContentProvider {
|
||||||
private interface IndexedKey {
|
|
||||||
String key(int index);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final String AUTHORITY = "se.ajpanton.statusbartweak.settings";
|
public static final String AUTHORITY = "se.ajpanton.statusbartweak.settings";
|
||||||
public static final String METHOD_GET_UNLOCKED = "get_unlocked";
|
public static final String METHOD_GET_UNLOCKED = "get_unlocked";
|
||||||
public static final String METHOD_GET_ALL = "get_all";
|
public static final String METHOD_GET_ALL = "get_all";
|
||||||
@@ -111,11 +109,7 @@ public class SbtSettingsProvider extends ContentProvider {
|
|||||||
out.putString(SbtSettings.KEY_BATTERY_BAR_DEFAULT_CHARGE_COLOR,
|
out.putString(SbtSettings.KEY_BATTERY_BAR_DEFAULT_CHARGE_COLOR,
|
||||||
prefs.getString(SbtSettings.KEY_BATTERY_BAR_DEFAULT_CHARGE_COLOR,
|
prefs.getString(SbtSettings.KEY_BATTERY_BAR_DEFAULT_CHARGE_COLOR,
|
||||||
SbtDefaults.BATTERY_BAR_DEFAULT_CHARGE_COLOR_DEFAULT));
|
SbtDefaults.BATTERY_BAR_DEFAULT_CHARGE_COLOR_DEFAULT));
|
||||||
out.putStringArrayList(
|
putStringSetArrayList(out, prefs, SbtSettings.KEY_BATTERY_BAR_THRESHOLDS);
|
||||||
SbtSettings.KEY_BATTERY_BAR_THRESHOLDS,
|
|
||||||
new ArrayList<>(prefs.getStringSet(
|
|
||||||
SbtSettings.KEY_BATTERY_BAR_THRESHOLDS,
|
|
||||||
java.util.Collections.emptySet())));
|
|
||||||
out.putBoolean(SbtSettings.KEY_CLOCK_ENABLED,
|
out.putBoolean(SbtSettings.KEY_CLOCK_ENABLED,
|
||||||
prefs.getBoolean(SbtSettings.KEY_CLOCK_ENABLED, SbtDefaults.CLOCK_ENABLED_DEFAULT));
|
prefs.getBoolean(SbtSettings.KEY_CLOCK_ENABLED, SbtDefaults.CLOCK_ENABLED_DEFAULT));
|
||||||
out.putBoolean(SbtSettings.KEY_CLOCK_ENABLED_LOCKSCREEN,
|
out.putBoolean(SbtSettings.KEY_CLOCK_ENABLED_LOCKSCREEN,
|
||||||
@@ -276,8 +270,8 @@ public class SbtSettingsProvider extends ContentProvider {
|
|||||||
SbtDefaults.LAYOUT_NOTIF_MIDDLE_AUTO_NEAREST_SIDE_DEFAULT,
|
SbtDefaults.LAYOUT_NOTIF_MIDDLE_AUTO_NEAREST_SIDE_DEFAULT,
|
||||||
SbtSettings::layoutNotifVerticalOffsetKey,
|
SbtSettings::layoutNotifVerticalOffsetKey,
|
||||||
SbtDefaults.LAYOUT_NOTIF_VERTICAL_OFFSET_PX_DEFAULT);
|
SbtDefaults.LAYOUT_NOTIF_VERTICAL_OFFSET_PX_DEFAULT);
|
||||||
out.putInt("layout_lock_notifications_count",
|
out.putInt(SbtSettings.KEY_LAYOUT_NOTIF_LOCK_COUNT,
|
||||||
prefs.getInt("layout_lock_notifications_count",
|
prefs.getInt(SbtSettings.KEY_LAYOUT_NOTIF_LOCK_COUNT,
|
||||||
prefs.getBoolean(
|
prefs.getBoolean(
|
||||||
SbtSettings.KEY_LAYOUT_NOTIF_ENABLED_LOCKSCREEN,
|
SbtSettings.KEY_LAYOUT_NOTIF_ENABLED_LOCKSCREEN,
|
||||||
SbtDefaults.LAYOUT_NOTIF_ENABLED_LOCKSCREEN_DEFAULT)
|
SbtDefaults.LAYOUT_NOTIF_ENABLED_LOCKSCREEN_DEFAULT)
|
||||||
@@ -297,8 +291,8 @@ public class SbtSettingsProvider extends ContentProvider {
|
|||||||
SbtDefaults.LAYOUT_NOTIF_MIDDLE_AUTO_NEAREST_SIDE_DEFAULT,
|
SbtDefaults.LAYOUT_NOTIF_MIDDLE_AUTO_NEAREST_SIDE_DEFAULT,
|
||||||
SbtSettings::layoutLockNotifVerticalOffsetKey,
|
SbtSettings::layoutLockNotifVerticalOffsetKey,
|
||||||
SbtDefaults.LAYOUT_NOTIF_VERTICAL_OFFSET_PX_DEFAULT);
|
SbtDefaults.LAYOUT_NOTIF_VERTICAL_OFFSET_PX_DEFAULT);
|
||||||
out.putInt("layout_aod_notifications_count",
|
out.putInt(SbtSettings.KEY_LAYOUT_NOTIF_AOD_COUNT,
|
||||||
prefs.getInt("layout_aod_notifications_count",
|
prefs.getInt(SbtSettings.KEY_LAYOUT_NOTIF_AOD_COUNT,
|
||||||
prefs.getBoolean(
|
prefs.getBoolean(
|
||||||
SbtSettings.KEY_LAYOUT_NOTIF_ENABLED_AOD,
|
SbtSettings.KEY_LAYOUT_NOTIF_ENABLED_AOD,
|
||||||
SbtDefaults.LAYOUT_NOTIF_ENABLED_AOD_DEFAULT)
|
SbtDefaults.LAYOUT_NOTIF_ENABLED_AOD_DEFAULT)
|
||||||
@@ -363,8 +357,8 @@ public class SbtSettingsProvider extends ContentProvider {
|
|||||||
SbtDefaults.LAYOUT_STATUS_MIDDLE_AUTO_NEAREST_SIDE_DEFAULT,
|
SbtDefaults.LAYOUT_STATUS_MIDDLE_AUTO_NEAREST_SIDE_DEFAULT,
|
||||||
SbtSettings::layoutStatusVerticalOffsetKey,
|
SbtSettings::layoutStatusVerticalOffsetKey,
|
||||||
SbtDefaults.LAYOUT_STATUS_VERTICAL_OFFSET_PX_DEFAULT);
|
SbtDefaults.LAYOUT_STATUS_VERTICAL_OFFSET_PX_DEFAULT);
|
||||||
out.putInt("layout_lock_status_count",
|
out.putInt(SbtSettings.KEY_LAYOUT_STATUS_LOCK_COUNT,
|
||||||
prefs.getInt("layout_lock_status_count",
|
prefs.getInt(SbtSettings.KEY_LAYOUT_STATUS_LOCK_COUNT,
|
||||||
prefs.getBoolean(
|
prefs.getBoolean(
|
||||||
SbtSettings.KEY_LAYOUT_STATUS_ENABLED_LOCKSCREEN,
|
SbtSettings.KEY_LAYOUT_STATUS_ENABLED_LOCKSCREEN,
|
||||||
SbtDefaults.LAYOUT_STATUS_ENABLED_LOCKSCREEN_DEFAULT)
|
SbtDefaults.LAYOUT_STATUS_ENABLED_LOCKSCREEN_DEFAULT)
|
||||||
@@ -384,8 +378,8 @@ public class SbtSettingsProvider extends ContentProvider {
|
|||||||
SbtDefaults.LAYOUT_STATUS_MIDDLE_AUTO_NEAREST_SIDE_DEFAULT,
|
SbtDefaults.LAYOUT_STATUS_MIDDLE_AUTO_NEAREST_SIDE_DEFAULT,
|
||||||
SbtSettings::layoutLockStatusVerticalOffsetKey,
|
SbtSettings::layoutLockStatusVerticalOffsetKey,
|
||||||
SbtDefaults.LAYOUT_STATUS_VERTICAL_OFFSET_PX_DEFAULT);
|
SbtDefaults.LAYOUT_STATUS_VERTICAL_OFFSET_PX_DEFAULT);
|
||||||
out.putInt("layout_aod_status_count",
|
out.putInt(SbtSettings.KEY_LAYOUT_STATUS_AOD_COUNT,
|
||||||
prefs.getInt("layout_aod_status_count",
|
prefs.getInt(SbtSettings.KEY_LAYOUT_STATUS_AOD_COUNT,
|
||||||
prefs.getBoolean(
|
prefs.getBoolean(
|
||||||
SbtSettings.KEY_LAYOUT_STATUS_ENABLED_AOD,
|
SbtSettings.KEY_LAYOUT_STATUS_ENABLED_AOD,
|
||||||
SbtDefaults.LAYOUT_STATUS_ENABLED_AOD_DEFAULT)
|
SbtDefaults.LAYOUT_STATUS_ENABLED_AOD_DEFAULT)
|
||||||
@@ -405,21 +399,9 @@ public class SbtSettingsProvider extends ContentProvider {
|
|||||||
SbtDefaults.LAYOUT_STATUS_MIDDLE_AUTO_NEAREST_SIDE_DEFAULT,
|
SbtDefaults.LAYOUT_STATUS_MIDDLE_AUTO_NEAREST_SIDE_DEFAULT,
|
||||||
SbtSettings::layoutAodStatusVerticalOffsetKey,
|
SbtSettings::layoutAodStatusVerticalOffsetKey,
|
||||||
SbtDefaults.LAYOUT_STATUS_VERTICAL_OFFSET_PX_DEFAULT);
|
SbtDefaults.LAYOUT_STATUS_VERTICAL_OFFSET_PX_DEFAULT);
|
||||||
out.putStringArrayList(
|
putStringSetArrayList(out, prefs, SbtSettings.KEY_CLOCK_CAMERA_TYPE_OVERRIDES);
|
||||||
SbtSettings.KEY_CLOCK_CAMERA_TYPE_OVERRIDES,
|
putStringSetArrayList(out, prefs, SbtSettings.KEY_SYSTEM_ICON_BLOCKED_MODES);
|
||||||
new ArrayList<>(prefs.getStringSet(
|
putStringSetArrayList(out, prefs, SbtSettings.KEY_SYSTEM_ICON_HIDE_SLOTS);
|
||||||
SbtSettings.KEY_CLOCK_CAMERA_TYPE_OVERRIDES,
|
|
||||||
java.util.Collections.emptySet())));
|
|
||||||
out.putStringArrayList(
|
|
||||||
SbtSettings.KEY_SYSTEM_ICON_BLOCKED_MODES,
|
|
||||||
new ArrayList<>(prefs.getStringSet(
|
|
||||||
SbtSettings.KEY_SYSTEM_ICON_BLOCKED_MODES,
|
|
||||||
java.util.Collections.emptySet())));
|
|
||||||
out.putStringArrayList(
|
|
||||||
SbtSettings.KEY_SYSTEM_ICON_HIDE_SLOTS,
|
|
||||||
new ArrayList<>(prefs.getStringSet(
|
|
||||||
SbtSettings.KEY_SYSTEM_ICON_HIDE_SLOTS,
|
|
||||||
java.util.Collections.emptySet())));
|
|
||||||
out.putBoolean(SbtSettings.KEY_STATUS_CHIPS_HIDE_ALL,
|
out.putBoolean(SbtSettings.KEY_STATUS_CHIPS_HIDE_ALL,
|
||||||
prefs.getBoolean(SbtSettings.KEY_STATUS_CHIPS_HIDE_ALL, false));
|
prefs.getBoolean(SbtSettings.KEY_STATUS_CHIPS_HIDE_ALL, false));
|
||||||
out.putBoolean(SbtSettings.KEY_STATUS_CHIPS_HIDE_MEDIA_UNLOCKED,
|
out.putBoolean(SbtSettings.KEY_STATUS_CHIPS_HIDE_MEDIA_UNLOCKED,
|
||||||
@@ -428,12 +410,14 @@ public class SbtSettingsProvider extends ContentProvider {
|
|||||||
prefs.getBoolean(SbtSettings.KEY_STATUS_CHIPS_HIDE_NAV_UNLOCKED, false));
|
prefs.getBoolean(SbtSettings.KEY_STATUS_CHIPS_HIDE_NAV_UNLOCKED, false));
|
||||||
out.putBoolean(SbtSettings.KEY_STATUS_CHIPS_HIDE_CALL,
|
out.putBoolean(SbtSettings.KEY_STATUS_CHIPS_HIDE_CALL,
|
||||||
prefs.getBoolean(SbtSettings.KEY_STATUS_CHIPS_HIDE_CALL, false));
|
prefs.getBoolean(SbtSettings.KEY_STATUS_CHIPS_HIDE_CALL, false));
|
||||||
out.putStringArrayList(
|
putStringCollectionArrayList(
|
||||||
|
out,
|
||||||
SbtSettings.KEY_APP_ICON_BLOCKED_MODES,
|
SbtSettings.KEY_APP_ICON_BLOCKED_MODES,
|
||||||
new ArrayList<>(AppIconRules.encodeBlockedModes(AppIconRules.loadBlockedModes(prefs))));
|
AppIconRules.encodeBlockedModes(AppIconRules.loadBlockedModes(prefs)));
|
||||||
out.putStringArrayList(
|
putStringCollectionArrayList(
|
||||||
|
out,
|
||||||
SbtSettings.KEY_APP_ICON_EXCEPTION_RULES,
|
SbtSettings.KEY_APP_ICON_EXCEPTION_RULES,
|
||||||
new ArrayList<>(AppIconRules.encodeExceptionRules(AppIconRules.loadExceptionRules(prefs))));
|
AppIconRules.encodeExceptionRules(AppIconRules.loadExceptionRules(prefs)));
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
if (METHOD_NOTE_SEEN_ICON_APP.equals(method)) {
|
if (METHOD_NOTE_SEEN_ICON_APP.equals(method)) {
|
||||||
@@ -477,13 +461,13 @@ public class SbtSettingsProvider extends ContentProvider {
|
|||||||
private static void putIconCopySettings(
|
private static void putIconCopySettings(
|
||||||
Bundle out,
|
Bundle out,
|
||||||
SharedPreferences prefs,
|
SharedPreferences prefs,
|
||||||
IndexedKey positionKey,
|
SbtSettings.IndexedKey positionKey,
|
||||||
String positionDefault,
|
String positionDefault,
|
||||||
IndexedKey middleSideKey,
|
SbtSettings.IndexedKey middleSideKey,
|
||||||
String middleSideDefault,
|
String middleSideDefault,
|
||||||
IndexedKey autoNearestKey,
|
SbtSettings.IndexedKey autoNearestKey,
|
||||||
boolean autoNearestDefault,
|
boolean autoNearestDefault,
|
||||||
IndexedKey verticalOffsetKey,
|
SbtSettings.IndexedKey verticalOffsetKey,
|
||||||
int verticalOffsetDefault
|
int verticalOffsetDefault
|
||||||
) {
|
) {
|
||||||
String position = positionDefault;
|
String position = positionDefault;
|
||||||
@@ -510,6 +494,19 @@ public class SbtSettingsProvider extends ContentProvider {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void putStringSetArrayList(Bundle out, SharedPreferences prefs, String key) {
|
||||||
|
putStringCollectionArrayList(out, key, prefs.getStringSet(key, Collections.emptySet()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void putStringCollectionArrayList(
|
||||||
|
Bundle out,
|
||||||
|
String key,
|
||||||
|
Collection<String> values
|
||||||
|
) {
|
||||||
|
out.putStringArrayList(key, new ArrayList<>(
|
||||||
|
values != null ? values : Collections.<String>emptySet()));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
|
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ public final class SystemIconRules {
|
|||||||
public static final int MODE_AOD = 1;
|
public static final int MODE_AOD = 1;
|
||||||
public static final int MODE_LOCK = 1 << 1;
|
public static final int MODE_LOCK = 1 << 1;
|
||||||
public static final int MODE_UNLOCK = 1 << 2;
|
public static final int MODE_UNLOCK = 1 << 2;
|
||||||
|
private static final int ALL_MODES = MODE_AOD | MODE_LOCK | MODE_UNLOCK;
|
||||||
private static final String MODE_NAME_AOD = "AOD";
|
private static final String MODE_NAME_AOD = "AOD";
|
||||||
private static final String MODE_NAME_LOCK = "LOCK";
|
private static final String MODE_NAME_LOCK = "LOCK";
|
||||||
private static final String MODE_NAME_UNLOCK = "UNLOCK";
|
private static final String MODE_NAME_UNLOCK = "UNLOCK";
|
||||||
@@ -42,10 +43,10 @@ public final class SystemIconRules {
|
|||||||
int mask;
|
int mask;
|
||||||
try {
|
try {
|
||||||
mask = Integer.parseInt(parts[1].trim());
|
mask = Integer.parseInt(parts[1].trim());
|
||||||
} catch (Throwable ignored) {
|
} catch (NumberFormatException ignored) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
mask &= (MODE_AOD | MODE_LOCK | MODE_UNLOCK);
|
mask &= ALL_MODES;
|
||||||
if (mask == 0) {
|
if (mask == 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -69,7 +70,7 @@ public final class SystemIconRules {
|
|||||||
if (maskObj == null) {
|
if (maskObj == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
int mask = maskObj & (MODE_AOD | MODE_LOCK | MODE_UNLOCK);
|
int mask = maskObj & ALL_MODES;
|
||||||
if (mask == 0) {
|
if (mask == 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -106,7 +107,7 @@ public final class SystemIconRules {
|
|||||||
if (normalizedSlot == null) {
|
if (normalizedSlot == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int validModeMask = modeMask & (MODE_AOD | MODE_LOCK | MODE_UNLOCK);
|
int validModeMask = modeMask & ALL_MODES;
|
||||||
if (validModeMask == 0) {
|
if (validModeMask == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -270,7 +270,7 @@ public final class BatteryBarFragment extends Fragment {
|
|||||||
try {
|
try {
|
||||||
java.lang.reflect.Method method = target.getClass().getMethod(methodName, int.class);
|
java.lang.reflect.Method method = target.getClass().getMethod(methodName, int.class);
|
||||||
method.invoke(target, value);
|
method.invoke(target, value);
|
||||||
} catch (Throwable ignored) {
|
} catch (Exception ignored) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -304,14 +304,14 @@ public final class BatteryBarFragment extends Fragment {
|
|||||||
final boolean[] updating = new boolean[]{false};
|
final boolean[] updating = new boolean[]{false};
|
||||||
if (minus != null) {
|
if (minus != null) {
|
||||||
minus.setOnClickListener(v -> {
|
minus.setOnClickListener(v -> {
|
||||||
int current = parseIntInput(input, prefs.getInt(key, fallback));
|
int current = ViewTreeSupport.parseInt(input, prefs.getInt(key, fallback));
|
||||||
persistInt(prefs, key, clampInt(current - 1, min, max), input, updating);
|
persistInt(prefs, key, ViewTreeSupport.clamp(current - 1, min, max), input, updating);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (plus != null) {
|
if (plus != null) {
|
||||||
plus.setOnClickListener(v -> {
|
plus.setOnClickListener(v -> {
|
||||||
int current = parseIntInput(input, prefs.getInt(key, fallback));
|
int current = ViewTreeSupport.parseInt(input, prefs.getInt(key, fallback));
|
||||||
persistInt(prefs, key, clampInt(current + 1, min, max), input, updating);
|
persistInt(prefs, key, ViewTreeSupport.clamp(current + 1, min, max), input, updating);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (input != null) {
|
if (input != null) {
|
||||||
@@ -333,16 +333,16 @@ public final class BatteryBarFragment extends Fragment {
|
|||||||
if (text.isEmpty()) {
|
if (text.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int current = parseIntInput(input, prefs.getInt(key, fallback));
|
int current = ViewTreeSupport.parseInt(input, prefs.getInt(key, fallback));
|
||||||
persistInt(prefs, key, clampInt(current, min, max), input, updating);
|
persistInt(prefs, key, ViewTreeSupport.clamp(current, min, max), input, updating);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
input.setOnFocusChangeListener((v, hasFocus) -> {
|
input.setOnFocusChangeListener((v, hasFocus) -> {
|
||||||
if (hasFocus) {
|
if (hasFocus) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int current = parseIntInput(input, prefs.getInt(key, fallback));
|
int current = ViewTreeSupport.parseInt(input, prefs.getInt(key, fallback));
|
||||||
persistInt(prefs, key, clampInt(current, min, max), input, updating);
|
persistInt(prefs, key, ViewTreeSupport.clamp(current, min, max), input, updating);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -360,9 +360,9 @@ public final class BatteryBarFragment extends Fragment {
|
|||||||
int min = Math.round(values.get(0));
|
int min = Math.round(values.get(0));
|
||||||
int max = Math.round(values.get(1));
|
int max = Math.round(values.get(1));
|
||||||
if (lower) {
|
if (lower) {
|
||||||
min = clampInt(min + delta, SbtDefaults.BATTERY_BAR_MIN_LEVEL_MIN, max - 1);
|
min = ViewTreeSupport.clamp(min + delta, SbtDefaults.BATTERY_BAR_MIN_LEVEL_MIN, max - 1);
|
||||||
} else {
|
} else {
|
||||||
max = clampInt(max + delta, min + 1, SbtDefaults.BATTERY_BAR_MAX_LEVEL_MAX);
|
max = ViewTreeSupport.clamp(max + delta, min + 1, SbtDefaults.BATTERY_BAR_MAX_LEVEL_MAX);
|
||||||
}
|
}
|
||||||
persistMapping(prefs, min, max, slider, minLabel, maxLabel);
|
persistMapping(prefs, min, max, slider, minLabel, maxLabel);
|
||||||
}
|
}
|
||||||
@@ -373,8 +373,8 @@ public final class BatteryBarFragment extends Fragment {
|
|||||||
RangeSlider slider,
|
RangeSlider slider,
|
||||||
TextView minLabel,
|
TextView minLabel,
|
||||||
TextView maxLabel) {
|
TextView maxLabel) {
|
||||||
min = clampInt(min, SbtDefaults.BATTERY_BAR_MIN_LEVEL_MIN, SbtDefaults.BATTERY_BAR_MIN_LEVEL_MAX);
|
min = ViewTreeSupport.clamp(min, SbtDefaults.BATTERY_BAR_MIN_LEVEL_MIN, SbtDefaults.BATTERY_BAR_MIN_LEVEL_MAX);
|
||||||
max = clampInt(max, SbtDefaults.BATTERY_BAR_MAX_LEVEL_MIN, SbtDefaults.BATTERY_BAR_MAX_LEVEL_MAX);
|
max = ViewTreeSupport.clamp(max, SbtDefaults.BATTERY_BAR_MAX_LEVEL_MIN, SbtDefaults.BATTERY_BAR_MAX_LEVEL_MAX);
|
||||||
if (max <= min) {
|
if (max <= min) {
|
||||||
max = Math.min(SbtDefaults.BATTERY_BAR_MAX_LEVEL_MAX, min + 1);
|
max = Math.min(SbtDefaults.BATTERY_BAR_MAX_LEVEL_MAX, min + 1);
|
||||||
if (max <= min) {
|
if (max <= min) {
|
||||||
@@ -442,9 +442,7 @@ public final class BatteryBarFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private ArrayList<BatteryBarStyle.Threshold> loadThresholds(SharedPreferences prefs) {
|
private ArrayList<BatteryBarStyle.Threshold> loadThresholds(SharedPreferences prefs) {
|
||||||
return BatteryBarStyle.decodeThresholds(prefs.getStringSet(
|
return BatteryBarStyle.loadThresholds(prefs, SbtSettings.KEY_BATTERY_BAR_THRESHOLDS);
|
||||||
SbtSettings.KEY_BATTERY_BAR_THRESHOLDS,
|
|
||||||
java.util.Collections.emptySet()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private ArrayList<BatteryBarStyle.Threshold> sortedThresholdsForUi(SharedPreferences prefs) {
|
private ArrayList<BatteryBarStyle.Threshold> sortedThresholdsForUi(SharedPreferences prefs) {
|
||||||
@@ -466,12 +464,12 @@ public final class BatteryBarFragment extends Fragment {
|
|||||||
LinearLayout row = new LinearLayout(context);
|
LinearLayout row = new LinearLayout(context);
|
||||||
row.setOrientation(LinearLayout.VERTICAL);
|
row.setOrientation(LinearLayout.VERTICAL);
|
||||||
row.setBackgroundResource(R.drawable.sbt_threshold_card);
|
row.setBackgroundResource(R.drawable.sbt_threshold_card);
|
||||||
int padding = dpToPx(context, 12);
|
int padding = ViewTreeSupport.dp(context, 12);
|
||||||
row.setPadding(padding, padding, padding, padding);
|
row.setPadding(padding, padding, padding, padding);
|
||||||
LinearLayout.LayoutParams rowParams = new LinearLayout.LayoutParams(
|
LinearLayout.LayoutParams rowParams = new LinearLayout.LayoutParams(
|
||||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||||
ViewGroup.LayoutParams.WRAP_CONTENT);
|
ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||||
rowParams.topMargin = dpToPx(context, 12);
|
rowParams.topMargin = ViewTreeSupport.dp(context, 12);
|
||||||
row.setLayoutParams(rowParams);
|
row.setLayoutParams(rowParams);
|
||||||
|
|
||||||
TextView title = new TextView(context);
|
TextView title = new TextView(context);
|
||||||
@@ -550,7 +548,7 @@ public final class BatteryBarFragment extends Fragment {
|
|||||||
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
|
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
|
||||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||||
ViewGroup.LayoutParams.WRAP_CONTENT);
|
ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||||
params.topMargin = dpToPx(context, 8);
|
params.topMargin = ViewTreeSupport.dp(context, 8);
|
||||||
button.setLayoutParams(params);
|
button.setLayoutParams(params);
|
||||||
return button;
|
return button;
|
||||||
}
|
}
|
||||||
@@ -656,9 +654,9 @@ public final class BatteryBarFragment extends Fragment {
|
|||||||
LinearLayout layout = new LinearLayout(context);
|
LinearLayout layout = new LinearLayout(context);
|
||||||
layout.setOrientation(LinearLayout.VERTICAL);
|
layout.setOrientation(LinearLayout.VERTICAL);
|
||||||
layout.setPadding(
|
layout.setPadding(
|
||||||
dpToPx(context, 24),
|
ViewTreeSupport.dp(context, 24),
|
||||||
dpToPx(context, 8),
|
ViewTreeSupport.dp(context, 8),
|
||||||
dpToPx(context, 24),
|
ViewTreeSupport.dp(context, 24),
|
||||||
0);
|
0);
|
||||||
EditText input = new EditText(context);
|
EditText input = new EditText(context);
|
||||||
input.setInputType(InputType.TYPE_CLASS_TEXT);
|
input.setInputType(InputType.TYPE_CLASS_TEXT);
|
||||||
@@ -677,7 +675,7 @@ public final class BatteryBarFragment extends Fragment {
|
|||||||
LinearLayout.LayoutParams noteParams = new LinearLayout.LayoutParams(
|
LinearLayout.LayoutParams noteParams = new LinearLayout.LayoutParams(
|
||||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||||
ViewGroup.LayoutParams.WRAP_CONTENT);
|
ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||||
noteParams.topMargin = dpToPx(context, 8);
|
noteParams.topMargin = ViewTreeSupport.dp(context, 8);
|
||||||
note.setLayoutParams(noteParams);
|
note.setLayoutParams(noteParams);
|
||||||
note.setGravity(Gravity.START);
|
note.setGravity(Gravity.START);
|
||||||
layout.addView(note);
|
layout.addView(note);
|
||||||
@@ -690,7 +688,7 @@ public final class BatteryBarFragment extends Fragment {
|
|||||||
LinearLayout.LayoutParams dischargeParams = new LinearLayout.LayoutParams(
|
LinearLayout.LayoutParams dischargeParams = new LinearLayout.LayoutParams(
|
||||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||||
ViewGroup.LayoutParams.WRAP_CONTENT);
|
ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||||
dischargeParams.topMargin = dpToPx(context, 8);
|
dischargeParams.topMargin = ViewTreeSupport.dp(context, 8);
|
||||||
sameAsDischargeButton.setLayoutParams(dischargeParams);
|
sameAsDischargeButton.setLayoutParams(dischargeParams);
|
||||||
layout.addView(sameAsDischargeButton);
|
layout.addView(sameAsDischargeButton);
|
||||||
|
|
||||||
@@ -702,7 +700,7 @@ public final class BatteryBarFragment extends Fragment {
|
|||||||
LinearLayout.LayoutParams defaultParams = new LinearLayout.LayoutParams(
|
LinearLayout.LayoutParams defaultParams = new LinearLayout.LayoutParams(
|
||||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||||
ViewGroup.LayoutParams.WRAP_CONTENT);
|
ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||||
defaultParams.topMargin = dpToPx(context, 8);
|
defaultParams.topMargin = ViewTreeSupport.dp(context, 8);
|
||||||
sameAsDefaultButton.setLayoutParams(defaultParams);
|
sameAsDefaultButton.setLayoutParams(defaultParams);
|
||||||
layout.addView(sameAsDefaultButton);
|
layout.addView(sameAsDefaultButton);
|
||||||
}
|
}
|
||||||
@@ -752,7 +750,7 @@ public final class BatteryBarFragment extends Fragment {
|
|||||||
.setNegativeButton(android.R.string.cancel, null)
|
.setNegativeButton(android.R.string.cancel, null)
|
||||||
.setPositiveButton(android.R.string.ok, (dialogInterface, which) -> {
|
.setPositiveButton(android.R.string.ok, (dialogInterface, which) -> {
|
||||||
int percent = BatteryBarStyle.clampPercent(
|
int percent = BatteryBarStyle.clampPercent(
|
||||||
parseIntInput(input, existing != null ? existing.percent : 15));
|
ViewTreeSupport.parseInt(input, existing != null ? existing.percent : 15));
|
||||||
if (existing == null && containsThreshold(loadThresholds(prefs), percent, -1)) {
|
if (existing == null && containsThreshold(loadThresholds(prefs), percent, -1)) {
|
||||||
showMessageDialog(R.string.battery_bar_threshold_duplicate);
|
showMessageDialog(R.string.battery_bar_threshold_duplicate);
|
||||||
return;
|
return;
|
||||||
@@ -770,45 +768,12 @@ public final class BatteryBarFragment extends Fragment {
|
|||||||
.show();
|
.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
private int parseIntInput(EditText input, int fallback) {
|
|
||||||
if (input == null) {
|
|
||||||
return fallback;
|
|
||||||
}
|
|
||||||
String text = input.getText() != null ? input.getText().toString().trim() : "";
|
|
||||||
if (text.isEmpty() || "-".equals(text)) {
|
|
||||||
return fallback;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
return Integer.parseInt(text);
|
|
||||||
} catch (NumberFormatException ignored) {
|
|
||||||
return fallback;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setIntInput(EditText input, int value) {
|
private void setIntInput(EditText input, int value) {
|
||||||
if (input != null) {
|
if (input != null) {
|
||||||
input.setText(String.valueOf(value));
|
input.setText(String.valueOf(value));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private int clampInt(int value, int min, int max) {
|
|
||||||
if (value < min) {
|
|
||||||
return min;
|
|
||||||
}
|
|
||||||
if (value > max) {
|
|
||||||
return max;
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int dpToPx(Context context, int dp) {
|
|
||||||
if (context == null) {
|
|
||||||
return dp;
|
|
||||||
}
|
|
||||||
float density = context.getResources().getDisplayMetrics().density;
|
|
||||||
return (int) (dp * density + 0.5f);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void applyPositionSelection(RadioButton top,
|
private void applyPositionSelection(RadioButton top,
|
||||||
RadioButton bottom,
|
RadioButton bottom,
|
||||||
String position) {
|
String position) {
|
||||||
|
|||||||
+1
-14
@@ -137,7 +137,7 @@ public class BlockAppNotificationIconsFragment extends Fragment {
|
|||||||
View content = root.findViewById(R.id.hidden_apps_content);
|
View content = root.findViewById(R.id.hidden_apps_content);
|
||||||
TextView disabledHint = root.findViewById(R.id.hidden_apps_disabled_hint);
|
TextView disabledHint = root.findViewById(R.id.hidden_apps_disabled_hint);
|
||||||
if (content != null) {
|
if (content != null) {
|
||||||
setViewTreeEnabled(content, enabled);
|
ViewTreeSupport.setEnabledRecursive(content, enabled);
|
||||||
content.setAlpha(enabled ? 1f : 0.45f);
|
content.setAlpha(enabled ? 1f : 0.45f);
|
||||||
}
|
}
|
||||||
if (disabledHint != null) {
|
if (disabledHint != null) {
|
||||||
@@ -146,17 +146,4 @@ public class BlockAppNotificationIconsFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setViewTreeEnabled(View view, boolean enabled) {
|
|
||||||
if (view == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
view.setEnabled(enabled);
|
|
||||||
if (view instanceof ViewGroup) {
|
|
||||||
ViewGroup group = (ViewGroup) view;
|
|
||||||
for (int i = 0; i < group.getChildCount(); i++) {
|
|
||||||
setViewTreeEnabled(group.getChildAt(i), enabled);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -146,8 +146,8 @@ public final class ClockFragment extends Fragment {
|
|||||||
|
|
||||||
LinearLayout container = new LinearLayout(context);
|
LinearLayout container = new LinearLayout(context);
|
||||||
container.setOrientation(LinearLayout.VERTICAL);
|
container.setOrientation(LinearLayout.VERTICAL);
|
||||||
int padding = dpToPx(context, 20);
|
int padding = ViewTreeSupport.dp(context, 20);
|
||||||
container.setPadding(padding, dpToPx(context, 8), padding, 0);
|
container.setPadding(padding, ViewTreeSupport.dp(context, 8), padding, 0);
|
||||||
|
|
||||||
EditText searchInput = new EditText(context);
|
EditText searchInput = new EditText(context);
|
||||||
searchInput.setHint(R.string.clock_font_picker_hint);
|
searchInput.setHint(R.string.clock_font_picker_hint);
|
||||||
@@ -161,8 +161,8 @@ public final class ClockFragment extends Fragment {
|
|||||||
listView.setDividerHeight(0);
|
listView.setDividerHeight(0);
|
||||||
LinearLayout.LayoutParams listParams = new LinearLayout.LayoutParams(
|
LinearLayout.LayoutParams listParams = new LinearLayout.LayoutParams(
|
||||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||||
dpToPx(context, 360));
|
ViewTreeSupport.dp(context, 360));
|
||||||
listParams.topMargin = dpToPx(context, 12);
|
listParams.topMargin = ViewTreeSupport.dp(context, 12);
|
||||||
container.addView(listView, listParams);
|
container.addView(listView, listParams);
|
||||||
|
|
||||||
FontFamilyAdapter adapter = new FontFamilyAdapter(context, filteredFamilies);
|
FontFamilyAdapter adapter = new FontFamilyAdapter(context, filteredFamilies);
|
||||||
@@ -253,7 +253,7 @@ public final class ClockFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
String[] lines = raw.toString().split("\\n", -1);
|
String[] lines = raw.toString().split("\\n", -1);
|
||||||
SpannableStringBuilder builder = new SpannableStringBuilder();
|
SpannableStringBuilder builder = new SpannableStringBuilder();
|
||||||
int bulletGap = dpToPx(view.getContext(), 8);
|
int bulletGap = ViewTreeSupport.dp(view.getContext(), 8);
|
||||||
for (int i = 0; i < lines.length; i++) {
|
for (int i = 0; i < lines.length; i++) {
|
||||||
String line = lines[i];
|
String line = lines[i];
|
||||||
boolean bulleted = line.startsWith("\u2022");
|
boolean bulleted = line.startsWith("\u2022");
|
||||||
@@ -274,14 +274,6 @@ public final class ClockFragment extends Fragment {
|
|||||||
view.setText(builder);
|
view.setText(builder);
|
||||||
}
|
}
|
||||||
|
|
||||||
private int dpToPx(Context context, int dp) {
|
|
||||||
if (context == null) {
|
|
||||||
return dp;
|
|
||||||
}
|
|
||||||
float density = context.getResources().getDisplayMetrics().density;
|
|
||||||
return Math.round(dp * density);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final class FontFamilyAdapter extends BaseAdapter {
|
private static final class FontFamilyAdapter extends BaseAdapter {
|
||||||
private static final String SAMPLE_PATTERN = "EEEE HH:mm:ss";
|
private static final String SAMPLE_PATTERN = "EEEE HH:mm:ss";
|
||||||
|
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ import java.util.Map;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.TimeZone;
|
import java.util.TimeZone;
|
||||||
|
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
final class HiddenAppsUiSupport {
|
final class HiddenAppsUiSupport {
|
||||||
interface RowChangedListener {
|
interface RowChangedListener {
|
||||||
void onChanged(RowItem row);
|
void onChanged(RowItem row);
|
||||||
@@ -147,12 +148,14 @@ final class HiddenAppsUiSupport {
|
|||||||
String label = packageName;
|
String label = packageName;
|
||||||
Drawable icon = fallbackIcon;
|
Drawable icon = fallbackIcon;
|
||||||
try {
|
try {
|
||||||
ApplicationInfo appInfo = packageManager.getApplicationInfo(packageName, 0);
|
ApplicationInfo appInfo = packageManager.getApplicationInfo(
|
||||||
|
packageName,
|
||||||
|
PackageManager.ApplicationInfoFlags.of(0));
|
||||||
CharSequence cs = packageManager.getApplicationLabel(appInfo);
|
CharSequence cs = packageManager.getApplicationLabel(appInfo);
|
||||||
if (cs != null && cs.length() > 0) {
|
if (cs != null && cs.length() > 0) {
|
||||||
label = cs.toString();
|
label = cs.toString();
|
||||||
}
|
}
|
||||||
icon = packageManager.getApplicationIcon(appInfo);
|
icon = packageManager.getApplicationIcon(packageName);
|
||||||
} catch (PackageManager.NameNotFoundException ignored) {
|
} catch (PackageManager.NameNotFoundException ignored) {
|
||||||
// Keep fallback label/icon.
|
// Keep fallback label/icon.
|
||||||
}
|
}
|
||||||
@@ -632,8 +635,11 @@ final class HiddenAppsUiSupport {
|
|||||||
holder.label.setText(row.label);
|
holder.label.setText(row.label);
|
||||||
int exceptionCount = row.exceptionCount();
|
int exceptionCount = row.exceptionCount();
|
||||||
if (exceptionCount > 0) {
|
if (exceptionCount > 0) {
|
||||||
holder.pkg.setText(context.getString(
|
holder.pkg.setText(context.getResources().getQuantityString(
|
||||||
R.string.hidden_apps_package_with_exceptions, row.packageName, exceptionCount));
|
R.plurals.hidden_apps_package_with_exceptions,
|
||||||
|
exceptionCount,
|
||||||
|
row.packageName,
|
||||||
|
exceptionCount));
|
||||||
} else {
|
} else {
|
||||||
holder.pkg.setText(row.packageName);
|
holder.pkg.setText(row.packageName);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,8 @@ import com.google.android.material.button.MaterialButton;
|
|||||||
import com.google.android.material.switchmaterial.SwitchMaterial;
|
import com.google.android.material.switchmaterial.SwitchMaterial;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import se.ajpanton.statusbartweak.R;
|
import se.ajpanton.statusbartweak.R;
|
||||||
@@ -82,37 +84,55 @@ public class IconsDebugFragment extends Fragment {
|
|||||||
|
|
||||||
SharedPreferences prefs = requireContext()
|
SharedPreferences prefs = requireContext()
|
||||||
.getSharedPreferences(SbtSettings.PREFS_NAME, Context.MODE_PRIVATE);
|
.getSharedPreferences(SbtSettings.PREFS_NAME, Context.MODE_PRIVATE);
|
||||||
bindWriteLogsSwitch(prefs, writeLogsSwitch);
|
ViewTreeSupport.bindBooleanPreference(
|
||||||
bindBooleanSwitch(
|
requireContext(),
|
||||||
|
prefs,
|
||||||
|
writeLogsSwitch,
|
||||||
|
SbtSettings.KEY_DEBUG_WRITE_LOGS,
|
||||||
|
SbtDefaults.DEBUG_WRITE_LOGS_DEFAULT,
|
||||||
|
true);
|
||||||
|
ViewTreeSupport.bindBooleanPreference(
|
||||||
|
requireContext(),
|
||||||
prefs,
|
prefs,
|
||||||
visualizeNotificationContainerSwitch,
|
visualizeNotificationContainerSwitch,
|
||||||
SbtSettings.KEY_DEBUG_VISUALIZE_NOTIFICATION_CONTAINER,
|
SbtSettings.KEY_DEBUG_VISUALIZE_NOTIFICATION_CONTAINER,
|
||||||
SbtDefaults.DEBUG_VISUALIZE_NOTIFICATION_CONTAINER_DEFAULT);
|
SbtDefaults.DEBUG_VISUALIZE_NOTIFICATION_CONTAINER_DEFAULT,
|
||||||
bindBooleanSwitch(
|
true);
|
||||||
|
ViewTreeSupport.bindBooleanPreference(
|
||||||
|
requireContext(),
|
||||||
prefs,
|
prefs,
|
||||||
visualizeStatusContainerSwitch,
|
visualizeStatusContainerSwitch,
|
||||||
SbtSettings.KEY_DEBUG_VISUALIZE_STATUS_CONTAINER,
|
SbtSettings.KEY_DEBUG_VISUALIZE_STATUS_CONTAINER,
|
||||||
SbtDefaults.DEBUG_VISUALIZE_STATUS_CONTAINER_DEFAULT);
|
SbtDefaults.DEBUG_VISUALIZE_STATUS_CONTAINER_DEFAULT,
|
||||||
bindBooleanSwitch(
|
true);
|
||||||
|
ViewTreeSupport.bindBooleanPreference(
|
||||||
|
requireContext(),
|
||||||
prefs,
|
prefs,
|
||||||
visualizeClockContainerSwitch,
|
visualizeClockContainerSwitch,
|
||||||
SbtSettings.KEY_DEBUG_VISUALIZE_CLOCK_CONTAINER,
|
SbtSettings.KEY_DEBUG_VISUALIZE_CLOCK_CONTAINER,
|
||||||
SbtDefaults.DEBUG_VISUALIZE_CLOCK_CONTAINER_DEFAULT);
|
SbtDefaults.DEBUG_VISUALIZE_CLOCK_CONTAINER_DEFAULT,
|
||||||
bindBooleanSwitch(
|
true);
|
||||||
|
ViewTreeSupport.bindBooleanPreference(
|
||||||
|
requireContext(),
|
||||||
prefs,
|
prefs,
|
||||||
visualizeChipContainerSwitch,
|
visualizeChipContainerSwitch,
|
||||||
SbtSettings.KEY_DEBUG_VISUALIZE_CHIP_CONTAINER,
|
SbtSettings.KEY_DEBUG_VISUALIZE_CHIP_CONTAINER,
|
||||||
SbtDefaults.DEBUG_VISUALIZE_CHIP_CONTAINER_DEFAULT);
|
SbtDefaults.DEBUG_VISUALIZE_CHIP_CONTAINER_DEFAULT,
|
||||||
bindBooleanSwitch(
|
true);
|
||||||
|
ViewTreeSupport.bindBooleanPreference(
|
||||||
|
requireContext(),
|
||||||
prefs,
|
prefs,
|
||||||
visualizeCameraCutoutSwitch,
|
visualizeCameraCutoutSwitch,
|
||||||
SbtSettings.KEY_DEBUG_VISUALIZE_CAMERA_CUTOUT,
|
SbtSettings.KEY_DEBUG_VISUALIZE_CAMERA_CUTOUT,
|
||||||
SbtDefaults.DEBUG_VISUALIZE_CAMERA_CUTOUT_DEFAULT);
|
SbtDefaults.DEBUG_VISUALIZE_CAMERA_CUTOUT_DEFAULT,
|
||||||
bindBooleanSwitch(
|
true);
|
||||||
|
ViewTreeSupport.bindBooleanPreference(
|
||||||
|
requireContext(),
|
||||||
prefs,
|
prefs,
|
||||||
visualizeAodStockContainersSwitch,
|
visualizeAodStockContainersSwitch,
|
||||||
SbtSettings.KEY_DEBUG_VISUALIZE_AOD_STOCK_CONTAINERS,
|
SbtSettings.KEY_DEBUG_VISUALIZE_AOD_STOCK_CONTAINERS,
|
||||||
SbtDefaults.DEBUG_VISUALIZE_AOD_STOCK_CONTAINERS_DEFAULT);
|
SbtDefaults.DEBUG_VISUALIZE_AOD_STOCK_CONTAINERS_DEFAULT,
|
||||||
|
true);
|
||||||
bindRestartSystemUiButton(restartSystemUiButton);
|
bindRestartSystemUiButton(restartSystemUiButton);
|
||||||
updateVisualizerSwitchAvailability(
|
updateVisualizerSwitchAvailability(
|
||||||
prefs,
|
prefs,
|
||||||
@@ -163,33 +183,6 @@ public class IconsDebugFragment extends Fragment {
|
|||||||
return root;
|
return root;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void bindWriteLogsSwitch(SharedPreferences prefs, SwitchMaterial writeLogsSwitch) {
|
|
||||||
if (prefs == null || writeLogsSwitch == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
writeLogsSwitch.setChecked(prefs.getBoolean(
|
|
||||||
SbtSettings.KEY_DEBUG_WRITE_LOGS,
|
|
||||||
SbtDefaults.DEBUG_WRITE_LOGS_DEFAULT));
|
|
||||||
writeLogsSwitch.setOnCheckedChangeListener((buttonView, isChecked) -> {
|
|
||||||
prefs.edit().putBoolean(SbtSettings.KEY_DEBUG_WRITE_LOGS, isChecked).commit();
|
|
||||||
SbtSettings.ensureReadable(requireContext());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void bindBooleanSwitch(SharedPreferences prefs,
|
|
||||||
SwitchMaterial switchView,
|
|
||||||
String key,
|
|
||||||
boolean defaultValue) {
|
|
||||||
if (prefs == null || switchView == null || key == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
switchView.setChecked(prefs.getBoolean(key, defaultValue));
|
|
||||||
switchView.setOnCheckedChangeListener((buttonView, isChecked) -> {
|
|
||||||
prefs.edit().putBoolean(key, isChecked).commit();
|
|
||||||
SbtSettings.ensureReadable(requireContext());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void bindRestartSystemUiButton(MaterialButton restartButton) {
|
private void bindRestartSystemUiButton(MaterialButton restartButton) {
|
||||||
if (restartButton == null) {
|
if (restartButton == null) {
|
||||||
return;
|
return;
|
||||||
@@ -236,7 +229,7 @@ public class IconsDebugFragment extends Fragment {
|
|||||||
.redirectErrorStream(true)
|
.redirectErrorStream(true)
|
||||||
.start();
|
.start();
|
||||||
success = process.waitFor() == 0;
|
success = process.waitFor() == 0;
|
||||||
} catch (Throwable ignored) {
|
} catch (Exception ignored) {
|
||||||
}
|
}
|
||||||
if (!success && isAdded()) {
|
if (!success && isAdded()) {
|
||||||
requireActivity().runOnUiThread(() -> Toast.makeText(
|
requireActivity().runOnUiThread(() -> Toast.makeText(
|
||||||
@@ -284,6 +277,7 @@ public class IconsDebugFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
private void ensureNotificationPermission() {
|
private void ensureNotificationPermission() {
|
||||||
Context context = requireContext();
|
Context context = requireContext();
|
||||||
if (ContextCompat.checkSelfPermission(context, Manifest.permission.POST_NOTIFICATIONS)
|
if (ContextCompat.checkSelfPermission(context, Manifest.permission.POST_NOTIFICATIONS)
|
||||||
@@ -297,6 +291,7 @@ public class IconsDebugFragment extends Fragment {
|
|||||||
Toast.LENGTH_SHORT).show();
|
Toast.LENGTH_SHORT).show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
@Override
|
@Override
|
||||||
public void onRequestPermissionsResult(int requestCode,
|
public void onRequestPermissionsResult(int requestCode,
|
||||||
@NonNull String[] permissions,
|
@NonNull String[] permissions,
|
||||||
@@ -329,10 +324,9 @@ public class IconsDebugFragment extends Fragment {
|
|||||||
? prefs.getString(SbtSettings.KEY_DEBUG_CURRENT_CAMERA_EFFECTIVE_TYPE, "")
|
? prefs.getString(SbtSettings.KEY_DEBUG_CURRENT_CAMERA_EFFECTIVE_TYPE, "")
|
||||||
: "";
|
: "";
|
||||||
|
|
||||||
Map<String, String> overrides = ClockCameraTypeSupport.parseOverrides(
|
Map<String, String> overrides = ClockCameraTypeSupport.loadOverrides(
|
||||||
prefs != null
|
prefs,
|
||||||
? prefs.getStringSet(SbtSettings.KEY_CLOCK_CAMERA_TYPE_OVERRIDES, java.util.Collections.emptySet())
|
SbtSettings.KEY_CLOCK_CAMERA_TYPE_OVERRIDES);
|
||||||
: java.util.Collections.emptySet());
|
|
||||||
|
|
||||||
if (TextUtils.isEmpty(cameraId)) {
|
if (TextUtils.isEmpty(cameraId)) {
|
||||||
identifiedView.setText(getString(R.string.debug_camera_identified_as,
|
identifiedView.setText(getString(R.string.debug_camera_identified_as,
|
||||||
@@ -376,7 +370,7 @@ public class IconsDebugFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
otherList.removeAllViews();
|
otherList.removeAllViews();
|
||||||
ArrayList<String> keys = new ArrayList<>(overrides.keySet());
|
ArrayList<String> keys = new ArrayList<>(overrides.keySet());
|
||||||
java.util.Collections.sort(keys);
|
Collections.sort(keys);
|
||||||
int shown = 0;
|
int shown = 0;
|
||||||
for (String key : keys) {
|
for (String key : keys) {
|
||||||
if (!TextUtils.isEmpty(cameraId) && TextUtils.equals(key, cameraId)) {
|
if (!TextUtils.isEmpty(cameraId) && TextUtils.equals(key, cameraId)) {
|
||||||
@@ -400,7 +394,7 @@ public class IconsDebugFragment extends Fragment {
|
|||||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||||
ViewGroup.LayoutParams.WRAP_CONTENT);
|
ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||||
if (addTopMargin) {
|
if (addTopMargin) {
|
||||||
rowParams.topMargin = dpToPx(context, 8);
|
rowParams.topMargin = ViewTreeSupport.dp(context, 8);
|
||||||
}
|
}
|
||||||
row.setLayoutParams(rowParams);
|
row.setLayoutParams(rowParams);
|
||||||
|
|
||||||
@@ -439,9 +433,9 @@ public class IconsDebugFragment extends Fragment {
|
|||||||
if (prefs == null || TextUtils.isEmpty(cameraId)) {
|
if (prefs == null || TextUtils.isEmpty(cameraId)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Map<String, String> overrides = new java.util.HashMap<>(
|
Map<String, String> overrides = new HashMap<>(ClockCameraTypeSupport.loadOverrides(
|
||||||
ClockCameraTypeSupport.parseOverrides(
|
prefs,
|
||||||
prefs.getStringSet(SbtSettings.KEY_CLOCK_CAMERA_TYPE_OVERRIDES, java.util.Collections.emptySet())));
|
SbtSettings.KEY_CLOCK_CAMERA_TYPE_OVERRIDES));
|
||||||
overrides.put(cameraId, ClockCameraTypeSupport.normalizeType(type));
|
overrides.put(cameraId, ClockCameraTypeSupport.normalizeType(type));
|
||||||
ClockCameraTypeSupport.saveOverrides(prefs, SbtSettings.KEY_CLOCK_CAMERA_TYPE_OVERRIDES, overrides);
|
ClockCameraTypeSupport.saveOverrides(prefs, SbtSettings.KEY_CLOCK_CAMERA_TYPE_OVERRIDES, overrides);
|
||||||
SbtSettings.ensureReadable(requireContext());
|
SbtSettings.ensureReadable(requireContext());
|
||||||
@@ -451,9 +445,9 @@ public class IconsDebugFragment extends Fragment {
|
|||||||
if (prefs == null || TextUtils.isEmpty(cameraId)) {
|
if (prefs == null || TextUtils.isEmpty(cameraId)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Map<String, String> overrides = new java.util.HashMap<>(
|
Map<String, String> overrides = new HashMap<>(ClockCameraTypeSupport.loadOverrides(
|
||||||
ClockCameraTypeSupport.parseOverrides(
|
prefs,
|
||||||
prefs.getStringSet(SbtSettings.KEY_CLOCK_CAMERA_TYPE_OVERRIDES, java.util.Collections.emptySet())));
|
SbtSettings.KEY_CLOCK_CAMERA_TYPE_OVERRIDES));
|
||||||
overrides.remove(cameraId);
|
overrides.remove(cameraId);
|
||||||
ClockCameraTypeSupport.saveOverrides(prefs, SbtSettings.KEY_CLOCK_CAMERA_TYPE_OVERRIDES, overrides);
|
ClockCameraTypeSupport.saveOverrides(prefs, SbtSettings.KEY_CLOCK_CAMERA_TYPE_OVERRIDES, overrides);
|
||||||
SbtSettings.ensureReadable(requireContext());
|
SbtSettings.ensureReadable(requireContext());
|
||||||
@@ -462,11 +456,4 @@ public class IconsDebugFragment extends Fragment {
|
|||||||
return ClockCameraTypeSupport.formatType(type);
|
return ClockCameraTypeSupport.formatType(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
private int dpToPx(Context context, int dp) {
|
|
||||||
if (context == null) {
|
|
||||||
return dp;
|
|
||||||
}
|
|
||||||
float density = context.getResources().getDisplayMetrics().density;
|
|
||||||
return (int) (dp * density + 0.5f);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import android.text.Editable;
|
|||||||
import android.text.InputFilter;
|
import android.text.InputFilter;
|
||||||
import android.text.TextWatcher;
|
import android.text.TextWatcher;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.MotionEvent;
|
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.view.inputmethod.EditorInfo;
|
import android.view.inputmethod.EditorInfo;
|
||||||
@@ -24,16 +23,9 @@ import android.widget.TextView;
|
|||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
import androidx.recyclerview.widget.ItemTouchHelper;
|
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
|
||||||
|
|
||||||
import com.google.android.material.button.MaterialButton;
|
import com.google.android.material.button.MaterialButton;
|
||||||
import com.google.android.material.card.MaterialCardView;
|
import com.google.android.material.card.MaterialCardView;
|
||||||
import com.google.android.material.switchmaterial.SwitchMaterial;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public final class LayoutFragment extends Fragment {
|
public final class LayoutFragment extends Fragment {
|
||||||
private static final int PADDING_MIN = -999;
|
private static final int PADDING_MIN = -999;
|
||||||
@@ -50,15 +42,6 @@ public final class LayoutFragment extends Fragment {
|
|||||||
hideUnlockedSubpageObsoleteControls(root);
|
hideUnlockedSubpageObsoleteControls(root);
|
||||||
reorderItemCards(root, prefs);
|
reorderItemCards(root, prefs);
|
||||||
|
|
||||||
SwitchMaterial enabledSwitch = root.findViewById(R.id.clock_enabled_switch);
|
|
||||||
enabledSwitch.setChecked(prefs.getBoolean(
|
|
||||||
SbtSettings.KEY_CLOCK_ENABLED,
|
|
||||||
SbtDefaults.CLOCK_ENABLED_DEFAULT));
|
|
||||||
enabledSwitch.setOnCheckedChangeListener((buttonView, isChecked) -> {
|
|
||||||
prefs.edit().putBoolean(SbtSettings.KEY_CLOCK_ENABLED, isChecked).apply();
|
|
||||||
SbtSettings.ensureReadable(requireContext());
|
|
||||||
});
|
|
||||||
|
|
||||||
setupPositionSection(root,
|
setupPositionSection(root,
|
||||||
prefs,
|
prefs,
|
||||||
R.id.clock_position_group,
|
R.id.clock_position_group,
|
||||||
@@ -100,32 +83,6 @@ public final class LayoutFragment extends Fragment {
|
|||||||
SbtSettings.KEY_LAYOUT_STATUS_MIDDLE_AUTO_NEAREST_SIDE,
|
SbtSettings.KEY_LAYOUT_STATUS_MIDDLE_AUTO_NEAREST_SIDE,
|
||||||
SbtSettings.KEY_LAYOUT_STATUS_MIDDLE_SIDE);
|
SbtSettings.KEY_LAYOUT_STATUS_MIDDLE_SIDE);
|
||||||
|
|
||||||
bindStepper(prefs,
|
|
||||||
SbtSettings.KEY_LAYOUT_PADDING_CUTOUT_PX,
|
|
||||||
root.findViewById(R.id.layout_cutout_gap_input),
|
|
||||||
root.findViewById(R.id.layout_cutout_gap_minus),
|
|
||||||
root.findViewById(R.id.layout_cutout_gap_plus),
|
|
||||||
SbtDefaults.LAYOUT_PADDING_CUTOUT_PX_DEFAULT);
|
|
||||||
bindStepper(prefs,
|
|
||||||
SbtSettings.KEY_LAYOUT_PADDING_LEFT_PX,
|
|
||||||
root.findViewById(R.id.layout_left_padding_input),
|
|
||||||
root.findViewById(R.id.layout_left_padding_minus),
|
|
||||||
root.findViewById(R.id.layout_left_padding_plus),
|
|
||||||
SbtDefaults.LAYOUT_PADDING_LEFT_PX_DEFAULT);
|
|
||||||
bindStepper(prefs,
|
|
||||||
SbtSettings.KEY_LAYOUT_PADDING_RIGHT_PX,
|
|
||||||
root.findViewById(R.id.layout_right_padding_input),
|
|
||||||
root.findViewById(R.id.layout_right_padding_minus),
|
|
||||||
root.findViewById(R.id.layout_right_padding_plus),
|
|
||||||
SbtDefaults.LAYOUT_PADDING_RIGHT_PX_DEFAULT);
|
|
||||||
bindStepper(prefs,
|
|
||||||
SbtSettings.KEY_LAYOUT_ITEM_PADDING_PX,
|
|
||||||
root.findViewById(R.id.layout_item_padding_input),
|
|
||||||
root.findViewById(R.id.layout_item_padding_minus),
|
|
||||||
root.findViewById(R.id.layout_item_padding_plus),
|
|
||||||
SbtDefaults.LAYOUT_ITEM_PADDING_PX_DEFAULT,
|
|
||||||
SbtDefaults.LAYOUT_ITEM_PADDING_PX_MIN,
|
|
||||||
SbtDefaults.LAYOUT_ITEM_PADDING_PX_MAX);
|
|
||||||
bindStepper(prefs,
|
bindStepper(prefs,
|
||||||
SbtSettings.KEY_CLOCK_VERTICAL_OFFSET_PX,
|
SbtSettings.KEY_CLOCK_VERTICAL_OFFSET_PX,
|
||||||
root.findViewById(R.id.clock_vertical_offset_input),
|
root.findViewById(R.id.clock_vertical_offset_input),
|
||||||
@@ -163,19 +120,6 @@ public final class LayoutFragment extends Fragment {
|
|||||||
root.findViewById(R.id.status_vertical_offset_plus_fast),
|
root.findViewById(R.id.status_vertical_offset_plus_fast),
|
||||||
root.findViewById(R.id.status_vertical_offset_reset),
|
root.findViewById(R.id.status_vertical_offset_reset),
|
||||||
SbtDefaults.LAYOUT_STATUS_VERTICAL_OFFSET_PX_DEFAULT);
|
SbtDefaults.LAYOUT_STATUS_VERTICAL_OFFSET_PX_DEFAULT);
|
||||||
bindCheckBoxPref(prefs, root.findViewById(R.id.layout_left_padding_add_stock),
|
|
||||||
SbtSettings.KEY_LAYOUT_PADDING_LEFT_ADD_STOCK,
|
|
||||||
SbtDefaults.LAYOUT_PADDING_LEFT_ADD_STOCK_DEFAULT);
|
|
||||||
bindCheckBoxPref(prefs, root.findViewById(R.id.layout_right_padding_add_stock),
|
|
||||||
SbtSettings.KEY_LAYOUT_PADDING_RIGHT_ADD_STOCK,
|
|
||||||
SbtDefaults.LAYOUT_PADDING_RIGHT_ADD_STOCK_DEFAULT);
|
|
||||||
bindCheckBoxPref(prefs, root.findViewById(R.id.layout_ignore_under_display_cameras),
|
|
||||||
SbtSettings.KEY_LAYOUT_IGNORE_UNDER_DISPLAY_CAMERAS,
|
|
||||||
SbtDefaults.LAYOUT_IGNORE_UNDER_DISPLAY_CAMERAS_DEFAULT);
|
|
||||||
|
|
||||||
bindCheckBoxPref(prefs, root.findViewById(R.id.clock_position_mode_lockscreen),
|
|
||||||
SbtSettings.KEY_CLOCK_ENABLED_LOCKSCREEN,
|
|
||||||
SbtDefaults.CLOCK_ENABLED_LOCKSCREEN_DEFAULT);
|
|
||||||
bindCheckBoxPref(prefs, root.findViewById(R.id.clock_position_mode_unlocked),
|
bindCheckBoxPref(prefs, root.findViewById(R.id.clock_position_mode_unlocked),
|
||||||
SbtSettings.KEY_CLOCK_ENABLED_UNLOCKED,
|
SbtSettings.KEY_CLOCK_ENABLED_UNLOCKED,
|
||||||
SbtDefaults.CLOCK_ENABLED_UNLOCKED_DEFAULT);
|
SbtDefaults.CLOCK_ENABLED_UNLOCKED_DEFAULT);
|
||||||
@@ -187,33 +131,15 @@ public final class LayoutFragment extends Fragment {
|
|||||||
LayoutSectionCopySupport.Section.CLOCK,
|
LayoutSectionCopySupport.Section.CLOCK,
|
||||||
false,
|
false,
|
||||||
this::refreshSelf);
|
this::refreshSelf);
|
||||||
bindCheckBoxPref(prefs, root.findViewById(R.id.notif_position_mode_aod),
|
|
||||||
SbtSettings.KEY_LAYOUT_NOTIF_ENABLED_AOD,
|
|
||||||
SbtDefaults.LAYOUT_NOTIF_ENABLED_AOD_DEFAULT);
|
|
||||||
bindCheckBoxPref(prefs, root.findViewById(R.id.notif_position_mode_lockscreen),
|
|
||||||
SbtSettings.KEY_LAYOUT_NOTIF_ENABLED_LOCKSCREEN,
|
|
||||||
SbtDefaults.LAYOUT_NOTIF_ENABLED_LOCKSCREEN_DEFAULT);
|
|
||||||
bindCheckBoxPref(prefs, root.findViewById(R.id.notif_position_mode_unlocked),
|
bindCheckBoxPref(prefs, root.findViewById(R.id.notif_position_mode_unlocked),
|
||||||
SbtSettings.KEY_LAYOUT_NOTIF_ENABLED_UNLOCKED,
|
SbtSettings.KEY_LAYOUT_NOTIF_ENABLED_UNLOCKED,
|
||||||
SbtDefaults.LAYOUT_NOTIF_ENABLED_UNLOCKED_DEFAULT);
|
SbtDefaults.LAYOUT_NOTIF_ENABLED_UNLOCKED_DEFAULT);
|
||||||
bindCheckBoxPref(prefs, root.findViewById(R.id.chip_position_mode_lockscreen),
|
|
||||||
SbtSettings.KEY_LAYOUT_CHIP_ENABLED_LOCKSCREEN,
|
|
||||||
SbtDefaults.LAYOUT_CHIP_ENABLED_LOCKSCREEN_DEFAULT);
|
|
||||||
bindCheckBoxPref(prefs, root.findViewById(R.id.chip_position_mode_unlocked),
|
bindCheckBoxPref(prefs, root.findViewById(R.id.chip_position_mode_unlocked),
|
||||||
SbtSettings.KEY_LAYOUT_CHIP_ENABLED_UNLOCKED,
|
SbtSettings.KEY_LAYOUT_CHIP_ENABLED_UNLOCKED,
|
||||||
SbtDefaults.LAYOUT_CHIP_ENABLED_UNLOCKED_DEFAULT);
|
SbtDefaults.LAYOUT_CHIP_ENABLED_UNLOCKED_DEFAULT);
|
||||||
bindCheckBoxPref(prefs, root.findViewById(R.id.status_position_mode_aod),
|
|
||||||
SbtSettings.KEY_LAYOUT_STATUS_ENABLED_AOD,
|
|
||||||
SbtDefaults.LAYOUT_STATUS_ENABLED_AOD_DEFAULT);
|
|
||||||
bindCheckBoxPref(prefs, root.findViewById(R.id.status_position_mode_lockscreen),
|
|
||||||
SbtSettings.KEY_LAYOUT_STATUS_ENABLED_LOCKSCREEN,
|
|
||||||
SbtDefaults.LAYOUT_STATUS_ENABLED_LOCKSCREEN_DEFAULT);
|
|
||||||
bindCheckBoxPref(prefs, root.findViewById(R.id.status_position_mode_unlocked),
|
bindCheckBoxPref(prefs, root.findViewById(R.id.status_position_mode_unlocked),
|
||||||
SbtSettings.KEY_LAYOUT_STATUS_ENABLED_UNLOCKED,
|
SbtSettings.KEY_LAYOUT_STATUS_ENABLED_UNLOCKED,
|
||||||
SbtDefaults.LAYOUT_STATUS_ENABLED_UNLOCKED_DEFAULT);
|
SbtDefaults.LAYOUT_STATUS_ENABLED_UNLOCKED_DEFAULT);
|
||||||
bindSortOrderGroup(prefs, root.findViewById(R.id.layout_sort_icons_group));
|
|
||||||
|
|
||||||
setupOrderingList(root, prefs);
|
|
||||||
setupUnlockedIconContainerCount(
|
setupUnlockedIconContainerCount(
|
||||||
root,
|
root,
|
||||||
prefs,
|
prefs,
|
||||||
@@ -257,10 +183,6 @@ public final class LayoutFragment extends Fragment {
|
|||||||
return root;
|
return root;
|
||||||
}
|
}
|
||||||
|
|
||||||
private interface IndexedKey {
|
|
||||||
String key(int index);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setupUnlockedIconContainerCount(
|
private void setupUnlockedIconContainerCount(
|
||||||
View root,
|
View root,
|
||||||
SharedPreferences prefs,
|
SharedPreferences prefs,
|
||||||
@@ -270,10 +192,10 @@ public final class LayoutFragment extends Fragment {
|
|||||||
int countDefault,
|
int countDefault,
|
||||||
String legacyEnabledKey,
|
String legacyEnabledKey,
|
||||||
boolean legacyEnabledDefault,
|
boolean legacyEnabledDefault,
|
||||||
IndexedKey positionKey,
|
SbtSettings.IndexedKey positionKey,
|
||||||
IndexedKey autoNearestKey,
|
SbtSettings.IndexedKey autoNearestKey,
|
||||||
IndexedKey middleSideKey,
|
SbtSettings.IndexedKey middleSideKey,
|
||||||
IndexedKey verticalOffsetKey,
|
SbtSettings.IndexedKey verticalOffsetKey,
|
||||||
String iconHeightKey,
|
String iconHeightKey,
|
||||||
String positionDefault,
|
String positionDefault,
|
||||||
boolean autoNearestDefault,
|
boolean autoNearestDefault,
|
||||||
@@ -304,7 +226,7 @@ public final class LayoutFragment extends Fragment {
|
|||||||
countContainer.removeAllViews();
|
countContainer.removeAllViews();
|
||||||
removeGeneratedCopyCards(cardsParent, copyTag);
|
removeGeneratedCopyCards(cardsParent, copyTag);
|
||||||
int count = iconContainerCount(prefs, countKey, countDefault, legacyEnabledKey, legacyEnabledDefault);
|
int count = iconContainerCount(prefs, countKey, countDefault, legacyEnabledKey, legacyEnabledDefault);
|
||||||
updateIconCardTitle(sourceCard, sectionTitleId, 0, count);
|
LayoutXmlCardSupport.setIndexedCardTitle(requireContext(), sourceCard, sectionTitleId, 0, count);
|
||||||
boolean cardsMode = LockedNotificationModeUi.MODE_CARDS.equals(
|
boolean cardsMode = LockedNotificationModeUi.MODE_CARDS.equals(
|
||||||
LockedNotificationModeUi.currentMode(requireContext()));
|
LockedNotificationModeUi.currentMode(requireContext()));
|
||||||
LayoutSectionCopySupport.addDropdownRow(
|
LayoutSectionCopySupport.addDropdownRow(
|
||||||
@@ -379,31 +301,26 @@ public final class LayoutFragment extends Fragment {
|
|||||||
String legacyEnabledKey,
|
String legacyEnabledKey,
|
||||||
Runnable onChanged
|
Runnable onChanged
|
||||||
) {
|
) {
|
||||||
LinearLayout outer = new LinearLayout(requireContext());
|
Context context = requireContext();
|
||||||
outer.setOrientation(LinearLayout.VERTICAL);
|
LinearLayout outer = ViewTreeSupport.verticalLayout(context);
|
||||||
TextView label = new TextView(requireContext());
|
TextView label = ViewTreeSupport.bodyText(context, R.string.layout_icon_container_count, 0);
|
||||||
label.setText(R.string.layout_icon_container_count);
|
|
||||||
label.setPadding(0, dp(8), 0, 0);
|
|
||||||
outer.addView(label);
|
outer.addView(label);
|
||||||
|
|
||||||
LinearLayout row = new LinearLayout(requireContext());
|
LinearLayout row = new LinearLayout(context);
|
||||||
row.setOrientation(LinearLayout.HORIZONTAL);
|
row.setOrientation(LinearLayout.HORIZONTAL);
|
||||||
row.setGravity(android.view.Gravity.CENTER_VERTICAL);
|
row.setGravity(android.view.Gravity.CENTER_VERTICAL);
|
||||||
MaterialButton minus = smallButton("-");
|
MaterialButton minus = ViewTreeSupport.outlinedStepperButton(context, "-");
|
||||||
MaterialButton plus = smallButton("+");
|
MaterialButton plus = ViewTreeSupport.outlinedStepperButton(context, "+");
|
||||||
EditText input = new EditText(requireContext());
|
EditText input = ViewTreeSupport.numericInput(context, false, 1);
|
||||||
input.setGravity(android.view.Gravity.CENTER);
|
|
||||||
input.setSingleLine(true);
|
|
||||||
input.setInputType(android.text.InputType.TYPE_CLASS_NUMBER);
|
|
||||||
input.setFilters(new InputFilter[]{new InputFilter.LengthFilter(1)});
|
|
||||||
input.setText(String.valueOf(current));
|
input.setText(String.valueOf(current));
|
||||||
row.addView(minus, compactButtonParams());
|
row.addView(minus, ViewTreeSupport.stepperButtonParams(context));
|
||||||
row.addView(input, compactInputParams());
|
row.addView(input, ViewTreeSupport.stepperInputParams(context));
|
||||||
row.addView(plus, compactButtonParams());
|
row.addView(plus, ViewTreeSupport.stepperButtonParams(context));
|
||||||
outer.addView(row);
|
outer.addView(row);
|
||||||
|
|
||||||
View.OnClickListener listener = view -> {
|
View.OnClickListener listener = view -> {
|
||||||
int next = clampIconContainerCount(parseInt(input, current) + (view == minus ? -1 : 1));
|
int next = SbtSettings.clampIconContainerCount(
|
||||||
|
ViewTreeSupport.parseInt(input, current) + (view == minus ? -1 : 1));
|
||||||
persistIconContainerCount(prefs, countKey, legacyEnabledKey, next);
|
persistIconContainerCount(prefs, countKey, legacyEnabledKey, next);
|
||||||
onChanged.run();
|
onChanged.run();
|
||||||
};
|
};
|
||||||
@@ -411,7 +328,7 @@ public final class LayoutFragment extends Fragment {
|
|||||||
plus.setOnClickListener(listener);
|
plus.setOnClickListener(listener);
|
||||||
input.setOnFocusChangeListener((v, hasFocus) -> {
|
input.setOnFocusChangeListener((v, hasFocus) -> {
|
||||||
if (!hasFocus) {
|
if (!hasFocus) {
|
||||||
int next = clampIconContainerCount(parseInt(input, current));
|
int next = SbtSettings.clampIconContainerCount(ViewTreeSupport.parseInt(input, current));
|
||||||
persistIconContainerCount(prefs, countKey, legacyEnabledKey, next);
|
persistIconContainerCount(prefs, countKey, legacyEnabledKey, next);
|
||||||
onChanged.run();
|
onChanged.run();
|
||||||
}
|
}
|
||||||
@@ -425,71 +342,59 @@ public final class LayoutFragment extends Fragment {
|
|||||||
int defaultValue,
|
int defaultValue,
|
||||||
int labelRes
|
int labelRes
|
||||||
) {
|
) {
|
||||||
LinearLayout outer = new LinearLayout(requireContext());
|
Context context = requireContext();
|
||||||
outer.setOrientation(LinearLayout.VERTICAL);
|
LinearLayout outer = ViewTreeSupport.verticalLayout(context);
|
||||||
TextView label = new TextView(requireContext());
|
TextView label = ViewTreeSupport.bodyText(context, labelRes, 0);
|
||||||
label.setText(labelRes);
|
|
||||||
label.setPadding(0, dp(8), 0, 0);
|
|
||||||
outer.addView(label);
|
outer.addView(label);
|
||||||
|
|
||||||
LinearLayout row = new LinearLayout(requireContext());
|
LinearLayout row = new LinearLayout(context);
|
||||||
row.setOrientation(LinearLayout.HORIZONTAL);
|
row.setOrientation(LinearLayout.HORIZONTAL);
|
||||||
row.setGravity(android.view.Gravity.CENTER_VERTICAL);
|
row.setGravity(android.view.Gravity.CENTER_VERTICAL);
|
||||||
MaterialButton minus = smallButton("-");
|
MaterialButton minus = ViewTreeSupport.outlinedStepperButton(context, "-");
|
||||||
MaterialButton plus = smallButton("+");
|
MaterialButton plus = ViewTreeSupport.outlinedStepperButton(context, "+");
|
||||||
MaterialButton reset = smallButton("D");
|
MaterialButton reset = ViewTreeSupport.outlinedStepperButton(context, "D");
|
||||||
EditText input = new EditText(requireContext());
|
EditText input = ViewTreeSupport.numericInput(context, false, 3);
|
||||||
input.setGravity(android.view.Gravity.CENTER);
|
int current = SbtSettings.clampIconHeightSteps(prefs.getInt(key, defaultValue));
|
||||||
input.setSingleLine(true);
|
|
||||||
input.setInputType(android.text.InputType.TYPE_CLASS_NUMBER);
|
|
||||||
input.setFilters(new InputFilter[]{new InputFilter.LengthFilter(3)});
|
|
||||||
int current = clampValue(
|
|
||||||
prefs.getInt(key, defaultValue),
|
|
||||||
SbtDefaults.LAYOUT_ICON_HEIGHT_STEPS_MIN,
|
|
||||||
SbtDefaults.LAYOUT_ICON_HEIGHT_STEPS_MAX);
|
|
||||||
input.setText(String.valueOf(current));
|
input.setText(String.valueOf(current));
|
||||||
row.addView(minus, compactButtonParams());
|
row.addView(minus, ViewTreeSupport.stepperButtonParams(context));
|
||||||
row.addView(input, compactInputParams());
|
row.addView(input, ViewTreeSupport.stepperInputParams(context));
|
||||||
row.addView(plus, compactButtonParams());
|
row.addView(plus, ViewTreeSupport.stepperButtonParams(context));
|
||||||
LinearLayout.LayoutParams resetParams = compactButtonParams();
|
LinearLayout.LayoutParams resetParams = ViewTreeSupport.stepperButtonParams(context);
|
||||||
resetParams.leftMargin = dp(8);
|
resetParams.leftMargin = ViewTreeSupport.dp(context, 8);
|
||||||
row.addView(reset, resetParams);
|
row.addView(reset, resetParams);
|
||||||
outer.addView(row);
|
outer.addView(row);
|
||||||
|
|
||||||
View.OnClickListener listener = view -> {
|
View.OnClickListener listener = view -> {
|
||||||
int next = clampValue(
|
int next = SbtSettings.clampIconHeightSteps(
|
||||||
parseInt(input, current) + (view == minus ? -1 : 1),
|
ViewTreeSupport.parseInt(input, current) + (view == minus ? -1 : 1));
|
||||||
SbtDefaults.LAYOUT_ICON_HEIGHT_STEPS_MIN,
|
persistIconHeight(prefs, key, input, next);
|
||||||
SbtDefaults.LAYOUT_ICON_HEIGHT_STEPS_MAX);
|
|
||||||
prefs.edit().putInt(key, next).apply();
|
|
||||||
SbtSettings.ensureReadable(requireContext());
|
|
||||||
input.setText(String.valueOf(next));
|
|
||||||
};
|
};
|
||||||
minus.setOnClickListener(listener);
|
minus.setOnClickListener(listener);
|
||||||
plus.setOnClickListener(listener);
|
plus.setOnClickListener(listener);
|
||||||
reset.setOnClickListener(v -> {
|
reset.setOnClickListener(v -> {
|
||||||
int next = clampValue(
|
int next = SbtSettings.clampIconHeightSteps(defaultValue);
|
||||||
defaultValue,
|
persistIconHeight(prefs, key, input, next);
|
||||||
SbtDefaults.LAYOUT_ICON_HEIGHT_STEPS_MIN,
|
|
||||||
SbtDefaults.LAYOUT_ICON_HEIGHT_STEPS_MAX);
|
|
||||||
prefs.edit().putInt(key, next).apply();
|
|
||||||
SbtSettings.ensureReadable(requireContext());
|
|
||||||
input.setText(String.valueOf(next));
|
|
||||||
});
|
});
|
||||||
input.setOnFocusChangeListener((v, hasFocus) -> {
|
input.setOnFocusChangeListener((v, hasFocus) -> {
|
||||||
if (!hasFocus) {
|
if (!hasFocus) {
|
||||||
int next = clampValue(
|
int next = SbtSettings.clampIconHeightSteps(ViewTreeSupport.parseInt(input, current));
|
||||||
parseInt(input, current),
|
persistIconHeight(prefs, key, input, next);
|
||||||
SbtDefaults.LAYOUT_ICON_HEIGHT_STEPS_MIN,
|
|
||||||
SbtDefaults.LAYOUT_ICON_HEIGHT_STEPS_MAX);
|
|
||||||
prefs.edit().putInt(key, next).apply();
|
|
||||||
SbtSettings.ensureReadable(requireContext());
|
|
||||||
input.setText(String.valueOf(next));
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return outer;
|
return outer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void persistIconHeight(
|
||||||
|
SharedPreferences prefs,
|
||||||
|
String key,
|
||||||
|
EditText input,
|
||||||
|
int value
|
||||||
|
) {
|
||||||
|
prefs.edit().putInt(key, value).apply();
|
||||||
|
SbtSettings.ensureReadable(requireContext());
|
||||||
|
input.setText(String.valueOf(value));
|
||||||
|
}
|
||||||
|
|
||||||
private void addChipHeightControl(View root, SharedPreferences prefs) {
|
private void addChipHeightControl(View root, SharedPreferences prefs) {
|
||||||
View offsetInput = root.findViewById(R.id.chip_vertical_offset_input);
|
View offsetInput = root.findViewById(R.id.chip_vertical_offset_input);
|
||||||
if (offsetInput == null) {
|
if (offsetInput == null) {
|
||||||
@@ -518,10 +423,10 @@ public final class LayoutFragment extends Fragment {
|
|||||||
int sourceCheckboxId,
|
int sourceCheckboxId,
|
||||||
int titleId,
|
int titleId,
|
||||||
int index,
|
int index,
|
||||||
IndexedKey positionKey,
|
SbtSettings.IndexedKey positionKey,
|
||||||
IndexedKey autoNearestKey,
|
SbtSettings.IndexedKey autoNearestKey,
|
||||||
IndexedKey middleSideKey,
|
SbtSettings.IndexedKey middleSideKey,
|
||||||
IndexedKey verticalOffsetKey,
|
SbtSettings.IndexedKey verticalOffsetKey,
|
||||||
String positionDefault,
|
String positionDefault,
|
||||||
boolean autoNearestDefault,
|
boolean autoNearestDefault,
|
||||||
String middleSideDefault,
|
String middleSideDefault,
|
||||||
@@ -531,13 +436,10 @@ public final class LayoutFragment extends Fragment {
|
|||||||
int cardId = sourceCheckboxId == R.id.notif_position_mode_unlocked
|
int cardId = sourceCheckboxId == R.id.notif_position_mode_unlocked
|
||||||
? R.id.layout_notif_card
|
? R.id.layout_notif_card
|
||||||
: R.id.layout_status_card;
|
: R.id.layout_status_card;
|
||||||
View card = inflateLayoutCard(cardId);
|
View card = LayoutXmlCardSupport.inflateCard(requireContext(), null, cardId);
|
||||||
card.setTag(copyTag);
|
card.setTag(copyTag);
|
||||||
TextView title = findCardTitle(card);
|
LayoutXmlCardSupport.setIndexedCardTitle(requireContext(), card, titleId, index, index + 1);
|
||||||
if (title != null) {
|
LayoutXmlCardSupport.removeModeContainerForCheckbox(card, sourceCheckboxId);
|
||||||
title.setText(getString(titleId) + " " + (index + 1));
|
|
||||||
}
|
|
||||||
removeModeContainerForCheckbox(card, sourceCheckboxId);
|
|
||||||
SharedPreferences prefs = requireContext()
|
SharedPreferences prefs = requireContext()
|
||||||
.getSharedPreferences(SbtSettings.PREFS_NAME, Context.MODE_PRIVATE);
|
.getSharedPreferences(SbtSettings.PREFS_NAME, Context.MODE_PRIVATE);
|
||||||
if (sourceCheckboxId == R.id.notif_position_mode_unlocked) {
|
if (sourceCheckboxId == R.id.notif_position_mode_unlocked) {
|
||||||
@@ -637,40 +539,6 @@ public final class LayoutFragment extends Fragment {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateIconCardTitle(@Nullable MaterialCardView card, int titleId, int index, int count) {
|
|
||||||
TextView title = findCardTitle(card);
|
|
||||||
if (title == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (count > 1) {
|
|
||||||
title.setText(getString(titleId) + " " + (index + 1));
|
|
||||||
} else {
|
|
||||||
title.setText(titleId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private MaterialButton smallButton(String text) {
|
|
||||||
MaterialButton button = new MaterialButton(requireContext(), null, com.google.android.material.R.attr.materialButtonOutlinedStyle);
|
|
||||||
button.setText(text);
|
|
||||||
button.setMinWidth(dp(40));
|
|
||||||
button.setMinHeight(dp(40));
|
|
||||||
button.setPadding(0, button.getPaddingTop(), 0, button.getPaddingBottom());
|
|
||||||
return button;
|
|
||||||
}
|
|
||||||
|
|
||||||
private LinearLayout.LayoutParams compactButtonParams() {
|
|
||||||
return new LinearLayout.LayoutParams(dp(40), ViewGroup.LayoutParams.WRAP_CONTENT);
|
|
||||||
}
|
|
||||||
|
|
||||||
private LinearLayout.LayoutParams compactInputParams() {
|
|
||||||
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
|
|
||||||
dp(48),
|
|
||||||
ViewGroup.LayoutParams.WRAP_CONTENT);
|
|
||||||
params.leftMargin = dp(8);
|
|
||||||
params.rightMargin = dp(8);
|
|
||||||
return params;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private MaterialCardView findAncestorCard(View view) {
|
private MaterialCardView findAncestorCard(View view) {
|
||||||
View current = view;
|
View current = view;
|
||||||
@@ -695,54 +563,6 @@ public final class LayoutFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private View inflateLayoutCard(int cardId) {
|
|
||||||
View fullLayout = LayoutInflater.from(requireContext()).inflate(R.layout.fragment_layout, null, false);
|
|
||||||
View card = fullLayout.findViewById(cardId);
|
|
||||||
if (card == null) {
|
|
||||||
return new View(requireContext());
|
|
||||||
}
|
|
||||||
if (card.getParent() instanceof ViewGroup parent) {
|
|
||||||
parent.removeView(card);
|
|
||||||
}
|
|
||||||
return card;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private TextView findCardTitle(View card) {
|
|
||||||
if (!(card instanceof ViewGroup cardGroup) || cardGroup.getChildCount() <= 0) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
View inner = cardGroup.getChildAt(0);
|
|
||||||
if (!(inner instanceof ViewGroup innerGroup) || innerGroup.getChildCount() <= 0) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
View title = innerGroup.getChildAt(0);
|
|
||||||
return title instanceof TextView textView ? textView : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private LinearLayout removeModeContainerForCheckbox(View root, int checkboxId) {
|
|
||||||
CheckBox checkbox = root.findViewById(checkboxId);
|
|
||||||
View modeContainer = directSectionChild(checkbox);
|
|
||||||
if (modeContainer == null || !(modeContainer.getParent() instanceof LinearLayout sectionContent)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
sectionContent.removeView(modeContainer);
|
|
||||||
return sectionContent;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private View directSectionChild(@Nullable View child) {
|
|
||||||
View current = child;
|
|
||||||
while (current != null && current.getParent() instanceof View parent) {
|
|
||||||
if (parent.getParent() instanceof MaterialCardView) {
|
|
||||||
return current;
|
|
||||||
}
|
|
||||||
current = parent;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int iconContainerCount(
|
private int iconContainerCount(
|
||||||
SharedPreferences prefs,
|
SharedPreferences prefs,
|
||||||
String countKey,
|
String countKey,
|
||||||
@@ -751,13 +571,7 @@ public final class LayoutFragment extends Fragment {
|
|||||||
boolean legacyEnabledDefault
|
boolean legacyEnabledDefault
|
||||||
) {
|
) {
|
||||||
int fallback = prefs.getBoolean(legacyEnabledKey, legacyEnabledDefault) ? countDefault : 0;
|
int fallback = prefs.getBoolean(legacyEnabledKey, legacyEnabledDefault) ? countDefault : 0;
|
||||||
return clampIconContainerCount(prefs.getInt(countKey, fallback));
|
return SbtSettings.clampIconContainerCount(prefs.getInt(countKey, fallback));
|
||||||
}
|
|
||||||
|
|
||||||
private int clampIconContainerCount(int value) {
|
|
||||||
return Math.max(
|
|
||||||
SbtDefaults.LAYOUT_ICON_CONTAINER_COUNT_MIN,
|
|
||||||
Math.min(SbtDefaults.LAYOUT_ICON_CONTAINER_COUNT_MAX, value));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void persistIconContainerCount(
|
private void persistIconContainerCount(
|
||||||
@@ -767,20 +581,13 @@ public final class LayoutFragment extends Fragment {
|
|||||||
int count
|
int count
|
||||||
) {
|
) {
|
||||||
prefs.edit()
|
prefs.edit()
|
||||||
.putInt(countKey, clampIconContainerCount(count))
|
.putInt(countKey, SbtSettings.clampIconContainerCount(count))
|
||||||
.putBoolean(legacyEnabledKey, count > 0)
|
.putBoolean(legacyEnabledKey, count > 0)
|
||||||
.apply();
|
.apply();
|
||||||
SbtSettings.ensureReadable(requireContext());
|
SbtSettings.ensureReadable(requireContext());
|
||||||
}
|
}
|
||||||
|
|
||||||
private int dp(int value) {
|
|
||||||
return Math.round(value * getResources().getDisplayMetrics().density);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void hideUnlockedSubpageObsoleteControls(View root) {
|
private void hideUnlockedSubpageObsoleteControls(View root) {
|
||||||
hide(root, R.id.layout_master_card);
|
|
||||||
hide(root, R.id.layout_padding_card);
|
|
||||||
hide(root, R.id.layout_ordering_card);
|
|
||||||
hide(root, R.id.clock_position_mode_lockscreen);
|
hide(root, R.id.clock_position_mode_lockscreen);
|
||||||
hide(root, R.id.notif_position_mode_aod);
|
hide(root, R.id.notif_position_mode_aod);
|
||||||
hide(root, R.id.notif_position_mode_lockscreen);
|
hide(root, R.id.notif_position_mode_lockscreen);
|
||||||
@@ -872,7 +679,7 @@ public final class LayoutFragment extends Fragment {
|
|||||||
middleOptions.setVisibility(View.VISIBLE);
|
middleOptions.setVisibility(View.VISIBLE);
|
||||||
}
|
}
|
||||||
boolean enabled = isMiddleSelection(checkedId);
|
boolean enabled = isMiddleSelection(checkedId);
|
||||||
setViewTreeEnabled(middleOptions, enabled);
|
ViewTreeSupport.setEnabledRecursive(middleOptions, enabled);
|
||||||
middleOptions.setAlpha(enabled ? 1f : 0.45f);
|
middleOptions.setAlpha(enabled ? 1f : 0.45f);
|
||||||
updateMiddlePrompt(prompt, autoNearest.isChecked());
|
updateMiddlePrompt(prompt, autoNearest.isChecked());
|
||||||
}
|
}
|
||||||
@@ -893,22 +700,6 @@ public final class LayoutFragment extends Fragment {
|
|||||||
: R.string.layout_middle_side_prompt_attach_only);
|
: R.string.layout_middle_side_prompt_attach_only);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void bindSortOrderGroup(SharedPreferences prefs, @Nullable RadioGroup group) {
|
|
||||||
if (prefs == null || group == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
String current = prefs.getString(
|
|
||||||
SbtSettings.KEY_LAYOUT_NOTIF_SORT_ORDER,
|
|
||||||
SbtDefaults.LAYOUT_NOTIF_SORT_ORDER_DEFAULT);
|
|
||||||
group.check(sortOrderIdForValue(current));
|
|
||||||
group.setOnCheckedChangeListener((radioGroup, checkedId) -> {
|
|
||||||
prefs.edit().putString(
|
|
||||||
SbtSettings.KEY_LAYOUT_NOTIF_SORT_ORDER,
|
|
||||||
sortOrderValueForId(checkedId)).apply();
|
|
||||||
SbtSettings.ensureReadable(requireContext());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void bindStepper(SharedPreferences prefs,
|
private void bindStepper(SharedPreferences prefs,
|
||||||
@Nullable String key,
|
@Nullable String key,
|
||||||
@Nullable EditText input,
|
@Nullable EditText input,
|
||||||
@@ -977,7 +768,7 @@ public final class LayoutFragment extends Fragment {
|
|||||||
if (input == null) {
|
if (input == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int startValue = clampValue(key != null ? prefs.getInt(key, initialValue) : initialValue, minValue, maxValue);
|
int startValue = ViewTreeSupport.clamp(key != null ? prefs.getInt(key, initialValue) : initialValue, minValue, maxValue);
|
||||||
input.setFilters(new InputFilter[]{new InputFilter.LengthFilter(4)});
|
input.setFilters(new InputFilter[]{new InputFilter.LengthFilter(4)});
|
||||||
setNumericText(input, startValue);
|
setNumericText(input, startValue);
|
||||||
final boolean[] updating = new boolean[]{false};
|
final boolean[] updating = new boolean[]{false};
|
||||||
@@ -989,7 +780,7 @@ public final class LayoutFragment extends Fragment {
|
|||||||
if (resetButton != null) {
|
if (resetButton != null) {
|
||||||
resetButton.setOnClickListener(v -> {
|
resetButton.setOnClickListener(v -> {
|
||||||
updating[0] = true;
|
updating[0] = true;
|
||||||
int next = clampValue(initialValue, minValue, maxValue);
|
int next = ViewTreeSupport.clamp(initialValue, minValue, maxValue);
|
||||||
setNumericText(input, next);
|
setNumericText(input, next);
|
||||||
updating[0] = false;
|
updating[0] = false;
|
||||||
persistIntPref(prefs, key, next);
|
persistIntPref(prefs, key, next);
|
||||||
@@ -1012,12 +803,13 @@ public final class LayoutFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
String text = s != null ? s.toString().trim() : "";
|
String text = s != null ? s.toString().trim() : "";
|
||||||
if (text.isEmpty() || "-".equals(text)) {
|
if (text.isEmpty() || "-".equals(text)) {
|
||||||
persistIntPref(prefs, key, clampValue(0, minValue, maxValue));
|
persistIntPref(prefs, key, ViewTreeSupport.clamp(0, minValue, maxValue));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
int parsed = clampValue(Integer.parseInt(text), minValue, maxValue);
|
int rawValue = Integer.parseInt(text);
|
||||||
if (parsed != Integer.parseInt(text)) {
|
int parsed = ViewTreeSupport.clamp(rawValue, minValue, maxValue);
|
||||||
|
if (parsed != rawValue) {
|
||||||
updating[0] = true;
|
updating[0] = true;
|
||||||
setNumericText(input, parsed);
|
setNumericText(input, parsed);
|
||||||
updating[0] = false;
|
updating[0] = false;
|
||||||
@@ -1030,7 +822,7 @@ public final class LayoutFragment extends Fragment {
|
|||||||
|
|
||||||
input.setOnEditorActionListener((v, actionId, event) -> {
|
input.setOnEditorActionListener((v, actionId, event) -> {
|
||||||
if (actionId == EditorInfo.IME_ACTION_DONE) {
|
if (actionId == EditorInfo.IME_ACTION_DONE) {
|
||||||
int next = clampValue(parseInt(input, 0), minValue, maxValue);
|
int next = ViewTreeSupport.clamp(ViewTreeSupport.parseInt(input, 0), minValue, maxValue);
|
||||||
updating[0] = true;
|
updating[0] = true;
|
||||||
setNumericText(input, next);
|
setNumericText(input, next);
|
||||||
updating[0] = false;
|
updating[0] = false;
|
||||||
@@ -1043,7 +835,7 @@ public final class LayoutFragment extends Fragment {
|
|||||||
if (hasFocus) {
|
if (hasFocus) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int next = clampValue(parseInt(input, 0), minValue, maxValue);
|
int next = ViewTreeSupport.clamp(ViewTreeSupport.parseInt(input, 0), minValue, maxValue);
|
||||||
updating[0] = true;
|
updating[0] = true;
|
||||||
setNumericText(input, next);
|
setNumericText(input, next);
|
||||||
updating[0] = false;
|
updating[0] = false;
|
||||||
@@ -1063,7 +855,7 @@ public final class LayoutFragment extends Fragment {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
button.setOnClickListener(v -> {
|
button.setOnClickListener(v -> {
|
||||||
int next = clampValue(parseInt(input, 0) + delta, minValue, maxValue);
|
int next = ViewTreeSupport.clamp(ViewTreeSupport.parseInt(input, 0) + delta, minValue, maxValue);
|
||||||
updating[0] = true;
|
updating[0] = true;
|
||||||
setNumericText(input, next);
|
setNumericText(input, next);
|
||||||
updating[0] = false;
|
updating[0] = false;
|
||||||
@@ -1075,14 +867,13 @@ public final class LayoutFragment extends Fragment {
|
|||||||
@Nullable CheckBox checkBox,
|
@Nullable CheckBox checkBox,
|
||||||
String key,
|
String key,
|
||||||
boolean defaultValue) {
|
boolean defaultValue) {
|
||||||
if (checkBox == null) {
|
ViewTreeSupport.bindBooleanPreference(
|
||||||
return;
|
requireContext(),
|
||||||
}
|
prefs,
|
||||||
checkBox.setChecked(prefs.getBoolean(key, defaultValue));
|
checkBox,
|
||||||
checkBox.setOnCheckedChangeListener((buttonView, isChecked) -> {
|
key,
|
||||||
prefs.edit().putBoolean(key, isChecked).apply();
|
defaultValue,
|
||||||
SbtSettings.ensureReadable(requireContext());
|
false);
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void persistIntPref(SharedPreferences prefs, @Nullable String key, int value) {
|
private void persistIntPref(SharedPreferences prefs, @Nullable String key, int value) {
|
||||||
@@ -1093,19 +884,6 @@ public final class LayoutFragment extends Fragment {
|
|||||||
SbtSettings.ensureReadable(requireContext());
|
SbtSettings.ensureReadable(requireContext());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setViewTreeEnabled(View view, boolean enabled) {
|
|
||||||
if (view == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
view.setEnabled(enabled);
|
|
||||||
if (view instanceof ViewGroup) {
|
|
||||||
ViewGroup group = (ViewGroup) view;
|
|
||||||
for (int i = 0; i < group.getChildCount(); i++) {
|
|
||||||
setViewTreeEnabled(group.getChildAt(i), enabled);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private int positionIdForValue(int groupId, @Nullable String value) {
|
private int positionIdForValue(int groupId, @Nullable String value) {
|
||||||
String normalized = value != null ? value : "left";
|
String normalized = value != null ? value : "left";
|
||||||
if (groupId == R.id.clock_position_group) {
|
if (groupId == R.id.clock_position_group) {
|
||||||
@@ -1188,35 +966,6 @@ public final class LayoutFragment extends Fragment {
|
|||||||
return id != View.NO_ID ? id : resolveLeftSideId(group);
|
return id != View.NO_ID ? id : resolveLeftSideId(group);
|
||||||
}
|
}
|
||||||
|
|
||||||
private int parseInt(EditText input, int fallback) {
|
|
||||||
if (input == null) {
|
|
||||||
return fallback;
|
|
||||||
}
|
|
||||||
String text = input.getText() != null ? input.getText().toString().trim() : "";
|
|
||||||
if (text.isEmpty() || "-".equals(text)) {
|
|
||||||
return fallback;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
return Integer.parseInt(text);
|
|
||||||
} catch (NumberFormatException ignored) {
|
|
||||||
return fallback;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private int clampPadding(int value) {
|
|
||||||
return clampValue(value, PADDING_MIN, PADDING_MAX);
|
|
||||||
}
|
|
||||||
|
|
||||||
private int clampValue(int value, int minValue, int maxValue) {
|
|
||||||
if (value < minValue) {
|
|
||||||
return minValue;
|
|
||||||
}
|
|
||||||
if (value > maxValue) {
|
|
||||||
return maxValue;
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setNumericText(EditText input, int value) {
|
private void setNumericText(EditText input, int value) {
|
||||||
if (input == null) {
|
if (input == null) {
|
||||||
return;
|
return;
|
||||||
@@ -1228,208 +977,4 @@ public final class LayoutFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private int sortOrderIdForValue(@Nullable String value) {
|
|
||||||
if ("stock".equals(value)) {
|
|
||||||
return R.id.layout_sort_icons_stock;
|
|
||||||
}
|
|
||||||
if ("reversed".equals(value)) {
|
|
||||||
return R.id.layout_sort_icons_reversed;
|
|
||||||
}
|
|
||||||
return R.id.layout_sort_icons_automatic;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String sortOrderValueForId(int checkedId) {
|
|
||||||
if (checkedId == R.id.layout_sort_icons_stock) {
|
|
||||||
return "stock";
|
|
||||||
}
|
|
||||||
if (checkedId == R.id.layout_sort_icons_reversed) {
|
|
||||||
return "reversed";
|
|
||||||
}
|
|
||||||
return "automatic";
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setupOrderingList(View root, SharedPreferences prefs) {
|
|
||||||
RecyclerView list = root.findViewById(R.id.layout_ordering_list);
|
|
||||||
if (list == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
ArrayList<OrderingItem> items = parseOrderingItems(
|
|
||||||
prefs.getString(SbtSettings.KEY_LAYOUT_ITEM_ORDER, SbtDefaults.LAYOUT_ITEM_ORDER_DEFAULT));
|
|
||||||
|
|
||||||
list.setLayoutManager(new LinearLayoutManager(requireContext()));
|
|
||||||
OrderingAdapter adapter = new OrderingAdapter(items, order -> {
|
|
||||||
prefs.edit().putString(SbtSettings.KEY_LAYOUT_ITEM_ORDER, order).apply();
|
|
||||||
SbtSettings.ensureReadable(requireContext());
|
|
||||||
});
|
|
||||||
list.setAdapter(adapter);
|
|
||||||
|
|
||||||
final ItemTouchHelper[] itemTouchHelperHolder = new ItemTouchHelper[1];
|
|
||||||
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(new ItemTouchHelper.SimpleCallback(
|
|
||||||
ItemTouchHelper.UP | ItemTouchHelper.DOWN, 0) {
|
|
||||||
@Override
|
|
||||||
public boolean onMove(@NonNull RecyclerView recyclerView,
|
|
||||||
@NonNull RecyclerView.ViewHolder viewHolder,
|
|
||||||
@NonNull RecyclerView.ViewHolder target) {
|
|
||||||
int from = viewHolder.getAdapterPosition();
|
|
||||||
int to = target.getAdapterPosition();
|
|
||||||
if (from == RecyclerView.NO_POSITION || to == RecyclerView.NO_POSITION) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
adapter.moveItem(from, to);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isLongPressDragEnabled() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
itemTouchHelper.attachToRecyclerView(list);
|
|
||||||
itemTouchHelperHolder[0] = itemTouchHelper;
|
|
||||||
adapter.setDragStarter(holder -> {
|
|
||||||
ItemTouchHelper helper = itemTouchHelperHolder[0];
|
|
||||||
if (helper != null) {
|
|
||||||
helper.startDrag(holder);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private ArrayList<OrderingItem> parseOrderingItems(@Nullable String encoded) {
|
|
||||||
if (encoded == null || encoded.isEmpty() || "clock,notifications,status".equals(encoded)) {
|
|
||||||
encoded = SbtDefaults.LAYOUT_ITEM_ORDER_DEFAULT;
|
|
||||||
}
|
|
||||||
ArrayList<OrderingItem> items = new ArrayList<>();
|
|
||||||
for (String token : encoded.split(",")) {
|
|
||||||
addOrderingItemIfValid(items, token != null ? token.trim() : "");
|
|
||||||
}
|
|
||||||
addCarrierOrderingItemIfMissing(items);
|
|
||||||
addOrderingItemIfValid(items, "clock");
|
|
||||||
addOrderingItemIfValid(items, "chip");
|
|
||||||
addOrderingItemIfValid(items, "status");
|
|
||||||
addOrderingItemIfValid(items, "notifications");
|
|
||||||
return items;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addCarrierOrderingItemIfMissing(ArrayList<OrderingItem> items) {
|
|
||||||
for (OrderingItem item : items) {
|
|
||||||
if ("carrier".equals(item.key)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
items.add(0, new OrderingItem("carrier", getString(R.string.layout_ordering_carrier)));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addOrderingItemIfValid(ArrayList<OrderingItem> items, String key) {
|
|
||||||
if (key == null || key.isEmpty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (OrderingItem item : items) {
|
|
||||||
if (item.key.equals(key)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
int labelRes;
|
|
||||||
if ("carrier".equals(key)) {
|
|
||||||
labelRes = R.string.layout_ordering_carrier;
|
|
||||||
} else if ("clock".equals(key)) {
|
|
||||||
labelRes = R.string.layout_ordering_clock;
|
|
||||||
} else if ("chip".equals(key)) {
|
|
||||||
labelRes = R.string.layout_ordering_chip;
|
|
||||||
} else if ("notifications".equals(key)) {
|
|
||||||
labelRes = R.string.layout_ordering_notif_icons;
|
|
||||||
} else if ("status".equals(key)) {
|
|
||||||
labelRes = R.string.layout_ordering_status_icons;
|
|
||||||
} else {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
items.add(new OrderingItem(key, getString(labelRes)));
|
|
||||||
}
|
|
||||||
|
|
||||||
private record OrderingItem(String key, String label) {
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final class OrderingAdapter extends RecyclerView.Adapter<OrderingViewHolder> {
|
|
||||||
interface DragStarter {
|
|
||||||
void startDrag(OrderingViewHolder holder);
|
|
||||||
}
|
|
||||||
|
|
||||||
interface OrderChangedListener {
|
|
||||||
void onOrderChanged(String encodedOrder);
|
|
||||||
}
|
|
||||||
|
|
||||||
private final List<OrderingItem> items;
|
|
||||||
private final OrderChangedListener orderChangedListener;
|
|
||||||
private DragStarter dragStarter;
|
|
||||||
|
|
||||||
OrderingAdapter(List<OrderingItem> items, OrderChangedListener orderChangedListener) {
|
|
||||||
this.items = items;
|
|
||||||
this.orderChangedListener = orderChangedListener;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setDragStarter(DragStarter dragStarter) {
|
|
||||||
this.dragStarter = dragStarter;
|
|
||||||
}
|
|
||||||
|
|
||||||
void moveItem(int from, int to) {
|
|
||||||
if (from == to || from < 0 || to < 0 || from >= items.size() || to >= items.size()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Collections.swap(items, from, to);
|
|
||||||
notifyItemMoved(from, to);
|
|
||||||
if (orderChangedListener != null) {
|
|
||||||
orderChangedListener.onOrderChanged(encodeOrder());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private String encodeOrder() {
|
|
||||||
StringBuilder builder = new StringBuilder();
|
|
||||||
for (OrderingItem item : items) {
|
|
||||||
if (builder.length() > 0) {
|
|
||||||
builder.append(',');
|
|
||||||
}
|
|
||||||
builder.append(item.key);
|
|
||||||
}
|
|
||||||
return builder.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
@Override
|
|
||||||
public OrderingViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
|
||||||
View view = LayoutInflater.from(parent.getContext())
|
|
||||||
.inflate(R.layout.item_layout_ordering, parent, false);
|
|
||||||
return new OrderingViewHolder(view);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onBindViewHolder(@NonNull OrderingViewHolder holder, int position) {
|
|
||||||
holder.label.setText(items.get(position).label);
|
|
||||||
holder.handle.setOnTouchListener((v, event) -> {
|
|
||||||
if (event.getActionMasked() == MotionEvent.ACTION_DOWN && dragStarter != null) {
|
|
||||||
dragStarter.startDrag(holder);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getItemCount() {
|
|
||||||
return items.size();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final class OrderingViewHolder extends RecyclerView.ViewHolder {
|
|
||||||
final TextView label;
|
|
||||||
final TextView handle;
|
|
||||||
|
|
||||||
OrderingViewHolder(@NonNull View itemView) {
|
|
||||||
super(itemView);
|
|
||||||
label = itemView.findViewById(R.id.layout_ordering_item_label);
|
|
||||||
handle = itemView.findViewById(R.id.layout_ordering_item_handle);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,11 +3,9 @@ package se.ajpanton.statusbartweak.shell.ui;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.text.InputFilter;
|
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.CheckBox;
|
|
||||||
import android.widget.EditText;
|
import android.widget.EditText;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
import android.widget.RadioGroup;
|
import android.widget.RadioGroup;
|
||||||
@@ -19,7 +17,6 @@ import androidx.annotation.Nullable;
|
|||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
|
|
||||||
import com.google.android.material.button.MaterialButton;
|
import com.google.android.material.button.MaterialButton;
|
||||||
import com.google.android.material.card.MaterialCardView;
|
|
||||||
import com.google.android.material.switchmaterial.SwitchMaterial;
|
import com.google.android.material.switchmaterial.SwitchMaterial;
|
||||||
|
|
||||||
import se.ajpanton.statusbartweak.R;
|
import se.ajpanton.statusbartweak.R;
|
||||||
@@ -41,9 +38,12 @@ public final class LayoutHomeFragment extends Fragment {
|
|||||||
Context context = requireContext();
|
Context context = requireContext();
|
||||||
SharedPreferences prefs = context.getSharedPreferences(SbtSettings.PREFS_NAME, Context.MODE_PRIVATE);
|
SharedPreferences prefs = context.getSharedPreferences(SbtSettings.PREFS_NAME, Context.MODE_PRIVATE);
|
||||||
ScrollView scroll = new ScrollView(context);
|
ScrollView scroll = new ScrollView(context);
|
||||||
LinearLayout root = new LinearLayout(context);
|
LinearLayout root = vertical(context);
|
||||||
root.setOrientation(LinearLayout.VERTICAL);
|
root.setPadding(
|
||||||
root.setPadding(dp(20), dp(20), dp(20), dp(20));
|
ViewTreeSupport.dp(context, 20),
|
||||||
|
ViewTreeSupport.dp(context, 20),
|
||||||
|
ViewTreeSupport.dp(context, 20),
|
||||||
|
ViewTreeSupport.dp(context, 20));
|
||||||
scroll.addView(root);
|
scroll.addView(root);
|
||||||
|
|
||||||
TextView title = title(context, R.string.layout_home_title);
|
TextView title = title(context, R.string.layout_home_title);
|
||||||
@@ -69,7 +69,7 @@ public final class LayoutHomeFragment extends Fragment {
|
|||||||
|
|
||||||
root.addView(miscCard(context, prefs));
|
root.addView(miscCard(context, prefs));
|
||||||
|
|
||||||
Runnable refreshAvailability = () -> refreshAvailability(prefs, master.isChecked());
|
Runnable refreshAvailability = () -> refreshAvailability(context, prefs, master.isChecked());
|
||||||
master.setOnCheckedChangeListener((buttonView, isChecked) -> {
|
master.setOnCheckedChangeListener((buttonView, isChecked) -> {
|
||||||
prefs.edit().putBoolean(SbtSettings.KEY_CLOCK_ENABLED, isChecked).apply();
|
prefs.edit().putBoolean(SbtSettings.KEY_CLOCK_ENABLED, isChecked).apply();
|
||||||
SbtSettings.ensureReadable(context);
|
SbtSettings.ensureReadable(context);
|
||||||
@@ -79,15 +79,15 @@ public final class LayoutHomeFragment extends Fragment {
|
|||||||
return scroll;
|
return scroll;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void refreshAvailability(SharedPreferences prefs, boolean layoutEnabled) {
|
private void refreshAvailability(Context context, SharedPreferences prefs, boolean layoutEnabled) {
|
||||||
setViewTreeEnabled(layoutOnContainer, layoutEnabled);
|
ViewTreeSupport.setEnabledRecursive(layoutOnContainer, layoutEnabled);
|
||||||
layoutOnContainer.setAlpha(layoutEnabled ? 1f : 0.45f);
|
layoutOnContainer.setAlpha(layoutEnabled ? 1f : 0.45f);
|
||||||
setViewTreeEnabled(miscLayoutOnContainer, layoutEnabled);
|
ViewTreeSupport.setEnabledRecursive(miscLayoutOnContainer, layoutEnabled);
|
||||||
miscLayoutOnContainer.setAlpha(layoutEnabled ? 1f : 0.45f);
|
miscLayoutOnContainer.setAlpha(layoutEnabled ? 1f : 0.45f);
|
||||||
setViewTreeEnabled(miscUnlockedOffOnlyContainer, !layoutEnabled);
|
ViewTreeSupport.setEnabledRecursive(miscUnlockedOffOnlyContainer, !layoutEnabled);
|
||||||
miscUnlockedOffOnlyContainer.setAlpha(layoutEnabled ? 0.45f : 1f);
|
miscUnlockedOffOnlyContainer.setAlpha(layoutEnabled ? 0.45f : 1f);
|
||||||
LockedNotificationModeUi.bind(
|
LockedNotificationModeUi.bind(
|
||||||
requireContext(),
|
context,
|
||||||
prefs,
|
prefs,
|
||||||
lockedModeGroup,
|
lockedModeGroup,
|
||||||
lockedModeHint);
|
lockedModeHint);
|
||||||
@@ -111,12 +111,13 @@ public final class LayoutHomeFragment extends Fragment {
|
|||||||
SbtDefaults.LAYOUT_PADDING_LEFT_PX_DEFAULT,
|
SbtDefaults.LAYOUT_PADDING_LEFT_PX_DEFAULT,
|
||||||
-999,
|
-999,
|
||||||
999,
|
999,
|
||||||
checkBox(
|
ViewTreeSupport.boundCheckBox(
|
||||||
context,
|
context,
|
||||||
prefs,
|
prefs,
|
||||||
R.string.layout_padding_add_stock,
|
R.string.layout_padding_add_stock,
|
||||||
SbtSettings.KEY_LAYOUT_PADDING_LEFT_ADD_STOCK,
|
SbtSettings.KEY_LAYOUT_PADDING_LEFT_ADD_STOCK,
|
||||||
SbtDefaults.LAYOUT_PADDING_LEFT_ADD_STOCK_DEFAULT)));
|
SbtDefaults.LAYOUT_PADDING_LEFT_ADD_STOCK_DEFAULT,
|
||||||
|
false)));
|
||||||
content.addView(stepper(
|
content.addView(stepper(
|
||||||
context,
|
context,
|
||||||
prefs,
|
prefs,
|
||||||
@@ -125,12 +126,13 @@ public final class LayoutHomeFragment extends Fragment {
|
|||||||
SbtDefaults.LAYOUT_PADDING_RIGHT_PX_DEFAULT,
|
SbtDefaults.LAYOUT_PADDING_RIGHT_PX_DEFAULT,
|
||||||
-999,
|
-999,
|
||||||
999,
|
999,
|
||||||
checkBox(
|
ViewTreeSupport.boundCheckBox(
|
||||||
context,
|
context,
|
||||||
prefs,
|
prefs,
|
||||||
R.string.layout_padding_add_stock,
|
R.string.layout_padding_add_stock,
|
||||||
SbtSettings.KEY_LAYOUT_PADDING_RIGHT_ADD_STOCK,
|
SbtSettings.KEY_LAYOUT_PADDING_RIGHT_ADD_STOCK,
|
||||||
SbtDefaults.LAYOUT_PADDING_RIGHT_ADD_STOCK_DEFAULT)));
|
SbtDefaults.LAYOUT_PADDING_RIGHT_ADD_STOCK_DEFAULT,
|
||||||
|
false)));
|
||||||
content.addView(stepper(
|
content.addView(stepper(
|
||||||
context,
|
context,
|
||||||
prefs,
|
prefs,
|
||||||
@@ -145,12 +147,13 @@ public final class LayoutHomeFragment extends Fragment {
|
|||||||
private View miscCard(Context context, SharedPreferences prefs) {
|
private View miscCard(Context context, SharedPreferences prefs) {
|
||||||
LinearLayout content = vertical(context);
|
LinearLayout content = vertical(context);
|
||||||
miscLayoutOnContainer = vertical(context);
|
miscLayoutOnContainer = vertical(context);
|
||||||
miscLayoutOnContainer.addView(checkBox(
|
miscLayoutOnContainer.addView(ViewTreeSupport.boundCheckBox(
|
||||||
context,
|
context,
|
||||||
prefs,
|
prefs,
|
||||||
R.string.layout_ignore_under_display_cameras,
|
R.string.layout_ignore_under_display_cameras,
|
||||||
SbtSettings.KEY_LAYOUT_IGNORE_UNDER_DISPLAY_CAMERAS,
|
SbtSettings.KEY_LAYOUT_IGNORE_UNDER_DISPLAY_CAMERAS,
|
||||||
SbtDefaults.LAYOUT_IGNORE_UNDER_DISPLAY_CAMERAS_DEFAULT));
|
SbtDefaults.LAYOUT_IGNORE_UNDER_DISPLAY_CAMERAS_DEFAULT,
|
||||||
|
false));
|
||||||
content.addView(miscLayoutOnContainer);
|
content.addView(miscLayoutOnContainer);
|
||||||
miscUnlockedOffOnlyContainer = vertical(context);
|
miscUnlockedOffOnlyContainer = vertical(context);
|
||||||
miscUnlockedOffOnlyContainer.addView(stepper(
|
miscUnlockedOffOnlyContainer.addView(stepper(
|
||||||
@@ -193,29 +196,25 @@ public final class LayoutHomeFragment extends Fragment {
|
|||||||
LinearLayout row = new LinearLayout(context);
|
LinearLayout row = new LinearLayout(context);
|
||||||
row.setOrientation(LinearLayout.HORIZONTAL);
|
row.setOrientation(LinearLayout.HORIZONTAL);
|
||||||
row.setGravity(android.view.Gravity.CENTER_VERTICAL);
|
row.setGravity(android.view.Gravity.CENTER_VERTICAL);
|
||||||
row.setPadding(0, dp(6), 0, dp(8));
|
row.setPadding(0, ViewTreeSupport.dp(context, 6), 0, ViewTreeSupport.dp(context, 8));
|
||||||
MaterialButton minus = button(context, "-");
|
MaterialButton minus = ViewTreeSupport.outlinedStepperButton(context, "-");
|
||||||
MaterialButton plus = button(context, "+");
|
MaterialButton plus = ViewTreeSupport.outlinedStepperButton(context, "+");
|
||||||
EditText input = new EditText(context);
|
EditText input = ViewTreeSupport.numericInput(context, true, 5);
|
||||||
input.setGravity(android.view.Gravity.CENTER);
|
input.setText(String.valueOf(ViewTreeSupport.clamp(prefs.getInt(key, defaultValue), min, max)));
|
||||||
input.setSingleLine(true);
|
row.addView(minus, ViewTreeSupport.stepperButtonParams(context));
|
||||||
input.setInputType(android.text.InputType.TYPE_CLASS_NUMBER | android.text.InputType.TYPE_NUMBER_FLAG_SIGNED);
|
row.addView(input, ViewTreeSupport.stepperInputParams(context));
|
||||||
input.setFilters(new InputFilter[]{new InputFilter.LengthFilter(5)});
|
row.addView(plus, ViewTreeSupport.stepperButtonParams(context));
|
||||||
input.setText(String.valueOf(clamp(prefs.getInt(key, defaultValue), min, max)));
|
|
||||||
row.addView(minus, buttonParams());
|
|
||||||
row.addView(input, inputParams());
|
|
||||||
row.addView(plus, buttonParams());
|
|
||||||
if (trailingView != null) {
|
if (trailingView != null) {
|
||||||
LinearLayout.LayoutParams trailingParams = new LinearLayout.LayoutParams(
|
LinearLayout.LayoutParams trailingParams = new LinearLayout.LayoutParams(
|
||||||
ViewGroup.LayoutParams.WRAP_CONTENT,
|
ViewGroup.LayoutParams.WRAP_CONTENT,
|
||||||
ViewGroup.LayoutParams.WRAP_CONTENT);
|
ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||||
trailingParams.leftMargin = dp(8);
|
trailingParams.leftMargin = ViewTreeSupport.dp(context, 8);
|
||||||
row.addView(trailingView, trailingParams);
|
row.addView(trailingView, trailingParams);
|
||||||
}
|
}
|
||||||
outer.addView(row);
|
outer.addView(row);
|
||||||
View.OnClickListener listener = v -> {
|
View.OnClickListener listener = v -> {
|
||||||
int delta = v == minus ? -1 : 1;
|
int delta = v == minus ? -1 : 1;
|
||||||
int next = clamp(parseInt(input, defaultValue) + delta, min, max);
|
int next = ViewTreeSupport.clamp(ViewTreeSupport.parseInt(input, defaultValue) + delta, min, max);
|
||||||
input.setText(String.valueOf(next));
|
input.setText(String.valueOf(next));
|
||||||
prefs.edit().putInt(key, next).apply();
|
prefs.edit().putInt(key, next).apply();
|
||||||
SbtSettings.ensureReadable(context);
|
SbtSettings.ensureReadable(context);
|
||||||
@@ -224,7 +223,7 @@ public final class LayoutHomeFragment extends Fragment {
|
|||||||
plus.setOnClickListener(listener);
|
plus.setOnClickListener(listener);
|
||||||
input.setOnFocusChangeListener((v, hasFocus) -> {
|
input.setOnFocusChangeListener((v, hasFocus) -> {
|
||||||
if (!hasFocus) {
|
if (!hasFocus) {
|
||||||
int next = clamp(parseInt(input, defaultValue), min, max);
|
int next = ViewTreeSupport.clamp(ViewTreeSupport.parseInt(input, defaultValue), min, max);
|
||||||
input.setText(String.valueOf(next));
|
input.setText(String.valueOf(next));
|
||||||
prefs.edit().putInt(key, next).apply();
|
prefs.edit().putInt(key, next).apply();
|
||||||
SbtSettings.ensureReadable(context);
|
SbtSettings.ensureReadable(context);
|
||||||
@@ -233,118 +232,23 @@ public final class LayoutHomeFragment extends Fragment {
|
|||||||
return outer;
|
return outer;
|
||||||
}
|
}
|
||||||
|
|
||||||
private CheckBox checkBox(
|
private View card(Context context, int titleId, View content) {
|
||||||
Context context,
|
return ViewTreeSupport.outlinedCard(context, sectionTitle(context, titleId), content);
|
||||||
SharedPreferences prefs,
|
|
||||||
int label,
|
|
||||||
String key,
|
|
||||||
boolean defaultValue
|
|
||||||
) {
|
|
||||||
CheckBox checkBox = new CheckBox(context);
|
|
||||||
checkBox.setText(label);
|
|
||||||
checkBox.setChecked(prefs.getBoolean(key, defaultValue));
|
|
||||||
checkBox.setOnCheckedChangeListener((buttonView, isChecked) -> {
|
|
||||||
prefs.edit().putBoolean(key, isChecked).apply();
|
|
||||||
SbtSettings.ensureReadable(context);
|
|
||||||
});
|
|
||||||
return checkBox;
|
|
||||||
}
|
|
||||||
|
|
||||||
private MaterialButton button(Context context, String text) {
|
|
||||||
MaterialButton button = new MaterialButton(context, null, com.google.android.material.R.attr.materialButtonOutlinedStyle);
|
|
||||||
button.setText(text);
|
|
||||||
button.setMinWidth(dp(40));
|
|
||||||
button.setMinHeight(dp(40));
|
|
||||||
button.setPadding(0, button.getPaddingTop(), 0, button.getPaddingBottom());
|
|
||||||
return button;
|
|
||||||
}
|
|
||||||
|
|
||||||
private LinearLayout.LayoutParams buttonParams() {
|
|
||||||
return new LinearLayout.LayoutParams(dp(40), ViewGroup.LayoutParams.WRAP_CONTENT);
|
|
||||||
}
|
|
||||||
|
|
||||||
private LinearLayout.LayoutParams inputParams() {
|
|
||||||
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
|
|
||||||
dp(48),
|
|
||||||
ViewGroup.LayoutParams.WRAP_CONTENT);
|
|
||||||
params.leftMargin = dp(8);
|
|
||||||
params.rightMargin = dp(8);
|
|
||||||
return params;
|
|
||||||
}
|
|
||||||
|
|
||||||
private MaterialCardView card(Context context, int titleId, View content) {
|
|
||||||
MaterialCardView card = new MaterialCardView(context);
|
|
||||||
LinearLayout.LayoutParams cardParams = new LinearLayout.LayoutParams(
|
|
||||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
|
||||||
ViewGroup.LayoutParams.WRAP_CONTENT);
|
|
||||||
cardParams.topMargin = dp(16);
|
|
||||||
card.setLayoutParams(cardParams);
|
|
||||||
card.setUseCompatPadding(true);
|
|
||||||
card.setStrokeColor(context.getColor(R.color.sbt_card_outline));
|
|
||||||
card.setStrokeWidth(dp(1));
|
|
||||||
LinearLayout inner = vertical(context);
|
|
||||||
inner.setPadding(dp(16), dp(16), dp(16), dp(16));
|
|
||||||
TextView title = sectionTitle(context, titleId);
|
|
||||||
inner.addView(title);
|
|
||||||
inner.addView(content);
|
|
||||||
card.addView(inner);
|
|
||||||
return card;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private LinearLayout vertical(Context context) {
|
private LinearLayout vertical(Context context) {
|
||||||
LinearLayout layout = new LinearLayout(context);
|
return ViewTreeSupport.verticalLayout(context);
|
||||||
layout.setOrientation(LinearLayout.VERTICAL);
|
|
||||||
return layout;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private TextView title(Context context, int stringId) {
|
private TextView title(Context context, int stringId) {
|
||||||
TextView view = new TextView(context);
|
return ViewTreeSupport.titleText(context, stringId);
|
||||||
view.setText(stringId);
|
|
||||||
view.setTextAppearance(com.google.android.material.R.style.TextAppearance_MaterialComponents_Headline5);
|
|
||||||
return view;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private TextView sectionTitle(Context context, int stringId) {
|
private TextView sectionTitle(Context context, int stringId) {
|
||||||
TextView view = new TextView(context);
|
return ViewTreeSupport.sectionTitleText(context, stringId, true);
|
||||||
view.setText(stringId);
|
|
||||||
view.setTextAppearance(com.google.android.material.R.style.TextAppearance_MaterialComponents_Subtitle1);
|
|
||||||
view.setAllCaps(true);
|
|
||||||
view.setTypeface(view.getTypeface(), android.graphics.Typeface.BOLD);
|
|
||||||
return view;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private TextView body(Context context, int stringId) {
|
private TextView body(Context context, int stringId) {
|
||||||
TextView view = new TextView(context);
|
return ViewTreeSupport.bodyText(context, stringId, 0);
|
||||||
view.setText(stringId);
|
|
||||||
view.setPadding(0, dp(8), 0, 0);
|
|
||||||
return view;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setViewTreeEnabled(View view, boolean enabled) {
|
|
||||||
if (view == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
view.setEnabled(enabled);
|
|
||||||
if (view instanceof ViewGroup group) {
|
|
||||||
for (int i = 0; i < group.getChildCount(); i++) {
|
|
||||||
setViewTreeEnabled(group.getChildAt(i), enabled);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private int parseInt(EditText input, int fallback) {
|
|
||||||
try {
|
|
||||||
return Integer.parseInt(input.getText().toString().trim());
|
|
||||||
} catch (Throwable ignored) {
|
|
||||||
return fallback;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private int clamp(int value, int min, int max) {
|
|
||||||
return Math.max(min, Math.min(max, value));
|
|
||||||
}
|
|
||||||
|
|
||||||
private int dp(int value) {
|
|
||||||
return Math.round(value * getResources().getDisplayMetrics().density);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,8 +17,6 @@ import androidx.recyclerview.widget.ItemTouchHelper;
|
|||||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
import com.google.android.material.card.MaterialCardView;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -41,7 +39,7 @@ final class LayoutOrderingUi {
|
|||||||
LinearLayout.LayoutParams listParams = new LinearLayout.LayoutParams(
|
LinearLayout.LayoutParams listParams = new LinearLayout.LayoutParams(
|
||||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||||
ViewGroup.LayoutParams.WRAP_CONTENT);
|
ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||||
listParams.topMargin = dp(context, 12);
|
listParams.topMargin = ViewTreeSupport.dp(context, 12);
|
||||||
content.addView(list, listParams);
|
content.addView(list, listParams);
|
||||||
bindOrderingList(context, prefs, list);
|
bindOrderingList(context, prefs, list);
|
||||||
|
|
||||||
@@ -50,7 +48,7 @@ final class LayoutOrderingUi {
|
|||||||
LinearLayout.LayoutParams sortTitleParams = new LinearLayout.LayoutParams(
|
LinearLayout.LayoutParams sortTitleParams = new LinearLayout.LayoutParams(
|
||||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||||
ViewGroup.LayoutParams.WRAP_CONTENT);
|
ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||||
sortTitleParams.topMargin = dp(context, 16);
|
sortTitleParams.topMargin = ViewTreeSupport.dp(context, 16);
|
||||||
content.addView(sortTitle, sortTitleParams);
|
content.addView(sortTitle, sortTitleParams);
|
||||||
|
|
||||||
RadioGroup sortGroup = new RadioGroup(context);
|
RadioGroup sortGroup = new RadioGroup(context);
|
||||||
@@ -70,7 +68,7 @@ final class LayoutOrderingUi {
|
|||||||
LinearLayout.LayoutParams sortParams = new LinearLayout.LayoutParams(
|
LinearLayout.LayoutParams sortParams = new LinearLayout.LayoutParams(
|
||||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||||
ViewGroup.LayoutParams.WRAP_CONTENT);
|
ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||||
sortParams.topMargin = dp(context, 8);
|
sortParams.topMargin = ViewTreeSupport.dp(context, 8);
|
||||||
content.addView(sortGroup, sortParams);
|
content.addView(sortGroup, sortParams);
|
||||||
|
|
||||||
return card(context, R.string.layout_ordering_title, content);
|
return card(context, R.string.layout_ordering_title, content);
|
||||||
@@ -227,52 +225,25 @@ final class LayoutOrderingUi {
|
|||||||
return tag instanceof String value ? value : "automatic";
|
return tag instanceof String value ? value : "automatic";
|
||||||
}
|
}
|
||||||
|
|
||||||
private static MaterialCardView card(Context context, int titleId, View content) {
|
private static View card(Context context, int titleId, View content) {
|
||||||
MaterialCardView card = new MaterialCardView(context);
|
return ViewTreeSupport.outlinedCard(
|
||||||
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
|
context,
|
||||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
ViewTreeSupport.sectionTitleText(context, titleId, true),
|
||||||
ViewGroup.LayoutParams.WRAP_CONTENT);
|
content);
|
||||||
params.topMargin = dp(context, 16);
|
|
||||||
card.setLayoutParams(params);
|
|
||||||
card.setUseCompatPadding(true);
|
|
||||||
card.setStrokeColor(context.getColor(R.color.sbt_card_outline));
|
|
||||||
card.setStrokeWidth(dp(context, 1));
|
|
||||||
|
|
||||||
LinearLayout inner = vertical(context);
|
|
||||||
inner.setPadding(dp(context, 16), dp(context, 16), dp(context, 16), dp(context, 16));
|
|
||||||
inner.addView(sectionTitle(context, titleId));
|
|
||||||
inner.addView(content);
|
|
||||||
card.addView(inner);
|
|
||||||
return card;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static LinearLayout vertical(Context context) {
|
private static LinearLayout vertical(Context context) {
|
||||||
LinearLayout layout = new LinearLayout(context);
|
return ViewTreeSupport.verticalLayout(context);
|
||||||
layout.setOrientation(LinearLayout.VERTICAL);
|
|
||||||
return layout;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static TextView sectionTitle(Context context, int stringId) {
|
|
||||||
TextView view = new TextView(context);
|
|
||||||
view.setText(stringId);
|
|
||||||
view.setTextAppearance(com.google.android.material.R.style.TextAppearance_MaterialComponents_Subtitle1);
|
|
||||||
view.setAllCaps(true);
|
|
||||||
view.setTypeface(view.getTypeface(), android.graphics.Typeface.BOLD);
|
|
||||||
return view;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static TextView body(Context context, int stringId) {
|
private static TextView body(Context context, int stringId) {
|
||||||
TextView view = new TextView(context);
|
TextView view = new TextView(context);
|
||||||
view.setText(stringId);
|
view.setText(stringId);
|
||||||
view.setTextAppearance(com.google.android.material.R.style.TextAppearance_MaterialComponents_Body2);
|
view.setTextAppearance(com.google.android.material.R.style.TextAppearance_MaterialComponents_Body2);
|
||||||
view.setPadding(0, dp(context, 8), 0, 0);
|
view.setPadding(0, ViewTreeSupport.dp(context, 8), 0, 0);
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int dp(Context context, int value) {
|
|
||||||
return Math.round(value * context.getResources().getDisplayMetrics().density);
|
|
||||||
}
|
|
||||||
|
|
||||||
private record OrderingItem(String key, String label) {
|
private record OrderingItem(String key, String label) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+22
-29
@@ -274,11 +274,11 @@ final class LayoutSectionCopySupport {
|
|||||||
if (mode == Mode.LOCKSCREEN) {
|
if (mode == Mode.LOCKSCREEN) {
|
||||||
return iconKeys(
|
return iconKeys(
|
||||||
SbtSettings.KEY_LAYOUT_NOTIF_ENABLED_LOCKSCREEN,
|
SbtSettings.KEY_LAYOUT_NOTIF_ENABLED_LOCKSCREEN,
|
||||||
"layout_lock_notifications_count",
|
SbtSettings.KEY_LAYOUT_NOTIF_LOCK_COUNT,
|
||||||
"layout_lock_notifications_position",
|
SbtSettings.KEY_LAYOUT_NOTIF_LOCK_POSITION,
|
||||||
"layout_lock_notifications_middle_auto_nearest_side",
|
SbtSettings.KEY_LAYOUT_NOTIF_LOCK_MIDDLE_AUTO_NEAREST_SIDE,
|
||||||
"layout_lock_notifications_middle_side",
|
SbtSettings.KEY_LAYOUT_NOTIF_LOCK_MIDDLE_SIDE,
|
||||||
"layout_lock_notifications_vertical_offset_px",
|
SbtSettings.KEY_LAYOUT_NOTIF_LOCK_VERTICAL_OFFSET_PX,
|
||||||
SbtSettings.layoutLockNotifIconHeightKey(),
|
SbtSettings.layoutLockNotifIconHeightKey(),
|
||||||
SbtDefaults.LAYOUT_NOTIF_ENABLED_LOCKSCREEN_DEFAULT,
|
SbtDefaults.LAYOUT_NOTIF_ENABLED_LOCKSCREEN_DEFAULT,
|
||||||
SbtDefaults.LAYOUT_NOTIF_UNLOCKED_COUNT_DEFAULT,
|
SbtDefaults.LAYOUT_NOTIF_UNLOCKED_COUNT_DEFAULT,
|
||||||
@@ -291,11 +291,11 @@ final class LayoutSectionCopySupport {
|
|||||||
if (mode == Mode.AOD) {
|
if (mode == Mode.AOD) {
|
||||||
return iconKeys(
|
return iconKeys(
|
||||||
SbtSettings.KEY_LAYOUT_NOTIF_ENABLED_AOD,
|
SbtSettings.KEY_LAYOUT_NOTIF_ENABLED_AOD,
|
||||||
"layout_aod_notifications_count",
|
SbtSettings.KEY_LAYOUT_NOTIF_AOD_COUNT,
|
||||||
"layout_aod_notifications_position",
|
SbtSettings.KEY_LAYOUT_NOTIF_AOD_POSITION,
|
||||||
"layout_aod_notifications_middle_auto_nearest_side",
|
SbtSettings.KEY_LAYOUT_NOTIF_AOD_MIDDLE_AUTO_NEAREST_SIDE,
|
||||||
"layout_aod_notifications_middle_side",
|
SbtSettings.KEY_LAYOUT_NOTIF_AOD_MIDDLE_SIDE,
|
||||||
"layout_aod_notifications_vertical_offset_px",
|
SbtSettings.KEY_LAYOUT_NOTIF_AOD_VERTICAL_OFFSET_PX,
|
||||||
SbtSettings.layoutAodNotifIconHeightKey(),
|
SbtSettings.layoutAodNotifIconHeightKey(),
|
||||||
SbtDefaults.LAYOUT_NOTIF_ENABLED_AOD_DEFAULT,
|
SbtDefaults.LAYOUT_NOTIF_ENABLED_AOD_DEFAULT,
|
||||||
SbtDefaults.LAYOUT_NOTIF_UNLOCKED_COUNT_DEFAULT,
|
SbtDefaults.LAYOUT_NOTIF_UNLOCKED_COUNT_DEFAULT,
|
||||||
@@ -326,11 +326,11 @@ final class LayoutSectionCopySupport {
|
|||||||
if (mode == Mode.LOCKSCREEN) {
|
if (mode == Mode.LOCKSCREEN) {
|
||||||
return iconKeys(
|
return iconKeys(
|
||||||
SbtSettings.KEY_LAYOUT_STATUS_ENABLED_LOCKSCREEN,
|
SbtSettings.KEY_LAYOUT_STATUS_ENABLED_LOCKSCREEN,
|
||||||
"layout_lock_status_count",
|
SbtSettings.KEY_LAYOUT_STATUS_LOCK_COUNT,
|
||||||
"layout_lock_status_position",
|
SbtSettings.KEY_LAYOUT_STATUS_LOCK_POSITION,
|
||||||
"layout_lock_status_middle_auto_nearest_side",
|
SbtSettings.KEY_LAYOUT_STATUS_LOCK_MIDDLE_AUTO_NEAREST_SIDE,
|
||||||
"layout_lock_status_middle_side",
|
SbtSettings.KEY_LAYOUT_STATUS_LOCK_MIDDLE_SIDE,
|
||||||
"layout_lock_status_vertical_offset_px",
|
SbtSettings.KEY_LAYOUT_STATUS_LOCK_VERTICAL_OFFSET_PX,
|
||||||
SbtSettings.layoutLockStatusIconHeightKey(),
|
SbtSettings.layoutLockStatusIconHeightKey(),
|
||||||
SbtDefaults.LAYOUT_STATUS_ENABLED_LOCKSCREEN_DEFAULT,
|
SbtDefaults.LAYOUT_STATUS_ENABLED_LOCKSCREEN_DEFAULT,
|
||||||
SbtDefaults.LAYOUT_STATUS_UNLOCKED_COUNT_DEFAULT,
|
SbtDefaults.LAYOUT_STATUS_UNLOCKED_COUNT_DEFAULT,
|
||||||
@@ -343,11 +343,11 @@ final class LayoutSectionCopySupport {
|
|||||||
if (mode == Mode.AOD) {
|
if (mode == Mode.AOD) {
|
||||||
return iconKeys(
|
return iconKeys(
|
||||||
SbtSettings.KEY_LAYOUT_STATUS_ENABLED_AOD,
|
SbtSettings.KEY_LAYOUT_STATUS_ENABLED_AOD,
|
||||||
"layout_aod_status_count",
|
SbtSettings.KEY_LAYOUT_STATUS_AOD_COUNT,
|
||||||
"layout_aod_status_position",
|
SbtSettings.KEY_LAYOUT_STATUS_AOD_POSITION,
|
||||||
"layout_aod_status_middle_auto_nearest_side",
|
SbtSettings.KEY_LAYOUT_STATUS_AOD_MIDDLE_AUTO_NEAREST_SIDE,
|
||||||
"layout_aod_status_middle_side",
|
SbtSettings.KEY_LAYOUT_STATUS_AOD_MIDDLE_SIDE,
|
||||||
"layout_aod_status_vertical_offset_px",
|
SbtSettings.KEY_LAYOUT_STATUS_AOD_VERTICAL_OFFSET_PX,
|
||||||
SbtSettings.layoutAodStatusIconHeightKey(),
|
SbtSettings.layoutAodStatusIconHeightKey(),
|
||||||
SbtDefaults.LAYOUT_STATUS_ENABLED_AOD_DEFAULT,
|
SbtDefaults.LAYOUT_STATUS_ENABLED_AOD_DEFAULT,
|
||||||
SbtDefaults.LAYOUT_STATUS_UNLOCKED_COUNT_DEFAULT,
|
SbtDefaults.LAYOUT_STATUS_UNLOCKED_COUNT_DEFAULT,
|
||||||
@@ -458,7 +458,7 @@ final class LayoutSectionCopySupport {
|
|||||||
LinearLayout.LayoutParams rowParams = new LinearLayout.LayoutParams(
|
LinearLayout.LayoutParams rowParams = new LinearLayout.LayoutParams(
|
||||||
ViewGroup.LayoutParams.WRAP_CONTENT,
|
ViewGroup.LayoutParams.WRAP_CONTENT,
|
||||||
ViewGroup.LayoutParams.WRAP_CONTENT);
|
ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||||
rowParams.leftMargin = dp(context, 12);
|
rowParams.leftMargin = ViewTreeSupport.dp(context, 12);
|
||||||
if (parent.getOrientation() == LinearLayout.HORIZONTAL) {
|
if (parent.getOrientation() == LinearLayout.HORIZONTAL) {
|
||||||
parent.addView(row, rowParams);
|
parent.addView(row, rowParams);
|
||||||
} else {
|
} else {
|
||||||
@@ -518,10 +518,6 @@ final class LayoutSectionCopySupport {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int dp(Context context, int value) {
|
|
||||||
return Math.round(value * context.getResources().getDisplayMetrics().density);
|
|
||||||
}
|
|
||||||
|
|
||||||
private record Option(@Nullable Mode mode, String label, boolean enabled) {
|
private record Option(@Nullable Mode mode, String label, boolean enabled) {
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
@@ -718,10 +714,7 @@ final class LayoutSectionCopySupport {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private String suffixed(String base, int index) {
|
private String suffixed(String base, int index) {
|
||||||
if (base == null || index <= 0) {
|
return SbtSettings.indexedKey(base, index);
|
||||||
return base;
|
|
||||||
}
|
|
||||||
return base + "_" + (index + 1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,94 @@
|
|||||||
|
package se.ajpanton.statusbartweak.shell.ui;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.CheckBox;
|
||||||
|
import android.widget.LinearLayout;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
|
import com.google.android.material.card.MaterialCardView;
|
||||||
|
|
||||||
|
import se.ajpanton.statusbartweak.R;
|
||||||
|
|
||||||
|
final class LayoutXmlCardSupport {
|
||||||
|
private LayoutXmlCardSupport() {
|
||||||
|
}
|
||||||
|
|
||||||
|
static View inflateCard(Context context, @Nullable ViewGroup parentForInflation, int cardId) {
|
||||||
|
View fullLayout = LayoutInflater.from(context)
|
||||||
|
.inflate(R.layout.fragment_layout, parentForInflation, false);
|
||||||
|
View card = fullLayout.findViewById(cardId);
|
||||||
|
if (card == null) {
|
||||||
|
return new View(context);
|
||||||
|
}
|
||||||
|
if (card.getParent() instanceof ViewGroup parent) {
|
||||||
|
parent.removeView(card);
|
||||||
|
}
|
||||||
|
return card;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void setCardTitle(View card, int titleId) {
|
||||||
|
TextView title = findCardTitle(card);
|
||||||
|
if (title != null) {
|
||||||
|
title.setText(titleId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void setIndexedCardTitle(
|
||||||
|
Context context,
|
||||||
|
View card,
|
||||||
|
int titleId,
|
||||||
|
int index,
|
||||||
|
int count
|
||||||
|
) {
|
||||||
|
TextView title = findCardTitle(card);
|
||||||
|
if (title == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (count > 1) {
|
||||||
|
title.setText(context.getString(titleId) + " " + (index + 1));
|
||||||
|
} else {
|
||||||
|
title.setText(titleId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
static TextView findCardTitle(View card) {
|
||||||
|
if (!(card instanceof ViewGroup cardGroup) || cardGroup.getChildCount() <= 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
View inner = cardGroup.getChildAt(0);
|
||||||
|
if (!(inner instanceof ViewGroup innerGroup) || innerGroup.getChildCount() <= 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
View title = innerGroup.getChildAt(0);
|
||||||
|
return title instanceof TextView textView ? textView : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
static LinearLayout removeModeContainerForCheckbox(View root, int checkboxId) {
|
||||||
|
CheckBox checkbox = root.findViewById(checkboxId);
|
||||||
|
View modeContainer = directSectionChild(checkbox);
|
||||||
|
if (modeContainer == null || !(modeContainer.getParent() instanceof LinearLayout sectionContent)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
sectionContent.removeView(modeContainer);
|
||||||
|
return sectionContent;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
static View directSectionChild(@Nullable View child) {
|
||||||
|
View current = child;
|
||||||
|
while (current != null && current.getParent() instanceof View parent) {
|
||||||
|
if (parent.getParent() instanceof MaterialCardView) {
|
||||||
|
return current;
|
||||||
|
}
|
||||||
|
current = parent;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
+62
-239
@@ -20,8 +20,6 @@ import androidx.annotation.Nullable;
|
|||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
|
|
||||||
import com.google.android.material.button.MaterialButton;
|
import com.google.android.material.button.MaterialButton;
|
||||||
import com.google.android.material.card.MaterialCardView;
|
|
||||||
|
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
|
|
||||||
import se.ajpanton.statusbartweak.R;
|
import se.ajpanton.statusbartweak.R;
|
||||||
@@ -47,7 +45,11 @@ abstract class LockedSceneLayoutFragment extends Fragment {
|
|||||||
SharedPreferences prefs = context.getSharedPreferences(SbtSettings.PREFS_NAME, Context.MODE_PRIVATE);
|
SharedPreferences prefs = context.getSharedPreferences(SbtSettings.PREFS_NAME, Context.MODE_PRIVATE);
|
||||||
ScrollView scroll = new ScrollView(context);
|
ScrollView scroll = new ScrollView(context);
|
||||||
LinearLayout root = vertical(context);
|
LinearLayout root = vertical(context);
|
||||||
root.setPadding(dp(20), dp(20), dp(20), dp(20));
|
root.setPadding(
|
||||||
|
ViewTreeSupport.dp(context, 20),
|
||||||
|
ViewTreeSupport.dp(context, 20),
|
||||||
|
ViewTreeSupport.dp(context, 20),
|
||||||
|
ViewTreeSupport.dp(context, 20));
|
||||||
scroll.addView(root);
|
scroll.addView(root);
|
||||||
|
|
||||||
root.addView(title(context, aod ? R.string.section_aod : R.string.section_lockscreen));
|
root.addView(title(context, aod ? R.string.section_aod : R.string.section_lockscreen));
|
||||||
@@ -146,7 +148,7 @@ abstract class LockedSceneLayoutFragment extends Fragment {
|
|||||||
SbtDefaults.LAYOUT_CARRIER_MIDDLE_SIDE_DEFAULT,
|
SbtDefaults.LAYOUT_CARRIER_MIDDLE_SIDE_DEFAULT,
|
||||||
SbtSettings.KEY_LAYOUT_CARRIER_VERTICAL_OFFSET_PX,
|
SbtSettings.KEY_LAYOUT_CARRIER_VERTICAL_OFFSET_PX,
|
||||||
SbtDefaults.LAYOUT_CARRIER_VERTICAL_OFFSET_PX_DEFAULT);
|
SbtDefaults.LAYOUT_CARRIER_VERTICAL_OFFSET_PX_DEFAULT);
|
||||||
setCardTitle(carrierCard, R.string.layout_carrier_position_title);
|
LayoutXmlCardSupport.setCardTitle(carrierCard, R.string.layout_carrier_position_title);
|
||||||
cardsByOrderKey.put("carrier", carrierCard);
|
cardsByOrderKey.put("carrier", carrierCard);
|
||||||
}
|
}
|
||||||
cardsByOrderKey.put("status", configuredIconContainersCardFromLayout(
|
cardsByOrderKey.put("status", configuredIconContainersCardFromLayout(
|
||||||
@@ -223,13 +225,6 @@ abstract class LockedSceneLayoutFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setCardTitle(View card, int titleId) {
|
|
||||||
TextView title = findCardTitle(card);
|
|
||||||
if (title != null) {
|
|
||||||
title.setText(titleId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private View configuredPositionCardFromLayout(
|
private View configuredPositionCardFromLayout(
|
||||||
Context context,
|
Context context,
|
||||||
SharedPreferences prefs,
|
SharedPreferences prefs,
|
||||||
@@ -258,7 +253,7 @@ abstract class LockedSceneLayoutFragment extends Fragment {
|
|||||||
String verticalOffsetKey,
|
String verticalOffsetKey,
|
||||||
int verticalOffsetDefault
|
int verticalOffsetDefault
|
||||||
) {
|
) {
|
||||||
View card = inflateLayoutCard(context, cardId);
|
View card = LayoutXmlCardSupport.inflateCard(context, dynamicContent, cardId);
|
||||||
configureSingleEnabledCheckbox(card, prefs, enabledCheckboxId, enabledKey, enabledDefault);
|
configureSingleEnabledCheckbox(card, prefs, enabledCheckboxId, enabledKey, enabledDefault);
|
||||||
bindXmlPositionSection(
|
bindXmlPositionSection(
|
||||||
card,
|
card,
|
||||||
@@ -459,9 +454,9 @@ abstract class LockedSceneLayoutFragment extends Fragment {
|
|||||||
int count,
|
int count,
|
||||||
@Nullable Runnable onCountChanged
|
@Nullable Runnable onCountChanged
|
||||||
) {
|
) {
|
||||||
View card = inflateLayoutCard(context, cardId);
|
View card = LayoutXmlCardSupport.inflateCard(context, dynamicContent, cardId);
|
||||||
removeSiblingModeCheckboxes(card, modeCheckboxId);
|
removeSiblingModeCheckboxes(card, modeCheckboxId);
|
||||||
LinearLayout sectionContent = removeModeContainerForCheckbox(card, modeCheckboxId);
|
LinearLayout sectionContent = LayoutXmlCardSupport.removeModeContainerForCheckbox(card, modeCheckboxId);
|
||||||
if (sectionContent != null && countKey != null && onCountChanged != null) {
|
if (sectionContent != null && countKey != null && onCountChanged != null) {
|
||||||
int insertIndex = Math.min(1, sectionContent.getChildCount());
|
int insertIndex = Math.min(1, sectionContent.getChildCount());
|
||||||
sectionContent.addView(
|
sectionContent.addView(
|
||||||
@@ -480,7 +475,7 @@ abstract class LockedSceneLayoutFragment extends Fragment {
|
|||||||
Math.min(insertIndex + 1, sectionContent.getChildCount()));
|
Math.min(insertIndex + 1, sectionContent.getChildCount()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
updateIconCardTitle(card, titleId, index, count);
|
LayoutXmlCardSupport.setIndexedCardTitle(context, card, titleId, index, count);
|
||||||
bindXmlPositionSection(
|
bindXmlPositionSection(
|
||||||
card,
|
card,
|
||||||
prefs,
|
prefs,
|
||||||
@@ -511,43 +506,6 @@ abstract class LockedSceneLayoutFragment extends Fragment {
|
|||||||
return card;
|
return card;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateIconCardTitle(View card, int titleId, int index, int count) {
|
|
||||||
TextView title = findCardTitle(card);
|
|
||||||
if (title == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (count > 1) {
|
|
||||||
title.setText(getString(titleId) + " " + (index + 1));
|
|
||||||
} else {
|
|
||||||
title.setText(titleId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private View inflateLayoutCard(Context context, int cardId) {
|
|
||||||
View fullLayout = LayoutInflater.from(context).inflate(R.layout.fragment_layout, dynamicContent, false);
|
|
||||||
View card = fullLayout.findViewById(cardId);
|
|
||||||
if (card == null) {
|
|
||||||
return new View(context);
|
|
||||||
}
|
|
||||||
if (card.getParent() instanceof ViewGroup parent) {
|
|
||||||
parent.removeView(card);
|
|
||||||
}
|
|
||||||
return card;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private TextView findCardTitle(View card) {
|
|
||||||
if (!(card instanceof ViewGroup cardGroup) || cardGroup.getChildCount() <= 0) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
View inner = cardGroup.getChildAt(0);
|
|
||||||
if (!(inner instanceof ViewGroup innerGroup) || innerGroup.getChildCount() <= 0) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
View title = innerGroup.getChildAt(0);
|
|
||||||
return title instanceof TextView textView ? textView : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void configureSingleEnabledCheckbox(
|
private void configureSingleEnabledCheckbox(
|
||||||
View root,
|
View root,
|
||||||
SharedPreferences prefs,
|
SharedPreferences prefs,
|
||||||
@@ -561,11 +519,13 @@ abstract class LockedSceneLayoutFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
hideSiblingCheckBoxes(enabled);
|
hideSiblingCheckBoxes(enabled);
|
||||||
enabled.setText(R.string.layout_item_enabled);
|
enabled.setText(R.string.layout_item_enabled);
|
||||||
enabled.setChecked(prefs.getBoolean(key, defaultValue));
|
ViewTreeSupport.bindBooleanPreference(
|
||||||
enabled.setOnCheckedChangeListener((buttonView, isChecked) -> {
|
requireContext(),
|
||||||
prefs.edit().putBoolean(key, isChecked).apply();
|
prefs,
|
||||||
SbtSettings.ensureReadable(requireContext());
|
enabled,
|
||||||
});
|
key,
|
||||||
|
defaultValue,
|
||||||
|
false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void removeSiblingModeCheckboxes(View root, int keptCheckboxId) {
|
private void removeSiblingModeCheckboxes(View root, int keptCheckboxId) {
|
||||||
@@ -577,47 +537,12 @@ abstract class LockedSceneLayoutFragment extends Fragment {
|
|||||||
if (kept == null) {
|
if (kept == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
View modeContainer = directSectionChild(kept);
|
View modeContainer = LayoutXmlCardSupport.directSectionChild(kept);
|
||||||
if (modeContainer instanceof ViewGroup group) {
|
if (modeContainer instanceof ViewGroup group) {
|
||||||
hideOtherCheckBoxes(group, kept);
|
ViewTreeSupport.hideCheckBoxesExcept(group, kept);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void hideOtherCheckBoxes(View view, CheckBox kept) {
|
|
||||||
if (view instanceof CheckBox checkBox && checkBox != kept) {
|
|
||||||
checkBox.setVisibility(View.GONE);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (view instanceof ViewGroup group) {
|
|
||||||
for (int i = 0; i < group.getChildCount(); i++) {
|
|
||||||
hideOtherCheckBoxes(group.getChildAt(i), kept);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private LinearLayout removeModeContainerForCheckbox(View root, int checkboxId) {
|
|
||||||
CheckBox checkbox = root.findViewById(checkboxId);
|
|
||||||
View modeContainer = directSectionChild(checkbox);
|
|
||||||
if (modeContainer == null || !(modeContainer.getParent() instanceof LinearLayout sectionContent)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
sectionContent.removeView(modeContainer);
|
|
||||||
return sectionContent;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private View directSectionChild(@Nullable View child) {
|
|
||||||
View current = child;
|
|
||||||
while (current != null && current.getParent() instanceof View parent) {
|
|
||||||
if (parent.getParent() instanceof MaterialCardView) {
|
|
||||||
return current;
|
|
||||||
}
|
|
||||||
current = parent;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private View cardsNotificationCard(Context context, SharedPreferences prefs, @Nullable Runnable refresh) {
|
private View cardsNotificationCard(Context context, SharedPreferences prefs, @Nullable Runnable refresh) {
|
||||||
LinearLayout content = vertical(context);
|
LinearLayout content = vertical(context);
|
||||||
LayoutSectionCopySupport.addCardsDropdown(context, prefs, content, copyMode(), refresh);
|
LayoutSectionCopySupport.addCardsDropdown(context, prefs, content, copyMode(), refresh);
|
||||||
@@ -637,18 +562,20 @@ abstract class LockedSceneLayoutFragment extends Fragment {
|
|||||||
aod ? SbtDefaults.CARDS_AOD_MAX_ICONS_PER_ROW_DEFAULT : SbtDefaults.CARDS_LOCK_MAX_ICONS_PER_ROW_DEFAULT,
|
aod ? SbtDefaults.CARDS_AOD_MAX_ICONS_PER_ROW_DEFAULT : SbtDefaults.CARDS_LOCK_MAX_ICONS_PER_ROW_DEFAULT,
|
||||||
aod ? SbtDefaults.CARDS_AOD_MAX_ICONS_PER_ROW_MIN : SbtDefaults.CARDS_LOCK_MAX_ICONS_PER_ROW_MIN,
|
aod ? SbtDefaults.CARDS_AOD_MAX_ICONS_PER_ROW_MIN : SbtDefaults.CARDS_LOCK_MAX_ICONS_PER_ROW_MIN,
|
||||||
aod ? SbtDefaults.CARDS_AOD_MAX_ICONS_PER_ROW_MAX : SbtDefaults.CARDS_LOCK_MAX_ICONS_PER_ROW_MAX));
|
aod ? SbtDefaults.CARDS_AOD_MAX_ICONS_PER_ROW_MAX : SbtDefaults.CARDS_LOCK_MAX_ICONS_PER_ROW_MAX));
|
||||||
content.addView(checkBox(
|
content.addView(ViewTreeSupport.boundCheckBox(
|
||||||
context,
|
context,
|
||||||
prefs,
|
prefs,
|
||||||
R.string.label_even_distribution,
|
R.string.label_even_distribution,
|
||||||
aod ? SbtSettings.KEY_CARDS_AOD_EVEN_DISTRIBUTION : SbtSettings.KEY_CARDS_LOCK_EVEN_DISTRIBUTION,
|
aod ? SbtSettings.KEY_CARDS_AOD_EVEN_DISTRIBUTION : SbtSettings.KEY_CARDS_LOCK_EVEN_DISTRIBUTION,
|
||||||
aod ? SbtDefaults.CARDS_AOD_EVEN_DISTRIBUTION_DEFAULT : SbtDefaults.CARDS_LOCK_EVEN_DISTRIBUTION_DEFAULT));
|
aod ? SbtDefaults.CARDS_AOD_EVEN_DISTRIBUTION_DEFAULT : SbtDefaults.CARDS_LOCK_EVEN_DISTRIBUTION_DEFAULT,
|
||||||
content.addView(checkBox(
|
false));
|
||||||
|
content.addView(ViewTreeSupport.boundCheckBox(
|
||||||
context,
|
context,
|
||||||
prefs,
|
prefs,
|
||||||
R.string.label_limit_screen_width,
|
R.string.label_limit_screen_width,
|
||||||
aod ? SbtSettings.KEY_CARDS_AOD_LIMIT_TO_WIDTH : SbtSettings.KEY_CARDS_LOCK_LIMIT_TO_WIDTH,
|
aod ? SbtSettings.KEY_CARDS_AOD_LIMIT_TO_WIDTH : SbtSettings.KEY_CARDS_LOCK_LIMIT_TO_WIDTH,
|
||||||
aod ? SbtDefaults.CARDS_AOD_LIMIT_TO_WIDTH_DEFAULT : SbtDefaults.CARDS_LOCK_LIMIT_TO_WIDTH_DEFAULT));
|
aod ? SbtDefaults.CARDS_AOD_LIMIT_TO_WIDTH_DEFAULT : SbtDefaults.CARDS_LOCK_LIMIT_TO_WIDTH_DEFAULT,
|
||||||
|
false));
|
||||||
content.addView(sizeStepper(
|
content.addView(sizeStepper(
|
||||||
context,
|
context,
|
||||||
prefs,
|
prefs,
|
||||||
@@ -675,18 +602,19 @@ abstract class LockedSceneLayoutFragment extends Fragment {
|
|||||||
LinearLayout row = new LinearLayout(context);
|
LinearLayout row = new LinearLayout(context);
|
||||||
row.setOrientation(LinearLayout.HORIZONTAL);
|
row.setOrientation(LinearLayout.HORIZONTAL);
|
||||||
row.setGravity(Gravity.CENTER_VERTICAL);
|
row.setGravity(Gravity.CENTER_VERTICAL);
|
||||||
MaterialButton minus = button(context, "-");
|
MaterialButton minus = ViewTreeSupport.outlinedStepperButton(context, "-");
|
||||||
MaterialButton plus = button(context, "+");
|
MaterialButton plus = ViewTreeSupport.outlinedStepperButton(context, "+");
|
||||||
EditText input = numericInput(context, false);
|
EditText input = ViewTreeSupport.numericInput(context, false, 4);
|
||||||
input.setFilters(new InputFilter[]{new InputFilter.LengthFilter(1)});
|
input.setFilters(new InputFilter[]{new InputFilter.LengthFilter(1)});
|
||||||
input.setText(String.valueOf(current));
|
input.setText(String.valueOf(current));
|
||||||
row.addView(minus, buttonParams());
|
row.addView(minus, ViewTreeSupport.stepperButtonParams(context));
|
||||||
row.addView(input, inputParams());
|
row.addView(input, ViewTreeSupport.stepperInputParams(context));
|
||||||
row.addView(plus, buttonParams());
|
row.addView(plus, ViewTreeSupport.stepperButtonParams(context));
|
||||||
outer.addView(row);
|
outer.addView(row);
|
||||||
|
|
||||||
View.OnClickListener listener = view -> {
|
View.OnClickListener listener = view -> {
|
||||||
int next = clampIconContainerCount(parseInt(input, current) + (view == minus ? -1 : 1));
|
int next = SbtSettings.clampIconContainerCount(
|
||||||
|
ViewTreeSupport.parseInt(input, current) + (view == minus ? -1 : 1));
|
||||||
persistIconContainerCount(prefs, countKey, legacyEnabledKey, next);
|
persistIconContainerCount(prefs, countKey, legacyEnabledKey, next);
|
||||||
onChanged.run();
|
onChanged.run();
|
||||||
};
|
};
|
||||||
@@ -694,7 +622,7 @@ abstract class LockedSceneLayoutFragment extends Fragment {
|
|||||||
plus.setOnClickListener(listener);
|
plus.setOnClickListener(listener);
|
||||||
input.setOnFocusChangeListener((v, hasFocus) -> {
|
input.setOnFocusChangeListener((v, hasFocus) -> {
|
||||||
if (!hasFocus) {
|
if (!hasFocus) {
|
||||||
int next = clampIconContainerCount(parseInt(input, current));
|
int next = SbtSettings.clampIconContainerCount(ViewTreeSupport.parseInt(input, current));
|
||||||
persistIconContainerCount(prefs, countKey, legacyEnabledKey, next);
|
persistIconContainerCount(prefs, countKey, legacyEnabledKey, next);
|
||||||
onChanged.run();
|
onChanged.run();
|
||||||
}
|
}
|
||||||
@@ -771,7 +699,7 @@ abstract class LockedSceneLayoutFragment extends Fragment {
|
|||||||
if (input == null) {
|
if (input == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int start = clamp(prefs.getInt(key, defaultValue), min, max);
|
int start = ViewTreeSupport.clamp(prefs.getInt(key, defaultValue), min, max);
|
||||||
input.setFilters(new InputFilter[]{new InputFilter.LengthFilter(4)});
|
input.setFilters(new InputFilter[]{new InputFilter.LengthFilter(4)});
|
||||||
input.setText(String.valueOf(start));
|
input.setText(String.valueOf(start));
|
||||||
bindXmlStepperButton(prefs, key, input, minusFast, -5, min, max);
|
bindXmlStepperButton(prefs, key, input, minusFast, -5, min, max);
|
||||||
@@ -786,7 +714,7 @@ abstract class LockedSceneLayoutFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
input.setOnFocusChangeListener((v, hasFocus) -> {
|
input.setOnFocusChangeListener((v, hasFocus) -> {
|
||||||
if (!hasFocus) {
|
if (!hasFocus) {
|
||||||
int next = clamp(parseInt(input, defaultValue), min, max);
|
int next = ViewTreeSupport.clamp(ViewTreeSupport.parseInt(input, defaultValue), min, max);
|
||||||
input.setText(String.valueOf(next));
|
input.setText(String.valueOf(next));
|
||||||
persistIntPref(prefs, key, next);
|
persistIntPref(prefs, key, next);
|
||||||
}
|
}
|
||||||
@@ -806,7 +734,7 @@ abstract class LockedSceneLayoutFragment extends Fragment {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
button.setOnClickListener(v -> {
|
button.setOnClickListener(v -> {
|
||||||
int next = clamp(parseInt(input, 0) + delta, min, max);
|
int next = ViewTreeSupport.clamp(ViewTreeSupport.parseInt(input, 0) + delta, min, max);
|
||||||
input.setText(String.valueOf(next));
|
input.setText(String.valueOf(next));
|
||||||
persistIntPref(prefs, key, next);
|
persistIntPref(prefs, key, next);
|
||||||
});
|
});
|
||||||
@@ -872,22 +800,8 @@ abstract class LockedSceneLayoutFragment extends Fragment {
|
|||||||
if (view.getVisibility() != View.VISIBLE) {
|
if (view.getVisibility() != View.VISIBLE) {
|
||||||
view.setVisibility(View.VISIBLE);
|
view.setVisibility(View.VISIBLE);
|
||||||
}
|
}
|
||||||
view.setEnabled(enabled);
|
ViewTreeSupport.setEnabledRecursive(view, enabled);
|
||||||
view.setAlpha(enabled ? 1f : 0.45f);
|
view.setAlpha(enabled ? 1f : 0.45f);
|
||||||
if (view instanceof ViewGroup group) {
|
|
||||||
for (int i = 0; i < group.getChildCount(); i++) {
|
|
||||||
updateMiddleOptionChild(group.getChildAt(i), enabled);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateMiddleOptionChild(View view, boolean enabled) {
|
|
||||||
view.setEnabled(enabled);
|
|
||||||
if (view instanceof ViewGroup group) {
|
|
||||||
for (int i = 0; i < group.getChildCount(); i++) {
|
|
||||||
updateMiddleOptionChild(group.getChildAt(i), enabled);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private View stepper(Context context, SharedPreferences prefs, int label, String key, int def, int min, int max) {
|
private View stepper(Context context, SharedPreferences prefs, int label, String key, int def, int min, int max) {
|
||||||
@@ -913,23 +827,25 @@ abstract class LockedSceneLayoutFragment extends Fragment {
|
|||||||
LinearLayout row = new LinearLayout(context);
|
LinearLayout row = new LinearLayout(context);
|
||||||
row.setOrientation(LinearLayout.HORIZONTAL);
|
row.setOrientation(LinearLayout.HORIZONTAL);
|
||||||
row.setGravity(Gravity.CENTER_VERTICAL);
|
row.setGravity(Gravity.CENTER_VERTICAL);
|
||||||
MaterialButton minus = button(context, "-");
|
MaterialButton minus = ViewTreeSupport.outlinedStepperButton(context, "-");
|
||||||
MaterialButton plus = button(context, "+");
|
MaterialButton plus = ViewTreeSupport.outlinedStepperButton(context, "+");
|
||||||
MaterialButton reset = showDefaultButton ? button(context, "D") : null;
|
MaterialButton reset = showDefaultButton
|
||||||
EditText input = numericInput(context, true);
|
? ViewTreeSupport.outlinedStepperButton(context, "D")
|
||||||
input.setText(String.valueOf(clamp(prefs.getInt(key, def), min, max)));
|
: null;
|
||||||
row.addView(minus, buttonParams());
|
EditText input = ViewTreeSupport.numericInput(context, true, 4);
|
||||||
row.addView(input, inputParams());
|
input.setText(String.valueOf(ViewTreeSupport.clamp(prefs.getInt(key, def), min, max)));
|
||||||
row.addView(plus, buttonParams());
|
row.addView(minus, ViewTreeSupport.stepperButtonParams(context));
|
||||||
|
row.addView(input, ViewTreeSupport.stepperInputParams(context));
|
||||||
|
row.addView(plus, ViewTreeSupport.stepperButtonParams(context));
|
||||||
if (reset != null) {
|
if (reset != null) {
|
||||||
LinearLayout.LayoutParams resetParams = buttonParams();
|
LinearLayout.LayoutParams resetParams = ViewTreeSupport.stepperButtonParams(context);
|
||||||
resetParams.leftMargin = dp(8);
|
resetParams.leftMargin = ViewTreeSupport.dp(context, 8);
|
||||||
row.addView(reset, resetParams);
|
row.addView(reset, resetParams);
|
||||||
}
|
}
|
||||||
outer.addView(row);
|
outer.addView(row);
|
||||||
View.OnClickListener listener = view -> {
|
View.OnClickListener listener = view -> {
|
||||||
int delta = view == minus ? -1 : 1;
|
int delta = view == minus ? -1 : 1;
|
||||||
int next = clamp(parseInt(input, def) + delta, min, max);
|
int next = ViewTreeSupport.clamp(ViewTreeSupport.parseInt(input, def) + delta, min, max);
|
||||||
input.setText(String.valueOf(next));
|
input.setText(String.valueOf(next));
|
||||||
persistIntPref(prefs, key, next);
|
persistIntPref(prefs, key, next);
|
||||||
};
|
};
|
||||||
@@ -937,14 +853,14 @@ abstract class LockedSceneLayoutFragment extends Fragment {
|
|||||||
plus.setOnClickListener(listener);
|
plus.setOnClickListener(listener);
|
||||||
if (reset != null) {
|
if (reset != null) {
|
||||||
reset.setOnClickListener(v -> {
|
reset.setOnClickListener(v -> {
|
||||||
int next = clamp(def, min, max);
|
int next = ViewTreeSupport.clamp(def, min, max);
|
||||||
input.setText(String.valueOf(next));
|
input.setText(String.valueOf(next));
|
||||||
persistIntPref(prefs, key, next);
|
persistIntPref(prefs, key, next);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
input.setOnFocusChangeListener((v, hasFocus) -> {
|
input.setOnFocusChangeListener((v, hasFocus) -> {
|
||||||
if (!hasFocus) {
|
if (!hasFocus) {
|
||||||
int next = clamp(parseInt(input, def), min, max);
|
int next = ViewTreeSupport.clamp(ViewTreeSupport.parseInt(input, def), min, max);
|
||||||
input.setText(String.valueOf(next));
|
input.setText(String.valueOf(next));
|
||||||
persistIntPref(prefs, key, next);
|
persistIntPref(prefs, key, next);
|
||||||
}
|
}
|
||||||
@@ -952,28 +868,6 @@ abstract class LockedSceneLayoutFragment extends Fragment {
|
|||||||
return outer;
|
return outer;
|
||||||
}
|
}
|
||||||
|
|
||||||
private EditText numericInput(Context context, boolean signed) {
|
|
||||||
EditText input = new EditText(context);
|
|
||||||
input.setSingleLine(true);
|
|
||||||
input.setGravity(Gravity.CENTER);
|
|
||||||
input.setInputType(signed
|
|
||||||
? android.text.InputType.TYPE_CLASS_NUMBER | android.text.InputType.TYPE_NUMBER_FLAG_SIGNED
|
|
||||||
: android.text.InputType.TYPE_CLASS_NUMBER);
|
|
||||||
input.setFilters(new InputFilter[]{new InputFilter.LengthFilter(4)});
|
|
||||||
return input;
|
|
||||||
}
|
|
||||||
|
|
||||||
private CheckBox checkBox(Context context, SharedPreferences prefs, int text, String key, boolean def) {
|
|
||||||
CheckBox checkBox = new CheckBox(context);
|
|
||||||
checkBox.setText(text);
|
|
||||||
checkBox.setChecked(prefs.getBoolean(key, def));
|
|
||||||
checkBox.setOnCheckedChangeListener((buttonView, isChecked) -> {
|
|
||||||
prefs.edit().putBoolean(key, isChecked).apply();
|
|
||||||
SbtSettings.ensureReadable(context);
|
|
||||||
});
|
|
||||||
return checkBox;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void persistIntPref(SharedPreferences prefs, String key, int value) {
|
private void persistIntPref(SharedPreferences prefs, String key, int value) {
|
||||||
prefs.edit().putInt(key, value).apply();
|
prefs.edit().putInt(key, value).apply();
|
||||||
SbtSettings.ensureReadable(requireContext());
|
SbtSettings.ensureReadable(requireContext());
|
||||||
@@ -986,7 +880,7 @@ abstract class LockedSceneLayoutFragment extends Fragment {
|
|||||||
boolean legacyEnabledDefault
|
boolean legacyEnabledDefault
|
||||||
) {
|
) {
|
||||||
int fallback = prefs.getBoolean(legacyEnabledKey, legacyEnabledDefault) ? 1 : 0;
|
int fallback = prefs.getBoolean(legacyEnabledKey, legacyEnabledDefault) ? 1 : 0;
|
||||||
return clampIconContainerCount(prefs.getInt(countKey, fallback));
|
return SbtSettings.clampIconContainerCount(prefs.getInt(countKey, fallback));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void persistIconContainerCount(
|
private void persistIconContainerCount(
|
||||||
@@ -995,7 +889,7 @@ abstract class LockedSceneLayoutFragment extends Fragment {
|
|||||||
String legacyEnabledKey,
|
String legacyEnabledKey,
|
||||||
int count
|
int count
|
||||||
) {
|
) {
|
||||||
int clamped = clampIconContainerCount(count);
|
int clamped = SbtSettings.clampIconContainerCount(count);
|
||||||
prefs.edit()
|
prefs.edit()
|
||||||
.putInt(countKey, clamped)
|
.putInt(countKey, clamped)
|
||||||
.putBoolean(legacyEnabledKey, clamped > 0)
|
.putBoolean(legacyEnabledKey, clamped > 0)
|
||||||
@@ -1003,19 +897,12 @@ abstract class LockedSceneLayoutFragment extends Fragment {
|
|||||||
SbtSettings.ensureReadable(requireContext());
|
SbtSettings.ensureReadable(requireContext());
|
||||||
}
|
}
|
||||||
|
|
||||||
private int clampIconContainerCount(int value) {
|
|
||||||
return clamp(
|
|
||||||
value,
|
|
||||||
SbtDefaults.LAYOUT_ICON_CONTAINER_COUNT_MIN,
|
|
||||||
SbtDefaults.LAYOUT_ICON_CONTAINER_COUNT_MAX);
|
|
||||||
}
|
|
||||||
|
|
||||||
private String sceneKey(String suffix) {
|
private String sceneKey(String suffix) {
|
||||||
return (aod ? "layout_aod_" : "layout_lock_") + suffix;
|
return (aod ? "layout_aod_" : "layout_lock_") + suffix;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String indexedSceneKey(String suffix, int index) {
|
private String indexedSceneKey(String suffix, int index) {
|
||||||
return index <= 0 ? sceneKey(suffix) : sceneKey(suffix) + "_" + (index + 1);
|
return SbtSettings.indexedKey(sceneKey(suffix), index);
|
||||||
}
|
}
|
||||||
|
|
||||||
private LayoutSectionCopySupport.Mode copyMode() {
|
private LayoutSectionCopySupport.Mode copyMode() {
|
||||||
@@ -1035,87 +922,23 @@ abstract class LockedSceneLayoutFragment extends Fragment {
|
|||||||
return content instanceof LinearLayout layout ? layout : null;
|
return content instanceof LinearLayout layout ? layout : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private MaterialButton button(Context context, String text) {
|
private View card(Context context, int titleId, View content) {
|
||||||
MaterialButton button = new MaterialButton(context, null, com.google.android.material.R.attr.materialButtonOutlinedStyle);
|
return ViewTreeSupport.outlinedCard(context, sectionTitle(context, titleId), content);
|
||||||
button.setText(text);
|
|
||||||
button.setMinWidth(dp(40));
|
|
||||||
button.setMinHeight(dp(40));
|
|
||||||
button.setPadding(0, button.getPaddingTop(), 0, button.getPaddingBottom());
|
|
||||||
return button;
|
|
||||||
}
|
|
||||||
|
|
||||||
private LinearLayout.LayoutParams buttonParams() {
|
|
||||||
return new LinearLayout.LayoutParams(dp(40), ViewGroup.LayoutParams.WRAP_CONTENT);
|
|
||||||
}
|
|
||||||
|
|
||||||
private LinearLayout.LayoutParams inputParams() {
|
|
||||||
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
|
|
||||||
dp(48),
|
|
||||||
ViewGroup.LayoutParams.WRAP_CONTENT);
|
|
||||||
params.leftMargin = dp(8);
|
|
||||||
params.rightMargin = dp(8);
|
|
||||||
return params;
|
|
||||||
}
|
|
||||||
|
|
||||||
private MaterialCardView card(Context context, int titleId, View content) {
|
|
||||||
MaterialCardView card = new MaterialCardView(context);
|
|
||||||
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
|
|
||||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
|
||||||
ViewGroup.LayoutParams.WRAP_CONTENT);
|
|
||||||
params.topMargin = dp(16);
|
|
||||||
card.setLayoutParams(params);
|
|
||||||
card.setUseCompatPadding(true);
|
|
||||||
card.setStrokeColor(context.getColor(R.color.sbt_card_outline));
|
|
||||||
card.setStrokeWidth(dp(1));
|
|
||||||
LinearLayout inner = vertical(context);
|
|
||||||
inner.setPadding(dp(16), dp(16), dp(16), dp(16));
|
|
||||||
inner.addView(sectionTitle(context, titleId));
|
|
||||||
inner.addView(content);
|
|
||||||
card.addView(inner);
|
|
||||||
return card;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private LinearLayout vertical(Context context) {
|
private LinearLayout vertical(Context context) {
|
||||||
LinearLayout layout = new LinearLayout(context);
|
return ViewTreeSupport.verticalLayout(context);
|
||||||
layout.setOrientation(LinearLayout.VERTICAL);
|
|
||||||
return layout;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private TextView title(Context context, int text) {
|
private TextView title(Context context, int text) {
|
||||||
TextView view = new TextView(context);
|
return ViewTreeSupport.titleText(context, text);
|
||||||
view.setText(text);
|
|
||||||
view.setTextAppearance(com.google.android.material.R.style.TextAppearance_MaterialComponents_Headline5);
|
|
||||||
return view;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private TextView sectionTitle(Context context, int text) {
|
private TextView sectionTitle(Context context, int text) {
|
||||||
TextView view = new TextView(context);
|
return ViewTreeSupport.sectionTitleText(context, text, false);
|
||||||
view.setText(text);
|
|
||||||
view.setAllCaps(true);
|
|
||||||
view.setTypeface(view.getTypeface(), android.graphics.Typeface.BOLD);
|
|
||||||
return view;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private TextView body(Context context, int text) {
|
private TextView body(Context context, int text) {
|
||||||
TextView view = new TextView(context);
|
return ViewTreeSupport.bodyText(context, text, 6);
|
||||||
view.setText(text);
|
|
||||||
view.setPadding(0, dp(8), 0, dp(6));
|
|
||||||
return view;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int parseInt(EditText input, int fallback) {
|
|
||||||
try {
|
|
||||||
return Integer.parseInt(input.getText().toString().trim());
|
|
||||||
} catch (Throwable ignored) {
|
|
||||||
return fallback;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private int clamp(int value, int min, int max) {
|
|
||||||
return Math.max(min, Math.min(max, value));
|
|
||||||
}
|
|
||||||
|
|
||||||
private int dp(int value) {
|
|
||||||
return Math.round(value * getResources().getDisplayMetrics().density);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,8 +15,6 @@ import androidx.annotation.NonNull;
|
|||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
|
|
||||||
import com.google.android.material.switchmaterial.SwitchMaterial;
|
|
||||||
|
|
||||||
public class MiscFragment extends Fragment {
|
public class MiscFragment extends Fragment {
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@@ -28,31 +26,21 @@ public class MiscFragment extends Fragment {
|
|||||||
.getSharedPreferences(SbtSettings.PREFS_NAME, Context.MODE_PRIVATE);
|
.getSharedPreferences(SbtSettings.PREFS_NAME, Context.MODE_PRIVATE);
|
||||||
SbtSettings.ensureReadable(requireContext());
|
SbtSettings.ensureReadable(requireContext());
|
||||||
|
|
||||||
bindSwitch(root, prefs,
|
ViewTreeSupport.bindBooleanPreference(requireContext(), prefs, root,
|
||||||
R.id.misc_aod_keep_visible_during_call_switch,
|
R.id.misc_aod_keep_visible_during_call_switch,
|
||||||
SbtSettings.KEY_AOD_KEEP_VISIBLE_DURING_CALL,
|
SbtSettings.KEY_AOD_KEEP_VISIBLE_DURING_CALL,
|
||||||
SbtDefaults.AOD_KEEP_VISIBLE_DURING_CALL_DEFAULT);
|
SbtDefaults.AOD_KEEP_VISIBLE_DURING_CALL_DEFAULT,
|
||||||
bindSwitch(root, prefs,
|
false);
|
||||||
|
ViewTreeSupport.bindBooleanPreference(requireContext(), prefs, root,
|
||||||
R.id.misc_battery_lockscreen_unplugged_percent_switch,
|
R.id.misc_battery_lockscreen_unplugged_percent_switch,
|
||||||
SbtSettings.KEY_BATTERY_LOCKSCREEN_UNPLUGGED_PERCENT,
|
SbtSettings.KEY_BATTERY_LOCKSCREEN_UNPLUGGED_PERCENT,
|
||||||
SbtDefaults.BATTERY_LOCKSCREEN_UNPLUGGED_PERCENT_DEFAULT);
|
SbtDefaults.BATTERY_LOCKSCREEN_UNPLUGGED_PERCENT_DEFAULT,
|
||||||
bindSwitch(root, prefs,
|
false);
|
||||||
|
ViewTreeSupport.bindBooleanPreference(requireContext(), prefs, root,
|
||||||
R.id.misc_battery_aod_unplugged_percent_switch,
|
R.id.misc_battery_aod_unplugged_percent_switch,
|
||||||
SbtSettings.KEY_BATTERY_AOD_UNPLUGGED_PERCENT,
|
SbtSettings.KEY_BATTERY_AOD_UNPLUGGED_PERCENT,
|
||||||
SbtDefaults.BATTERY_AOD_UNPLUGGED_PERCENT_DEFAULT);
|
SbtDefaults.BATTERY_AOD_UNPLUGGED_PERCENT_DEFAULT,
|
||||||
|
false);
|
||||||
return root;
|
return root;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void bindSwitch(View root,
|
|
||||||
SharedPreferences prefs,
|
|
||||||
int switchId,
|
|
||||||
String key,
|
|
||||||
boolean defaultValue) {
|
|
||||||
SwitchMaterial toggle = root.findViewById(switchId);
|
|
||||||
toggle.setChecked(prefs.getBoolean(key, defaultValue));
|
|
||||||
toggle.setOnCheckedChangeListener((buttonView, isChecked) -> {
|
|
||||||
prefs.edit().putBoolean(key, isChecked).apply();
|
|
||||||
SbtSettings.ensureReadable(requireContext());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,8 +14,6 @@ import androidx.annotation.NonNull;
|
|||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
|
|
||||||
import com.google.android.material.switchmaterial.SwitchMaterial;
|
|
||||||
|
|
||||||
public class StatusChipsFragment extends Fragment {
|
public class StatusChipsFragment extends Fragment {
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@@ -27,27 +25,26 @@ public class StatusChipsFragment extends Fragment {
|
|||||||
.getSharedPreferences(SbtSettings.PREFS_NAME, Context.MODE_PRIVATE);
|
.getSharedPreferences(SbtSettings.PREFS_NAME, Context.MODE_PRIVATE);
|
||||||
SbtSettings.ensureReadable(requireContext());
|
SbtSettings.ensureReadable(requireContext());
|
||||||
|
|
||||||
bindSwitch(root, prefs, R.id.status_chips_hide_all_switch,
|
ViewTreeSupport.bindBooleanPreference(requireContext(), prefs, root,
|
||||||
SbtSettings.KEY_STATUS_CHIPS_HIDE_ALL, false);
|
R.id.status_chips_hide_all_switch,
|
||||||
bindSwitch(root, prefs, R.id.status_chips_hide_media_unlocked_switch,
|
SbtSettings.KEY_STATUS_CHIPS_HIDE_ALL,
|
||||||
SbtSettings.KEY_STATUS_CHIPS_HIDE_MEDIA_UNLOCKED, false);
|
false,
|
||||||
bindSwitch(root, prefs, R.id.status_chips_hide_navigation_unlocked_switch,
|
true);
|
||||||
SbtSettings.KEY_STATUS_CHIPS_HIDE_NAV_UNLOCKED, false);
|
ViewTreeSupport.bindBooleanPreference(requireContext(), prefs, root,
|
||||||
bindSwitch(root, prefs, R.id.status_chips_hide_call_unlocked_switch,
|
R.id.status_chips_hide_media_unlocked_switch,
|
||||||
SbtSettings.KEY_STATUS_CHIPS_HIDE_CALL, false);
|
SbtSettings.KEY_STATUS_CHIPS_HIDE_MEDIA_UNLOCKED,
|
||||||
|
false,
|
||||||
|
true);
|
||||||
|
ViewTreeSupport.bindBooleanPreference(requireContext(), prefs, root,
|
||||||
|
R.id.status_chips_hide_navigation_unlocked_switch,
|
||||||
|
SbtSettings.KEY_STATUS_CHIPS_HIDE_NAV_UNLOCKED,
|
||||||
|
false,
|
||||||
|
true);
|
||||||
|
ViewTreeSupport.bindBooleanPreference(requireContext(), prefs, root,
|
||||||
|
R.id.status_chips_hide_call_unlocked_switch,
|
||||||
|
SbtSettings.KEY_STATUS_CHIPS_HIDE_CALL,
|
||||||
|
false,
|
||||||
|
true);
|
||||||
return root;
|
return root;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void bindSwitch(View root,
|
|
||||||
SharedPreferences prefs,
|
|
||||||
int switchId,
|
|
||||||
String key,
|
|
||||||
boolean defaultValue) {
|
|
||||||
SwitchMaterial toggle = root.findViewById(switchId);
|
|
||||||
toggle.setChecked(prefs.getBoolean(key, defaultValue));
|
|
||||||
toggle.setOnCheckedChangeListener((buttonView, isChecked) -> {
|
|
||||||
prefs.edit().putBoolean(key, isChecked).commit();
|
|
||||||
SbtSettings.ensureReadable(requireContext());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import se.ajpanton.statusbartweak.shell.settings.SbtDefaults;
|
|||||||
import se.ajpanton.statusbartweak.shell.settings.SbtSettings;
|
import se.ajpanton.statusbartweak.shell.settings.SbtSettings;
|
||||||
import se.ajpanton.statusbartweak.shell.settings.SystemIconRules;
|
import se.ajpanton.statusbartweak.shell.settings.SystemIconRules;
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.content.res.ColorStateList;
|
import android.content.res.ColorStateList;
|
||||||
@@ -38,7 +39,6 @@ import java.util.HashMap;
|
|||||||
public class SystemIconsFragment extends Fragment {
|
public class SystemIconsFragment extends Fragment {
|
||||||
|
|
||||||
private static final String QUICKSTAR_PACKAGE = "com.samsung.android.qstuner";
|
private static final String QUICKSTAR_PACKAGE = "com.samsung.android.qstuner";
|
||||||
private static final String SYSTEMUI_PACKAGE = "com.android.systemui";
|
|
||||||
private static final int TOGGLE_ICON_DP = 24;
|
private static final int TOGGLE_ICON_DP = 24;
|
||||||
|
|
||||||
private static final List<SystemIconSection> SECTIONS = Arrays.asList(
|
private static final List<SystemIconSection> SECTIONS = Arrays.asList(
|
||||||
@@ -156,7 +156,7 @@ public class SystemIconsFragment extends Fragment {
|
|||||||
View content = root.findViewById(R.id.system_icons_content);
|
View content = root.findViewById(R.id.system_icons_content);
|
||||||
TextView disabledHint = root.findViewById(R.id.system_icons_disabled_hint);
|
TextView disabledHint = root.findViewById(R.id.system_icons_disabled_hint);
|
||||||
if (content != null) {
|
if (content != null) {
|
||||||
setViewTreeEnabled(content, enabled);
|
ViewTreeSupport.setEnabledRecursive(content, enabled);
|
||||||
content.setAlpha(enabled ? 1f : 0.45f);
|
content.setAlpha(enabled ? 1f : 0.45f);
|
||||||
}
|
}
|
||||||
if (disabledHint != null) {
|
if (disabledHint != null) {
|
||||||
@@ -165,19 +165,6 @@ public class SystemIconsFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setViewTreeEnabled(View view, boolean enabled) {
|
|
||||||
if (view == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
view.setEnabled(enabled);
|
|
||||||
if (view instanceof ViewGroup) {
|
|
||||||
ViewGroup group = (ViewGroup) view;
|
|
||||||
for (int i = 0; i < group.getChildCount(); i++) {
|
|
||||||
setViewTreeEnabled(group.getChildAt(i), enabled);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private View createRow(ViewGroup parent,
|
private View createRow(ViewGroup parent,
|
||||||
SharedPreferences prefs,
|
SharedPreferences prefs,
|
||||||
Map<String, Integer> blockedModes,
|
Map<String, Integer> blockedModes,
|
||||||
@@ -189,7 +176,7 @@ public class SystemIconsFragment extends Fragment {
|
|||||||
row.setLayoutParams(new LinearLayout.LayoutParams(
|
row.setLayoutParams(new LinearLayout.LayoutParams(
|
||||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||||
ViewGroup.LayoutParams.WRAP_CONTENT));
|
ViewGroup.LayoutParams.WRAP_CONTENT));
|
||||||
row.setPadding(0, dpToPx(context, 6), 0, dpToPx(context, 6));
|
row.setPadding(0, ViewTreeSupport.dp(context, 6), 0, ViewTreeSupport.dp(context, 6));
|
||||||
|
|
||||||
LinearLayout modeStrip = new LinearLayout(context);
|
LinearLayout modeStrip = new LinearLayout(context);
|
||||||
modeStrip.setOrientation(LinearLayout.HORIZONTAL);
|
modeStrip.setOrientation(LinearLayout.HORIZONTAL);
|
||||||
@@ -210,7 +197,7 @@ public class SystemIconsFragment extends Fragment {
|
|||||||
0,
|
0,
|
||||||
ViewGroup.LayoutParams.WRAP_CONTENT);
|
ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||||
labelParams.weight = 1f;
|
labelParams.weight = 1f;
|
||||||
labelParams.leftMargin = dpToPx(context, 8);
|
labelParams.leftMargin = ViewTreeSupport.dp(context, 8);
|
||||||
label.setLayoutParams(labelParams);
|
label.setLayoutParams(labelParams);
|
||||||
label.setText(context.getString(entry.labelRes));
|
label.setText(context.getString(entry.labelRes));
|
||||||
label.setTextAppearance(com.google.android.material.R.style.TextAppearance_MaterialComponents_Body1);
|
label.setTextAppearance(com.google.android.material.R.style.TextAppearance_MaterialComponents_Body1);
|
||||||
@@ -228,13 +215,13 @@ public class SystemIconsFragment extends Fragment {
|
|||||||
cell.setOrientation(LinearLayout.HORIZONTAL);
|
cell.setOrientation(LinearLayout.HORIZONTAL);
|
||||||
cell.setGravity(Gravity.CENTER);
|
cell.setGravity(Gravity.CENTER);
|
||||||
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
|
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
|
||||||
dpToPx(context, 32), ViewGroup.LayoutParams.WRAP_CONTENT);
|
ViewTreeSupport.dp(context, 32), ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||||
cell.setLayoutParams(params);
|
cell.setLayoutParams(params);
|
||||||
|
|
||||||
FrameLayout iconCell = new FrameLayout(context);
|
FrameLayout iconCell = new FrameLayout(context);
|
||||||
LinearLayout.LayoutParams iconCellParams = new LinearLayout.LayoutParams(
|
LinearLayout.LayoutParams iconCellParams = new LinearLayout.LayoutParams(
|
||||||
dpToPx(context, TOGGLE_ICON_DP),
|
ViewTreeSupport.dp(context, TOGGLE_ICON_DP),
|
||||||
dpToPx(context, TOGGLE_ICON_DP));
|
ViewTreeSupport.dp(context, TOGGLE_ICON_DP));
|
||||||
iconCell.setLayoutParams(iconCellParams);
|
iconCell.setLayoutParams(iconCellParams);
|
||||||
|
|
||||||
ImageView iconView = new ImageView(context);
|
ImageView iconView = new ImageView(context);
|
||||||
@@ -320,7 +307,7 @@ public class SystemIconsFragment extends Fragment {
|
|||||||
for (String name : entry.quickStarDrawableNames) {
|
for (String name : entry.quickStarDrawableNames) {
|
||||||
Drawable drawable = loadPackageDrawable(context, QUICKSTAR_PACKAGE, name);
|
Drawable drawable = loadPackageDrawable(context, QUICKSTAR_PACKAGE, name);
|
||||||
if (drawable == null) {
|
if (drawable == null) {
|
||||||
drawable = loadPackageDrawable(context, SYSTEMUI_PACKAGE, name);
|
drawable = loadPackageDrawable(context, SbtSettings.PACKAGE_SYSTEMUI, name);
|
||||||
}
|
}
|
||||||
if (drawable != null) {
|
if (drawable != null) {
|
||||||
return drawable;
|
return drawable;
|
||||||
@@ -334,6 +321,7 @@ public class SystemIconsFragment extends Fragment {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressLint("DiscouragedApi")
|
||||||
private Drawable loadPackageDrawable(Context context, String packageName, String drawableName) {
|
private Drawable loadPackageDrawable(Context context, String packageName, String drawableName) {
|
||||||
if (context == null || drawableName == null || drawableName.trim().isEmpty()) {
|
if (context == null || drawableName == null || drawableName.trim().isEmpty()) {
|
||||||
return null;
|
return null;
|
||||||
@@ -363,7 +351,7 @@ public class SystemIconsFragment extends Fragment {
|
|||||||
quickStarContext = pkgContext;
|
quickStarContext = pkgContext;
|
||||||
}
|
}
|
||||||
return pkgContext;
|
return pkgContext;
|
||||||
} catch (Throwable ignored) {
|
} catch (Exception ignored) {
|
||||||
if (QUICKSTAR_PACKAGE.equals(packageName)) {
|
if (QUICKSTAR_PACKAGE.equals(packageName)) {
|
||||||
quickStarContext = null;
|
quickStarContext = null;
|
||||||
}
|
}
|
||||||
@@ -381,7 +369,7 @@ public class SystemIconsFragment extends Fragment {
|
|||||||
Drawable copy = state.newDrawable(context.getResources(), context.getTheme());
|
Drawable copy = state.newDrawable(context.getResources(), context.getTheme());
|
||||||
return copy != null ? copy.mutate() : drawable.mutate();
|
return copy != null ? copy.mutate() : drawable.mutate();
|
||||||
}
|
}
|
||||||
} catch (Throwable ignored) {
|
} catch (Exception ignored) {
|
||||||
}
|
}
|
||||||
return drawable.mutate();
|
return drawable.mutate();
|
||||||
}
|
}
|
||||||
@@ -402,11 +390,6 @@ public class SystemIconsFragment extends Fragment {
|
|||||||
return drawable;
|
return drawable;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int dpToPx(Context context, int dp) {
|
|
||||||
float density = context.getResources().getDisplayMetrics().density;
|
|
||||||
return Math.round(dp * density);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final class SystemIconSection {
|
private static final class SystemIconSection {
|
||||||
final int labelRes;
|
final int labelRes;
|
||||||
final List<SystemIconEntry> entries;
|
final List<SystemIconEntry> entries;
|
||||||
|
|||||||
@@ -0,0 +1,200 @@
|
|||||||
|
package se.ajpanton.statusbartweak.shell.ui;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
import android.text.InputFilter;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.CheckBox;
|
||||||
|
import android.widget.CompoundButton;
|
||||||
|
import android.widget.EditText;
|
||||||
|
import android.widget.LinearLayout;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import com.google.android.material.button.MaterialButton;
|
||||||
|
import com.google.android.material.card.MaterialCardView;
|
||||||
|
|
||||||
|
import se.ajpanton.statusbartweak.R;
|
||||||
|
|
||||||
|
import se.ajpanton.statusbartweak.shell.settings.SbtSettings;
|
||||||
|
|
||||||
|
final class ViewTreeSupport {
|
||||||
|
private ViewTreeSupport() {
|
||||||
|
}
|
||||||
|
|
||||||
|
static void setEnabledRecursive(View view, boolean enabled) {
|
||||||
|
if (view == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
view.setEnabled(enabled);
|
||||||
|
if (view instanceof ViewGroup group) {
|
||||||
|
for (int i = 0; i < group.getChildCount(); i++) {
|
||||||
|
setEnabledRecursive(group.getChildAt(i), enabled);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hideCheckBoxesExcept(View view, CheckBox kept) {
|
||||||
|
if (view instanceof CheckBox checkBox && checkBox != kept) {
|
||||||
|
checkBox.setVisibility(View.GONE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (view instanceof ViewGroup group) {
|
||||||
|
for (int i = 0; i < group.getChildCount(); i++) {
|
||||||
|
hideCheckBoxesExcept(group.getChildAt(i), kept);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dp(Context context, int value) {
|
||||||
|
return Math.round(value * context.getResources().getDisplayMetrics().density);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int clamp(int value, int min, int max) {
|
||||||
|
return Math.max(min, Math.min(max, value));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int parseInt(EditText input, int fallback) {
|
||||||
|
if (input == null || input.getText() == null) {
|
||||||
|
return fallback;
|
||||||
|
}
|
||||||
|
String text = input.getText().toString().trim();
|
||||||
|
if (text.isEmpty() || "-".equals(text)) {
|
||||||
|
return fallback;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return Integer.parseInt(text);
|
||||||
|
} catch (NumberFormatException ignored) {
|
||||||
|
return fallback;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void bindBooleanPreference(Context context,
|
||||||
|
SharedPreferences prefs,
|
||||||
|
View root,
|
||||||
|
int buttonId,
|
||||||
|
String key,
|
||||||
|
boolean defaultValue,
|
||||||
|
boolean commit) {
|
||||||
|
CompoundButton button = root != null ? root.findViewById(buttonId) : null;
|
||||||
|
bindBooleanPreference(context, prefs, button, key, defaultValue, commit);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void bindBooleanPreference(Context context,
|
||||||
|
SharedPreferences prefs,
|
||||||
|
CompoundButton button,
|
||||||
|
String key,
|
||||||
|
boolean defaultValue,
|
||||||
|
boolean commit) {
|
||||||
|
if (context == null || prefs == null || button == null || key == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
button.setChecked(prefs.getBoolean(key, defaultValue));
|
||||||
|
button.setOnCheckedChangeListener((buttonView, isChecked) -> {
|
||||||
|
SharedPreferences.Editor editor = prefs.edit().putBoolean(key, isChecked);
|
||||||
|
if (commit) {
|
||||||
|
editor.commit();
|
||||||
|
} else {
|
||||||
|
editor.apply();
|
||||||
|
}
|
||||||
|
SbtSettings.ensureReadable(context);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static CheckBox boundCheckBox(Context context,
|
||||||
|
SharedPreferences prefs,
|
||||||
|
int text,
|
||||||
|
String key,
|
||||||
|
boolean defaultValue,
|
||||||
|
boolean commit) {
|
||||||
|
CheckBox checkBox = new CheckBox(context);
|
||||||
|
checkBox.setText(text);
|
||||||
|
bindBooleanPreference(context, prefs, checkBox, key, defaultValue, commit);
|
||||||
|
return checkBox;
|
||||||
|
}
|
||||||
|
|
||||||
|
static MaterialButton outlinedStepperButton(Context context, String text) {
|
||||||
|
MaterialButton button = new MaterialButton(
|
||||||
|
context,
|
||||||
|
null,
|
||||||
|
com.google.android.material.R.attr.materialButtonOutlinedStyle);
|
||||||
|
button.setText(text);
|
||||||
|
button.setMinWidth(dp(context, 40));
|
||||||
|
button.setMinHeight(dp(context, 40));
|
||||||
|
button.setPadding(0, button.getPaddingTop(), 0, button.getPaddingBottom());
|
||||||
|
return button;
|
||||||
|
}
|
||||||
|
|
||||||
|
static LinearLayout.LayoutParams stepperButtonParams(Context context) {
|
||||||
|
return new LinearLayout.LayoutParams(dp(context, 40), ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
static LinearLayout.LayoutParams stepperInputParams(Context context) {
|
||||||
|
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
|
||||||
|
dp(context, 48),
|
||||||
|
ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||||
|
params.leftMargin = dp(context, 8);
|
||||||
|
params.rightMargin = dp(context, 8);
|
||||||
|
return params;
|
||||||
|
}
|
||||||
|
|
||||||
|
static EditText numericInput(Context context, boolean signed, int maxLength) {
|
||||||
|
EditText input = new EditText(context);
|
||||||
|
input.setGravity(android.view.Gravity.CENTER);
|
||||||
|
input.setSingleLine(true);
|
||||||
|
input.setInputType(signed
|
||||||
|
? android.text.InputType.TYPE_CLASS_NUMBER | android.text.InputType.TYPE_NUMBER_FLAG_SIGNED
|
||||||
|
: android.text.InputType.TYPE_CLASS_NUMBER);
|
||||||
|
input.setFilters(new InputFilter[]{new InputFilter.LengthFilter(maxLength)});
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
|
||||||
|
static LinearLayout verticalLayout(Context context) {
|
||||||
|
LinearLayout layout = new LinearLayout(context);
|
||||||
|
layout.setOrientation(LinearLayout.VERTICAL);
|
||||||
|
return layout;
|
||||||
|
}
|
||||||
|
|
||||||
|
static TextView titleText(Context context, int text) {
|
||||||
|
TextView view = new TextView(context);
|
||||||
|
view.setText(text);
|
||||||
|
view.setTextAppearance(com.google.android.material.R.style.TextAppearance_MaterialComponents_Headline5);
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
static TextView sectionTitleText(Context context, int text, boolean applySubtitleAppearance) {
|
||||||
|
TextView view = new TextView(context);
|
||||||
|
view.setText(text);
|
||||||
|
if (applySubtitleAppearance) {
|
||||||
|
view.setTextAppearance(com.google.android.material.R.style.TextAppearance_MaterialComponents_Subtitle1);
|
||||||
|
}
|
||||||
|
view.setAllCaps(true);
|
||||||
|
view.setTypeface(view.getTypeface(), android.graphics.Typeface.BOLD);
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
static TextView bodyText(Context context, int text, int bottomPaddingDp) {
|
||||||
|
TextView view = new TextView(context);
|
||||||
|
view.setText(text);
|
||||||
|
view.setPadding(0, dp(context, 8), 0, dp(context, bottomPaddingDp));
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
static MaterialCardView outlinedCard(Context context, View title, View content) {
|
||||||
|
MaterialCardView card = new MaterialCardView(context);
|
||||||
|
LinearLayout.LayoutParams cardParams = new LinearLayout.LayoutParams(
|
||||||
|
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||||
|
ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||||
|
cardParams.topMargin = dp(context, 16);
|
||||||
|
card.setLayoutParams(cardParams);
|
||||||
|
card.setUseCompatPadding(true);
|
||||||
|
card.setStrokeColor(context.getColor(R.color.sbt_card_outline));
|
||||||
|
card.setStrokeWidth(dp(context, 1));
|
||||||
|
LinearLayout inner = verticalLayout(context);
|
||||||
|
inner.setPadding(dp(context, 16), dp(context, 16), dp(context, 16), dp(context, 16));
|
||||||
|
inner.addView(title);
|
||||||
|
inner.addView(content);
|
||||||
|
card.addView(inner);
|
||||||
|
return card;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -16,39 +16,6 @@
|
|||||||
android:text="@string/layout_title"
|
android:text="@string/layout_title"
|
||||||
android:textAppearance="?attr/textAppearanceHeadline5" />
|
android:textAppearance="?attr/textAppearanceHeadline5" />
|
||||||
|
|
||||||
<com.google.android.material.card.MaterialCardView
|
|
||||||
android:id="@+id/layout_master_card"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="16dp"
|
|
||||||
app:cardUseCompatPadding="true"
|
|
||||||
app:strokeColor="@color/sbt_card_outline"
|
|
||||||
app:strokeWidth="1dp">
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:padding="16dp">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@string/layout_master_toggle_title"
|
|
||||||
android:textAppearance="?attr/textAppearanceSubtitle1"
|
|
||||||
android:textAllCaps="true"
|
|
||||||
android:letterSpacing="0.03"
|
|
||||||
android:textStyle="bold" />
|
|
||||||
|
|
||||||
<com.google.android.material.switchmaterial.SwitchMaterial
|
|
||||||
android:id="@+id/clock_enabled_switch"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="8dp"
|
|
||||||
android:text="@string/layout_enabled" />
|
|
||||||
</LinearLayout>
|
|
||||||
</com.google.android.material.card.MaterialCardView>
|
|
||||||
|
|
||||||
<com.google.android.material.card.MaterialCardView
|
<com.google.android.material.card.MaterialCardView
|
||||||
android:id="@+id/layout_clock_card"
|
android:id="@+id/layout_clock_card"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
@@ -934,307 +901,5 @@
|
|||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</com.google.android.material.card.MaterialCardView>
|
</com.google.android.material.card.MaterialCardView>
|
||||||
|
|
||||||
<com.google.android.material.card.MaterialCardView
|
|
||||||
android:id="@+id/layout_ordering_card"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="16dp"
|
|
||||||
android:layout_marginBottom="20dp"
|
|
||||||
app:cardUseCompatPadding="true"
|
|
||||||
app:strokeColor="@color/sbt_card_outline"
|
|
||||||
app:strokeWidth="1dp">
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:padding="16dp">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@string/layout_ordering_title"
|
|
||||||
android:textAppearance="?attr/textAppearanceSubtitle1"
|
|
||||||
android:textAllCaps="true"
|
|
||||||
android:letterSpacing="0.03"
|
|
||||||
android:textStyle="bold" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="8dp"
|
|
||||||
android:text="@string/layout_ordering_hint"
|
|
||||||
android:textAppearance="?attr/textAppearanceBody2" />
|
|
||||||
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
|
||||||
android:id="@+id/layout_ordering_list"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="12dp"
|
|
||||||
android:nestedScrollingEnabled="false" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="16dp"
|
|
||||||
android:text="@string/layout_sort_icons_title"
|
|
||||||
android:textAppearance="?attr/textAppearanceBody2"
|
|
||||||
android:textStyle="bold" />
|
|
||||||
|
|
||||||
<RadioGroup
|
|
||||||
android:id="@+id/layout_sort_icons_group"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="8dp"
|
|
||||||
android:orientation="horizontal">
|
|
||||||
|
|
||||||
<RadioButton
|
|
||||||
android:id="@+id/layout_sort_icons_stock"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_weight="1"
|
|
||||||
android:maxLines="1"
|
|
||||||
android:singleLine="true"
|
|
||||||
android:text="@string/layout_sort_icons_stock" />
|
|
||||||
|
|
||||||
<RadioButton
|
|
||||||
android:id="@+id/layout_sort_icons_reversed"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_weight="1"
|
|
||||||
android:maxLines="1"
|
|
||||||
android:singleLine="true"
|
|
||||||
android:text="@string/layout_sort_icons_reversed" />
|
|
||||||
|
|
||||||
<RadioButton
|
|
||||||
android:id="@+id/layout_sort_icons_automatic"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_weight="1"
|
|
||||||
android:checked="true"
|
|
||||||
android:maxLines="1"
|
|
||||||
android:singleLine="true"
|
|
||||||
android:text="@string/layout_sort_icons_automatic" />
|
|
||||||
</RadioGroup>
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
</com.google.android.material.card.MaterialCardView>
|
|
||||||
|
|
||||||
<com.google.android.material.card.MaterialCardView
|
|
||||||
android:id="@+id/layout_padding_card"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="16dp"
|
|
||||||
android:layout_marginBottom="20dp"
|
|
||||||
app:cardUseCompatPadding="true"
|
|
||||||
app:strokeColor="@color/sbt_card_outline"
|
|
||||||
app:strokeWidth="1dp">
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:padding="16dp">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@string/layout_padding_title"
|
|
||||||
android:textAppearance="?attr/textAppearanceSubtitle1"
|
|
||||||
android:textAllCaps="true"
|
|
||||||
android:letterSpacing="0.03"
|
|
||||||
android:textStyle="bold" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="12dp"
|
|
||||||
android:text="@string/layout_cutout_gap_label"
|
|
||||||
android:textAppearance="?attr/textAppearanceBody2" />
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="8dp"
|
|
||||||
android:gravity="center_vertical"
|
|
||||||
android:orientation="horizontal">
|
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
|
||||||
android:id="@+id/layout_cutout_gap_minus"
|
|
||||||
style="?attr/materialButtonOutlinedStyle"
|
|
||||||
android:layout_width="40dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="-" />
|
|
||||||
|
|
||||||
<EditText
|
|
||||||
android:id="@+id/layout_cutout_gap_input"
|
|
||||||
android:layout_width="48dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="8dp"
|
|
||||||
android:layout_marginEnd="8dp"
|
|
||||||
android:ems="4"
|
|
||||||
android:gravity="center"
|
|
||||||
android:importantForAutofill="no"
|
|
||||||
android:inputType="numberSigned"
|
|
||||||
android:maxLines="1"
|
|
||||||
android:singleLine="true" />
|
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
|
||||||
android:id="@+id/layout_cutout_gap_plus"
|
|
||||||
style="?attr/materialButtonOutlinedStyle"
|
|
||||||
android:layout_width="40dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="+" />
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="12dp"
|
|
||||||
android:text="@string/layout_left_padding_label"
|
|
||||||
android:textAppearance="?attr/textAppearanceBody2" />
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="8dp"
|
|
||||||
android:gravity="center_vertical"
|
|
||||||
android:orientation="horizontal">
|
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
|
||||||
android:id="@+id/layout_left_padding_minus"
|
|
||||||
style="?attr/materialButtonOutlinedStyle"
|
|
||||||
android:layout_width="40dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="-" />
|
|
||||||
|
|
||||||
<EditText
|
|
||||||
android:id="@+id/layout_left_padding_input"
|
|
||||||
android:layout_width="48dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="8dp"
|
|
||||||
android:layout_marginEnd="8dp"
|
|
||||||
android:ems="4"
|
|
||||||
android:gravity="center"
|
|
||||||
android:importantForAutofill="no"
|
|
||||||
android:inputType="numberSigned"
|
|
||||||
android:maxLines="1"
|
|
||||||
android:singleLine="true" />
|
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
|
||||||
android:id="@+id/layout_left_padding_plus"
|
|
||||||
style="?attr/materialButtonOutlinedStyle"
|
|
||||||
android:layout_width="40dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="+" />
|
|
||||||
|
|
||||||
<CheckBox
|
|
||||||
android:id="@+id/layout_left_padding_add_stock"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="8dp"
|
|
||||||
android:text="@string/layout_padding_add_stock" />
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="12dp"
|
|
||||||
android:text="@string/layout_right_padding_label"
|
|
||||||
android:textAppearance="?attr/textAppearanceBody2" />
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="8dp"
|
|
||||||
android:gravity="center_vertical"
|
|
||||||
android:orientation="horizontal">
|
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
|
||||||
android:id="@+id/layout_right_padding_minus"
|
|
||||||
style="?attr/materialButtonOutlinedStyle"
|
|
||||||
android:layout_width="40dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="-" />
|
|
||||||
|
|
||||||
<EditText
|
|
||||||
android:id="@+id/layout_right_padding_input"
|
|
||||||
android:layout_width="48dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="8dp"
|
|
||||||
android:layout_marginEnd="8dp"
|
|
||||||
android:ems="4"
|
|
||||||
android:gravity="center"
|
|
||||||
android:importantForAutofill="no"
|
|
||||||
android:inputType="numberSigned"
|
|
||||||
android:maxLines="1"
|
|
||||||
android:singleLine="true" />
|
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
|
||||||
android:id="@+id/layout_right_padding_plus"
|
|
||||||
style="?attr/materialButtonOutlinedStyle"
|
|
||||||
android:layout_width="40dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="+" />
|
|
||||||
|
|
||||||
<CheckBox
|
|
||||||
android:id="@+id/layout_right_padding_add_stock"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="8dp"
|
|
||||||
android:text="@string/layout_padding_add_stock" />
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="12dp"
|
|
||||||
android:text="@string/layout_item_padding_label"
|
|
||||||
android:textAppearance="?attr/textAppearanceBody2" />
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="8dp"
|
|
||||||
android:gravity="center_vertical"
|
|
||||||
android:orientation="horizontal">
|
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
|
||||||
android:id="@+id/layout_item_padding_minus"
|
|
||||||
style="?attr/materialButtonOutlinedStyle"
|
|
||||||
android:layout_width="40dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="-" />
|
|
||||||
|
|
||||||
<EditText
|
|
||||||
android:id="@+id/layout_item_padding_input"
|
|
||||||
android:layout_width="48dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="8dp"
|
|
||||||
android:layout_marginEnd="8dp"
|
|
||||||
android:ems="4"
|
|
||||||
android:gravity="center"
|
|
||||||
android:importantForAutofill="no"
|
|
||||||
android:inputType="number"
|
|
||||||
android:maxLines="1"
|
|
||||||
android:singleLine="true" />
|
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
|
||||||
android:id="@+id/layout_item_padding_plus"
|
|
||||||
style="?attr/materialButtonOutlinedStyle"
|
|
||||||
android:layout_width="40dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="+" />
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<CheckBox
|
|
||||||
android:id="@+id/layout_ignore_under_display_cameras"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="12dp"
|
|
||||||
android:checked="true"
|
|
||||||
android:text="@string/layout_ignore_under_display_cameras" />
|
|
||||||
</LinearLayout>
|
|
||||||
</com.google.android.material.card.MaterialCardView>
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
|
|||||||
@@ -1,6 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<background android:drawable="@drawable/ic_launcher_background" />
|
|
||||||
<foreground android:drawable="@drawable/ic_launcher_foreground" />
|
|
||||||
<monochrome android:drawable="@drawable/ic_launcher_foreground" />
|
|
||||||
</adaptive-icon>
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 2.8 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 1.7 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 3.8 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 5.8 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 7.6 KiB |
@@ -100,7 +100,10 @@
|
|||||||
<string name="hidden_apps_empty">No apps yet. Generate a notification first.</string>
|
<string name="hidden_apps_empty">No apps yet. Generate a notification first.</string>
|
||||||
<string name="hidden_apps_close">Close</string>
|
<string name="hidden_apps_close">Close</string>
|
||||||
<string name="hidden_apps_exception_regex_input_hint">Regex</string>
|
<string name="hidden_apps_exception_regex_input_hint">Regex</string>
|
||||||
<string name="hidden_apps_package_with_exceptions">%1$s \u2022 %2$d exceptions</string>
|
<plurals name="hidden_apps_package_with_exceptions">
|
||||||
|
<item quantity="one">%1$s \u2022 %2$d exception</item>
|
||||||
|
<item quantity="other">%1$s \u2022 %2$d exceptions</item>
|
||||||
|
</plurals>
|
||||||
<string name="hidden_apps_last_seen">Last seen: %1$s</string>
|
<string name="hidden_apps_last_seen">Last seen: %1$s</string>
|
||||||
<string name="hidden_apps_default_modes_title">Default settings</string>
|
<string name="hidden_apps_default_modes_title">Default settings</string>
|
||||||
<string name="hidden_apps_add_exception">Add exception</string>
|
<string name="hidden_apps_add_exception">Add exception</string>
|
||||||
@@ -160,7 +163,6 @@
|
|||||||
<string name="clock_title">Clock</string>
|
<string name="clock_title">Clock</string>
|
||||||
<string name="layout_home_title">Layout</string>
|
<string name="layout_home_title">Layout</string>
|
||||||
<string name="layout_title">Unlocked</string>
|
<string name="layout_title">Unlocked</string>
|
||||||
<string name="clock_master_toggles_title">Master toggles</string>
|
|
||||||
<string name="layout_master_toggle_title">Master toggle</string>
|
<string name="layout_master_toggle_title">Master toggle</string>
|
||||||
<string name="clock_enabled">Use custom clock</string>
|
<string name="clock_enabled">Use custom clock</string>
|
||||||
<string name="layout_enabled">Use custom layout</string>
|
<string name="layout_enabled">Use custom layout</string>
|
||||||
@@ -211,10 +213,8 @@
|
|||||||
<string name="clock_middle_cutout_prompt">Else, or if the overlap is centred, move clock to:</string>
|
<string name="clock_middle_cutout_prompt">Else, or if the overlap is centred, move clock to:</string>
|
||||||
<string name="clock_middle_side_left">Left side</string>
|
<string name="clock_middle_side_left">Left side</string>
|
||||||
<string name="clock_middle_side_right">Right side</string>
|
<string name="clock_middle_side_right">Right side</string>
|
||||||
<string name="clock_middle_cutout_gap_label">Gap from cutout (px)</string>
|
|
||||||
<string name="clock_custom_format_title">Custom format</string>
|
<string name="clock_custom_format_title">Custom format</string>
|
||||||
<string name="clock_custom_format_enabled">Use custom date/time pattern</string>
|
<string name="clock_custom_format_enabled">Use custom date/time pattern</string>
|
||||||
<string name="clock_ignore_under_display_cameras">Ignore under-display cameras</string>
|
|
||||||
<string name="clock_custom_format_hint">Examples: HH:mm, EEE d MMM HH:mm:ss, {#batterybar big @sans-serif-condensed}HH:mm</string>
|
<string name="clock_custom_format_hint">Examples: HH:mm, EEE d MMM HH:mm:ss, {#batterybar big @sans-serif-condensed}HH:mm</string>
|
||||||
<string name="clock_custom_format_help_common">Date/time patterns:\n\u2022 Uses Java SimpleDateFormat-style pattern letters\n\u2022 Common symbols: yyyy yy MMMM MMM MM EEEE EEE dd d HH hh mm ss a\n\nTags:\n\u2022 Supported tags: <i>, <u>, <small>, <big>, <font color=\'...\'>, <font face=\'...\'>\n\u2022 <b> is not supported\n\u2022 Custom font tags: <sans>, <serif>, <mono>, <condensed>\n\u2022 {/font} closes any open <font ...> tag\n\u2022 Opening a new colour or font face automatically closes the previous one</string>
|
<string name="clock_custom_format_help_common">Date/time patterns:\n\u2022 Uses Java SimpleDateFormat-style pattern letters\n\u2022 Common symbols: yyyy yy MMMM MMM MM EEEE EEE dd d HH hh mm ss a\n\nTags:\n\u2022 Supported tags: <i>, <u>, <small>, <big>, <font color=\'...\'>, <font face=\'...\'>\n\u2022 <b> is not supported\n\u2022 Custom font tags: <sans>, <serif>, <mono>, <condensed>\n\u2022 {/font} closes any open <font ...> tag\n\u2022 Opening a new colour or font face automatically closes the previous one</string>
|
||||||
<string name="clock_custom_format_help_styling">Shorthand blocks:\n\u2022 {#FA0 big @sans-serif-condensed} is shorthand for opening multiple tags in order\n\u2022 In shorthand: / closes a tag, # sets font colour, @ sets font face\n\u2022 Each whitespace-separated token inside {} becomes its own tag\n\nLine breaks:\n\u2022 Use \\n, {\\n} or {\\n15}; the number is the line-height delta in px\n\u2022 Omit the number to use the default row spacing\n\u2022 { /\\n } style line breaks are written without spaces: {/\\n} or {/\\n15}\n\u2022 Normal line breaks propagate open tags onto the next row\n\u2022 A / line break ends all currently open tags before the next row starts\n\nPipes and grouping:\n\u2022 Maximum two pipes per row; more than two is a syntax error for that row only\n\u2022 Pipes inside single quotes or {} do not split the row\n\u2022 One pipe splits into left and right segments\n\u2022 Two pipes remove the middle section, then split using the outer pipes\n\u2022 Tags are logically continued across pipe splits, even if the middle section is ignored\n\u2022 Rows without pipes are independent; rows with pipes share one common pipe group\n\u2022 A syntax-error row becomes the text Syntax error, with no whole-clock fallback\n\nColours:\n\u2022 Supported colour literals: #RGB, #ARGB, #RRGGBB, #AARRGGBB\n\u2022 {#bright|#dark} means bright text on dark backgrounds, dark text on bright backgrounds\n\u2022 {#batterybar} copies the current battery bar colour\n\u2022 After |, if the next token is not #, the dark variant is built with math\n\u2022 Dark-variant math can start with inv or an operator (+ - * /)\n\u2022 Math runs strictly left to right; there is no operator precedence\n\u2022 Decimal numbers affect R, G and B only; alpha stays unchanged\n\u2022 Hex operands use 00..FF channel values for + and -, and channel/255 scaling for * and /\n\u2022 8-digit hex operands can also affect alpha</string>
|
<string name="clock_custom_format_help_styling">Shorthand blocks:\n\u2022 {#FA0 big @sans-serif-condensed} is shorthand for opening multiple tags in order\n\u2022 In shorthand: / closes a tag, # sets font colour, @ sets font face\n\u2022 Each whitespace-separated token inside {} becomes its own tag\n\nLine breaks:\n\u2022 Use \\n, {\\n} or {\\n15}; the number is the line-height delta in px\n\u2022 Omit the number to use the default row spacing\n\u2022 { /\\n } style line breaks are written without spaces: {/\\n} or {/\\n15}\n\u2022 Normal line breaks propagate open tags onto the next row\n\u2022 A / line break ends all currently open tags before the next row starts\n\nPipes and grouping:\n\u2022 Maximum two pipes per row; more than two is a syntax error for that row only\n\u2022 Pipes inside single quotes or {} do not split the row\n\u2022 One pipe splits into left and right segments\n\u2022 Two pipes remove the middle section, then split using the outer pipes\n\u2022 Tags are logically continued across pipe splits, even if the middle section is ignored\n\u2022 Rows without pipes are independent; rows with pipes share one common pipe group\n\u2022 A syntax-error row becomes the text Syntax error, with no whole-clock fallback\n\nColours:\n\u2022 Supported colour literals: #RGB, #ARGB, #RRGGBB, #AARRGGBB\n\u2022 {#bright|#dark} means bright text on dark backgrounds, dark text on bright backgrounds\n\u2022 {#batterybar} copies the current battery bar colour\n\u2022 After |, if the next token is not #, the dark variant is built with math\n\u2022 Dark-variant math can start with inv or an operator (+ - * /)\n\u2022 Math runs strictly left to right; there is no operator precedence\n\u2022 Decimal numbers affect R, G and B only; alpha stays unchanged\n\u2022 Hex operands use 00..FF channel values for + and -, and channel/255 scaling for * and /\n\u2022 8-digit hex operands can also affect alpha</string>
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?><!--
|
|
||||||
Sample backup rules file; uncomment and customize as necessary.
|
|
||||||
See https://developer.android.com/guide/topics/data/autobackup
|
|
||||||
for details.
|
|
||||||
Note: This file is ignored for devices older than API 31
|
|
||||||
See https://developer.android.com/about/versions/12/backup-restore
|
|
||||||
-->
|
|
||||||
<full-backup-content>
|
|
||||||
<!--
|
|
||||||
<include domain="sharedpref" path="."/>
|
|
||||||
<exclude domain="sharedpref" path="device.xml"/>
|
|
||||||
-->
|
|
||||||
</full-backup-content>
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?><!--
|
|
||||||
Sample data extraction rules file; uncomment and customize as necessary.
|
|
||||||
See https://developer.android.com/about/versions/12/backup-restore#xml-changes
|
|
||||||
for details.
|
|
||||||
-->
|
|
||||||
<data-extraction-rules>
|
|
||||||
<cloud-backup>
|
|
||||||
<!-- TODO: Use <include> and <exclude> to control what is backed up.
|
|
||||||
<include .../>
|
|
||||||
<exclude .../>
|
|
||||||
-->
|
|
||||||
</cloud-backup>
|
|
||||||
<!--
|
|
||||||
<device-transfer>
|
|
||||||
<include .../>
|
|
||||||
<exclude .../>
|
|
||||||
</device-transfer>
|
|
||||||
-->
|
|
||||||
</data-extraction-rules>
|
|
||||||
Reference in New Issue
Block a user