Expand emulator compatibility coverage
This commit is contained in:
@@ -1,11 +1,13 @@
|
|||||||
# StatusBarTweak
|
# StatusBarTweak
|
||||||
|
|
||||||
StatusBarTweak is an Xposed/LSPosed module for Samsung SystemUI. It focuses on
|
StatusBarTweak is an Xposed/LSPosed module originally built for Samsung
|
||||||
making the status bar, lockscreen, and Always On Display more configurable while
|
SystemUI. It focuses on making the status bar, lockscreen, and Always On
|
||||||
still keeping Samsung's own icons and visual style where possible.
|
Display more configurable while still keeping the system's own icons and visual
|
||||||
|
style where possible.
|
||||||
|
|
||||||
The project is currently tested only on a Samsung Galaxy Z Fold5 running One UI
|
The project is physically tested only on a Samsung Galaxy Z Fold5 running One UI
|
||||||
8.0 / Android 16. Expect device- and One UI-version-specific behaviour.
|
8.0 / Android 16. Other SystemUI builds have emulator-tested support as shown
|
||||||
|
in the compatibility matrix.
|
||||||
|
|
||||||
## AI Assistance
|
## AI Assistance
|
||||||
|
|
||||||
@@ -14,7 +16,8 @@ decisions, physical device testing, and final behaviour are still manually revie
|
|||||||
|
|
||||||
## What It Does
|
## What It Does
|
||||||
|
|
||||||
- Custom status bar layout for the unlocked screen, lockscreen, and AOD.
|
- Custom status bar layout for the unlocked screen, lockscreen, and AOD where
|
||||||
|
supported by the SystemUI build.
|
||||||
- Independent placement of clock, carrier text, notification icons, status
|
- Independent placement of clock, carrier text, notification icons, status
|
||||||
icons, and Samsung status chips.
|
icons, and Samsung status chips.
|
||||||
- Separate notification display handling for Samsung's cards, icons, and dot
|
- Separate notification display handling for Samsung's cards, icons, and dot
|
||||||
@@ -52,15 +55,16 @@ The in-app clock page has the full syntax help and examples.
|
|||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
- A rooted Android device or emulator.
|
- A rooted Android 14+ device or emulator. Actual feature support depends on
|
||||||
|
the SystemUI implementation; see the compatibility matrix.
|
||||||
- A modern Xposed implementation such as LSPosed or another libxposed-compatible runtime.
|
- A modern Xposed implementation such as LSPosed or another libxposed-compatible runtime.
|
||||||
- Xposed API 101 or newer.
|
- Xposed API 101 or newer.
|
||||||
- SystemUI access for the module scope.
|
- SystemUI access for the module scope.
|
||||||
|
|
||||||
The module is currently developed and manually tested on a Samsung Galaxy Z
|
The module is developed and manually tested on a Samsung Galaxy Z Fold5 running
|
||||||
Fold5 running One UI 8.0 / Android 16. Other Android versions and non-Samsung
|
One UI 8.0 / Android 16. Non-Samsung builds have emulator-tested support as
|
||||||
SystemUI builds are being investigated, but should be treated as experimental
|
shown below, but hardware-dependent behavior remains experimental unless it has
|
||||||
until the compatibility matrix says otherwise.
|
also been verified on physical hardware.
|
||||||
|
|
||||||
## Device Compatibility
|
## Device Compatibility
|
||||||
|
|
||||||
@@ -74,35 +78,35 @@ expose the required hardware or state for real verification.
|
|||||||
|
|
||||||
| 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 |
|
| Module loads in SystemUI | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||||
| Settings app opens and writes settings | ✅ | Untested | Untested | ✅ | Untested | Untested | Untested | Untested |
|
| Settings app opens and writes settings | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||||
| Custom unlocked statusbar layout | ✅ | Untested | Untested | ✅ | Untested | Untested | Untested | Untested |
|
| Custom unlocked statusbar layout | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||||
| Custom lockscreen statusbar layout | ✅ | Untested | Untested | ✅ | Untested | Untested | Untested | Untested |
|
| Custom lockscreen statusbar layout | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||||
| Custom AOD statusbar layout | ✅ | Untested | Untested | ⚠️ Experimental | Untested | Untested | Untested | Untested |
|
| Custom AOD statusbar layout | ✅ | ⚠️ Experimental | ⚠️ Experimental | ⚠️ Experimental | ⚠️ Experimental | ⚠️ Experimental | ⚠️ Experimental | ⚠️ Experimental |
|
||||||
| Notification icons mode | ✅ | Untested | Untested | ✅ AOD experimental | Untested | Untested | Untested | Untested |
|
| Notification icons mode | ✅ | ✅ AOD experimental | ✅ AOD experimental | ✅ AOD experimental | ✅ AOD experimental | ✅ AOD experimental | ✅ AOD experimental | ✅ AOD experimental |
|
||||||
| Notification cards mode | ✅ | Untested | Untested | ❌ | Untested | Untested | Untested | Untested |
|
| Notification cards mode | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
|
||||||
| Notification dot mode and read-state behavior | ✅ | Untested | Untested | ❌ | Untested | Untested | Untested | Untested |
|
| Notification dot mode and read-state behavior | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
|
||||||
| Hide notification icons by app | ✅ | Untested | Untested | ✅ AOD experimental | Untested | Untested | Untested | Untested |
|
| Hide notification icons by app | ✅ | ✅ AOD experimental | ✅ AOD experimental | ✅ AOD experimental | ✅ AOD experimental | ✅ AOD experimental | ✅ AOD experimental | ✅ AOD experimental |
|
||||||
| Hide status icons | ✅ | Untested | Untested | ✅ AOD experimental | Untested | Untested | Untested | Untested |
|
| Hide status icons | ✅ | ✅ AOD experimental | ✅ AOD experimental | ✅ AOD experimental | ✅ AOD experimental | ✅ AOD experimental | ✅ AOD experimental | ✅ AOD experimental |
|
||||||
| Dual-SIM status icon handling | ✅ | Untested | Untested | ⚠️ Experimental | Untested | Untested | Untested | Untested |
|
| Dual-SIM status icon handling | ✅ | ⚠️ Experimental | ⚠️ Experimental | ⚠️ Experimental | ⚠️ Experimental | ⚠️ Experimental | ⚠️ Experimental | ⚠️ Experimental |
|
||||||
| Samsung status chips: media/navigation/call | ✅ | Untested | Untested | ❌ | Untested | Untested | Untested | Untested |
|
| Samsung status chips: media/navigation/call | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
|
||||||
| Samsung charging chip handling | ✅ | Untested | Untested | ❌ | Untested | Untested | Untested | Untested |
|
| Samsung charging chip handling | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
|
||||||
| Privacy indicator stability | ✅ | Untested | Untested | ✅ | Untested | Untested | Untested | Untested |
|
| Privacy indicator stability | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||||
| Custom statusbar clock text | ✅ | Untested | Untested | ✅ | Untested | Untested | Untested | Untested |
|
| Custom statusbar clock text | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||||
| Custom drawer clock/date text | ✅ | Untested | Untested | ✅ | Untested | Untested | Untested | Untested |
|
| Custom drawer clock/date text | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||||
| Stored clock pattern previews | ✅ | Untested | Untested | ✅ | Untested | Untested | Untested | Untested |
|
| Stored clock pattern previews | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||||
| Battery bar: base statusbar modes | ✅ | Untested | Untested | ✅ | Untested | Untested | Untested | Untested |
|
| Battery bar: base statusbar modes | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||||
| Battery bar: fullscreen and transparent statusbar modes | ✅ | Untested | Untested | ✅ | Untested | Untested | Untested | Untested |
|
| Battery bar: fullscreen and transparent statusbar modes | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||||
| Battery bar: curved top-edge geometry | ✅ | Untested | Untested | ⚠️ Experimental | Untested | Untested | Untested | Untested |
|
| Battery bar: curved top-edge geometry | ✅ | ⚠️ Experimental | ⚠️ Experimental | ⚠️ Experimental | ⚠️ Experimental | ⚠️ Experimental | ⚠️ Experimental | ⚠️ Experimental |
|
||||||
| Battery bar threshold colours and colour math | ✅ | Untested | Untested | ✅ | Untested | Untested | Untested | Untested |
|
| Battery bar threshold colours and colour math | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||||
| Camera cutout and under-display-camera handling | ✅ | Untested | Untested | ⚠️ Experimental | Untested | Untested | Untested | Untested |
|
| Camera cutout and under-display-camera handling | ✅ | ⚠️ Experimental | ⚠️ Experimental | ⚠️ Experimental | ⚠️ Experimental | ⚠️ Experimental | ⚠️ Experimental | ⚠️ Experimental |
|
||||||
| Rotation and fold/unfold handling | ✅ | Untested | Untested | ✅ rotation verified | Untested | Untested | Untested | Untested |
|
| Rotation and fold/unfold handling | ✅ | ✅ rotation verified | ✅ rotation verified | ✅ rotation verified | ✅ rotation verified | ✅ rotation verified | ✅ rotation verified | ✅ rotation verified |
|
||||||
| Drawer scrolling and background-work performance | ✅ | Untested | Untested | ✅ | Untested | Untested | Untested | Untested |
|
| Drawer scrolling and background-work performance | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||||
| Debug visualizers and debug notifications | ✅ | Untested | Untested | ✅ | Untested | Untested | Untested | Untested |
|
| Debug visualizers and debug notifications | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||||
|
|
||||||
Current emulator targets use rooted LSPosed snapshots in a local test lab. They
|
Current emulator targets use rooted LSPosed snapshots. They are useful for
|
||||||
are useful for compatibility work, but the matrix above is intentionally not
|
compatibility work, but hardware-specific entries remain marked as experimental
|
||||||
optimistic: until a target has been tested, it remains `Untested`.
|
when the emulator cannot expose the required state.
|
||||||
|
|
||||||
## Build
|
## Build
|
||||||
|
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ android {
|
|||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId = "se.ajpanton.statusbartweak"
|
applicationId = "se.ajpanton.statusbartweak"
|
||||||
minSdk = 35
|
minSdk = 34
|
||||||
targetSdk = 36
|
targetSdk = 36
|
||||||
val buildVersionName = project.findProperty("sbtVersionName")?.toString()
|
val buildVersionName = project.findProperty("sbtVersionName")?.toString()
|
||||||
?: fallbackVersionName
|
?: fallbackVersionName
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package se.ajpanton.statusbartweak.runtime.hooks;
|
|||||||
|
|
||||||
import java.lang.reflect.Constructor;
|
import java.lang.reflect.Constructor;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
|
import java.lang.reflect.Modifier;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
@@ -34,6 +35,9 @@ public final class XposedHookSupport {
|
|||||||
if (!methodName.equals(method.getName())) {
|
if (!methodName.equals(method.getName())) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (Modifier.isAbstract(method.getModifiers())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
method.setAccessible(true);
|
method.setAccessible(true);
|
||||||
handles.add(framework.hook(method).intercept(hooker));
|
handles.add(framework.hook(method).intercept(hooker));
|
||||||
}
|
}
|
||||||
@@ -59,6 +63,9 @@ public final class XposedHookSupport {
|
|||||||
if (!methodName.equals(method.getName())) {
|
if (!methodName.equals(method.getName())) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (Modifier.isAbstract(method.getModifiers())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
method.setAccessible(true);
|
method.setAccessible(true);
|
||||||
handles.add(framework.hook(method).intercept(hooker));
|
handles.add(framework.hook(method).intercept(hooker));
|
||||||
}
|
}
|
||||||
@@ -83,4 +90,20 @@ public final class XposedHookSupport {
|
|||||||
}
|
}
|
||||||
return handles;
|
return handles;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static List<XposedInterface.HookHandle> hookAllConstructorsIfExists(
|
||||||
|
XposedInterface framework,
|
||||||
|
Class<?> type,
|
||||||
|
XposedInterface.Hooker hooker
|
||||||
|
) {
|
||||||
|
Objects.requireNonNull(framework, "framework");
|
||||||
|
Objects.requireNonNull(type, "type");
|
||||||
|
Objects.requireNonNull(hooker, "hooker");
|
||||||
|
List<XposedInterface.HookHandle> handles = new ArrayList<>();
|
||||||
|
for (Constructor<?> constructor : type.getDeclaredConstructors()) {
|
||||||
|
constructor.setAccessible(true);
|
||||||
|
handles.add(framework.hook(constructor).intercept(hooker));
|
||||||
|
}
|
||||||
|
return handles;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -33,7 +33,7 @@ final class DarkIconDispatcherGuard {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void install(Class<?> darkIconDispatcherClass) {
|
void install(Class<?> darkIconDispatcherClass) {
|
||||||
XposedHookSupport.hookAllConstructors(
|
XposedHookSupport.hookAllConstructorsIfExists(
|
||||||
runtimeContext.getFramework(),
|
runtimeContext.getFramework(),
|
||||||
darkIconDispatcherClass,
|
darkIconDispatcherClass,
|
||||||
chain -> {
|
chain -> {
|
||||||
|
|||||||
@@ -27,7 +27,8 @@
|
|||||||
<activity
|
<activity
|
||||||
android:name=".ScenarioActivity"
|
android:name=".ScenarioActivity"
|
||||||
android:configChanges="keyboardHidden|orientation|screenSize"
|
android:configChanges="keyboardHidden|orientation|screenSize"
|
||||||
android:exported="false" />
|
android:exported="true"
|
||||||
|
android:launchMode="singleTop" />
|
||||||
<activity
|
<activity
|
||||||
android:name=".MainActivity"
|
android:name=".MainActivity"
|
||||||
android:exported="true">
|
android:exported="true">
|
||||||
|
|||||||
+15
-1
@@ -2,6 +2,7 @@ package se.ajpanton.statusbartweak.harness;
|
|||||||
|
|
||||||
import android.Manifest;
|
import android.Manifest;
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
|
import android.content.Intent;
|
||||||
import android.content.pm.ActivityInfo;
|
import android.content.pm.ActivityInfo;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
@@ -51,7 +52,20 @@ public final class ScenarioActivity extends Activity {
|
|||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
String scenario = getIntent().getStringExtra(EXTRA_SCENARIO);
|
applyScenario(getIntent());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onNewIntent(Intent intent) {
|
||||||
|
super.onNewIntent(intent);
|
||||||
|
setIntent(intent);
|
||||||
|
stopCamera();
|
||||||
|
stopMicrophone();
|
||||||
|
applyScenario(intent);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void applyScenario(Intent intent) {
|
||||||
|
String scenario = intent != null ? intent.getStringExtra(EXTRA_SCENARIO) : null;
|
||||||
if (scenario == null) {
|
if (scenario == null) {
|
||||||
scenario = SCENARIO_OPAQUE_LIGHT;
|
scenario = SCENARIO_OPAQUE_LIGHT;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user