Compare commits

..

No commits in common. "main" and "v1.0.1" have entirely different histories.
main ... v1.0.1

35 changed files with 306 additions and 1176 deletions

View File

@ -1,59 +0,0 @@
name: Bug report
description: Report errors or unexpected behavior.
labels: [bug]
body:
- type: markdown
attributes:
value: |
To make it easier for us to help you please enter detailed information below.
- type: input
attributes:
label: LSPosed version
description: Only official LSPosed is supported. Don't use 'latest'. Specify actual version with 4 digits.
validations:
required: true
- type: input
attributes:
label: Android version
validations:
required: true
- type: input
attributes:
label: Custom OS version
validations:
required: true
- type: checkboxes
id: latest
attributes:
label: Version requirement
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
description: Please provide the log zip saved from manager.
placeholder: Upload logs zip by clicking the bar on the bottom.
validations:
required: true
- type: textarea
attributes:
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

View File

@ -1 +0,0 @@
blank_issues_enabled: false

View File

@ -1,24 +0,0 @@
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

@ -1,62 +0,0 @@
name: Android CI
on:
push:
pull_request:
workflow_dispatch:
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
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
- name: Write key
if: github.event_name != 'pull_request' && github.ref == 'refs/heads/main'
run: |
if [ ! -z "${{ secrets.SIGNING_KEY }}" ]; then
echo storePassword='${{ secrets.KEY_STORE_PASSWORD }}' >> local.properties
echo keyAlias='${{ secrets.ALIAS }}' >> local.properties
echo keyPassword='${{ secrets.KEY_PASSWORD }}' >> local.properties
echo storeFile='key.jks' >> local.properties
echo ${{ secrets.SIGNING_KEY }} | base64 --decode > key.jks
fi
- name: Build with Gradle
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@v4
with:
name: Signed app bundle
path: app/build/outputs/apk

View File

@ -1,15 +1,2 @@
# Enable Screenshot (formerly known as Disable FLAG_SECURE) # DisableFlagSecure
Enabling screenshots in apps that normally wouldn\'t allow it, and disabling screenshot(Android 14+) & screen record(Android 15+) detection. Disable FLAG_SECURE on all windows, enabling screenshots in apps that normally wouldn\'t allow it.
**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

View File

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

View File

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

View File

@ -3,66 +3,32 @@ plugins {
} }
android { android {
compileSdk 36 compileSdkVersion 30
buildToolsVersion "36.0.0" buildToolsVersion "30.0.3"
defaultConfig { defaultConfig {
applicationId "io.github.lsposed.disableflagsecure" applicationId "io.github.lsposed.disableflagsecure"
minSdkVersion 31 minSdkVersion 21
targetSdkVersion 36 targetSdkVersion 30
versionCode rootProject.ext.commitCount versionCode 2
versionName "4.2.0" versionName "1.0.1"
}
Properties localProperties = new Properties()
if (project.rootProject.file('local.properties').exists()) {
localProperties.load(project.rootProject.file('local.properties').newDataInputStream())
}
signingConfigs {
if (localProperties.getProperty("storeFile") != null) {
config {
storeFile project.rootProject.file(localProperties.getProperty("storeFile"))
storePassword localProperties.getProperty("storePassword")
keyAlias localProperties.getProperty("keyAlias")
keyPassword localProperties.getProperty("keyPassword")
}
}
} }
buildTypes { buildTypes {
debug {
if (localProperties.getProperty("storeFile") != null) {
signingConfig signingConfigs.config
}
}
release { release {
if (localProperties.getProperty("storeFile") != null) { minifyEnabled false
signingConfig signingConfigs.config proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
} else {
signingConfig signingConfigs.debug
}
vcsInfo.include false
minifyEnabled true
proguardFiles 'proguard-rules.pro'
} }
} }
compileOptions { compileOptions {
sourceCompatibility JavaVersion.VERSION_21 sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_21 targetCompatibility JavaVersion.VERSION_1_8
}
lint {
checkReleaseBuilds false
} }
dependenciesInfo.includeInApk false dependenciesInfo.includeInApk false
namespace 'io.github.lsposed.disableflagsecure'
} }
dependencies { dependencies {
compileOnly 'androidx.annotation:annotation:1.9.1' compileOnly 'de.robv.android.xposed:api:82'
compileOnly 'io.github.libxposed:api:100'
compileOnly project(":libxposed-compat")
} }

View File

