AXP Magisk resurrection track: Speckit 009 port AXP/LOS22 to LOS23.

Ship Magisk like GOLDEN; KernelSU optional recycle only; parallel to sunfish-a16-rom standby.
This commit is contained in:
sunfish-admin committed 2026-09-16 21:56:22 +00:00
commit 12d2179c20
150 files changed
+26263

No files matched your search

@@ -0,0 +1,32 @@
# 008 call-rec + FLAG_SECURE patches
Idempotent apply for LOS 23.2 on `rom-dev01`.
```bash
python3 vendor/sunfish-a16/patches/008-call-rec-flag-secure/apply_008_call_rec_flag_secure.py
```
## Attribution
- **Call recording**: EXTENDROM `er.sh` F_CALLREC / AXP GOLDEN
(`extendrom_call_recording`). steadfasterX EXTENDROM.
- **FLAG_SECURE**: AOSP `Settings.Secure.DISABLE_SECURE_WINDOWS` already
wired in `WindowManagerService` on A16; DO preference
`allow_flag_secure_override` writes that key.
## Touched paths
| Area | Path under `/srv/rom/src/lineage/` |
|------|-------------------------------------|
| Secure call-rec | `frameworks/base/core/java/android/provider/Settings.java` (`ER_ALLOW_ANY_CALL_REC`) |
| Dialer gate | `packages/apps/Dialer/java/com/android/incallui/call/CallRecorder.java` |
| Dialer config | already `call_recording_enabled=true` / audio `4` (verified) |
| Settings controllers | `…/ER_CallRec*.java`, `…/FlagSecureOverride*.java` |
| Settings DO XML + strings | `res/xml/development_settings.xml`, `res/values/strings.xml` |
| Dashboard | `DevelopmentSettingsDashboardFragment.java` |
| Capture path | stock WMS `disable_secure_windows` (no extra WM patch) |
Backups: `/srv/rom/artifacts/008-call-rec-flag-secure/bak-snapshots/`
Marker: `SUNFISH_A16_008_CALL_REC_FLAG_SECURE`
See `docs/008-call-rec-flag-secure-runbook.md`.
@@ -0,0 +1,482 @@
#!/usr/bin/env python3
"""Apply sunfish-a16 008 call-rec + FLAG_SECURE Developer Options on LOS 23.2.
Call recording (AXP GOLDEN / EXTENDROM F_CALLREC):
- Settings.Secure.ER_ALLOW_ANY_CALL_REC = \"extendrom_call_recording\"
- DO switch + Dialer CallRecorder.canRecordInCurrentCountry early-return
FLAG_SECURE (AOSP A16 already implements WM path):
- DO switch writes Settings.Secure.DISABLE_SECURE_WINDOWS
(\"disable_secure_windows\"). WindowManagerService.updateDisableSecureWindows()
already honours it on debuggable builds (LAB userdebug).
Attribution: EXTENDROM (steadfasterX) for call-rec; AOSP DISABLE_SECURE_WINDOWS
for capture; sunfish-a16 DO wiring.
Run on rom-dev01:
python3 vendor/sunfish-a16/patches/008-call-rec-flag-secure/apply_008_call_rec_flag_secure.py
"""
from __future__ import annotations
import shutil
from pathlib import Path
TREE = Path("/srv/rom/src/lineage")
MARKER = "SUNFISH_A16_008_CALL_REC_FLAG_SECURE"
BAK_ROOT = Path("/srv/rom/artifacts/008-call-rec-flag-secure/bak-snapshots")
CALL_REC_CTRL = """/*
* Copyright (C) 2024 steadfasterX <steadfasterX |AT| binbash #DOT# rocks>
* LICENSE: GNU General Public License v3.0
* Ported to LOS 23.2 / sunfish-a16-rom ({marker}).
*/
package com.android.settings.development;
import android.content.Context;
import android.provider.Settings;
import androidx.annotation.VisibleForTesting;
import androidx.preference.Preference;
import androidx.preference.SwitchPreference;
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settingslib.development.DeveloperOptionsPreferenceController;
public class ER_CallRecPreferenceController extends DeveloperOptionsPreferenceController
implements Preference.OnPreferenceChangeListener, PreferenceControllerMixin {{
private static final String ER_ALLOW_ANY_CALL_REC_KEY = "extendrom_call_recording";
@VisibleForTesting
static final int SETTING_VALUE_ON = 1;
@VisibleForTesting
static final int SETTING_VALUE_OFF = 0;
public ER_CallRecPreferenceController(Context context) {{
super(context);
}}
@Override
public String getPreferenceKey() {{
return ER_ALLOW_ANY_CALL_REC_KEY;
}}
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {{
final boolean isEnabled = (Boolean) newValue;
Settings.Secure.putInt(mContext.getContentResolver(),
Settings.Secure.ER_ALLOW_ANY_CALL_REC,
isEnabled ? SETTING_VALUE_ON : SETTING_VALUE_OFF);
return true;
}}
@Override
public void updateState(Preference preference) {{
final int recMode = Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.ER_ALLOW_ANY_CALL_REC, SETTING_VALUE_OFF);
((SwitchPreference) mPreference).setChecked(recMode != SETTING_VALUE_OFF);
}}
@Override
protected void onDeveloperOptionsSwitchDisabled() {{
super.onDeveloperOptionsSwitchDisabled();
Settings.Secure.putInt(mContext.getContentResolver(),
Settings.Secure.ER_ALLOW_ANY_CALL_REC, SETTING_VALUE_OFF);
((SwitchPreference) mPreference).setChecked(false);
}}
}}
""".format(marker=MARKER)
CALL_REC_INFO = """/*
* Copyright (C) 2024 steadfasterX <steadfasterX |AT| binbash #DOT# rocks>
* LICENSE: GNU General Public License v3.0
* Ported to LOS 23.2 / sunfish-a16-rom ({marker}).
*/
package com.android.settings.development;
import android.content.Context;
import androidx.preference.Preference;
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settingslib.development.DeveloperOptionsPreferenceController;
public class ER_CallRecInfo extends DeveloperOptionsPreferenceController
implements Preference.OnPreferenceChangeListener, PreferenceControllerMixin {{
private static final String ER_ALLOW_ANY_CALL_REC_KEY_INFO = "extendrom_call_recording_info";
public ER_CallRecInfo(Context context) {{
super(context);
}}
@Override
public String getPreferenceKey() {{
return ER_ALLOW_ANY_CALL_REC_KEY_INFO;
}}
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {{
return true;
}}
}}
""".format(marker=MARKER)
FLAG_SECURE_CTRL = """/*
* sunfish-a16-rom ({marker}): Developer Options gate for AOSP
* Settings.Secure.DISABLE_SECURE_WINDOWS (WindowManagerService already
* honours this on debuggable builds).
*/
package com.android.settings.development;
import android.content.Context;
import android.provider.Settings;
import androidx.annotation.VisibleForTesting;
import androidx.preference.Preference;
import androidx.preference.SwitchPreference;
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settingslib.development.DeveloperOptionsPreferenceController;
public class FlagSecureOverridePreferenceController extends DeveloperOptionsPreferenceController
implements Preference.OnPreferenceChangeListener, PreferenceControllerMixin {{
private static final String PREF_KEY = "allow_flag_secure_override";
@VisibleForTesting
static final int SETTING_VALUE_ON = 1;
@VisibleForTesting
static final int SETTING_VALUE_OFF = 0;
public FlagSecureOverridePreferenceController(Context context) {{
super(context);
}}
@Override
public String getPreferenceKey() {{
return PREF_KEY;
}}
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {{
final boolean isEnabled = (Boolean) newValue;
Settings.Secure.putInt(mContext.getContentResolver(),
Settings.Secure.DISABLE_SECURE_WINDOWS,
isEnabled ? SETTING_VALUE_ON : SETTING_VALUE_OFF);
return true;
}}
@Override
public void updateState(Preference preference) {{
final int mode = Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.DISABLE_SECURE_WINDOWS, SETTING_VALUE_OFF);
((SwitchPreference) mPreference).setChecked(mode != SETTING_VALUE_OFF);
}}
@Override
protected void onDeveloperOptionsSwitchDisabled() {{
super.onDeveloperOptionsSwitchDisabled();
Settings.Secure.putInt(mContext.getContentResolver(),
Settings.Secure.DISABLE_SECURE_WINDOWS, SETTING_VALUE_OFF);
((SwitchPreference) mPreference).setChecked(false);
}}
}}
""".format(marker=MARKER)
FLAG_SECURE_INFO = """/*
* sunfish-a16-rom ({marker}).
*/
package com.android.settings.development;
import android.content.Context;
import androidx.preference.Preference;
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settingslib.development.DeveloperOptionsPreferenceController;
public class FlagSecureOverrideInfo extends DeveloperOptionsPreferenceController
implements Preference.OnPreferenceChangeListener, PreferenceControllerMixin {{
private static final String PREF_KEY = "allow_flag_secure_override_info";
public FlagSecureOverrideInfo(Context context) {{
super(context);
}}
@Override
public String getPreferenceKey() {{
return PREF_KEY;
}}
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {{
return true;
}}
}}
""".format(marker=MARKER)
def backup(path: Path) -> None:
BAK_ROOT.mkdir(parents=True, exist_ok=True)
try:
rel = path.relative_to(TREE)
except ValueError:
rel = path
bak = BAK_ROOT / str(rel).replace("/", "_")
if not bak.exists():
shutil.copy2(path, bak)
def write_new(path: Path, content: str) -> None:
if path.exists() and MARKER in path.read_text(errors="ignore"):
print(f"{path.name}: already present")
return
path.parent.mkdir(parents=True, exist_ok=True)
if path.exists():
backup(path)
path.write_text(content)
print(f"{path.name}: written")
def patch_settings_secure() -> None:
path = TREE / "frameworks/base/core/java/android/provider/Settings.java"
text = path.read_text()
if "ER_ALLOW_ANY_CALL_REC" in text:
print("Settings.java: ER_ALLOW_ANY_CALL_REC already present")
return
backup(path)
needle = ' public static final String ALLOW_SIGNATURE_FAKE = "allow_signature_fake";'
if needle not in text:
raise SystemExit("ALLOW_SIGNATURE_FAKE anchor not found in Settings.java")
insert = (
needle
+ "\n\n"
+ " /**\n"
+ f" * {MARKER} / EXTENDROM: unrestricted call recording (AXP GOLDEN).\n"
+ " *\n"
+ " * <p>1 = permit any country to record\n"
+ " * <p>0 = allow only defined countries to record\n"
+ " * @hide\n"
+ " */\n"
+ ' public static final String ER_ALLOW_ANY_CALL_REC = "extendrom_call_recording";'
)
text = text.replace(needle, insert, 1)
path.write_text(text)
print("Settings.java: ER_ALLOW_ANY_CALL_REC added")
def patch_call_recorder() -> None:
path = (
TREE
/ "packages/apps/Dialer/java/com/android/incallui/call/CallRecorder.java"
)
text = path.read_text()
if "extendrom_call_recording" in text or MARKER in text:
print("CallRecorder.java: already patched")
return
backup(path)
if "import android.provider.Settings;" not in text:
# after last import
lines = text.splitlines(keepends=True)
last_import = max(i for i, ln in enumerate(lines) if ln.startswith("import "))
lines.insert(last_import + 1, "import android.provider.Settings; // " + MARKER + "\n")
text = "".join(lines)
old = """ public boolean canRecordInCurrentCountry() {
if (!isEnabled()) {
return false;
}
if (RECORD_ALLOWED_STATE_BY_COUNTRY.isEmpty()) {
loadAllowedStates();
}
String currentCountryIso = GeoUtil.getCurrentCountryIso(context);
Boolean allowedState = RECORD_ALLOWED_STATE_BY_COUNTRY.get(currentCountryIso);
return allowedState != null && allowedState;
}"""
new = """ public boolean canRecordInCurrentCountry() {
if (!isEnabled()) {
return false;
}
// """ + MARKER + """ / EXTENDROM F_CALLREC (AXP GOLDEN)
int ER_CallRecordingEnabled = Settings.Secure.getInt(
context.getContentResolver(),
"extendrom_call_recording", 0);
if (ER_CallRecordingEnabled == 1) {
return true;
}
// END: """ + MARKER + """
if (RECORD_ALLOWED_STATE_BY_COUNTRY.isEmpty()) {
loadAllowedStates();
}
String currentCountryIso = GeoUtil.getCurrentCountryIso(context);
Boolean allowedState = RECORD_ALLOWED_STATE_BY_COUNTRY.get(currentCountryIso);
return allowedState != null && allowedState;
}"""
if old not in text:
raise SystemExit("canRecordInCurrentCountry block not found exactly")
path.write_text(text.replace(old, new, 1))
print("CallRecorder.java: patched")
def patch_development_xml() -> None:
path = TREE / "packages/apps/Settings/res/xml/development_settings.xml"
text = path.read_text()
if "extendrom_call_recording" in text and "allow_flag_secure_override" in text:
print("development_settings.xml: already patched")
return
backup(path)
block = f"""
<!-- {MARKER} / EXTENDROM call recording (AXP GOLDEN) -->
<PreferenceCategory
android:key="extendrom_call_recording_category"
android:title="@string/extendrom_call_recording_category"
android:order="9980">
<Preference
android:key="extendrom_call_recording_info"
android:summary="@string/extendrom_call_recording_details" />
<SwitchPreference
android:key="extendrom_call_recording"
android:title="@string/extendrom_call_recording"
android:summary="@string/extendrom_call_recording_summary"
android:defaultValue="false" />
</PreferenceCategory>
<!-- end: {MARKER} call recording -->
<!-- {MARKER}: FLAG_SECURE / DISABLE_SECURE_WINDOWS DO gate -->
<PreferenceCategory
android:key="flag_secure_override_category"
android:title="@string/flag_secure_override_category"
android:order="9970">
<Preference
android:key="allow_flag_secure_override_info"
android:summary="@string/allow_flag_secure_override_details" />
<SwitchPreference
android:key="allow_flag_secure_override"
android:title="@string/allow_flag_secure_override"
android:summary="@string/allow_flag_secure_override_summary"
android:defaultValue="false" />
</PreferenceCategory>
<!-- end: {MARKER} FLAG_SECURE -->
"""
# Insert after signature spoof category (after first PreferenceCategory block that ends before next)
anchor = ' <!-- SUNFISH_A16_005_SIGSPOOF / EXTENDROM signature spoofing -->'
if anchor not in text:
# fall back: after development_prefs_screen open
needle = 'android:title="@string/development_settings_title">'
if needle not in text:
raise SystemExit("development_settings.xml anchor not found")
text = text.replace(needle, needle + "\n" + block, 1)
else:
# place our categories immediately before 005 category
text = text.replace(anchor, block + " " + anchor.lstrip(), 1)
path.write_text(text)
print("development_settings.xml: patched")
def patch_strings() -> None:
path = TREE / "packages/apps/Settings/res/values/strings.xml"
text = path.read_text()
if "extendrom_call_recording_category" in text and "allow_flag_secure_override" in text:
print("strings.xml: already patched")
return
backup(path)
if not text.rstrip().endswith("</resources>"):
raise SystemExit("strings.xml does not end with </resources>")
add = f"""
<!-- {MARKER} / EXTENDROM call recording -->
<string name="extendrom_call_recording_category">Call recording support</string>
<string name="extendrom_call_recording">Disable call recording restrictions</string>
<string name="extendrom_call_recording_summary">If activated call recording limitations per country will be disabled</string>
<string name="extendrom_call_recording_details">YOU are responsible for checking whether call recording is legal in your country before overriding the default restrictions with this setting!\\nSee: https://axpos.org/r</string>
<!-- {MARKER}: FLAG_SECURE override (writes AOSP disable_secure_windows) -->
<string name="flag_secure_override_category">Secure window screenshots</string>
<string name="allow_flag_secure_override">Allow screenshots of secure windows</string>
<string name="allow_flag_secure_override_summary">When enabled, apps that set FLAG_SECURE can still be captured by the system screenshot / screen record paths (debuggable builds). Weakens app privacy.</string>
<string name="allow_flag_secure_override_details">Writes Settings.Secure.disable_secure_windows. On userdebug/eng, WindowManager treats FLAG_SECURE windows as capturable. Default OFF restores stock secure-window behaviour.</string>
"""
text = text.replace("</resources>", add + "</resources>", 1)
path.write_text(text)
print("strings.xml: patched")
def patch_dashboard() -> None:
path = (
TREE
/ "packages/apps/Settings/src/com/android/settings/development/"
"DevelopmentSettingsDashboardFragment.java"
)
text = path.read_text()
if "ER_CallRecPreferenceController" in text and "FlagSecureOverridePreferenceController" in text:
print("DevelopmentSettingsDashboardFragment: already patched")
return
backup(path)
needle = """ // SUNFISH_A16_005_SIGSPOOF
controllers.add(new SpoofSignaturePreferenceController(context));
controllers.add(new SpoofSignatureInfo(context));"""
if needle not in text:
raise SystemExit("005 SpoofSignature controllers anchor not found")
insert = (
needle
+ f"""
// {MARKER} call-rec (EXTENDROM / AXP GOLDEN)
controllers.add(new ER_CallRecPreferenceController(context));
controllers.add(new ER_CallRecInfo(context));
// {MARKER} FLAG_SECURE (AOSP DISABLE_SECURE_WINDOWS)
controllers.add(new FlagSecureOverridePreferenceController(context));
controllers.add(new FlagSecureOverrideInfo(context));"""
)
path.write_text(text.replace(needle, insert, 1))
print("DevelopmentSettingsDashboardFragment: patched")
def verify_dialer_config() -> None:
path = (
TREE
/ "packages/apps/Dialer/java/com/android/dialer/callrecord/res/values/config.xml"
)
text = path.read_text()
if 'call_recording_enabled">true' in text or "call_recording_enabled\">true" in text:
print("Dialer config.xml: call_recording_enabled=true (OK)")
else:
print("WARNING: Dialer call_recording_enabled not true — check overlay")
if "call_recording_audio_source\">4" in text or 'call_recording_audio_source">4' in text:
print("Dialer config.xml: call_recording_audio_source=4 (OK)")
def main() -> None:
if not TREE.is_dir():
raise SystemExit(f"LOS tree missing: {TREE}")
BAK_ROOT.mkdir(parents=True, exist_ok=True)
settings_dev = TREE / "packages/apps/Settings/src/com/android/settings/development"
write_new(settings_dev / "ER_CallRecPreferenceController.java", CALL_REC_CTRL)
write_new(settings_dev / "ER_CallRecInfo.java", CALL_REC_INFO)
write_new(settings_dev / "FlagSecureOverridePreferenceController.java", FLAG_SECURE_CTRL)
write_new(settings_dev / "FlagSecureOverrideInfo.java", FLAG_SECURE_INFO)
patch_settings_secure()
patch_call_recorder()
patch_strings()
patch_development_xml()
patch_dashboard()
verify_dialer_config()
print("done:", MARKER)
if __name__ == "__main__":
main()