Compare commits

..

93 Commits
v3.1.0 ... main

Author SHA1 Message Date
tehcneko
b64046f57c update compile sdk to 36 2025-04-05 12:57:11 +08:00
tehcneko
bc17c4c9bb update ci to jdk 21 2025-04-05 12:57:11 +08:00
tehcneko
401f196e2e check caller method with stack walker 2025-04-05 12:57:11 +08:00
tehcneko
bf5cdb513d replace @TargetApi with @RequireApi 2025-04-05 12:57:11 +08:00
tehcneko
f11e16da7d update AGP 2025-04-05 12:57:11 +08:00
tehcneko
de591e925e
fix issue template 2025-04-05 12:49:42 +08:00
tehcneko
4b426733ca bump version 2025-03-04 19:49:27 +08:00
tehcneko
a5461af177 support scrcpy 2025-03-04 19:48:49 +08:00
tehcneko
aa56f32b6a update issue template 2025-03-04 19:35:08 +08:00
tehcneko
cf19309b6b add support info to README 2025-03-04 19:30:47 +08:00
tehcneko
cd14a26f54 remove support for Android 11- 2025-03-04 19:10:58 +08:00
tehcneko
20c7f4c30d update gradle 2025-03-04 18:55:48 +08:00
tehcneko
624a493311 update gradle 2025-01-12 11:56:00 +08:00
Wang Han
a5e8659290
Bump version 2024-12-02 11:00:19 +08:00
Wang Han
375469dd23
Hook OplusScreenCapture#setUid on Oplus A15 (#75)
Or surfaceflinger will silently reject screen capture after checking uid.
2024-11-30 21:09:03 +08:00
dependabot[bot]
2baedef66f
Bump com.android.application from 8.6.1 to 8.7.2 (#72) 2024-11-30 16:53:10 +08:00
dependabot[bot]
469d58c95f
Bump androidx.annotation:annotation from 1.8.2 to 1.9.1 (#71) 2024-11-30 16:49:55 +08:00
tehcneko
e0203a480f update gradle 2024-09-29 21:08:34 +08:00
dependabot[bot]
197f971cbb
Bump com.android.application from 8.5.2 to 8.6.0 (#62) 2024-08-30 08:57:44 +08:00
tehcneko
9fbc536136 fix SOURCE_URL 2024-08-19 18:04:32 +08:00
tehcneko
610af286b7 fix typo 2024-08-19 17:55:50 +08:00
tehcneko
8ba19d5779 mention screen record detection removal 2024-08-19 17:54:22 +08:00
tehcneko
f166d733f0 bump version 2024-08-19 17:51:43 +08:00
tehcneko
5ddd76fe39 bump min sdk 2024-08-19 17:51:29 +08:00
tehcneko
c991e3dac1 Add test activity 2024-08-18 14:17:15 +08:00
tehcneko
42ae2ab20d Disable screen record detection on Android 15 2024-08-18 14:17:15 +08:00
tehcneko
caa953cd11 Support Android 15 Beta 4 2024-08-18 14:17:15 +08:00
dependabot[bot]
4a811dd16a
Bump com.android.application from 8.5.1 to 8.5.2 (#58) 2024-08-10 09:29:32 +08:00
dependabot[bot]
bdea05344b
Bump androidx.annotation:annotation from 1.8.1 to 1.8.2 (#57) 2024-08-09 15:06:42 +08:00
tehcneko
fd0b56f651 update compile sdk 2024-07-29 11:18:42 +08:00
tehcneko
92c067bb15 fix annotations 2024-07-29 11:17:24 +08:00
dependabot[bot]
5f342219df Bump androidx.annotation:annotation from 1.8.0 to 1.8.1
Bumps androidx.annotation:annotation from 1.8.0 to 1.8.1.

---
updated-dependencies:
- dependency-name: androidx.annotation:annotation
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-07-29 10:54:14 +08:00
tehcneko
52e281a380 bump version 2024-07-29 10:48:43 +08:00
tehcneko
9343df3060 update gradle 2024-07-29 10:44:55 +08:00
tehcneko
b222af63b4 update libxposed 2024-07-29 10:42:15 +08:00
tehcneko
3525dd69a8 Create SOURCE 2024-07-29 10:36:24 +08:00
tehcneko
3b2efdea96 Delete useless template 2024-07-29 10:36:24 +08:00
dependabot[bot]
dab601582f Bump com.android.application from 8.5.0 to 8.5.1
Bumps com.android.application from 8.5.0 to 8.5.1.

---
updated-dependencies:
- dependency-name: com.android.application
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-07-21 16:12:39 +08:00
tehcneko
ac95d737da Merge source code 2024-07-21 16:11:31 +08:00
5ec1cff
3481cbbfac fix oplus in system server 2024-06-23 10:08:24 +08:00
tehcneko
201040ed64
Delete SOURCE_URL 2024-06-17 20:01:27 +08:00
tehcneko
aee7d86bb3 bump version 2024-06-17 19:21:48 +08:00
tehcneko
5fddba5a28 don't alter allowProtected 2024-06-17 17:57:57 +08:00
tehcneko
c5f1300bad replace toast with dialog 2024-06-17 17:57:57 +08:00
dependabot[bot]
8fa24bf735
Bump com.android.application from 8.4.2 to 8.5.0 (#50) 2024-06-14 08:28:29 +08:00
dependabot[bot]
7df5373528
Bump com.android.application from 8.4.1 to 8.4.2 (#49) 2024-06-11 05:49:31 +08:00
tehcneko
21ae4664bf
bump version 2024-06-07 18:30:41 +08:00
tehcneko
cbf58ade17 update issue template 2024-06-04 10:29:10 +08:00
tehcneko
a3e40a7a86 update issue template 2024-06-04 10:26:57 +08:00
tehcneko
0379101d04 update issue template 2024-06-04 10:25:29 +08:00
dependabot[bot]
7a092d6522
Bump actions/setup-java from 3 to 4 (#46) 2024-06-04 10:22:05 +08:00
dependabot[bot]
e2d1852b3a
Bump actions/checkout from 3 to 4 (#47) 2024-06-04 10:21:55 +08:00
dependabot[bot]
f24af7ae41
Bump actions/upload-artifact from 3 to 4 (#48) 2024-06-04 10:21:43 +08:00
tehcneko
e8c1d9335b hook screen capture in system_server on S to U 2024-06-01 22:27:44 +08:00
tehcneko
df2f067432 Add issue template 2024-05-30 20:09:48 +08:00
tehcneko
4df65a68c3
enable dependabot for actions 2024-05-29 19:24:48 +08:00
tehcneko
ad2a9422b0
Update SUMMARY 2024-05-29 09:56:19 +08:00
tehcneko
d4c648c0d6
Update README.md 2024-05-29 09:55:15 +08:00
tehcneko
fa125bb7bf rename module to enable screenshot 2024-05-29 09:54:51 +08:00
tehcneko
e11555632a support oneui 2024-05-28 20:18:28 +08:00
tehcneko
34f0dd41c4 use commit count as version code 2024-05-28 19:40:15 +08:00
tehcneko
622283dd14 hook native methods instead 2024-05-28 16:35:37 +08:00
5ec1cff
ad92151c28 fix oplus and flyme 2024-05-28 16:35:37 +08:00
tehcneko
2c3aa5b9f7 mark hook hyper os as target U 2024-05-28 10:40:46 +08:00
tehcneko
f9a1c1321e update comments 2024-05-27 20:38:18 +08:00
tehcneko
5a5fa2ba19 fix detection 2024-05-27 20:20:45 +08:00
tehcneko
ced188ff61 switch to new bypass method (A12+) 2024-05-27 20:08:07 +08:00
tehcneko
465cb2ed9b fix display content deoptimization 2024-05-27 17:26:04 +08:00
tehcneko
ee0bfdf9b6 support new oplus methods 2024-05-27 17:07:38 +08:00
tehcneko
c0f48f54ba update gradle 2024-05-27 14:57:28 +08:00
dependabot[bot]
de43fcbbe0
Bump androidx.annotation:annotation from 1.7.1 to 1.8.0 (#37) 2024-05-15 09:40:14 +08:00
dependabot[bot]
f19dfcaae6
Bump com.android.application from 8.3.1 to 8.3.2 (#34) 2024-04-11 08:49:05 +08:00
dependabot[bot]
ca497ee3e6 Bump com.android.application from 8.3.0 to 8.3.1
Bumps com.android.application from 8.3.0 to 8.3.1.

---
updated-dependencies:
- dependency-name: com.android.application
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-03-20 01:27:24 +08:00
tehcneko
f45da54b81 Remove unnecessary deoptimization 2024-03-13 17:25:18 +08:00
tehcneko
9143d52b8f Fix oplus 2024-03-13 17:25:18 +08:00
tehcneko
e58a818f92
Update bug_report.yml 2024-03-13 16:56:18 +08:00
tehcneko
2e4f7549bd Add dependabot 2024-03-12 17:25:39 +08:00
tehcneko
4f9eef8b0c Use fixed libxposed commit 2024-03-12 17:20:59 +08:00
tehcneko
9e1bdeaf16 Update build files 2024-03-11 21:34:16 +08:00
tehcneko
150963caae Update CI 2024-03-11 21:25:26 +08:00
tehcneko
440d85714c Update CI 2024-03-11 21:25:03 +08:00
tehcneko
68ac14a2b8 Rewrite with libxposed 2024-03-11 21:08:15 +08:00
tehcneko
d1275e4cf6 Update AGP 2024-03-07 19:13:05 +08:00
tehcneko
cd8d101b8c Check isFirstApplication 2024-02-14 23:04:40 +08:00
tehcneko
e6bc968ab6
Update README.md 2024-01-17 19:28:34 +08:00
tehcneko
e4445075b3
Update SUMMARY 2024-01-17 19:28:16 +08:00
tehcneko
6c8ecc6091
Update SUMMARY 2024-01-17 19:27:59 +08:00
tehcneko
e9d7255888
Update README.md 2024-01-17 19:27:43 +08:00
tehcneko
29da41af0f
Update SUMMARY 2021-02-20 12:21:16 +08:00
tehcneko
b66d2549d5
Create SOURCE_URL 2021-02-19 23:42:51 +08:00
tehcneko
8825a0fabe Update README 2021-02-19 22:37:51 +08:00
LoveSy
65d04b4c65
Create SUMMARY 2021-02-12 01:53:26 +08:00
LoveSy
8fa792e7a9
Initial commit 2021-02-03 16:45:25 +08:00
34 changed files with 763 additions and 202 deletions

View File

@ -9,7 +9,7 @@ body:
- type: input
attributes:
label: LSPosed version
description: Don't use 'latest'. Specify actual version with 4 digits.
description: Only official LSPosed is supported. Don't use 'latest'. Specify actual version with 4 digits.
validations:
required: true
- type: input
@ -29,6 +29,20 @@ body:
options:
- label: I am using latest debug CI version
required: true
- type: checkboxes
id: official
attributes:
label: LSPosed requirement
options:
- label: I am using official LSPosed version
required: true
- type: textarea
attributes:
label: Behavior
description: Please describe the behavior when trying to screenshot.
placeholder: The screenshot is black. / Cannot screenshot with error notification or toast.
validations:
required: true
- type: textarea
attributes:
label: Logs
@ -38,8 +52,8 @@ body:
required: true
- type: textarea
attributes:
label: Framework JAR
description: Please upload your /system/framework/framework.jar.
placeholder: Upload jar by clicking the bar on the bottom.
label: Framework, Services, and Screenshot App
description: Please upload your /system/framework/framework.jar, services.jar, and the screenshot app of your ROM(on AOSP, it's System UI), compressed in a zip file. If the file size is too large to fit GitHub's limit, please upload it to https://catbox.moe and provide the link.
placeholder: Upload by clicking the bar on the bottom.
validations:
required: true
required: true

View File

@ -1 +1 @@
blank_issues_enabled: false
blank_issues_enabled: false

24
.github/dependabot.yml vendored Normal file
View File

@ -0,0 +1,24 @@
version: 2
updates:
- package-ecosystem: gradle
directory: "/"
schedule:
interval: daily
time: "21:00"
open-pull-requests-limit: 10
target-branch: main
registries:
- maven-google
- gralde-plugin
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
registries:
maven-google:
type: maven-repository
url: "https://dl.google.com/dl/android/maven2/"
gralde-plugin:
type: maven-repository
url: "https://plugins.gradle.org/m2/"

View File

@ -2,7 +2,6 @@ name: Android CI
on:
push:
branches: [ "main" ]
pull_request:
workflow_dispatch:
@ -12,12 +11,22 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: set up JDK 17
uses: actions/setup-java@v3
- uses: actions/checkout@v4
with:
java-version: '17'
fetch-depth: 0
- name: Checkout libxposed/api
uses: actions/checkout@v4
with:
repository: libxposed/api
ref: 64e29bd657ef4d2540b34402f5a988778f29e676
path: libxposed/api
fetch-depth: 0
- name: set up JDK 21
uses: actions/setup-java@v4
with:
java-version: '21'
distribution: 'temurin'
cache: gradle
@ -33,10 +42,21 @@ jobs:
fi
- name: Build with Gradle
run: ./gradlew assembleRelease assembleDebug
run: |
# gradle properties
mkdir -p ~/.gradle
echo 'org.gradle.caching=true' >> ~/.gradle/gradle.properties
echo 'org.gradle.parallel=true' >> ~/.gradle/gradle.properties
echo 'org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 -XX:+UseParallelGC' >> ~/.gradle/gradle.properties
echo 'android.native.buildOutput=verbose' >> ~/.gradle/gradle.properties
# build dependencies
cd libxposed/api && ./gradlew publishToMavenLocal && cd ../..
# build DisableFlagSecure
chmod +x gradlew
./gradlew assembleRelease assembleDebug
- name: Upload artifact
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: Signed app bundle
path: app/build/outputs/apk

View File

@ -1,2 +1,15 @@
# DisableFlagSecure
Disable FLAG_SECURE on all windows, enabling screenshots in apps that normally wouldn\'t allow it.
# Enable Screenshot (formerly known as Disable FLAG_SECURE)
Enabling screenshots in apps that normally wouldn\'t allow it, and disabling screenshot(Android 14+) & screen record(Android 15+) detection.
**Unofficial LSPosed versions are not supported.**
## Supported OSes
- Android 12-16 Beta 3 (Custom ROMs are **not** supported)
- Xiaomi Hyper OS
- OPlus OS (Color OS/Realme UI/Oxygen OS)
- Samsung One UI
## Usage
1. Enable the module
2. Select **ONLY** recommended apps
3. Reboot

1
SOURCE_URL Normal file
View File

@ -0,0 +1 @@
https://github.com/LSPosed/DisableFlagSecure

1
SUMMARY Normal file
View File

@ -0,0 +1 @@
Enabling screenshots in apps that normally wouldn't allow it, and disabling screenshot(Android 14+) & screen record(Android 15+) detection.

View File

@ -3,15 +3,15 @@ plugins {
}
android {
compileSdk 34
buildToolsVersion "34.0.0"
compileSdk 36
buildToolsVersion "36.0.0"
defaultConfig {
applicationId "io.github.lsposed.disableflagsecure"
minSdkVersion 24
targetSdkVersion 34
versionCode 8
versionName "3.1.0"
minSdkVersion 31
targetSdkVersion 36
versionCode rootProject.ext.commitCount
versionName "4.2.0"
}
Properties localProperties = new Properties()
@ -42,14 +42,15 @@ android {
} else {
signingConfig signingConfigs.debug
}
vcsInfo.include false
minifyEnabled true
proguardFiles 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_11
targetCompatibility JavaVersion.VERSION_11
sourceCompatibility JavaVersion.VERSION_21
targetCompatibility JavaVersion.VERSION_21
}
lint {
@ -61,5 +62,7 @@ android {
}
dependencies {
compileOnly 'de.robv.android.xposed:api:82'
compileOnly 'androidx.annotation:annotation:1.9.1'
compileOnly 'io.github.libxposed:api:100'
compileOnly project(":libxposed-compat")
}

View File

@ -1,5 +1,21 @@
-keep class io.github.lsposed.disableflagsecure.DisableFlagSecure
-adaptresourcefilecontents META-INF/xposed/java_init.list
-keepattributes RuntimeVisibleAnnotations
-keep,allowobfuscation,allowoptimization public class * extends io.github.libxposed.api.XposedModule {
public <init>(...);
public void onPackageLoaded(...);
public void onSystemServerLoaded(...);
}
-keep,allowshrinking,allowoptimization,allowobfuscation class ** implements io.github.libxposed.api.XposedInterface$Hooker
-keepclassmembers,allowoptimization class ** implements io.github.libxposed.api.XposedInterface$Hooker {
public *** before(***);
public *** after(***);
public static *** before();
public static *** before(io.github.libxposed.api.XposedInterface$BeforeHookCallback);
public static void after();
public static void after(io.github.libxposed.api.XposedInterface$AfterHookCallback);
public static void after(io.github.libxposed.api.XposedInterface$AfterHookCallback, ***);
}
-repackageclasses
-allowaccessmodification
-overloadaggressively
-allowaccessmodification

View File

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android">
<application tools:ignore="MissingApplicationIcon">
<activity
android:name=".TestActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="de.robv.android.xposed.category.MODULE_SETTINGS" />
</intent-filter>
</activity>
</application>
</manifest>

View File

@ -0,0 +1,63 @@
package io.github.lsposed.disableflagsecure;
import android.app.Activity;
import android.graphics.Paint;
import android.os.Bundle;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.WindowManager;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
public class TestActivity extends Activity implements SurfaceHolder.Callback {
private TextView textView;
private SurfaceView surfaceView;
private final Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG) {{
setColor(0xFF00FFFF);
}};
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE);
var linearLayout = new LinearLayout(this);
linearLayout.setOrientation(LinearLayout.VERTICAL);
linearLayout.setBackgroundColor(0xFFFFFF00);
setContentView(linearLayout, new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT));
textView = new TextView(this);
linearLayout.addView(textView, new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT, 1.0f));
surfaceView = new SurfaceView(this);
surfaceView.setZOrderOnTop(true);
surfaceView.setSecure(true);
surfaceView.getHolder().addCallback(this);
linearLayout.addView(surfaceView, new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT, 1.0f));
}
@Override
public void surfaceCreated(@NonNull SurfaceHolder holder) {
var canvas = holder.lockCanvas();
canvas.drawRect(0, 0, surfaceView.getMeasuredWidth(), surfaceView.getMeasuredHeight(), paint);
textView.setText("SurfaceView");
textView.draw(canvas);
textView.setText("TextView");
holder.unlockCanvasAndPost(canvas);
}
@Override
public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, int height) {
}
@Override
public void surfaceDestroyed(@NonNull SurfaceHolder holder) {
}
}

View File

@ -5,20 +5,8 @@
<application
android:allowBackup="true"
android:label="@string/app_name"
android:description="@string/xposed_description"
android:supportsRtl="true"
tools:ignore="AllowBackup,MissingApplicationIcon">
<meta-data
android:name="xposedmodule"
android:value="true" />
<meta-data
android:name="xposeddescription"
android:value="@string/xposed_description" />
<meta-data
android:name="xposedminversion"
android:value="53" />
<meta-data
android:name="xposedscope"
android:resource="@array/scope" />
</application>
tools:ignore="AllowBackup,MissingApplicationIcon" />
</manifest>

View File

@ -1,144 +1,470 @@
package io.github.lsposed.disableflagsecure;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.AlertDialog;
import android.hardware.display.DisplayManager;
import android.os.Build;
import android.util.Log;
import android.widget.Toast;
import android.view.SurfaceControl;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.function.BiConsumer;
import java.util.function.BiPredicate;
import de.robv.android.xposed.IXposedHookLoadPackage;
import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.XC_MethodReplacement;
import de.robv.android.xposed.XposedBridge;
import de.robv.android.xposed.XposedHelpers;
import de.robv.android.xposed.callbacks.XC_LoadPackage;
import io.github.libxposed.api.XposedInterface;
import io.github.libxposed.api.XposedModule;
import io.github.libxposed.api.annotations.BeforeInvocation;
import io.github.libxposed.api.annotations.XposedHooker;
public class DisableFlagSecure implements IXposedHookLoadPackage {
private final static Method deoptimizeMethod;
@SuppressLint({"PrivateApi", "BlockedPrivateApi"})
public class DisableFlagSecure extends XposedModule {
private static final String SYSTEMUI = "com.android.systemui";
private static final String OPLUS_APPPLATFORM = "com.oplus.appplatform";
private static final String OPLUS_SCREENSHOT = "com.oplus.screenshot";
private static final String FLYME_SYSTEMUIEX = "com.flyme.systemuiex";
private static final String MIUI_SCREENSHOT = "com.miui.screenshot";
static {
Method m = null;
try {
//noinspection JavaReflectionMemberAccess
m = XposedBridge.class.getDeclaredMethod("deoptimizeMethod", Member.class);
} catch (Throwable t) {
XposedBridge.log(t);
}
deoptimizeMethod = m;
}
private static XposedModule module;
static void deoptimizeMethod(Class<?> c, String n) throws InvocationTargetException, IllegalAccessException {
for (Method m : c.getDeclaredMethods()) {
if (deoptimizeMethod != null && m.getName().equals(n)) {
deoptimizeMethod.invoke(null, m);
Log.d("DisableFlagSecure", "Deoptimized " + m);
}
}
public DisableFlagSecure(XposedInterface base, ModuleLoadedParam param) {
super(base, param);
module = this;
}
@Override
public void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam) {
if (loadPackageParam.packageName.equals("android")) {
public void onSystemServerLoaded(@NonNull SystemServerLoadedParam param) {
var classLoader = param.getClassLoader();
try {
deoptimizeSystemServer(classLoader);
} catch (Throwable t) {
log("deoptimize system server failed", t);
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM) {
// Screen record detection (V~Baklava)
try {
Class<?> windowsState = XposedHelpers.findClass("com.android.server.wm.WindowState", loadPackageParam.classLoader);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
XposedHelpers.findAndHookMethod(
windowsState,
"isSecureLocked",
XC_MethodReplacement.returnConstant(false));
} else {
XposedHelpers.findAndHookMethod(
"com.android.server.wm.WindowManagerService",
loadPackageParam.classLoader,
"isSecureLocked",
windowsState,
XC_MethodReplacement.returnConstant(false));
}
hookWindowManagerService(classLoader);
} catch (Throwable t) {
XposedBridge.log(t);
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
try {
XposedHelpers.findAndHookMethod(
"com.android.server.wm.ActivityTaskManagerService",
loadPackageParam.classLoader,
"registerScreenCaptureObserver",
"android.os.IBinder",
"android.app.IScreenCaptureObserver",
XC_MethodReplacement.DO_NOTHING);
} catch (Throwable t) {
XposedBridge.log(t);
}
log("hook WindowManagerService failed", t);
}
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
// Screenshot detection (U~Baklava)
try {
deoptimizeMethod(XposedHelpers.findClass("com.android.server.wm.WindowStateAnimator", loadPackageParam.classLoader), "createSurfaceLocked");
var c = XposedHelpers.findClass("com.android.server.display.DisplayManagerService", loadPackageParam.classLoader);
deoptimizeMethod(c, "setUserPreferredModeForDisplayLocked");
deoptimizeMethod(c, "setUserPreferredDisplayModeInternal");
c = XposedHelpers.findClass("com.android.server.wm.InsetsPolicy$InsetsPolicyAnimationControlListener", loadPackageParam.classLoader);
for (var m : c.getDeclaredConstructors()) {
deoptimizeMethod.invoke(null, m);
}
c = XposedHelpers.findClass("com.android.server.wm.InsetsPolicy", loadPackageParam.classLoader);
deoptimizeMethod(c, "startAnimation");
deoptimizeMethod(c, "controlAnimationUnchecked");
for (int i = 0; i < 20; i++) {
c = XposedHelpers.findClassIfExists("com.android.server.wm.DisplayContent$$ExternalSyntheticLambda" + i, loadPackageParam.classLoader);
if (c != null && BiPredicate.class.isAssignableFrom(c)) {
deoptimizeMethod(c, "test");
}
}
c = XposedHelpers.findClass("com.android.server.wm.WindowManagerService", loadPackageParam.classLoader);
deoptimizeMethod(c, "relayoutWindow");
for (int i = 0; i < 20; i++) {
c = XposedHelpers.findClassIfExists("com.android.server.wm.RootWindowContainer$$ExternalSyntheticLambda" + i, loadPackageParam.classLoader);
if (c != null && BiConsumer.class.isAssignableFrom(c)) {
deoptimizeMethod(c, "accept");
}
}
hookActivityTaskManagerService(classLoader);
} catch (Throwable t) {
XposedBridge.log(t);
log("hook ActivityTaskManagerService failed", t);
}
// Xiaomi HyperOS (U~Baklava)
// OS2.0.250220.1.WOCCNXM.PRE
try {
Class<?> windowsManagerServiceImpl = XposedHelpers.findClassIfExists("com.android.server.wm.WindowManagerServiceImpl", loadPackageParam.classLoader);
if (windowsManagerServiceImpl != null) {
XposedBridge.hookAllMethods(
windowsManagerServiceImpl,
"notAllowCaptureDisplay",
XC_MethodReplacement.returnConstant(false));
}
hookHyperOS(classLoader);
} catch (ClassNotFoundException ignored) {
} catch (Throwable t) {
XposedBridge.log(t);
log("hook HyperOS failed", t);
}
} else if (loadPackageParam.packageName.equals("com.flyme.systemuiex")) {
}
// ScreenCapture in WindowManagerService (S~Baklava)
try {
hookScreenCapture(classLoader);
} catch (Throwable t) {
log("hook ScreenCapture failed", t);
}
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
// Blackout permission check (S~T)
try {
XposedHelpers.findAndHookMethod("android.view.SurfaceControl$ScreenshotHardwareBuffer", loadPackageParam.classLoader, "containsSecureLayers", XC_MethodReplacement.returnConstant(false));
hookActivityManagerService(classLoader);
} catch (Throwable t) {
XposedBridge.log(t);
log("hook ActivityManagerService failed", t);
}
} else if (loadPackageParam.packageName.equals("com.oplus.screenshot")) {
try {
Class<?> screenshotContext = XposedHelpers.findClassIfExists("com.oplus.screenshot.screenshot.core.ScreenshotContext", loadPackageParam.classLoader);
XposedBridge.hookAllMethods(screenshotContext, "setScreenshotReject", XC_MethodReplacement.DO_NOTHING);
XposedBridge.hookAllMethods(screenshotContext, "setLongshotReject", XC_MethodReplacement.DO_NOTHING);
} catch (Throwable t) {
XposedBridge.log(t);
}
// WifiDisplay (S~Baklava) / OverlayDisplay (S~Baklava) / VirtualDisplay (U~Baklava)
try {
hookDisplayControl(classLoader);
} catch (Throwable t) {
log("hook DisplayControl failed", t);
}
// VirtualDisplay with MediaProjection (S~Baklava)
try {
hookVirtualDisplayAdapter(classLoader);
} catch (Throwable t) {
log("hook VirtualDisplayAdapter failed", t);
}
// OneUI
try {
hookScreenshotHardwareBuffer(classLoader);
} catch (Throwable t) {
if (!(t instanceof ClassNotFoundException)) {
log("hook ScreenshotHardwareBuffer failed", t);
}
}
try {
hookOneUI(classLoader);
} catch (Throwable t) {
if (!(t instanceof ClassNotFoundException)) {
log("hook OneUI failed", t);
}
}
// secureLocked flag
try {
// Screenshot
hookWindowState(classLoader);
} catch (Throwable t) {
log("hook WindowState failed", t);
}
// oplus dumpsys
// dumpsys window screenshot systemQuickTileScreenshotOut display_id=0
try {
hookOplus(classLoader);
} catch (Throwable t) {
if (!(t instanceof ClassNotFoundException)) {
log("hook Oplus failed", t);
}
} else {
XposedHelpers.findAndHookMethod(Activity.class, "onResume", new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) {
Activity activity = (Activity) param.thisObject;
Toast.makeText(activity, "DFS: Incorrect module usage, remove this app from scope.", Toast.LENGTH_LONG).show();
activity.finish();
}
});
}
}
@SuppressLint("PrivateApi")
@Override
public void onPackageLoaded(@NonNull PackageLoadedParam param) {
if (!param.isFirstPackage()) return;
var classLoader = param.getClassLoader();
var pn = param.getPackageName();
switch (pn) {
case OPLUS_SCREENSHOT:
// Oplus Screenshot 15.0.0
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM) {
try {
hookOplusScreenCapture(classLoader);
} catch (Throwable t) {
if (!(t instanceof ClassNotFoundException)) {
log("hook OplusScreenCapture failed", t);
}
}
}
case FLYME_SYSTEMUIEX:
case OPLUS_APPPLATFORM:
// Flyme SystemUI Ext 10.3.0
// OPlus AppPlatform 13.1.0 / 14.0.0
try {
hookScreenshotHardwareBuffer(classLoader);
} catch (Throwable t) {
if (!(t instanceof ClassNotFoundException)) {
log("hook ScreenshotHardwareBuffer failed", t);
}
}
case SYSTEMUI:
case MIUI_SCREENSHOT:
if (OPLUS_APPPLATFORM.equals(pn) || OPLUS_SCREENSHOT.equals(pn) ||
Build.VERSION.SDK_INT < Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
// ScreenCapture in App (S~T) (OPlus S~V)
// TODO: test Oplus Baklava
try {
hookScreenCapture(classLoader);
} catch (Throwable t) {
log("hook ScreenCapture failed", t);
}
}
break;
default:
try {
hookOnResume();
} catch (Throwable ignored) {
}
}
}
private void deoptimizeSystemServer(ClassLoader classLoader) throws ClassNotFoundException {
deoptimizeMethods(
classLoader.loadClass("com.android.server.wm.WindowStateAnimator"),
"createSurfaceLocked");
deoptimizeMethods(
classLoader.loadClass("com.android.server.wm.WindowManagerService"),
"relayoutWindow");
for (int i = 0; i < 20; i++) {
try {
var clazz = classLoader.loadClass("com.android.server.wm.RootWindowContainer$$ExternalSyntheticLambda" + i);
if (BiConsumer.class.isAssignableFrom(clazz)) {
deoptimizeMethods(clazz, "accept");
}
} catch (ClassNotFoundException ignored) {
}
try {
var clazz = classLoader.loadClass("com.android.server.wm.DisplayContent$" + i);
if (BiPredicate.class.isAssignableFrom(clazz)) {
deoptimizeMethods(clazz, "test");
}
} catch (ClassNotFoundException ignored) {
}
}
}
private void deoptimizeMethods(Class<?> clazz, String... names) {
var list = Arrays.asList(names);
Arrays.stream(clazz.getDeclaredMethods())
.filter(method -> list.contains(method.getName()))
.forEach(this::deoptimize);
}
private void hookWindowState(ClassLoader classLoader) throws ClassNotFoundException, NoSuchMethodException {
var windowStateClazz = classLoader.loadClass("com.android.server.wm.WindowState");
var isSecureLockedMethod = windowStateClazz.getDeclaredMethod("isSecureLocked");
hook(isSecureLockedMethod, SecureLockedHooker.class);
}
private static Field captureSecureLayersField;
private void hookScreenCapture(ClassLoader classLoader) throws ClassNotFoundException, NoSuchFieldException {
var screenCaptureClazz = Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE ?
classLoader.loadClass("android.window.ScreenCapture") :
SurfaceControl.class;
var captureArgsClazz = classLoader.loadClass(Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE ?
"android.window.ScreenCapture$CaptureArgs" :
"android.view.SurfaceControl$CaptureArgs");
captureSecureLayersField = captureArgsClazz.getDeclaredField("mCaptureSecureLayers");
captureSecureLayersField.setAccessible(true);
hookMethods(screenCaptureClazz, ScreenCaptureHooker.class, "nativeCaptureDisplay");
hookMethods(screenCaptureClazz, ScreenCaptureHooker.class, "nativeCaptureLayers");
}
private void hookDisplayControl(ClassLoader classLoader) throws ClassNotFoundException, NoSuchMethodException {
var displayControlClazz = Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE ?
classLoader.loadClass("com.android.server.display.DisplayControl") :
SurfaceControl.class;
var method = displayControlClazz.getDeclaredMethod(
Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM ?
"createVirtualDisplay" :
"createDisplay", String.class, boolean.class);
hook(method, CreateDisplayHooker.class);
}
private void hookVirtualDisplayAdapter(ClassLoader classLoader) throws ClassNotFoundException {
var displayControlClazz = classLoader.loadClass("com.android.server.display.VirtualDisplayAdapter");
hookMethods(displayControlClazz, CreateVirtualDisplayLockedHooker.class, "createVirtualDisplayLocked");
}
@RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
private void hookActivityTaskManagerService(ClassLoader classLoader) throws ClassNotFoundException, NoSuchMethodException {
var activityTaskManagerServiceClazz = classLoader.loadClass("com.android.server.wm.ActivityTaskManagerService");
var iBinderClazz = classLoader.loadClass("android.os.IBinder");
var iScreenCaptureObserverClazz = classLoader.loadClass("android.app.IScreenCaptureObserver");
var method = activityTaskManagerServiceClazz.getDeclaredMethod("registerScreenCaptureObserver", iBinderClazz, iScreenCaptureObserverClazz);
hook(method, ReturnNullHooker.class);
}
@RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
private void hookWindowManagerService(ClassLoader classLoader) throws ClassNotFoundException, NoSuchMethodException {
var windowManagerServiceClazz = classLoader.loadClass("com.android.server.wm.WindowManagerService");
var iScreenRecordingCallbackClazz = classLoader.loadClass("android.window.IScreenRecordingCallback");
var method = windowManagerServiceClazz.getDeclaredMethod("registerScreenRecordingCallback", iScreenRecordingCallbackClazz);
hook(method, ReturnFalseHooker.class);
}
private void hookActivityManagerService(ClassLoader classLoader) throws ClassNotFoundException, NoSuchMethodException {
var activityTaskManagerServiceClazz = classLoader.loadClass("com.android.server.am.ActivityManagerService");
var method = activityTaskManagerServiceClazz.getDeclaredMethod("checkPermission", String.class, int.class, int.class);
hook(method, CheckPermissionHooker.class);
}
@RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
private void hookHyperOS(ClassLoader classLoader) throws ClassNotFoundException {
var windowManagerServiceImplClazz = classLoader.loadClass("com.android.server.wm.WindowManagerServiceImpl");
hookMethods(windowManagerServiceImplClazz, ReturnFalseHooker.class, "notAllowCaptureDisplay");
}
private void hookScreenshotHardwareBuffer(ClassLoader classLoader) throws ClassNotFoundException, NoSuchMethodException {
var screenshotHardwareBufferClazz = classLoader.loadClass(
Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE ?
"android.window.ScreenCapture$ScreenshotHardwareBuffer" :
"android.view.SurfaceControl$ScreenshotHardwareBuffer");
var method = screenshotHardwareBufferClazz.getDeclaredMethod("containsSecureLayers");
hook(method, ReturnFalseHooker.class);
}
@RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
private void hookOplusScreenCapture(ClassLoader classLoader) throws ClassNotFoundException, NoSuchMethodException {
var oplusScreenCaptureClazz = classLoader.loadClass("com.oplus.screenshot.OplusScreenCapture$CaptureArgs$Builder");
var method = oplusScreenCaptureClazz.getDeclaredMethod("setUid", long.class);
hook(method, OplusScreenCaptureHooker.class);
}
private void hookOplus(ClassLoader classLoader) throws ClassNotFoundException {
// caller: com.android.server.wm.OplusLongshotWindowDump#dumpWindows
var longshotMainClazz = classLoader.loadClass("com.android.server.wm.OplusLongshotMainWindow");
hookMethods(longshotMainClazz, ReturnFalseHooker.class, "hasSecure");
}
private void hookOneUI(ClassLoader classLoader) throws ClassNotFoundException {
var wmScreenshotControllerClazz = classLoader.loadClass("com.android.server.wm.WmScreenshotController");
hookMethods(wmScreenshotControllerClazz, ReturnTrueHooker.class, "canBeScreenshotTarget");
}
private void hookMethods(Class<?> clazz, Class<? extends Hooker> hooker, String... names) {
var list = Arrays.asList(names);
Arrays.stream(clazz.getDeclaredMethods())
.filter(method -> list.contains(method.getName()))
.forEach(method -> hook(method, hooker));
}
private void hookOnResume() throws NoSuchMethodException {
var method = Activity.class.getDeclaredMethod("onResume");
hook(method, ToastHooker.class);
}
@XposedHooker
private static class CreateDisplayHooker implements Hooker {
@BeforeInvocation
public static void before(@NonNull BeforeHookCallback callback) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
var stackTrace = new Throwable().getStackTrace();
for (int i = 4; i < stackTrace.length && i < 8; i++) {
var name = stackTrace[i].getMethodName();
if (name.equals("createVirtualDisplayLocked")) {
return;
}
}
}
callback.getArgs()[1] = true;
}
}
@XposedHooker
private static class CheckPermissionHooker implements Hooker {
@BeforeInvocation
public static void before(@NonNull BeforeHookCallback callback) {
var permission = callback.getArgs()[0];
if ("android.permission.CAPTURE_BLACKOUT_CONTENT".equals(permission)) {
callback.getArgs()[0] = "android.permission.READ_FRAME_BUFFER";
}
}
}
@XposedHooker
private static class OplusScreenCaptureHooker implements Hooker {
@BeforeInvocation
public static void before(@NonNull BeforeHookCallback callback) {
callback.getArgs()[0] = -1;
}
}
@XposedHooker
private static class ScreenCaptureHooker implements Hooker {
@BeforeInvocation
public static void before(@NonNull BeforeHookCallback callback) {
var captureArgs = callback.getArgs()[0];
try {
captureSecureLayersField.set(captureArgs, true);
} catch (IllegalAccessException t) {
module.log("ScreenCaptureHooker failed", t);
}
}
}
@XposedHooker
private static class CreateVirtualDisplayLockedHooker implements Hooker {
@BeforeInvocation
public static void before(@NonNull BeforeHookCallback callback) {
var caller = (int) callback.getArgs()[2];
if (caller >= 10000 && callback.getArgs()[1] == null) {
// not os and not media projection
return;
}
for (int i = 3; i < callback.getArgs().length; i++) {
var arg = callback.getArgs()[i];
if (arg instanceof Integer) {
var flags = (int) arg;
flags |= DisplayManager.VIRTUAL_DISPLAY_FLAG_SECURE;
callback.getArgs()[i] = flags;
return;
}
}
module.log("flag not found in CreateVirtualDisplayLockedHooker");
}
}
@XposedHooker
private static class SecureLockedHooker implements Hooker {
@BeforeInvocation
public static void before(@NonNull BeforeHookCallback callback) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
var walker = StackWalker.getInstance();
var match = walker.walk(frames -> frames
.map(StackWalker.StackFrame::getMethodName)
.limit(6)
.skip(2)
.anyMatch(s -> s.equals("setInitialSurfaceControlProperties") || s.equals("createSurfaceLocked")));
if (match) return;
} else {
var stackTrace = new Throwable().getStackTrace();
for (int i = 4; i < stackTrace.length && i < 8; i++) {
var name = stackTrace[i].getMethodName();
if (name.equals("setInitialSurfaceControlProperties") ||
name.equals("createSurfaceLocked")) {
return;
}
}
}
callback.returnAndSkip(false);
}
}
@XposedHooker
private static class ReturnTrueHooker implements Hooker {
@BeforeInvocation
public static void before(@NonNull BeforeHookCallback callback) {
callback.returnAndSkip(true);
}
}
@XposedHooker
private static class ReturnFalseHooker implements Hooker {
@BeforeInvocation
public static void before(@NonNull BeforeHookCallback callback) {
callback.returnAndSkip(false);
}
}
@XposedHooker
private static class ReturnNullHooker implements Hooker {
@BeforeInvocation
public static void before(@NonNull BeforeHookCallback callback) {
callback.returnAndSkip(null);
}
}
@XposedHooker
private static class ToastHooker implements Hooker {
@BeforeInvocation
public static void before(@NonNull BeforeHookCallback callback) {
var activity = (Activity) callback.getThisObject();
new AlertDialog.Builder(activity)
.setTitle("Enable Screenshot")
.setMessage("Incorrect module usage, remove this app from scope.")
.setCancelable(false)
.setPositiveButton("OK", (dialog, which) -> System.exit(0))
.show();
}
}
}

View File

@ -1,3 +1,3 @@
<resources>
<string name="xposed_description">Disable FLAG_SECURE on all windows, enabling screenshots in apps that normally wouldn\'t allow it and disabling screenshot detection.</string>
<string name="xposed_description">Enabling screenshots in apps that normally wouldn\'t allow it and disabling screenshot detection.</string>
</resources>

View File

@ -0,0 +1,3 @@
<resources>
<string name="xposed_description">Enabling screenshots in apps that normally wouldn\'t allow it and disabling screenshot &amp; screen record detection.</string>
</resources>

View File

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="xposed_description">对所有 Window 禁用 FLAG_SECURE在通常不允许截图的应用中启用屏幕截图并禁用截图检测。</string>
<string name="xposed_description">在通常不允许截图的应用中启用屏幕截图并禁用截图检测。</string>
</resources>

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="xposed_description">在通常不允许截图的应用中启用屏幕截图并禁用截图与录屏检测。</string>
</resources>

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">禁用 FLAG_SECURE</string>
<string name="xposed_description">对所有 Window 禁用 FLAG_SECURE在通常不允许截图的应用中启用屏幕截图。</string>
<string name="app_name">启用截图</string>
<string name="xposed_description">在通常不允许截图的应用中启用屏幕截图。</string>
</resources>

View File

@ -1,9 +1,4 @@
<resources>
<string name="app_name">Disable FLAG_SECURE</string>
<string name="xposed_description">Disable FLAG_SECURE on all windows, enabling screenshots in apps that normally wouldn\'t allow it.</string>
<string-array name="scope">
<item>android</item>
<item>com.flyme.systemuiex</item>
<item>com.oplus.screenshot</item>
</string-array>
<string name="app_name">Enable Screenshot</string>
<string name="xposed_description">Enabling screenshots in apps that normally wouldn\'t allow it.</string>
</resources>

View File

@ -0,0 +1,3 @@
minApiVersion=100
targetApiVersion=100
staticScope=true

View File

@ -0,0 +1,6 @@
system
com.android.systemui
com.flyme.systemuiex
com.miui.screenshot
com.oplus.appplatform
com.oplus.screenshot

View File

@ -1,25 +1,11 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
google()
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:8.2.0'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
plugins {
id 'com.android.application' version '8.9.1' apply false
id 'org.lsposed.lsplugin.jgit' version "1.1"
}
allprojects {
repositories {
google()
mavenCentral()
maven { url = "https://api.xposed.info" }
}
tasks.register('clean', Delete) {
delete rootProject.layout.buildDirectory
}
task clean(type: Delete) {
delete rootProject.buildDir
}
var repo = jgit.repo(true)
ext.commitCount = repo.commitCount('refs/remotes/origin/main')

Binary file not shown.

View File

@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME

8
gradlew vendored Executable file → Normal file
View File

@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
# SPDX-License-Identifier: Apache-2.0
#
##############################################################################
#
@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@ -84,7 +86,7 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@ -203,7 +205,7 @@ fi
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.

22
gradlew.bat vendored
View File

@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@rem SPDX-License-Identifier: Apache-2.0
@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@ -43,11 +45,11 @@ set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if %ERRORLEVEL% equ 0 goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
echo. 1>&2
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
@ -57,11 +59,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
echo. 1>&2
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail

1
libxposed-compat/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/build

View File

@ -0,0 +1,18 @@
plugins {
id 'com.android.library'
}
android {
namespace 'io.github.libxposed'
compileSdk 35
defaultConfig {
minSdk 24
targetSdk 35
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_21
targetCompatibility JavaVersion.VERSION_21
}
}

View File

@ -0,0 +1,3 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest>
</manifest>

View File

@ -0,0 +1,11 @@
package io.github.libxposed.api.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface AfterInvocation {
}

View File

@ -0,0 +1,11 @@
package io.github.libxposed.api.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface BeforeInvocation {
}

View File

@ -0,0 +1,11 @@
package io.github.libxposed.api.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.TYPE_USE})
public @interface XposedHooker {
}

View File

@ -1,2 +1,22 @@
rootProject.name = "Disable FLAG_SECURE"
pluginManagement {
repositories {
gradlePluginPortal()
google()
mavenCentral()
}
}
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
mavenLocal {
content {
includeGroup("io.github.libxposed")
}
}
}
}
rootProject.name = "DisableFlagSecure"
include ':app'
include ':libxposed-compat'