@ -1,21 +1,21 @@
-adaptresourcefilecontents META-INF/xposed/java_init.list # Add project specific ProGuard rules here.
-keepattributes RuntimeVisibleAnnotations # You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
-keep,allowobfuscation,allowoptimization public class * extends io.github.libxposed.api.XposedModule { # If your project uses WebView with JS, uncomment the following
public <init>(...); # and specify the fully qualified class name to the JavaScript interface
public void onPackageLoaded(...); # class:
public void onSystemServerLoaded(...); #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
} # public *;
-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 # Uncomment this to preserve the line number information for
-allowaccessmodification # debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

View File

@ -1,16 +0,0 @@
<?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

@ -1,63 +0,0 @@
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

@ -1,12 +1,25 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"> xmlns:tools="http://schemas.android.com/tools"
package="io.github.lsposed.disableflagsecure">
<application <application
android:allowBackup="true" android:allowBackup="true"
android:label="@string/app_name" android:label="@string/app_name"
android:description="@string/xposed_description"
android:supportsRtl="true" android:supportsRtl="true"
tools:ignore="AllowBackup,MissingApplicationIcon" /> 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>
</manifest> </manifest>

View File

@ -1,470 +1,38 @@
package io.github.lsposed.disableflagsecure; 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.os.Build;
import android.view.SurfaceControl;
import androidx.annotation.NonNull; import de.robv.android.xposed.IXposedHookLoadPackage;
import androidx.annotation.RequiresApi; 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 java.lang.reflect.Field; public class DisableFlagSecure implements IXposedHookLoadPackage {
import java.util.Arrays;
import java.util.function.BiConsumer;
import java.util.function.BiPredicate;
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;
@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";
private static XposedModule module;
public DisableFlagSecure(XposedInterface base, ModuleLoadedParam param) {
super(base, param);
module = this;
}
@Override @Override
public void onSystemServerLoaded(@NonNull SystemServerLoadedParam param) { public void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam) {
var classLoader = param.getClassLoader(); if (loadPackageParam.packageName.equals("android")) {
try { try {
deoptimizeSystemServer(classLoader); Class<?> windowsState = XposedHelpers.findClass("com.android.server.wm.WindowState", loadPackageParam.classLoader);
} catch (Throwable t) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
log("deoptimize system server failed", t); XposedHelpers.findAndHookMethod(
} windowsState,
"isSecureLocked",
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM) { XC_MethodReplacement.returnConstant(false));
// Screen record detection (V~Baklava)
try {
hookWindowManagerService(classLoader);
} catch (Throwable t) {
log("hook WindowManagerService failed", t);
}
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
// Screenshot detection (U~Baklava)
try {
hookActivityTaskManagerService(classLoader);
} catch (Throwable t) {
log("hook ActivityTaskManagerService failed", t);
}
// Xiaomi HyperOS (U~Baklava)
// OS2.0.250220.1.WOCCNXM.PRE
try {
hookHyperOS(classLoader);
} catch (ClassNotFoundException ignored) {
} catch (Throwable t) {
log("hook HyperOS failed", t);
}
}
// 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 {
hookActivityManagerService(classLoader);
} catch (Throwable t) {
log("hook ActivityManagerService failed", 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);
}
}
}
@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 { } else {
var stackTrace = new Throwable().getStackTrace(); XposedHelpers.findAndHookMethod(
for (int i = 4; i < stackTrace.length && i < 8; i++) { "com.android.server.wm.WindowManagerService",
var name = stackTrace[i].getMethodName(); loadPackageParam.classLoader,
if (name.equals("setInitialSurfaceControlProperties") || "isSecureLocked",
name.equals("createSurfaceLocked")) { windowsState,
return; XC_MethodReplacement.returnConstant(false));
} }
} catch (Throwable t) {
XposedBridge.log(t);
} }
} }
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 +0,0 @@
<resources>
<string name="xposed_description">Enabling screenshots in apps that normally wouldn\'t allow it and disabling screenshot detection.</string>
</resources>

View File

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

View File

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

View File

@ -1,4 +1,7 @@
<resources> <resources>
<string name="app_name">Enable Screenshot</string> <string name="app_name">Disable FLAG_SECURE</string>
<string name="xposed_description">Enabling screenshots in apps that normally wouldn\'t allow it.</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>
</string-array>
</resources> </resources>

View File

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

View File

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

View File

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

View File

@ -6,7 +6,7 @@
# http://www.gradle.org/docs/current/userguide/build_environment.html # http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process. # Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings. # The setting is particularly useful for tweaking memory settings.
# org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
# When configured, Gradle will run in incubating parallel mode. # When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit # This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
@ -15,10 +15,5 @@
# Android operating system, and which are packaged with your app"s APK # Android operating system, and which are packaged with your app"s APK
# https://developer.android.com/topic/libraries/support-library/androidx-rn # https://developer.android.com/topic/libraries/support-library/androidx-rn
android.useAndroidX=true android.useAndroidX=true
android.nonTransitiveRClass=true # Automatically convert third-party libraries to use AndroidX
android.enableAppCompileTimeRClass=true android.enableJetifier=true
android.enableR8.fullMode=true
android.experimental.enableNewResourceShrinker=true
android.experimental.enableNewResourceShrinker.preciseShrinking=true
android.defaults.buildfeatures.buildconfig=false
android.nonFinalResIds=false

