Add initial AOSP statusbar compatibility
This commit is contained in:
@@ -73,31 +73,31 @@ should.
|
|||||||
|
|
||||||
| Feature | Galaxy Z Fold5<br>One UI 8 / Android 16 | AOSP API 34<br>Android 14 | AOSP API 35<br>Android 15 | AOSP API 36<br>Android 16 | Google APIs API 35<br>Android 15 | Google APIs API 36<br>Android 16 | LineageOS 22<br>Android 15 | LineageOS 23<br>Android 16 |
|
| Feature | Galaxy Z Fold5<br>One UI 8 / Android 16 | AOSP API 34<br>Android 14 | AOSP API 35<br>Android 15 | AOSP API 36<br>Android 16 | Google APIs API 35<br>Android 15 | Google APIs API 36<br>Android 16 | LineageOS 22<br>Android 15 | LineageOS 23<br>Android 16 |
|
||||||
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
|
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
|
||||||
| Module loads in SystemUI | ✅ | Untested | Untested | Untested | Untested | Untested | Untested | Untested |
|
| Module loads in SystemUI | ✅ | Untested | Untested | ✅ | Untested | Untested | Untested | Untested |
|
||||||
| Settings app opens and writes settings | ✅ | Untested | Untested | Untested | Untested | Untested | Untested | Untested |
|
| Settings app opens and writes settings | ✅ | Untested | Untested | ✅ opens; settings provider applies | Untested | Untested | Untested | Untested |
|
||||||
| Custom unlocked statusbar layout | ✅ | Untested | Untested | Untested | Untested | Untested | Untested | Untested |
|
| Custom unlocked statusbar layout | ✅ | Untested | Untested | ✅ basic unlocked layout verified | Untested | Untested | Untested | Untested |
|
||||||
| Custom lockscreen statusbar layout | ✅ | Untested | Untested | Untested | Untested | Untested | Untested | Untested |
|
| Custom lockscreen statusbar layout | ✅ | Untested | Untested | Untested | Untested | Untested | Untested | Untested |
|
||||||
| Custom AOD statusbar layout | ✅ | Untested | Untested | Untested | Untested | Untested | Untested | Untested |
|
| Custom AOD statusbar layout | ✅ | Untested | Untested | ❌ OneUI AOD hooks only | Untested | Untested | Untested | Untested |
|
||||||
| Notification icons mode | ✅ | Untested | Untested | Untested | Untested | Untested | Untested | Untested |
|
| Notification icons mode | ✅ | Untested | Untested | ✅ unlocked icons verified; lockscreen/AOD untested | Untested | Untested | Untested | Untested |
|
||||||
| Notification cards mode | ✅ | Untested | Untested | Untested | Untested | Untested | Untested | Untested |
|
| Notification cards mode | ✅ | Untested | Untested | ❌ OneUI cards mode only | Untested | Untested | Untested | Untested |
|
||||||
| Notification dot mode and read-state behavior | ✅ | Untested | Untested | Untested | Untested | Untested | Untested | Untested |
|
| Notification dot mode and read-state behavior | ✅ | Untested | Untested | Untested; lockscreen/AOD style detection is OneUI-specific | Untested | Untested | Untested | Untested |
|
||||||
| Hide notification icons by app | ✅ | Untested | Untested | Untested | Untested | Untested | Untested | Untested |
|
| Hide notification icons by app | ✅ | Untested | Untested | Untested | Untested | Untested | Untested | Untested |
|
||||||
| Hide status icons | ✅ | Untested | Untested | Untested | Untested | Untested | Untested | Untested |
|
| Hide status icons | ✅ | Untested | Untested | ✅ unlocked Wi-Fi slot verified | Untested | Untested | Untested | Untested |
|
||||||
| Dual-SIM status icon handling | ✅ | Untested | Untested | Untested | Untested | Untested | Untested | Untested |
|
| Dual-SIM status icon handling | ✅ | Untested | Untested | Untested; emulator has no dual-SIM signal state | Untested | Untested | Untested | Untested |
|
||||||
| Samsung status chips: media/navigation/call | ✅ | Untested | Untested | Untested | Untested | Untested | Untested | Untested |
|
| Samsung status chips: media/navigation/call | ✅ | Untested | Untested | ❌ OneUI-only | Untested | Untested | Untested | Untested |
|
||||||
| Samsung charging chip handling | ✅ | Untested | Untested | Untested | Untested | Untested | Untested | Untested |
|
| Samsung charging chip handling | ✅ | Untested | Untested | ❌ OneUI-only | Untested | Untested | Untested | Untested |
|
||||||
| Privacy indicator stability | ✅ | Untested | Untested | Untested | Untested | Untested | Untested | Untested |
|
| Privacy indicator stability | ✅ | Untested | Untested | Untested | Untested | Untested | Untested | Untested |
|
||||||
| Custom statusbar clock text | ✅ | Untested | Untested | Untested | Untested | Untested | Untested | Untested |
|
| Custom statusbar clock text | ✅ | Untested | Untested | ✅ layout-on and layout-off clocks verified | Untested | Untested | Untested | Untested |
|
||||||
| Custom drawer clock/date text | ✅ | Untested | Untested | Untested | Untested | Untested | Untested | Untested |
|
| Custom drawer clock/date text | ✅ | Untested | Untested | ✅ expanded QS clock/date verified | Untested | Untested | Untested | Untested |
|
||||||
| Stored clock pattern previews | ✅ | Untested | Untested | Untested | Untested | Untested | Untested | Untested |
|
| Stored clock pattern previews | ✅ | Untested | Untested | Untested | Untested | Untested | Untested | Untested |
|
||||||
| Battery bar: base statusbar modes | ✅ | Untested | Untested | Untested | Untested | Untested | Untested | Untested |
|
| Battery bar: base statusbar modes | ✅ | Untested | Untested | ✅ unlocked verified; lockscreen/AOD untested | Untested | Untested | Untested | Untested |
|
||||||
| Battery bar: fullscreen and transparent statusbar modes | ✅ | Untested | Untested | Untested | Untested | Untested | Untested | Untested |
|
| Battery bar: fullscreen and transparent statusbar modes | ✅ | Untested | Untested | ✅ fullscreen root verified; transparent untested | Untested | Untested | Untested | Untested |
|
||||||
| Battery bar: curved top-edge geometry | ✅ | Untested | Untested | Untested | Untested | Untested | Untested | Untested |
|
| Battery bar: curved top-edge geometry | ✅ | Untested | Untested | Untested; emulator has no curved screen edge | Untested | Untested | Untested | Untested |
|
||||||
| Battery bar threshold colours and colour math | ✅ | Untested | Untested | Untested | Untested | Untested | Untested | Untested |
|
| Battery bar threshold colours and colour math | ✅ | Untested | Untested | Untested | Untested | Untested | Untested | Untested |
|
||||||
| Camera cutout and under-display-camera handling | ✅ | Untested | Untested | Untested | Untested | Untested | Untested | Untested |
|
| Camera cutout and under-display-camera handling | ✅ | Untested | Untested | Untested; emulator has no cutout/UDC | Untested | Untested | Untested | Untested |
|
||||||
| Rotation and fold/unfold handling | ✅ | Untested | Untested | Untested | Untested | Untested | Untested | Untested |
|
| Rotation and fold/unfold handling | ✅ | Untested | Untested | Untested | Untested | Untested | Untested | Untested |
|
||||||
| Drawer scrolling and background-work performance | ✅ | Untested | Untested | Untested | Untested | Untested | Untested | Untested |
|
| Drawer scrolling and background-work performance | ✅ | Untested | Untested | Untested | Untested | Untested | Untested | Untested |
|
||||||
| Debug visualizers and debug notifications | ✅ | Untested | Untested | Untested | Untested | Untested | Untested | Untested |
|
| Debug visualizers and debug notifications | ✅ | Untested | Untested | ✅ unlocked visualizers verified; debug notifications untested | Untested | Untested | Untested | Untested |
|
||||||
|
|
||||||
Current emulator targets use rooted LSPosed snapshots in a local test lab. They
|
Current emulator targets use rooted LSPosed snapshots in a local test lab. They
|
||||||
are useful for compatibility work, but the matrix above is intentionally not
|
are useful for compatibility work, but the matrix above is intentionally not
|
||||||
|
|||||||
+50
-5
@@ -38,8 +38,10 @@ import se.ajpanton.statusbartweak.shell.settings.SbtSettings;
|
|||||||
|
|
||||||
final class StockClockController {
|
final class StockClockController {
|
||||||
|
|
||||||
private static final String CLOCK_CLASS_NAME =
|
private static final String[] CLOCK_CLASS_NAMES = {
|
||||||
"com.android.systemui.statusbar.policy.QSClockIndicatorView";
|
"com.android.systemui.statusbar.policy.QSClockIndicatorView",
|
||||||
|
"com.android.systemui.statusbar.policy.Clock"
|
||||||
|
};
|
||||||
|
|
||||||
private final RuntimeContext runtimeContext;
|
private final RuntimeContext runtimeContext;
|
||||||
private final Set<TextView> trackedClocks =
|
private final Set<TextView> trackedClocks =
|
||||||
@@ -64,8 +66,25 @@ final class StockClockController {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
registerLayoutModeListenerIfNeeded();
|
registerLayoutModeListenerIfNeeded();
|
||||||
Class<?> clockClass = ReflectionSupport.requireClass(CLOCK_CLASS_NAME, classLoader);
|
ArrayList<Class<?>> clockClasses = new ArrayList<>();
|
||||||
|
for (String className : CLOCK_CLASS_NAMES) {
|
||||||
|
Class<?> clockClass = ReflectionSupport.findClassIfExists(className, classLoader);
|
||||||
|
if (clockClass != null) {
|
||||||
|
clockClasses.add(clockClass);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (clockClasses.isEmpty()) {
|
||||||
|
hooksInstalled = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
XposedInterface framework = runtimeContext.getFramework();
|
XposedInterface framework = runtimeContext.getFramework();
|
||||||
|
for (Class<?> clockClass : clockClasses) {
|
||||||
|
hookClockClass(framework, clockClass);
|
||||||
|
}
|
||||||
|
hooksInstalled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void hookClockClass(XposedInterface framework, Class<?> clockClass) {
|
||||||
XposedHookSupport.hookAllMethodsIfExists(framework, clockClass, "onAttachedToWindow", chain -> {
|
XposedHookSupport.hookAllMethodsIfExists(framework, clockClass, "onAttachedToWindow", chain -> {
|
||||||
Object result = chain.proceed();
|
Object result = chain.proceed();
|
||||||
Object target = chain.getThisObject();
|
Object target = chain.getThisObject();
|
||||||
@@ -104,7 +123,7 @@ final class StockClockController {
|
|||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
});
|
});
|
||||||
XposedHookSupport.hookAllMethods(framework, clockClass, "notifyTimeChanged", chain -> {
|
XposedHookSupport.hookAllMethodsIfExists(framework, clockClass, "notifyTimeChanged", chain -> {
|
||||||
Object result = chain.proceed();
|
Object result = chain.proceed();
|
||||||
Object target = chain.getThisObject();
|
Object target = chain.getThisObject();
|
||||||
if (!(target instanceof TextView)) {
|
if (!(target instanceof TextView)) {
|
||||||
@@ -123,6 +142,14 @@ final class StockClockController {
|
|||||||
trackAndApply(clockView, bellSound);
|
trackAndApply(clockView, bellSound);
|
||||||
return result;
|
return result;
|
||||||
});
|
});
|
||||||
|
XposedHookSupport.hookAllMethodsIfExists(framework, clockClass, "updateClock", chain -> {
|
||||||
|
Object result = chain.proceed();
|
||||||
|
Object target = chain.getThisObject();
|
||||||
|
if (target instanceof TextView clockView) {
|
||||||
|
trackAndApply(clockView, null);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
});
|
||||||
XposedHookSupport.hookAllMethodsIfExists(framework, clockClass, "setTextColor", chain -> {
|
XposedHookSupport.hookAllMethodsIfExists(framework, clockClass, "setTextColor", chain -> {
|
||||||
Object result = chain.proceed();
|
Object result = chain.proceed();
|
||||||
if (chain.getThisObject() instanceof TextView clockView) {
|
if (chain.getThisObject() instanceof TextView clockView) {
|
||||||
@@ -137,7 +164,6 @@ final class StockClockController {
|
|||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
});
|
});
|
||||||
hooksInstalled = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void reapplyClockIfCustomOrOwned(TextView clockView) {
|
private void reapplyClockIfCustomOrOwned(TextView clockView) {
|
||||||
@@ -162,6 +188,9 @@ final class StockClockController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void trackAndApply(TextView clockView, Object bellSound) {
|
private void trackAndApply(TextView clockView, Object bellSound) {
|
||||||
|
if (isNotificationShadeDescendant(clockView)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
trackedClocks.add(clockView);
|
trackedClocks.add(clockView);
|
||||||
registerReceiverIfNeeded(clockView.getContext());
|
registerReceiverIfNeeded(clockView.getContext());
|
||||||
if (bellSound != null) {
|
if (bellSound != null) {
|
||||||
@@ -219,6 +248,10 @@ final class StockClockController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void applyClockText(TextView clockView) {
|
private void applyClockText(TextView clockView) {
|
||||||
|
if (isNotificationShadeDescendant(clockView)) {
|
||||||
|
restoreOwnedClock(clockView);
|
||||||
|
return;
|
||||||
|
}
|
||||||
SbtSettings settings = RuntimeSettingsCache.get(clockView.getContext());
|
SbtSettings settings = RuntimeSettingsCache.get(clockView.getContext());
|
||||||
boolean layoutEnabled = settings.clockEnabled;
|
boolean layoutEnabled = settings.clockEnabled;
|
||||||
if (layoutEnabled) {
|
if (layoutEnabled) {
|
||||||
@@ -330,6 +363,18 @@ final class StockClockController {
|
|||||||
|| (settings.clockCustomFormatEnabled && !pattern.isEmpty());
|
|| (settings.clockCustomFormatEnabled && !pattern.isEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isNotificationShadeDescendant(View view) {
|
||||||
|
View current = view;
|
||||||
|
while (current != null) {
|
||||||
|
if (current.getClass().getName().contains("NotificationShadeWindowView")) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
Object parent = current.getParent();
|
||||||
|
current = parent instanceof View ? (View) parent : null;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
private void applyClockLineMode(TextView clockView) {
|
private void applyClockLineMode(TextView clockView) {
|
||||||
clockView.setSingleLine(true);
|
clockView.setSingleLine(true);
|
||||||
clockView.setHorizontallyScrolling(false);
|
clockView.setHorizontallyScrolling(false);
|
||||||
|
|||||||
+8
-5
@@ -43,8 +43,11 @@ final class StockUnlockedNotificationIconsController {
|
|||||||
if (hooksInstalled || classLoader == null) {
|
if (hooksInstalled || classLoader == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Class<?> containerClass = ReflectionSupport.requireClass(CONTAINER_CLASS_NAME, classLoader);
|
Class<?> containerClass = ReflectionSupport.findClassIfExists(CONTAINER_CLASS_NAME, classLoader);
|
||||||
XposedHookSupport.hookAllMethods(runtimeContext.getFramework(), containerClass, "onAttachedToWindow", chain -> {
|
if (containerClass == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
XposedHookSupport.hookAllMethodsIfExists(runtimeContext.getFramework(), containerClass, "onAttachedToWindow", chain -> {
|
||||||
Object result = chain.proceed();
|
Object result = chain.proceed();
|
||||||
if (chain.getThisObject() instanceof View view) {
|
if (chain.getThisObject() instanceof View view) {
|
||||||
if (shouldManageContainer(view)) {
|
if (shouldManageContainer(view)) {
|
||||||
@@ -54,7 +57,7 @@ final class StockUnlockedNotificationIconsController {
|
|||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
});
|
});
|
||||||
XposedHookSupport.hookAllMethods(runtimeContext.getFramework(), containerClass, "calculateIconXTranslations", chain -> {
|
XposedHookSupport.hookAllMethodsIfExists(runtimeContext.getFramework(), containerClass, "calculateIconXTranslations", chain -> {
|
||||||
if (chain.getThisObject() instanceof View view) {
|
if (chain.getThisObject() instanceof View view) {
|
||||||
if (shouldManageContainer(view)) {
|
if (shouldManageContainer(view)) {
|
||||||
trackContainer(view);
|
trackContainer(view);
|
||||||
@@ -63,7 +66,7 @@ final class StockUnlockedNotificationIconsController {
|
|||||||
}
|
}
|
||||||
return chain.proceed();
|
return chain.proceed();
|
||||||
});
|
});
|
||||||
XposedHookSupport.hookAllMethods(runtimeContext.getFramework(), containerClass, "onLayout", chain -> {
|
XposedHookSupport.hookAllMethodsIfExists(runtimeContext.getFramework(), containerClass, "onLayout", chain -> {
|
||||||
Object result = chain.proceed();
|
Object result = chain.proceed();
|
||||||
if (chain.getThisObject() instanceof View view) {
|
if (chain.getThisObject() instanceof View view) {
|
||||||
if (shouldManageContainer(view)) {
|
if (shouldManageContainer(view)) {
|
||||||
@@ -75,7 +78,7 @@ final class StockUnlockedNotificationIconsController {
|
|||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
});
|
});
|
||||||
XposedHookSupport.hookAllMethods(runtimeContext.getFramework(), containerClass, "shouldForceOverflow", chain -> {
|
XposedHookSupport.hookAllMethodsIfExists(runtimeContext.getFramework(), containerClass, "shouldForceOverflow", chain -> {
|
||||||
if (!(chain.getThisObject() instanceof View view)) {
|
if (!(chain.getThisObject() instanceof View view)) {
|
||||||
return chain.proceed();
|
return chain.proceed();
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-3
@@ -94,6 +94,7 @@ final class StockLayoutCanvasController {
|
|||||||
|
|
||||||
private static final Set<String> TARGET_CLASS_SUBSTRINGS = Set.of(
|
private static final Set<String> TARGET_CLASS_SUBSTRINGS = Set.of(
|
||||||
"QSClockIndicatorView",
|
"QSClockIndicatorView",
|
||||||
|
"statusbar.policy.Clock",
|
||||||
"SecShelfNotificationIconContainer"
|
"SecShelfNotificationIconContainer"
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -638,13 +639,19 @@ final class StockLayoutCanvasController {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Class<?> clockClass = ReflectionSupport.findClassIfExists(
|
String[] clockClassNames = {
|
||||||
"com.android.systemui.statusbar.policy.QSClockIndicatorView",
|
"com.android.systemui.statusbar.policy.QSClockIndicatorView",
|
||||||
classLoader);
|
"com.android.systemui.statusbar.policy.Clock"
|
||||||
if (clockClass != null) {
|
};
|
||||||
|
for (String className : clockClassNames) {
|
||||||
|
Class<?> clockClass = ReflectionSupport.findClassIfExists(className, classLoader);
|
||||||
|
if (clockClass == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
hookViewAppearanceInvalidation(clockClass, "onDarkChanged");
|
hookViewAppearanceInvalidation(clockClass, "onDarkChanged");
|
||||||
hookViewAppearanceInvalidation(clockClass, "setTextColor");
|
hookViewAppearanceInvalidation(clockClass, "setTextColor");
|
||||||
hookClockTextInvalidation(clockClass, "notifyTimeChanged");
|
hookClockTextInvalidation(clockClass, "notifyTimeChanged");
|
||||||
|
hookClockTextInvalidation(clockClass, "updateClock");
|
||||||
hookClockTextInvalidation(clockClass, "setText");
|
hookClockTextInvalidation(clockClass, "setText");
|
||||||
hookViewLayoutInvalidation(clockClass, "onLayout");
|
hookViewLayoutInvalidation(clockClass, "onLayout");
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-1
@@ -317,7 +317,7 @@ final class UnlockedStockSourceCollector {
|
|||||||
}
|
}
|
||||||
if (clockView == null
|
if (clockView == null
|
||||||
&& view instanceof TextView textView
|
&& view instanceof TextView textView
|
||||||
&& view.getClass().getName().contains("QSClockIndicatorView")) {
|
&& isStatusbarClockView(textView)) {
|
||||||
clockView = textView;
|
clockView = textView;
|
||||||
}
|
}
|
||||||
if (statusEndContent == null && idName.equals("status_bar_end_side_content")) {
|
if (statusEndContent == null && idName.equals("status_bar_end_side_content")) {
|
||||||
@@ -370,6 +370,12 @@ final class UnlockedStockSourceCollector {
|
|||||||
carrierView);
|
carrierView);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isStatusbarClockView(TextView view) {
|
||||||
|
String className = view.getClass().getName();
|
||||||
|
return className.contains("QSClockIndicatorView")
|
||||||
|
|| className.equals("com.android.systemui.statusbar.policy.Clock");
|
||||||
|
}
|
||||||
|
|
||||||
private boolean isCarrierTextView(TextView view) {
|
private boolean isCarrierTextView(TextView view) {
|
||||||
if (view == null) {
|
if (view == null) {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
Reference in New Issue
Block a user