├── .gitignore ├── LICENSE ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── main │ ├── AndroidManifest.xml │ ├── assets │ │ └── xposed_init │ ├── java │ │ └── me │ │ │ └── neversleep │ │ │ └── plusplus │ │ │ ├── HookImpl.java │ │ │ ├── MainActivity.java │ │ │ ├── PowerMangerService.java │ │ │ ├── QuickStartService.java │ │ │ ├── ShellUtil.java │ │ │ ├── XMain.java │ │ │ └── XUtils.java │ └── res │ │ ├── drawable-v24 │ │ └── ic_launcher_foreground.xml │ │ ├── drawable │ │ ├── baseline_help_outline_16.xml │ │ ├── baseline_help_outline_24.xml │ │ ├── baseline_help_outline_8.xml │ │ ├── baseline_question_mark_16.xml │ │ ├── baseline_question_mark_24.xml │ │ ├── ic_launcher_background.xml │ │ ├── ic_power_new_24.xml │ │ └── unchecked_background.xml │ │ ├── layout │ │ └── activity_main.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── values-zh-rCN │ │ └── strings.xml │ │ ├── values │ │ ├── arrays.xml │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── themes.xml │ │ └── xml │ │ ├── backup_rules.xml │ │ └── data_extraction_rules.xml │ └── test │ └── java │ └── me │ └── neversleep │ └── plusplus │ ├── A.java │ └── ExampleUnitTest.kt ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea 5 | .DS_Store 6 | /build 7 | /captures 8 | .externalNativeBuild 9 | .cxx 10 | local.properties 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Humenger 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | /release -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | import java.text.SimpleDateFormat 2 | 3 | plugins { 4 | id 'com.android.application' 5 | id 'org.jetbrains.kotlin.android' 6 | } 7 | 8 | android { 9 | namespace 'me.neversleep.plusplus' 10 | compileSdk 34 11 | 12 | defaultConfig { 13 | applicationId "me.neversleep.plusplus" 14 | minSdk 21 15 | targetSdk 34 16 | versionCode 17 17 | versionName "1.7.2" 18 | 19 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 20 | vectorDrawables { 21 | useSupportLibrary true 22 | } 23 | } 24 | 25 | applicationVariants.all { variant -> 26 | variant.outputs.all { output -> 27 | if (variant.buildType.name == 'release') { 28 | def timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()) 29 | def fileName = "${defaultConfig.versionName}_${timeStamp}_release.apk" 30 | outputFileName = fileName 31 | } 32 | } 33 | } 34 | 35 | buildTypes { 36 | release { 37 | minifyEnabled false 38 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 39 | } 40 | } 41 | compileOptions { 42 | sourceCompatibility JavaVersion.VERSION_1_8 43 | targetCompatibility JavaVersion.VERSION_1_8 44 | } 45 | kotlinOptions { 46 | jvmTarget = '1.8' 47 | } 48 | buildFeatures { 49 | buildConfig = true 50 | } 51 | composeOptions { 52 | kotlinCompilerExtensionVersion '1.4.3' 53 | } 54 | packaging { 55 | resources { 56 | excludes += '/META-INF/{AL2.0,LGPL2.1}' 57 | } 58 | } 59 | } 60 | 61 | dependencies { 62 | 63 | testImplementation 'junit:junit:4.13.2' 64 | compileOnly "de.robv.android.xposed:api:82" 65 | implementation 'androidx.appcompat:appcompat:1.6.1' 66 | implementation 'androidx.constraintlayout:constraintlayout:1.1.3' 67 | implementation 'com.google.android.material:material:1.5.0' 68 | } -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 15 | 18 | 19 | 20 | 21 | 22 | 23 | 29 | 30 | 31 | 32 | 35 | 36 | 37 | 38 | 41 | 44 | 47 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /app/src/main/assets/xposed_init: -------------------------------------------------------------------------------- 1 | me.neversleep.plusplus.XMain 2 | -------------------------------------------------------------------------------- /app/src/main/java/me/neversleep/plusplus/HookImpl.java: -------------------------------------------------------------------------------- 1 | package me.neversleep.plusplus; 2 | 3 | import android.os.Build; 4 | import android.os.IBinder; 5 | import android.util.Log; 6 | 7 | import de.robv.android.xposed.XC_MethodHook; 8 | import de.robv.android.xposed.XC_MethodReplacement; 9 | import de.robv.android.xposed.XSharedPreferences; 10 | import de.robv.android.xposed.XposedBridge; 11 | import de.robv.android.xposed.XposedHelpers; 12 | 13 | public class HookImpl { 14 | public static final String TAG = "neversleep"; 15 | 16 | public static void main(final ClassLoader classLoader) { 17 | try { 18 | final XSharedPreferences xSharedPreferences = new XSharedPreferences(BuildConfig.APPLICATION_ID, "x_conf"); 19 | xSharedPreferences.makeWorldReadable(); 20 | xSharedPreferences.reload(); 21 | XposedBridge.hookAllMethods(XposedHelpers.findClass("com.android.server.policy.PhoneWindowManager", classLoader), "powerPress", new XC_MethodHook() { // from class: me.neversleep.plusplus.HookImpl.1 22 | int mode = 0; 23 | 24 | protected void beforeHookedMethod(XC_MethodHook.MethodHookParam methodHookParam) throws Throwable { 25 | super.beforeHookedMethod(methodHookParam); 26 | try { 27 | XUtils.xLog("neversleep", "beforeHookedMethod: start"); 28 | xSharedPreferences.reload(); 29 | int i = 0; 30 | if (!xSharedPreferences.getBoolean("power", false)) { 31 | Log.e("neversleep", "beforeHookedMethod: power is false"); 32 | return; 33 | } 34 | XUtils.xLog("neversleep", "beforeHookedMethod: power is true"); 35 | Class cls = Class.forName("android.view.SurfaceControl", false, classLoader); 36 | IBinder iBinder = getDisplayBinder(classLoader); 37 | if (iBinder != null) { 38 | XposedHelpers.callStaticMethod(cls, "setDisplayPowerMode", iBinder, this.mode); 39 | if (this.mode == 0) { 40 | i = 2; 41 | } 42 | this.mode = i; 43 | } 44 | methodHookParam.setResult(null); 45 | XUtils.xLog("neversleep", "replace success"); 46 | } catch (Throwable th) { 47 | XUtils.xLog("neversleep", "beforeHookedMethod: error:", th); 48 | } 49 | } 50 | }); 51 | XUtils.xLog("neversleep", "main: Hook success"); 52 | } catch (Throwable th) { 53 | th.printStackTrace(); 54 | XUtils.xLog("neversleep", "main: error:" + th.getMessage(), th); 55 | } 56 | } 57 | 58 | static IBinder getDisplayBinder(ClassLoader classLoader){ 59 | try { 60 | Class clsSurfaceControl = XposedHelpers.findClass("android.view.SurfaceControl", classLoader); 61 | if(Build.VERSION.SDK_INT clsDisplayControl = XposedHelpers.findClass("com.android.server.display.DisplayControl", classLoader); 67 | long[] ids= (long[]) XposedHelpers.callStaticMethod(clsDisplayControl,"getPhysicalDisplayIds"); 68 | if(ids==null||ids.length==0){ 69 | return null; 70 | } 71 | return (IBinder) XposedHelpers.callStaticMethod(clsDisplayControl,"getPhysicalDisplayToken",ids[0]); 72 | } 73 | 74 | }catch (Throwable t){ 75 | XUtils.xLog(TAG,"getDisplayBinder",t); 76 | } 77 | return null; 78 | } 79 | 80 | } 81 | -------------------------------------------------------------------------------- /app/src/main/java/me/neversleep/plusplus/MainActivity.java: -------------------------------------------------------------------------------- 1 | package me.neversleep.plusplus; 2 | 3 | import android.annotation.SuppressLint; 4 | import android.app.AlertDialog; 5 | import android.content.ClipData; 6 | import android.content.ClipboardManager; 7 | import android.content.ComponentName; 8 | import android.content.Context; 9 | import android.content.Intent; 10 | import android.content.SharedPreferences; 11 | import android.net.Uri; 12 | import android.os.Build; 13 | import android.os.Bundle; 14 | import android.service.quicksettings.TileService; 15 | import android.view.View; 16 | import android.widget.CheckBox; 17 | import android.widget.TextView; 18 | import android.widget.Toast; 19 | 20 | import androidx.appcompat.app.AppCompatActivity; 21 | import androidx.appcompat.widget.SwitchCompat; 22 | import androidx.core.internal.view.SupportMenu; 23 | import androidx.core.view.InputDeviceCompat; 24 | 25 | public class MainActivity extends AppCompatActivity { 26 | private SharedPreferences xConf; 27 | 28 | public static int getActiveVersion() { 29 | return 0; 30 | } 31 | 32 | public void onCreate(Bundle bundle) { 33 | super.onCreate(bundle); 34 | setContentView(R.layout.activity_main); 35 | main(); 36 | } 37 | 38 | private void checkEdXposed() { 39 | try { 40 | this.xConf = getSharedPreferences("x_conf", MODE_WORLD_READABLE); 41 | } catch (SecurityException unused) { 42 | new AlertDialog.Builder(this).setMessage(getString(R.string.not_supported)).setPositiveButton(android.R.string.ok, (dialogInterface, i) -> finish()).setNegativeButton(R.string.ignore, null).show(); 43 | } 44 | } 45 | 46 | public void onRequestPermissionsResult(int i, String[] strArr, int[] iArr) { 47 | super.onRequestPermissionsResult(i, strArr, iArr); 48 | if (i != 10002 || iArr.length <= 0) { 49 | return; 50 | } 51 | if (iArr[0] == 0) { 52 | main(); 53 | } else { 54 | Toast.makeText(this, getString(R.string.auth_failed), Toast.LENGTH_LONG).show(); 55 | } 56 | } 57 | 58 | public void onResume() { 59 | super.onResume(); 60 | main(); 61 | } 62 | 63 | @SuppressLint("RestrictedApi") 64 | protected void main() { 65 | TextView textView = findViewById(R.id.tips); 66 | TextView textView2 = findViewById(R.id.shell_control); 67 | TextView info = findViewById(R.id.info); 68 | CheckBox disableSleep = findViewById(R.id.disable_sleep); 69 | SwitchCompat switchCompat = findViewById(R.id.power); 70 | info.setOnClickListener(view -> { 71 | Uri uri = Uri.parse("https://github.com/jitcor"); 72 | Intent intent = new Intent(Intent.ACTION_VIEW, uri); 73 | startActivity(intent); 74 | }); 75 | if (xConf != null) { 76 | disableSleep.setChecked(xConf.getBoolean("disable_sleep", false)); 77 | } 78 | disableSleep.setOnCheckedChangeListener((buttonView, isChecked) -> { 79 | if (xConf != null) { 80 | boolean old = xConf.getBoolean("disable_sleep", false); 81 | if (old != isChecked) { 82 | if (!xConf.edit().putBoolean("disable_sleep", isChecked).commit()) { 83 | Toast.makeText(MainActivity.this, R.string.disable_sleep_error_tips, Toast.LENGTH_SHORT).show(); 84 | } 85 | } 86 | } else { 87 | Toast.makeText(this, "error: xConf is null!", Toast.LENGTH_SHORT).show(); 88 | } 89 | }); 90 | info.setText(String.format("v%s | jitcor", BuildConfig.VERSION_NAME)); 91 | String command = "am start -n me.neversleep.plusplus/.MainActivity --ez power true/false"; 92 | textView2.setText(String.format(getString(R.string.shell_control), command)); 93 | textView2.setOnLongClickListener(view -> { 94 | ClipboardManager clipboardManager = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE); 95 | if (clipboardManager != null) { 96 | clipboardManager.setPrimaryClip(ClipData.newPlainText(null, command)); 97 | Toast.makeText(MainActivity.this, getString(R.string.copy_success), Toast.LENGTH_LONG).show(); 98 | return true; 99 | } 100 | Toast.makeText(MainActivity.this, getString(R.string.copy_failed), Toast.LENGTH_LONG).show(); 101 | return false; 102 | 103 | }); 104 | if (getActiveVersion() == 0) { 105 | textView.setVisibility(View.VISIBLE); 106 | textView.setText(R.string.active_tips); 107 | textView.setTextColor(SupportMenu.CATEGORY_MASK); 108 | } else if (BuildConfig.VERSION_CODE == getActiveVersion()) { 109 | textView.setVisibility(View.INVISIBLE); 110 | } else { 111 | textView.setVisibility(View.VISIBLE); 112 | textView.setText(String.format(getString(R.string.active_warn), getActiveVersion(), BuildConfig.VERSION_CODE)); 113 | textView.setTextColor(InputDeviceCompat.SOURCE_ANY); 114 | } 115 | switchCompat.setOnCheckedChangeListener((compoundButton, z) -> { 116 | SharedPreferences sharedPreferences = MainActivity.this.xConf; 117 | if (sharedPreferences != null) { 118 | if (!sharedPreferences.edit().putBoolean("power", z).commit()) { 119 | Toast.makeText(MainActivity.this, getString(R.string.failed_tips), Toast.LENGTH_LONG).show(); 120 | } 121 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { 122 | TileService.requestListeningState(MainActivity.this, new ComponentName(BuildConfig.APPLICATION_ID, QuickStartService.class.getName())); 123 | } 124 | } 125 | 126 | }); 127 | checkEdXposed(); 128 | if (this.xConf == null) { 129 | Toast.makeText(this, "error: xConf is null!", Toast.LENGTH_LONG).show(); 130 | } else if (getIntent().hasExtra("power")) { 131 | if (!this.xConf.edit().putBoolean("power", getIntent().getBooleanExtra("power", false)).commit()) { 132 | Toast.makeText(this, "error: change power failed", Toast.LENGTH_LONG).show(); 133 | } else { 134 | Toast.makeText(this, "success", Toast.LENGTH_LONG).show(); 135 | } 136 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { 137 | TileService.requestListeningState(this, new ComponentName(BuildConfig.APPLICATION_ID, QuickStartService.class.getName())); 138 | } 139 | finish(); 140 | } else { 141 | switchCompat.setChecked(this.xConf.getBoolean("power", false)); 142 | } 143 | 144 | } 145 | 146 | 147 | } 148 | -------------------------------------------------------------------------------- /app/src/main/java/me/neversleep/plusplus/PowerMangerService.java: -------------------------------------------------------------------------------- 1 | package me.neversleep.plusplus; 2 | 3 | public class PowerMangerService { 4 | public static final String TAG = PowerMangerService.class.getSimpleName(); 5 | 6 | // Dirty bit: mWakeLocks changed 7 | public static final int DIRTY_WAKE_LOCKS = 1 << 0; 8 | // Dirty bit: mWakefulness changed 9 | public static final int DIRTY_WAKEFULNESS = 1 << 1; 10 | // Dirty bit: user activity was poked or may have timed out 11 | public static final int DIRTY_USER_ACTIVITY = 1 << 2; 12 | // Dirty bit: actual display power state was updated asynchronously 13 | public static final int DIRTY_ACTUAL_DISPLAY_POWER_STATE_UPDATED = 1 << 3; 14 | // Dirty bit: mBootCompleted changed 15 | public static final int DIRTY_BOOT_COMPLETED = 1 << 4; 16 | // Dirty bit: settings changed 17 | public static final int DIRTY_SETTINGS = 1 << 5; 18 | // Dirty bit: mIsPowered changed 19 | public static final int DIRTY_IS_POWERED = 1 << 6; 20 | // Dirty bit: mStayOn changed 21 | public static final int DIRTY_STAY_ON = 1 << 7; 22 | // Dirty bit: battery state changed 23 | public static final int DIRTY_BATTERY_STATE = 1 << 8; 24 | // Dirty bit: proximity state changed 25 | public static final int DIRTY_PROXIMITY_POSITIVE = 1 << 9; 26 | // Dirty bit: dock state changed 27 | public static final int DIRTY_DOCK_STATE = 1 << 10; 28 | 29 | // Wakefulness: The device is asleep and can only be awoken by a call to wakeUp(). 30 | // The screen should be off or in the process of being turned off by the display controller. 31 | // The device typically passes through the dozing state first. 32 | public static final int WAKEFULNESS_ASLEEP = 0; 33 | // Wakefulness: The device is fully awake. It can be put to sleep by a call to goToSleep(). 34 | // When the user activity timeout expires, the device may start dreaming or go to sleep. 35 | public static final int WAKEFULNESS_AWAKE = 1; 36 | // Wakefulness: The device is dreaming. It can be awoken by a call to wakeUp(), 37 | // which ends the dream. The device goes to sleep when goToSleep() is called, when 38 | // the dream ends or when unplugged. 39 | // User activity may brighten the screen but does not end the dream. 40 | public static final int WAKEFULNESS_DREAMING = 2; 41 | // Wakefulness: The device is dozing. It is almost asleep but is allowing a special 42 | // low-power "doze" dream to run which keeps the display on but lets the application 43 | // processor be suspended. It can be awoken by a call to wakeUp() which ends the dream. 44 | // The device fully goes to sleep if the dream cannot be started or ends on its own. 45 | public static final int WAKEFULNESS_DOZING = 3; 46 | 47 | // Summarizes the state of all active wakelocks. 48 | public static final int WAKE_LOCK_CPU = 1 << 0; 49 | public static final int WAKE_LOCK_SCREEN_BRIGHT = 1 << 1; 50 | public static final int WAKE_LOCK_SCREEN_DIM = 1 << 2; 51 | public static final int WAKE_LOCK_BUTTON_BRIGHT = 1 << 3; 52 | public static final int WAKE_LOCK_PROXIMITY_SCREEN_OFF = 1 << 4; 53 | public static final int WAKE_LOCK_STAY_AWAKE = 1 << 5; // only set if already awake 54 | public static final int WAKE_LOCK_DOZE = 1 << 6; 55 | 56 | // Summarizes the user activity state. 57 | public static final int USER_ACTIVITY_SCREEN_BRIGHT = 1 << 0; 58 | public static final int USER_ACTIVITY_SCREEN_DIM = 1 << 1; 59 | public static final int USER_ACTIVITY_SCREEN_DREAM = 1 << 2; 60 | 61 | // Default timeout in milliseconds. This is only used until the settings 62 | // provider populates the actual default value (R.integer.def_screen_off_timeout). 63 | public static final int DEFAULT_SCREEN_OFF_TIMEOUT = 15 * 1000; 64 | public static final int DEFAULT_SLEEP_TIMEOUT = -1; 65 | 66 | // Power hints defined in hardware/libhardware/include/hardware/power.h. 67 | public static final int POWER_HINT_INTERACTION = 2; 68 | public static final int POWER_HINT_LOW_POWER = 5; 69 | 70 | } 71 | -------------------------------------------------------------------------------- /app/src/main/java/me/neversleep/plusplus/QuickStartService.java: -------------------------------------------------------------------------------- 1 | package me.neversleep.plusplus; 2 | 3 | import android.annotation.TargetApi; 4 | import android.content.SharedPreferences; 5 | import android.os.Build; 6 | import android.service.quicksettings.TileService; 7 | import android.util.Log; 8 | import android.widget.Toast; 9 | 10 | @TargetApi(Build.VERSION_CODES.N) 11 | public class QuickStartService extends TileService { 12 | public static final String TAG = "QurkStartService"; 13 | private SharedPreferences xConf; 14 | 15 | @Override // android.app.Service 16 | public void onCreate() { 17 | super.onCreate(); 18 | try { 19 | this.xConf = getSharedPreferences("x_conf", 1); 20 | Log.e(TAG, "onCreate: xConf" + this.xConf); 21 | } catch (SecurityException e) { 22 | Toast.makeText(this, "error: " + e.getMessage(), 1).show(); 23 | } 24 | } 25 | 26 | @Override // android.service.quicksettings.TileService 27 | public void onClick() { 28 | super.onClick(); 29 | if (this.xConf == null) { 30 | return; 31 | } 32 | int state = getQsTile().getState(); 33 | if (state == 1) { 34 | getQsTile().setState(2); 35 | this.xConf.edit().putBoolean("power", true).apply(); 36 | } else if (state == 2) { 37 | getQsTile().setState(1); 38 | this.xConf.edit().putBoolean("power", false).apply(); 39 | } 40 | getQsTile().updateTile(); 41 | Log.e(TAG, "onClick: " + getQsTile().getState()); 42 | } 43 | 44 | @Override // android.service.quicksettings.TileService 45 | public void onTileAdded() { 46 | super.onTileAdded(); 47 | if (this.xConf == null) { 48 | return; 49 | } 50 | getQsTile().setState(this.xConf.getBoolean("power", false) ? 2 : 1); 51 | getQsTile().updateTile(); 52 | Log.e(TAG, "onTileAdded: " + this.xConf.getBoolean("power", false) + ":" + getQsTile().getState()); 53 | } 54 | 55 | @Override // android.service.quicksettings.TileService 56 | public void onStartListening() { 57 | super.onStartListening(); 58 | if (this.xConf == null) { 59 | return; 60 | } 61 | getQsTile().setState(this.xConf.getBoolean("power", false) ? 2 : 1); 62 | getQsTile().updateTile(); 63 | Log.e(TAG, "onStartListening: update" + this.xConf.getBoolean("power", false) + ":" + getQsTile().getState()); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /app/src/main/java/me/neversleep/plusplus/ShellUtil.java: -------------------------------------------------------------------------------- 1 | package me.neversleep.plusplus; 2 | 3 | 4 | import java.io.BufferedReader; 5 | import java.io.DataOutputStream; 6 | import java.io.IOException; 7 | import java.io.InputStreamReader; 8 | import java.util.List; 9 | 10 | /** 11 | * ShellUtil 12 | * 16 | * 25 | * 26 | * @author Trinea 2013-5-16 27 | */ 28 | public class ShellUtil { 29 | public static final String TAG = "ShellUtil"; 30 | public static final String COMMAND_SU = "su"; 31 | public static final String COMMAND_SH = "sh"; 32 | public static final String COMMAND_EXIT = "exit\n"; 33 | public static final String COMMAND_LINE_END = "\n"; 34 | 35 | public static final OnExecResultInfoListener mOnExecResultInfoListener = null; 36 | 37 | /** 38 | * check whether has root permission 39 | * 40 | * @return 41 | */ 42 | public static boolean permission() { 43 | return execCommand("echo root", true, false).result == 0; 44 | } 45 | 46 | /** 47 | * execute shell command, default return result msg 48 | * 49 | * @param command command 50 | * @param isRoot whether need to run with root 51 | * @return 52 | * @see ShellUtil#execCommand(String[], boolean, boolean) 53 | */ 54 | public static CommandResult execCommand(String command, boolean isRoot) { 55 | return execCommand(new String[]{command}, isRoot, true); 56 | } 57 | 58 | /** 59 | * execute shell commands, default return result msg 60 | * 61 | * @param commands command list 62 | * @param isRoot whether need to run with root 63 | * @return 64 | * @see ShellUtil#execCommand(String[], boolean, boolean) 65 | */ 66 | public static CommandResult execCommand(List commands, boolean isRoot) { 67 | return execCommand(commands == null ? null : commands.toArray(new String[]{}), isRoot, true); 68 | } 69 | 70 | /** 71 | * execute shell commands, default return result msg 72 | * 73 | * @param commands command array 74 | * @param isRoot whether need to run with root 75 | * @return 76 | * @see ShellUtil#execCommand(String[], boolean, boolean) 77 | */ 78 | public static CommandResult execCommand(String[] commands, boolean isRoot) { 79 | return execCommand(commands, isRoot, true); 80 | } 81 | 82 | /** 83 | * execute shell command 84 | * 85 | * @param command command 86 | * @param isRoot whether need to run with root 87 | * @param isNeedResultMsg whether need result msg 88 | * @return 89 | * @see ShellUtil#execCommand(String[], boolean, boolean) 90 | */ 91 | public static CommandResult execCommand(String command, boolean isRoot, boolean isNeedResultMsg) { 92 | return execCommand(new String[]{command}, isRoot, isNeedResultMsg); 93 | } 94 | 95 | public static void execCommand(String command, boolean isRoot, OnExecResultInfoListener eListener) { 96 | 97 | execCommand(new String[]{command}, isRoot, eListener); 98 | 99 | } 100 | 101 | /** 102 | * execute shell commands 103 | * 104 | * @param commands command list 105 | * @param isRoot whether need to run with root 106 | * @param isNeedResultMsg whether need result msg 107 | * @return 108 | * @see ShellUtil#execCommand(String[], boolean, boolean) 109 | */ 110 | public static CommandResult execCommand(List commands, boolean isRoot, boolean isNeedResultMsg) { 111 | return execCommand(commands == null ? null : commands.toArray(new String[]{}), isRoot, isNeedResultMsg); 112 | } 113 | 114 | public static CommandResult execCommand(String[] commands, boolean isRoot, boolean isNeedResultMsg) { 115 | int result = -1; 116 | if (commands == null || commands.length == 0) { 117 | return new CommandResult(result, null, null); 118 | } 119 | 120 | Process process = null; 121 | BufferedReader successResult = null; 122 | BufferedReader errorResult = null; 123 | StringBuilder successMsg = null; 124 | StringBuilder errorMsg = null; 125 | 126 | DataOutputStream os = null; 127 | try { 128 | process = Runtime.getRuntime().exec(isRoot ? COMMAND_SU : COMMAND_SH); 129 | os = new DataOutputStream(process.getOutputStream()); 130 | for (String command : commands) { 131 | if (command == null) { 132 | continue; 133 | } 134 | 135 | // donnot use os.writeBytes(commmand), avoid chinese charset error 136 | os.write(command.getBytes()); 137 | os.writeBytes(COMMAND_LINE_END); 138 | os.flush(); 139 | } 140 | os.writeBytes(COMMAND_EXIT); 141 | os.flush(); 142 | 143 | result = process.waitFor(); 144 | // get command result 145 | if (isNeedResultMsg) { 146 | successMsg = new StringBuilder(); 147 | errorMsg = new StringBuilder(); 148 | successResult = new BufferedReader(new InputStreamReader(process.getInputStream())); 149 | errorResult = new BufferedReader(new InputStreamReader(process.getErrorStream())); 150 | String s; 151 | while ((s = successResult.readLine()) != null) { 152 | successMsg.append(s + "\n"); 153 | } 154 | while ((s = errorResult.readLine()) != null) { 155 | errorMsg.append(s + "\n"); 156 | } 157 | } 158 | } catch (IOException e) { 159 | e.printStackTrace(); 160 | } catch (Exception e) { 161 | e.printStackTrace(); 162 | } finally { 163 | try { 164 | if (os != null) { 165 | os.close(); 166 | } 167 | if (successResult != null) { 168 | successResult.close(); 169 | } 170 | if (errorResult != null) { 171 | errorResult.close(); 172 | } 173 | } catch (IOException e) { 174 | e.printStackTrace(); 175 | } 176 | 177 | if (process != null) { 178 | process.destroy(); 179 | } 180 | } 181 | return new CommandResult(result, successMsg == null ? null : successMsg.toString(), errorMsg == null ? null 182 | : errorMsg.toString()); 183 | } 184 | 185 | /** 186 | * execute shell commands 187 | * 188 | * @param commands command array 189 | * @param isRoot whether need to run with root 190 | * @param onExecResultinfolistener 监听器 191 | * @return
    192 | *
  • if isNeedResultMsg is false, {@link CommandResult#successMsg} is null and 193 | * {@link CommandResult#errorMsg} is null.
  • 194 | *
  • if {@link CommandResult#result} is -1, there maybe some excepiton.
  • 195 | *
196 | */ 197 | public static void execCommand(String[] commands, boolean isRoot, OnExecResultInfoListener onExecResultinfolistener) { 198 | if (commands == null || commands.length == 0) { 199 | return; 200 | } 201 | 202 | Process process = null; 203 | BufferedReader successResult = null; 204 | BufferedReader errorResult = null; 205 | StringBuilder successMsg = null; 206 | StringBuilder errorMsg = null; 207 | 208 | DataOutputStream os = null; 209 | 210 | try { 211 | process = Runtime.getRuntime().exec(isRoot ? COMMAND_SU : COMMAND_SH); 212 | os = new DataOutputStream(process.getOutputStream()); 213 | for (String command : commands) { 214 | if (command == null) { 215 | continue; 216 | } 217 | 218 | // donnot use os.writeBytes(commmand), avoid chinese charset error 219 | os.write(command.getBytes()); 220 | os.writeBytes(COMMAND_LINE_END); 221 | os.flush(); 222 | } 223 | 224 | os.writeBytes(COMMAND_EXIT); 225 | 226 | os.flush(); 227 | 228 | successMsg = new StringBuilder(); 229 | errorMsg = new StringBuilder(); 230 | while (true) { 231 | if (onExecResultinfolistener != null && onExecResultinfolistener instanceof OnExecResultInfoCallback) { 232 | if (((OnExecResultInfoCallback) onExecResultinfolistener).isStop()) break; 233 | } 234 | successResult = new BufferedReader(new InputStreamReader(process.getInputStream())); 235 | 236 | errorResult = new BufferedReader(new InputStreamReader(process.getErrorStream())); 237 | 238 | if (!(null != successResult | null != errorResult)) continue; 239 | 240 | String s; 241 | 242 | while ((s = successResult.readLine()) != null) { 243 | 244 | successMsg.append(s + "\n"); 245 | 246 | if (null == onExecResultinfolistener) continue; 247 | 248 | onExecResultinfolistener.OnResult(s); 249 | 250 | } 251 | 252 | while ((s = errorResult.readLine()) != null) { 253 | 254 | errorMsg.append(s + "\n"); 255 | 256 | if (null == onExecResultinfolistener) continue; 257 | 258 | onExecResultinfolistener.OnResult(s); 259 | 260 | } 261 | 262 | Thread.sleep(500); 263 | 264 | } 265 | 266 | } catch (IOException e) { 267 | e.printStackTrace(); 268 | } catch (Exception e) { 269 | e.printStackTrace(); 270 | } finally { 271 | try { 272 | if (os != null) { 273 | os.close(); 274 | } 275 | if (successResult != null) { 276 | successResult.close(); 277 | } 278 | if (errorResult != null) { 279 | errorResult.close(); 280 | } 281 | } catch (IOException e) { 282 | e.printStackTrace(); 283 | } 284 | 285 | if (process != null) { 286 | process.destroy(); 287 | } 288 | } 289 | 290 | } 291 | 292 | /** 293 | * 重启设备 294 | * 295 | * @param isSoft 软重启 296 | * @return 是否重启成功 297 | */ 298 | public static boolean reboot(boolean isSoft) { 299 | if (isSoft) { 300 | CommandResult commandResult = execCommand("setprop ctl.restart surfaceflinger; setprop ctl.restart zygote", true); 301 | return commandResult.result == 0; 302 | } else { 303 | CommandResult commandResult = execCommand("/system/bin/reboot", true); 304 | if (commandResult.result != 0) 305 | commandResult = execCommand("/system/xbin/reboot", true); 306 | return commandResult.result == 0; 307 | } 308 | } 309 | 310 | //设置返回信息监听 311 | 312 | public interface OnExecResultInfoListener { 313 | void OnResult(String result); 314 | } 315 | 316 | /** 317 | * result of command 318 | *
    319 | *
  • {@link CommandResult#result} means result of command, 0 means normal, else means error, same to excute in 320 | * linux shell
  • 321 | *
  • {@link CommandResult#successMsg} means success message of command result
  • 322 | *
  • {@link CommandResult#errorMsg} means error message of command result
  • 323 | *
324 | * 325 | * @author Trinea 2013-5-16 326 | */ 327 | public static class CommandResult { 328 | 329 | /** 330 | * result of command 331 | **/ 332 | public int result; 333 | /** 334 | * success message of command result 335 | **/ 336 | public String successMsg; 337 | /** 338 | * error message of command result 339 | **/ 340 | public String errorMsg; 341 | 342 | public CommandResult(int result) { 343 | this.result = result; 344 | } 345 | 346 | public CommandResult(int result, String successMsg, String errorMsg) { 347 | this.result = result; 348 | this.successMsg = successMsg; 349 | this.errorMsg = errorMsg; 350 | } 351 | } 352 | 353 | public abstract static class OnExecResultInfoCallback implements OnExecResultInfoListener { 354 | protected abstract boolean isStop(); 355 | } 356 | } 357 | 358 | -------------------------------------------------------------------------------- /app/src/main/java/me/neversleep/plusplus/XMain.java: -------------------------------------------------------------------------------- 1 | package me.neversleep.plusplus; 2 | 3 | import android.content.Context; 4 | import android.util.Log; 5 | 6 | import java.lang.reflect.Field; 7 | 8 | import de.robv.android.xposed.IXposedHookLoadPackage; 9 | import de.robv.android.xposed.XC_MethodHook; 10 | import de.robv.android.xposed.XSharedPreferences; 11 | import de.robv.android.xposed.XposedBridge; 12 | import de.robv.android.xposed.XposedHelpers; 13 | import de.robv.android.xposed.callbacks.XC_LoadPackage; 14 | 15 | public class XMain implements IXposedHookLoadPackage { 16 | 17 | public static final String TAG = "neversleep"; 18 | 19 | public void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable { 20 | XUtils.xLog(TAG, "package:" + loadPackageParam.packageName); 21 | XUtils.xLog(TAG, "process:" + loadPackageParam.processName); 22 | if ("android".equals(loadPackageParam.packageName)) { 23 | XUtils.xLog(TAG, "start hook system_server..."); 24 | hookAndroid(loadPackageParam); 25 | XUtils.xLog(TAG, "end hook system_server..."); 26 | } 27 | if (BuildConfig.APPLICATION_ID.equals(loadPackageParam.packageName)) { 28 | hookSelf(loadPackageParam); 29 | } 30 | } 31 | 32 | 33 | private void hookSelf(XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable { 34 | XposedHelpers.findAndHookMethod("me.neversleep.plusplus.MainActivity", loadPackageParam.classLoader, "getActiveVersion", new XC_MethodHook() { 35 | protected void afterHookedMethod(XC_MethodHook.MethodHookParam methodHookParam) throws Throwable { 36 | super.afterHookedMethod(methodHookParam); 37 | methodHookParam.setResult(BuildConfig.VERSION_CODE); 38 | } 39 | }); 40 | } 41 | 42 | private void hookAndroid(XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable { 43 | final XSharedPreferences xSharedPreferences = new XSharedPreferences(BuildConfig.APPLICATION_ID, "x_conf"); 44 | xSharedPreferences.makeWorldReadable(); 45 | xSharedPreferences.reload(); 46 | try { 47 | XposedBridge.hookAllMethods(XposedHelpers.findClass("com.android.server.am.ActivityManagerService", loadPackageParam.classLoader), "systemReady", new XC_MethodHook() { // from class: me.neversleep.plusplus.XMain.2 48 | protected void beforeHookedMethod(XC_MethodHook.MethodHookParam methodHookParam) throws Throwable { 49 | try { 50 | XUtils.xLog(TAG, "Preparing system"); 51 | XUtils.xLog(TAG, " Preparing system"); 52 | getContext(methodHookParam.thisObject); 53 | } catch (Throwable th) { 54 | XUtils.xLog(TAG, Log.getStackTraceString(th)); 55 | } 56 | } 57 | 58 | protected void afterHookedMethod(XC_MethodHook.MethodHookParam methodHookParam) throws Throwable { 59 | try { 60 | XUtils.xLog(TAG, "System ready"); 61 | getContext(methodHookParam.thisObject); 62 | HookImpl.main(methodHookParam.thisObject.getClass().getClassLoader()); 63 | } catch (Throwable th) { 64 | XUtils.xLog(TAG, Log.getStackTraceString(th)); 65 | XposedBridge.log(th); 66 | } 67 | } 68 | 69 | private Context getContext(Object obj) throws Throwable { 70 | Context context = null; 71 | for (Class cls = obj.getClass(); cls != null && context == null; cls = cls.getSuperclass()) { 72 | Field[] declaredFields = cls.getDeclaredFields(); 73 | int length = declaredFields.length; 74 | int i = 0; 75 | while (true) { 76 | if (i < length) { 77 | Field field = declaredFields[i]; 78 | if (field.getType().equals(Context.class)) { 79 | field.setAccessible(true); 80 | context = (Context) field.get(obj); 81 | XUtils.xLog(TAG, "Context found in " + cls + " as " + field.getName()); 82 | break; 83 | } 84 | i++; 85 | } 86 | } 87 | } 88 | if (context != null) { 89 | return context; 90 | } 91 | throw new Throwable("Context not found"); 92 | } 93 | }); 94 | } catch (Throwable error) { 95 | XUtils.xLog(TAG, "systemReady error:", error); 96 | } 97 | Class powerManagerServiceClass = XposedHelpers.findClass("com.android.server.power.PowerManagerService", loadPackageParam.classLoader); 98 | 99 | //部分设备没效果:Redmi note5 android 9 100 | try { 101 | // Class powerGroupClass = XposedHelpers.findClass("com.android.server.power.PowerGroup", loadPackageParam.classLoader); 102 | 103 | XposedBridge.hookAllMethods(powerManagerServiceClass, "isBeingKeptAwakeLocked", new XC_MethodHook() { 104 | protected void afterHookedMethod(XC_MethodHook.MethodHookParam param) throws Throwable { 105 | xSharedPreferences.reload(); 106 | XUtils.xLog(TAG, "get_disable_sleep: disable_sleep is " + xSharedPreferences.getBoolean("disable_sleep", false)); 107 | 108 | if (!xSharedPreferences.getBoolean("disable_sleep", false)) { 109 | XUtils.xLog(TAG, "afterHookedMethod: disable_sleep is false"); 110 | return; 111 | } 112 | param.setResult(true); 113 | XUtils.xLog(TAG, "afterHookedMethod: disable_sleep is true"); 114 | 115 | } 116 | }); 117 | } catch (Throwable error) { 118 | XUtils.xLog(TAG, "isBeingKeptAwakeLocked error:", error); 119 | } 120 | if (false) { 121 | //完全没效果 122 | try { 123 | XposedHelpers.findAndHookMethod(powerManagerServiceClass, "goToSleep", long.class, int.class, int.class, new XC_MethodHook() { 124 | @Override 125 | protected void beforeHookedMethod(MethodHookParam param) throws Throwable { 126 | super.beforeHookedMethod(param); 127 | xSharedPreferences.reload(); 128 | XUtils.xLog(TAG, "[goToSleep]get_disable_sleep: disable_sleep is " + xSharedPreferences.getBoolean("disable_sleep", false)); 129 | 130 | if (!xSharedPreferences.getBoolean("disable_sleep", false)) { 131 | XUtils.xLog(TAG, "[goToSleep]afterHookedMethod: disable_sleep is false"); 132 | return; 133 | } 134 | param.setResult(null); 135 | XUtils.xLog(TAG, "[goToSleep]afterHookedMethod: disable_sleep is true"); 136 | } 137 | }); 138 | } catch (Throwable error) { 139 | XUtils.xLog(TAG, "goToSleep error:", error); 140 | } 141 | } 142 | if (false) { 143 | //会导致黑屏 144 | try { 145 | XposedBridge.hookAllMethods(powerManagerServiceClass, "getScreenOffTimeoutLocked", new XC_MethodHook() { 146 | @Override 147 | protected void afterHookedMethod(MethodHookParam param) throws Throwable { 148 | super.afterHookedMethod(param); 149 | xSharedPreferences.reload(); 150 | XUtils.xLog(TAG, "[getScreenOffTimeoutLocked]get_disable_sleep: disable_sleep is " + xSharedPreferences.getBoolean("disable_sleep", false)); 151 | 152 | if (!xSharedPreferences.getBoolean("disable_sleep", false)) { 153 | XUtils.xLog(TAG, "[getScreenOffTimeoutLocked]afterHookedMethod: disable_sleep is false"); 154 | return; 155 | } 156 | param.setResult(Long.MAX_VALUE); 157 | XUtils.xLog(TAG, "[getScreenOffTimeoutLocked]afterHookedMethod: disable_sleep is true"); 158 | } 159 | }); 160 | } catch (Throwable error) { 161 | XUtils.xLog(TAG, "getScreenOffTimeoutLocked error:", error); 162 | } 163 | } 164 | //目前测试没什么问题 165 | try { 166 | XposedHelpers.findAndHookMethod( 167 | "com.android.server.power.PowerManagerService", 168 | loadPackageParam.classLoader, 169 | "updateUserActivitySummaryLocked", 170 | long.class, 171 | int.class, 172 | new XC_MethodHook() { 173 | 174 | @Override 175 | protected void afterHookedMethod(MethodHookParam param) throws Throwable { 176 | super.afterHookedMethod(param); 177 | xSharedPreferences.reload(); 178 | XUtils.xLog(TAG, "[updateUserActivitySummaryLocked]get_disable_sleep: disable_sleep is " + xSharedPreferences.getBoolean("disable_sleep", false)); 179 | 180 | if (!xSharedPreferences.getBoolean("disable_sleep", false)) { 181 | XUtils.xLog(TAG, "[updateUserActivitySummaryLocked]afterHookedMethod: disable_sleep is false"); 182 | return; 183 | } 184 | // 修改结果,确保屏幕不会进入 SCREEN_OFF 状态 185 | Object powerManagerService = param.thisObject; 186 | int mUserActivitySummary = (int) XposedHelpers.getObjectField(powerManagerService, "mUserActivitySummary"); 187 | 188 | // 如果当前状态是屏幕暗或亮,则不修改 189 | if ((mUserActivitySummary & PowerMangerService.USER_ACTIVITY_SCREEN_BRIGHT) != 0 || 190 | (mUserActivitySummary & PowerMangerService.USER_ACTIVITY_SCREEN_DIM) != 0) { 191 | return; 192 | } 193 | 194 | // 修改结果为 SCREEN_DIM,确保屏幕不会进入 SCREEN_OFF 状态 195 | mUserActivitySummary = PowerMangerService.USER_ACTIVITY_SCREEN_DIM; 196 | XposedHelpers.setObjectField(powerManagerService, "mUserActivitySummary", mUserActivitySummary); 197 | 198 | XUtils.xLog(TAG, "Modified mUserActivitySummary to prevent SCREEN_OFF"); 199 | } 200 | } 201 | ); 202 | } catch (Throwable error) { 203 | XUtils.xLog(TAG, "updateUserActivitySummaryLocked error:", error); 204 | } 205 | 206 | XUtils.xLog(TAG, "hookAndroid finish"); 207 | 208 | } 209 | } 210 | -------------------------------------------------------------------------------- /app/src/main/java/me/neversleep/plusplus/XUtils.java: -------------------------------------------------------------------------------- 1 | package me.neversleep.plusplus; 2 | 3 | import android.util.Log; 4 | 5 | import de.robv.android.xposed.XposedBridge; 6 | 7 | public class XUtils { 8 | public static final String TAG = "Utils"; 9 | 10 | public static void xLog(String str, String str2) { 11 | xLog(str, str2, null); 12 | } 13 | 14 | public static void xLog(String str, String str2, Throwable th) { 15 | XposedBridge.log("me.neversleep.plusplus::" + str + "::" + str2); 16 | if (th != null) { 17 | XposedBridge.log(th); 18 | } 19 | if (th != null) { 20 | Log.e(str, str2, th); 21 | } else { 22 | Log.e(str, str2); 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 15 | 18 | 21 | 22 | 23 | 24 | 30 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/baseline_help_outline_16.xml: -------------------------------------------------------------------------------- 1 | 8 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/baseline_help_outline_24.xml: -------------------------------------------------------------------------------- 1 | 8 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/baseline_help_outline_8.xml: -------------------------------------------------------------------------------- 1 | 8 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/baseline_question_mark_16.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/baseline_question_mark_24.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50 | 55 | 60 | 65 | 70 | 75 | 80 | 85 | 90 | 95 | 100 | 105 | 110 | 115 | 120 | 125 | 130 | 135 | 140 | 145 | 150 | 155 | 160 | 165 | 170 | 171 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_power_new_24.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/unchecked_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 19 | 20 | 32 | 33 | 44 | 45 | 58 | 59 | 71 | 72 | 86 | 87 | 97 | 98 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xpko/FakeScreen/02cbc8ba142d2f11297829e3c127c02bd3335f17/app/src/main/res/mipmap-hdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xpko/FakeScreen/02cbc8ba142d2f11297829e3c127c02bd3335f17/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xpko/FakeScreen/02cbc8ba142d2f11297829e3c127c02bd3335f17/app/src/main/res/mipmap-mdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xpko/FakeScreen/02cbc8ba142d2f11297829e3c127c02bd3335f17/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xpko/FakeScreen/02cbc8ba142d2f11297829e3c127c02bd3335f17/app/src/main/res/mipmap-xhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xpko/FakeScreen/02cbc8ba142d2f11297829e3c127c02bd3335f17/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xpko/FakeScreen/02cbc8ba142d2f11297829e3c127c02bd3335f17/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xpko/FakeScreen/02cbc8ba142d2f11297829e3c127c02bd3335f17/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xpko/FakeScreen/02cbc8ba142d2f11297829e3c127c02bd3335f17/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xpko/FakeScreen/02cbc8ba142d2f11297829e3c127c02bd3335f17/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/values-zh-rCN/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 请先激活模块!! 4 | 当前激活版本:%d,非已安装版本:%d 5 | FakeScreen 6 | 授权失败 7 | 复制失败 8 | 复制成功 9 | 永不休眠却不想屏幕亮着 10 | failed 11 | 忽略 12 | 您似乎正在使用过时的 LSPosed 版本或 LSPosed 未激活,请更新 LSPosed 或者激活后再试。 13 | shell控制命令:%s 14 | @string/app_name 15 | 开启后,点击电源键将只息屏,其他状态不变 16 | 禁用休眠 17 | 可选功能,手机将永不休眠 18 | 更改设置失败 19 | -------------------------------------------------------------------------------- /app/src/main/res/values/arrays.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #FFBB86FC 4 | #FF6200EE 5 | #FF3700B3 6 | #FF03DAC5 7 | #FF018786 8 | #FF000000 9 | #FFFFFFFF 10 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | FakeScreen 3 | @string/app_name 4 | After it is turned on, clicking the power button will only turn off the screen, and other states will remain unchanged. 5 | Shell control commands: %s 6 | Ignore 7 | Please activate the module first! ! 8 | Current activated version: %d, non-installed version: %d 9 | It seems that you are using an out dated version of LSPosed or LSPosed is not activated, please update LSPosed or try again after activated. 10 | Authorization failed 11 | copy failed 12 | copy success 13 | Never sleep but don\'t want the screen to be on 14 | Failed 15 | Disable sleep 16 | Optional, phone will never sleeps 17 | Failed to change settings 18 | 19 | -------------------------------------------------------------------------------- /app/src/main/res/values/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 15 | 16 | -------------------------------------------------------------------------------- /app/src/main/res/xml/backup_rules.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/xml/data_extraction_rules.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | 12 | 13 | 19 | -------------------------------------------------------------------------------- /app/src/test/java/me/neversleep/plusplus/A.java: -------------------------------------------------------------------------------- 1 | package me.neversleep.plusplus; 2 | 3 | public class A { 4 | public static final String TAG = A.class.getSimpleName(); 5 | 6 | public int getCode() { 7 | return 0; 8 | } 9 | 10 | } 11 | -------------------------------------------------------------------------------- /app/src/test/java/me/neversleep/plusplus/ExampleUnitTest.kt: -------------------------------------------------------------------------------- 1 | package me.neversleep.plusplus 2 | 3 | import org.junit.Assert.assertEquals 4 | import org.junit.Test 5 | 6 | /** 7 | * Example local unit test, which will execute on the development machine (host). 8 | * 9 | * See [testing documentation](http://d.android.com/tools/testing). 10 | */ 11 | class ExampleUnitTest { 12 | @Test 13 | fun addition_isCorrect() { 14 | assertEquals(4, 2 + 2) 15 | for (method in A().javaClass.methods) { 16 | println("method.name:" + method.name) 17 | println("method:" + method.genericReturnType.toString()) 18 | } 19 | } 20 | 21 | } -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | plugins { 3 | id 'com.android.application' version '8.1.0' apply false 4 | id 'org.jetbrains.kotlin.android' version '1.8.10' apply false 5 | } -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | # IDE (e.g. Android Studio) users: 3 | # Gradle settings configured through the IDE *will override* 4 | # any settings specified in this file. 5 | # For more details on how to configure your build environment visit 6 | # http://www.gradle.org/docs/current/userguide/build_environment.html 7 | # Specifies the JVM arguments used for the daemon process. 8 | # The setting is particularly useful for tweaking memory settings. 9 | org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 10 | # When configured, Gradle will run in incubating parallel mode. 11 | # This option should only be used with decoupled projects. More details, visit 12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 13 | # org.gradle.parallel=true 14 | # AndroidX package structure to make it clearer which packages are bundled with the 15 | # Android operating system, and which are packaged with your app's APK 16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn 17 | android.useAndroidX=true 18 | # Kotlin code style for this project: "official" or "obsolete": 19 | kotlin.code.style=official 20 | # Enables namespacing of each library's R class so that its R class includes only the 21 | # resources declared in the library itself and none from the library's dependencies, 22 | # thereby reducing the size of the R class for that library 23 | android.nonTransitiveRClass=true -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xpko/FakeScreen/02cbc8ba142d2f11297829e3c127c02bd3335f17/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Tue Dec 12 14:32:07 CST 2023 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip 5 | zipStoreBase=GRADLE_USER_HOME 6 | zipStorePath=wrapper/dists 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ 2 | env sh 3 | 4 | # 5 | 6 | # Copyright 2015 the original author or authors. 7 | # 8 | 9 | # Licensed under the Apache License, Version 2.0 (the "License"); 10 | # you may not use this file except in compliance with the License. 11 | # You may obtain a copy of the License at 12 | # 13 | 14 | # https://www.apache.org/licenses/LICENSE-2.0 15 | # 16 | 17 | # Unless required by applicable law or agreed to in writing, software 18 | # distributed under the License is distributed on an "AS IS" BASIS, 19 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 20 | # See the License for the specific language governing permissions and 21 | # limitations under the License. 22 | # 23 | 24 | ############################################################################## 25 | ## 26 | ## 27 | Gradle start 28 | up script 29 | for 30 | UN *X 31 | ## 32 | ############################################################################## 33 | 34 | # Attempt to set APP_HOME 35 | # Resolve links: $0 may be a link 36 | PRG = "$0" 37 | # Need this for relative symlinks. 38 | while [ -h "$PRG" ]; do 39 | ls = 40 | `ls -ld "$PRG"` 41 | link = 42 | `expr "$ls" : '.*-> \(.*\)$'` 43 | if expr "$link" : '/.*' > /dev/ 44 | null; 45 | then 46 | PRG = "$link" 47 | else 48 | PRG = 49 | `dirname "$PRG"`"/$link" 50 | fi 51 | done 52 | SAVED = "`pwd`" 53 | cd "`dirname \"$PRG\"`/" >/dev/ 54 | null 55 | APP_HOME = "`pwd -P`" 56 | cd "$SAVED" >/dev/ 57 | null 58 | 59 | APP_NAME = "Gradle" 60 | APP_BASE_NAME = 61 | `basename "$0"` 62 | 63 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 64 | DEFAULT_JVM_OPTS = '"-Xmx64m" "-Xms64m"' 65 | 66 | # Use the maximum available, or set MAX_FD != -1 to use that value. 67 | MAX_FD = "maximum" 68 | 69 | warn() { 70 | echo 71 | "$*" 72 | } 73 | 74 | die() { 75 | echo 76 | echo 77 | "$*" 78 | echo 79 | exit 80 | 1 81 | } 82 | 83 | # OS specific support (must be 'true' or 'false'). 84 | cygwin = false 85 | msys = false 86 | darwin = false 87 | nonstop = false 88 | case "`uname`" 89 | in 90 | CYGWIN 91 | * ) 92 | cygwin = true;; 93 | Darwin* ) 94 | darwin = true;; 95 | MINGW* ) 96 | msys = true;; 97 | NONSTOP* ) 98 | nonstop = true;; 99 | esac 100 | 101 | CLASSPATH = $APP_HOME / gradle / wrapper / gradle - wrapper.jar 102 | 103 | 104 | # Determine the Java command to use to start the JVM. 105 | if [ -n "$JAVA_HOME" ]; then 106 | if [ -x "$JAVA_HOME/jre/sh/java" ]; 107 | then 108 | # IBM's JDK on AIX uses strange locations for the executables 109 | JAVACMD = "$JAVA_HOME/jre/sh/java" 110 | else 111 | JAVACMD = "$JAVA_HOME/bin/java" 112 | fi 113 | if [ ! -x "$JAVACMD" ]; 114 | then 115 | die 116 | "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 117 | 118 | Please set 119 | the JAVA_HOME 120 | variable in 121 | your environment 122 | to match 123 | the 124 | location 125 | of your 126 | Java installation 127 | ." 128 | fi 129 | else 130 | JAVACMD = "java" 131 | which java 132 | >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 133 | 134 | Please set 135 | the JAVA_HOME 136 | variable in 137 | your environment 138 | to match 139 | the 140 | location 141 | of your 142 | Java installation 143 | ." 144 | fi 145 | 146 | # Increase the maximum file descriptors if we can. 147 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ]; 148 | then 149 | MAX_FD_LIMIT = 150 | `ulimit -H -n` 151 | if [ $? -eq 0 ]; then 152 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ]; 153 | then 154 | MAX_FD = "$MAX_FD_LIMIT" 155 | fi 156 | ulimit 157 | - 158 | n $MAX_FD 159 | if [ $? -ne 0 ]; 160 | then 161 | warn 162 | "Could not set maximum file descriptor limit: $MAX_FD" 163 | fi 164 | else 165 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 166 | fi 167 | fi 168 | 169 | # For Darwin, add options to specify how the application appears in the dock 170 | if 171 | $darwin; 172 | then 173 | GRADLE_OPTS = "$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 174 | fi 175 | 176 | # For Cygwin or MSYS, switch paths to Windows format before running java 177 | if [ "$cygwin" = "true" -o "$msys" = "true" ]; 178 | then 179 | APP_HOME = 180 | `cygpath --path --mixed "$APP_HOME"` 181 | CLASSPATH = 182 | `cygpath --path --mixed "$CLASSPATH"` 183 | 184 | JAVACMD = 185 | `cygpath --unix "$JAVACMD"` 186 | 187 | # We build the pattern for arguments to be converted via cygpath 188 | ROOTDIRSRAW = 189 | `find -L / -maxdepth 1 -mindepth 1 - 190 | type d 191 | 2>/dev/null` 192 | SEP = "" 193 | for 194 | dir in 195 | $ROOTDIRSRAW; 196 | do 197 | ROOTDIRS = "$ROOTDIRS$SEP$dir" 198 | SEP = "|" 199 | done 200 | OURCYGPATTERN = "(^($ROOTDIRS))" 201 | # Add a user-defined pattern to the cygpath arguments 202 | if [ "$GRADLE_CYGPATTERN" != "" ]; 203 | then 204 | OURCYGPATTERN = "$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 205 | fi 206 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 207 | i = 0 208 | for 209 | arg in 210 | "$@"; do 211 | CHECK = 212 | `echo "$arg"|egrep -c "$OURCYGPATTERN" -` 213 | CHECK2 = 214 | `echo "$arg"|egrep -c "^-"` ### Determine if 215 | an option 216 | 217 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ]; then ### 218 | Added a 219 | condition 220 | eval 221 | ` 222 | echo args$i 223 | `=`cygpath --path --ignore --mixed "$arg"` 224 | else 225 | eval ` 226 | echo args$i 227 | `="\"$arg\"" 228 | fi 229 | i = 230 | ` 231 | expr $i 232 | + 1` 233 | done 234 | case 235 | $i in 236 | 0) set --;; 237 | 1) set -- "$args0";; 238 | 2) set -- "$args0" "$args1";; 239 | 3) set -- "$args0" "$args1" "$args2";; 240 | 4) set -- "$args0" "$args1" "$args2" "$args3";; 241 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4";; 242 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5";; 243 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6";; 244 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7";; 245 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8";; 246 | esac 247 | fi 248 | 249 | # Escape application args 250 | 251 | save() { 252 | for 253 | i 254 | do printf % s\\n 255 | "$i" | sed 256 | "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/"; 257 | done 258 | echo 259 | " " 260 | } 261 | 262 | APP_ARGS = 263 | `save "$@"` 264 | 265 | # Collect all arguments for the java command, following the shell quoting and substitution rules 266 | eval set 267 | -- 268 | $DEFAULT_JVM_OPTS $JAVA_OPTS 269 | $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 270 | 271 | exec "$JAVACMD" "$@" 272 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | google() 4 | mavenCentral() 5 | gradlePluginPortal() 6 | } 7 | } 8 | dependencyResolutionManagement { 9 | repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) 10 | repositories { 11 | maven { 12 | url 'https://jitpack.io' 13 | } 14 | google() 15 | jcenter() 16 | mavenCentral() 17 | maven { url 'https://maven.aliyun.com/nexus/content/groups/public/' } 18 | maven { url "https://oss.jfrog.org/libs-snapshot" } 19 | } 20 | } 21 | 22 | rootProject.name = "FakeScreen" 23 | include ':app' 24 | --------------------------------------------------------------------------------