Binary file not shown.

View File

@ -1,7 +1,6 @@
#Wed Feb 03 16:00:02 CST 2021
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionUrl=https\://services.gradle.org/distributions/gradle-6.8-bin.zip
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME

309
gradlew vendored
View File

@ -1,129 +1,78 @@
#!/bin/sh #!/usr/bin/env sh
#
# Copyright © 2015-2021 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# SPDX-License-Identifier: Apache-2.0
#
############################################################################## ##############################################################################
# ##
# Gradle start up script for POSIX generated by Gradle. ## Gradle start up script for UN*X
# ##
# Important for running:
#
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
# noncompliant, but you have some other compliant shell such as ksh or
# bash, then to run this script, type that shell name before the whole
# command line, like:
#
# ksh Gradle
#
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
# * functions;
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
# * compound commands having a testable exit status, especially «case»;
# * various built-in commands including «command», «set», and «ulimit».
#
# Important for patching:
#
# (2) This script targets any POSIX shell, so it avoids extensions provided
# by Bash, Ksh, etc; in particular arrays are avoided.
#
# The "traditional" practice of packing multiple parameters into a
# space-separated string is a well documented source of bugs and security
# problems, so this is (mostly) avoided, by progressively accumulating
# options in "$@", and eventually passing that to Java.
#
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
# see the in-line comments for details.
#
# There are tweaks for specific operating systems such as AIX, CygWin,
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# 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/.
#
############################################################################## ##############################################################################
# Attempt to set APP_HOME # Attempt to set APP_HOME
# Resolve links: $0 may be a link # Resolve links: $0 may be a link
app_path=$0 PRG="$0"
# Need this for relative symlinks.
# Need this for daisy-chained symlinks. while [ -h "$PRG" ] ; do
while ls=`ls -ld "$PRG"`
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path link=`expr "$ls" : '.*-> \(.*\)$'`
[ -h "$app_path" ] if expr "$link" : '/.*' > /dev/null; then
do PRG="$link"
ls=$( ls -ld "$app_path" ) else
link=${ls#*' -> '} PRG=`dirname "$PRG"`"/$link"
case $link in #( fi
/*) app_path=$link ;; #(
*) app_path=$APP_HOME$link ;;
esac
done done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
# This is normally unused APP_NAME="Gradle"
# shellcheck disable=SC2034 APP_BASE_NAME=`basename "$0"`
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit DEFAULT_JVM_OPTS=""
# Use the maximum available, or set MAX_FD != -1 to use that value. # Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum MAX_FD="maximum"
warn () { warn () {
echo "$*" echo "$*"
} >&2 }
die () { die () {
echo echo
echo "$*" echo "$*"
echo echo
exit 1 exit 1
} >&2 }
# OS specific support (must be 'true' or 'false'). # OS specific support (must be 'true' or 'false').
cygwin=false cygwin=false
msys=false msys=false
darwin=false darwin=false
nonstop=false nonstop=false
case "$( uname )" in #( case "`uname`" in
CYGWIN* ) cygwin=true ;; #( CYGWIN* )
Darwin* ) darwin=true ;; #( cygwin=true
MSYS* | MINGW* ) msys=true ;; #( ;;
NONSTOP* ) nonstop=true ;; Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM. # Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables # IBM's JDK on AIX uses strange locations for the executables
JAVACMD=$JAVA_HOME/jre/sh/java JAVACMD="$JAVA_HOME/jre/sh/java"
else else
JAVACMD=$JAVA_HOME/bin/java JAVACMD="$JAVA_HOME/bin/java"
fi fi
if [ ! -x "$JAVACMD" ] ; then if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
@ -132,120 +81,92 @@ Please set the JAVA_HOME variable in your environment to match the
location of your Java installation." location of your Java installation."
fi fi
else else
JAVACMD=java JAVACMD="java"
if ! command -v java >/dev/null 2>&1 which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
then
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the Please set the JAVA_HOME variable in your environment to match the
location of your Java installation." location of your Java installation."
fi
fi fi
# Increase the maximum file descriptors if we can. # Increase the maximum file descriptors if we can.
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
case $MAX_FD in #( MAX_FD_LIMIT=`ulimit -H -n`
max*) if [ $? -eq 0 ] ; then
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
# shellcheck disable=SC2039,SC3045 MAX_FD="$MAX_FD_LIMIT"
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC2039,SC3045
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
fi
# Collect all arguments for the java command, stacking in reverse order:
# * args from the command line
# * the main class name
# * -classpath
# * -D...appname settings
# * --module-path (only if needed)
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
# Now convert the arguments - kludge to limit ourselves to /bin/sh
for arg do
if
case $arg in #(
-*) false ;; # don't mess with options #(
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
[ -e "$t" ] ;; #(
*) false ;;
esac
then
arg=$( cygpath --path --ignore --mixed "$arg" )
fi fi
# Roll the args list around exactly as many times as the number of ulimit -n $MAX_FD
# args, so each arg winds up back in the position where it started, but if [ $? -ne 0 ] ; then
# possibly modified. warn "Could not set maximum file descriptor limit: $MAX_FD"
# fi
# NB: a `for` loop captures its iteration list before it begins, so else
# changing the positional parameters here affects neither the number of warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
# iterations, nor the values presented in `arg`. fi
shift # remove old arg fi
set -- "$@" "$arg" # push replacement arg
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi fi
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=$(save "$@")
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. # Collect all arguments for the java command, following the shell quoting and substitution rules
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# Collect all arguments for the java command: # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
# and any embedded shellness will be escaped. cd "$(dirname "$0")"
# * 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.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
org.gradle.wrapper.GradleWrapperMain \
"$@"
# Stop when "xargs" is not available.
if ! command -v xargs >/dev/null 2>&1
then
die "xargs is not available"
fi fi
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
#
# In Bash we could simply go:
#
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
# set -- "${ARGS[@]}" "$@"
#
# but POSIX shell has neither arrays nor command substitution, so instead we
# post-process each arg (as a line of input to sed) to backslash-escape any
# character that might be a shell metacharacter, then use eval to reverse
# that process (while maintaining the separation between arguments), and wrap
# the whole thing up as a single "set" statement.
#
# This will of course break if any of these variables contains a newline or
# an unmatched quote.
#
eval "set -- $(
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
xargs -n1 |
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
tr '\n' ' '
)" '"$@"'
exec "$JAVACMD" "$@" exec "$JAVACMD" "$@"

78
gradlew.bat vendored
View File

@ -1,22 +1,4 @@
@rem @if "%DEBUG%" == "" @echo off
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@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 ########################################################################## @rem ##########################################################################
@rem @rem
@rem Gradle startup script for Windows @rem Gradle startup script for Windows
@ -27,29 +9,25 @@
if "%OS%"=="Windows_NT" setlocal if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0 set DIRNAME=%~dp0
if "%DIRNAME%"=="" set DIRNAME=. if "%DIRNAME%" == "" set DIRNAME=.
@rem This is normally unused
set APP_BASE_NAME=%~n0 set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME% set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" set DEFAULT_JVM_OPTS=
@rem Find java.exe @rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1 %JAVA_EXE% -version >NUL 2>&1
if %ERRORLEVEL% equ 0 goto execute if "%ERRORLEVEL%" == "0" goto init
echo. 1>&2 echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo. 1>&2 echo.
echo Please set the JAVA_HOME variable in your environment to match the 1>&2 echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation. 1>&2 echo location of your Java installation.
goto fail goto fail
@ -57,36 +35,48 @@ goto fail
set JAVA_HOME=%JAVA_HOME:"=% set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute if exist "%JAVA_EXE%" goto init
echo. 1>&2 echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo. 1>&2 echo.
echo Please set the JAVA_HOME variable in your environment to match the 1>&2 echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation. 1>&2 echo location of your Java installation.
goto fail goto fail
:init
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
:execute :execute
@rem Setup the command line @rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle @rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end :end
@rem End local scope for the variables with windows NT shell @rem End local scope for the variables with windows NT shell
if %ERRORLEVEL% equ 0 goto mainEnd if "%ERRORLEVEL%"=="0" goto mainEnd
:fail :fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code! rem the _cmd.exe /c_ return code!
set EXIT_CODE=%ERRORLEVEL% if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
if %EXIT_CODE% equ 0 set EXIT_CODE=1 exit /b 1
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
exit /b %EXIT_CODE%
:mainEnd :mainEnd
if "%OS%"=="Windows_NT" endlocal if "%OS%"=="Windows_NT" endlocal

View File

@ -1 +0,0 @@
/build

View File

@ -1,18 +0,0 @@
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

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

View File

@ -1,11 +0,0 @@
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

@ -1,11 +0,0 @@
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

@ -1,11 +0,0 @@
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,22 +1,2 @@
pluginManagement { rootProject.name = "Disable FLAG_SECURE"
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 ':app'
include ':libxposed-compat'