diff --git a/README-MOBILE.md b/README-MOBILE.md deleted file mode 100644 index 234ef9ed..00000000 --- a/README-MOBILE.md +++ /dev/null @@ -1,260 +0,0 @@ -**This is for Android mobile users who do not have a PC. Floating apps or similar is recommended to read this page while working at the same time** - -**BEST VIEWED ON MOBILE!** - -# Quick links -- [Prerequisites](https://github.com/LGLTeam/Android-Mod-Menu/blob/master/README.md#prerequisites) -- [What you need](#what-you-need) -- [Video Tutorial](#video-tutorial) -- [Installation](#installation) -- [Setting up AIDE](#setting-up-aide) -- [Files to work with and making changes](#files-to-work-with-and-making-changes) -- [Implementing the menu to the target game](#implementing-the-menu-to-the-target-game) -- [FAQ](#faq) -- [Troubleshooting](#troubleshooting) -- [Credits/Acknowledgements](#creditsacknowledgements) - -# What you need -* Modded AIDE app, choose one of them you like to use. The official AIDE from Play Store will not work with this project - * [AIDE CMODs](https://secufiles.com/nE9J/AIDE_CMODs_3.2.200108.apk) - * [AIDE Lite Mod](https://mega.nz/file/bIpCQL6I#BzyLf1pB1Sf7EayW_PEJHl3f50qHHZDdb0BpB8FYdVo) -* NDK support for modded AIDE - * NDK for 32-bit/ARMv7 phones: [ndk_arm.tar.gz](https://mega.nz/folder/2c1TWIJD#UCzO7kIo1e4WpFwZHIMYVw/file/XRlRTIjJ) - * NDK for 64-bit/ARM64 phones: [ndk_arm64.tar.gz](https://mega.nz/folder/2c1TWIJD#UCzO7kIo1e4WpFwZHIMYVw/file/7RdTzYxQ) -* Any File Manager app you like to use but these are recommended - * [X-plore](https://play.google.com/store/apps/details?id=com.lonelycatgames.Xplore&hl=en): - * [MT Manager](https://bbs.binmt.cc/forum-2-1.html) [(Mirror link)](https://secufiles.com/js6i/MT2.9.2.apk) With build-in Apktool and editors to modify APK file. Note: It requires VIP to edit `AndroidManifest.xml` more than 200 lines -* Apktool app to edit `AndroidManifest.xml` for free: [Modded APK Editor Pro app](https://mega.nz/file/zQxA0YDY#eNRgcyrHwpWh1nSTHhcc4quxzeXrXcUHlYPoRyltKEw) or [APK Repacker](https://mega.nz/file/LIom0DDL#hJyIchPDCk2n_gcDmutNsOKS86WXQN58qpEGa9JsLrU) (We use APK Editor Pro) -* [Floating apps](https://play.google.com/store/apps/details?id=com.lwi.android.flappsfull&hl=en) (optional): You can use it to read this page and working at the same time or use a build-in feature by OEM - -# Video Tutorial -Note: Videos may be quite outdated - -Mahmoud Gaming: https://www.youtube.com/watch?v=SMCsUy60Hs8 - -NSRAÎNA HACKER: https://www.youtube.com/watch?v=MkkZ_loEDTU - -BROKE MODS OFC (Customized menu): https://www.youtube.com/watch?v=IYREVGc-quM - -# Installation - -Go to releases page https://github.com/LGLTeam/Android-Mod-Menu/releases/ and download **Source code (zip)** - -To download latest commit, enable desktop mode on your browser then click **Code**, and click **Download ZIP** - -![](https://i.imgur.com/EZnbd10.png) - -# Setting up AIDE - -Now let's begin - -Firstly, make sure you know your phone's hardware well, and download correct NDK file coresponding to your phone's architecture. ndk_arm.tar.gz for 32-bit/ARMv7 phones, ndk_arm64.tar.gz for 64-bit/ARM64 phones. Installing incorrect version will cause problems - -Now install NDK support for modded AIDE. Click on 3 dots on the right-corner. Click **More... - Settings** - -![](https://i.imgur.com/LyZMkK1.png) - -Go to **Build & Run**, and click on **Manage native code support**. - -![](https://images2.imgbox.com/6e/5c/DootVB4P_o.png) - -A prompt will ask to input the path of NDK file. - -If you use X-plore, you can show details of the file and copy file path easly. - -![](https://images2.imgbox.com/54/2b/G0gVbhrN_o.png) - -Paste it in the prompt box. - -![](https://images2.imgbox.com/e1/c0/HSj9yQS9_o.png) - -Click install and wait - -![](https://images2.imgbox.com/1d/55/7LPXB7CI_o.png) - -After installiation, you can now use AIDE with NDK support - -# Opening project in AIDE - -On the main screen, it says **No open files**. We simply click on **No open files** to show file explorer. Navigate to the directory of the project and open **app** folder - -An option **Open Android app Project** will appear. Click on it to open - -![](https://images2.imgbox.com/dc/7f/Jtq8ZEl1_o.png) - -Now that the file explorer will look like this, means the project has been opened - -![](https://images2.imgbox.com/2f/9a/EA0zZr8R_o.png) - -Press play to compile the project whether it works or not - -If successful, it will ask you to install the APK. It may ask you to allow installation from unknown sources. Please allow when asked - -Open the app to test - -# Files to work with and making changes - -See more: https://github.com/LGLTeam/Android-Mod-Menu#files-to-work-with-and-making-changes - -Important for 32-bit users: Please remove arm64-v8a from application.mk - -# Implementing the menu to the target game - -### 1. Exporting to APK - -We need to compile the project into APK file - -Click on 3 dots icon on the corner. **More... - Project - Publish project** - -![](https://images2.imgbox.com/e3/2b/8uBsyDwe_o.png) - -This dialog will show but why is export greyed? Because you need to create your own keystore first. Click **Create keystore** - -![](https://images2.imgbox.com/ec/86/pQMmCpiN_o.png) - -There is no need to put your organization info. Just your alias, password and name are fine. Don't forget your password! - -After you created your keystore, you can now export - -![](https://images2.imgbox.com/7c/4b/dkSUTXpx_o.png) - -Enter your keystore password - -![](https://images2.imgbox.com/3f/05/0Ois42P5_o.png) - -After that, it will tell you the APK has been experted - -![](https://images2.imgbox.com/4b/7b/GZuUcUOi_o.png) - -### 2. Downloading standalone APK from apkcombo - -It is not a good idea to pull out installed APK from phone because sometimes it comes with splitted APKs, it's a dumb feature, we should use Apkcombo to download standalone APK - -Try to use armv7 standalone APK as possible. It support on all armv7, x86 and arm64 devices - -https://apkcombo.com/ - -### 3. Know the game's main activity - -We are looking for main activity. X-plore app can get main activity of the app so we will use that - -Click **Show**, check **App manager**. - -![](https://images2.imgbox.com/d9/f2/wFQs1Nwi_o.png) - -Long press on an app and click **Show details**, then click **App** and expand **Activity** - -Here we can see the main activity. It's always on top - -![](https://images2.imgbox.com/fd/e4/CQFS4fJJ_o.png) - -Note it down somewhere to remember it. We will explain this later - -### 4. Adding dex and lib file - -We will use MT Manager to modify APK. Edit the files inside APK is pretty much straight forward, we do not need to decompile the whole APK to storage at all. - -Open the APK file. Click **View** to show its content - -![](https://images2.imgbox.com/f6/6c/6xd8CxIa_o.png) - -You will now see the content structure inside the APK - -![](https://images2.imgbox.com/68/b6/ejdGhu1M_o.png) - -Do the same on compiled mod menu APK on the other pane - -We need to rename the dex on our mod menu APK to add dex into the game APK. We name it to classes2.dex since it contain only single dex. If the game have multiple dexes, like classes.dex, classes2.dex, classes3.dex, we would name it to classes4.dex. Mod menu dex must always be last - -![](https://images2.imgbox.com/2d/f2/0ySkQexV_o.png) - -Press and hold on our dex, and click **+ Add**. This dialog will show. Enable **Auto Sign**, leave Update mode **Replace All** - -![](https://images2.imgbox.com/42/94/6awBaOeG_o.png) - -Click OK, it will copy and auto sign. - -Copy your library file (.so file) too. Make sure to copy to the correct architecture -armeabi-v7a is armeabi-v7a, arm64-v8a is arm64-v8a, and so on. - -PUTTING THE .SO file ON A WRONG ARCHITECTURE WILL RESULT IN A CRASH! - -![](https://images2.imgbox.com/34/93/NqI2kgOl_o.png) - -### 5. Making corresponding changes and compile - -Ok, we go back to the main directory inside APK. You can press **..** to go back - -**I don't want to explain it here again, so please go to main README.md to read: https://github.com/LGLTeam/Android-Mod-Menu/blob/master/README.md#2-making-corresponding-changes-in-the-files** - -**Editing DEX file using MT Manager** - -Open `classes.dex` directly, choose **Dex Editor Plus** - -![](https://images2.imgbox.com/d4/65/UlDjc5EY_o.png) - -This dialog will show if it have multidex. **SELECT ALL** and click OK - -![](https://images2.imgbox.com/c3/65/3vpID6Um_o.png) - -The editor opens. - -Make some changes. After you're done, save it - -![](https://images2.imgbox.com/ad/7c/JyAKmAwA_o.png) - -Go back and **save and exit** - -![](https://images2.imgbox.com/f2/a3/x0V6dgjH_o.png) - -Click OK to update the changes to the game's APK file with auto sign on - -![](https://images2.imgbox.com/1a/5a/4Dw9YFv9_o.png) - -Go back outside APK. You will now see a green text which tells you that you have recently modified the file - -![](https://images2.imgbox.com/dc/c3/SX5pHGPj_o.png) - -**Editing XML file using APK Editor Pro** - -MT Manage requires an account to edit `AndroidManifest.xml` and VIP account to edit more than 200 lines. No, we don't need VIP, we will use APK Editor Pro to edit - -Open APK Editor Pro, click "Select an Apk file". Navigate to the location where you have stored APK, and select it to edit - -![](https://images2.imgbox.com/97/05/bIwx800E_o.png) - -Open `AndroidManifest.xml` - -![](https://images2.imgbox.com/01/11/eP695bXz_o.png) - -Make some changes. After you're done, save it - -![](https://images2.imgbox.com/e4/e5/CgmEHFof_o.png) - -Go back, save the APK file - -![](https://images2.imgbox.com/ca/4d/0zeGiS91_o.png) - -Wait until it finish compiling. This screen will show after it's done. You can choose to install the APK right now. You may need to uninstall original APK first - -![](https://images2.imgbox.com/30/3e/hNbeXhYr_o.png) - -It's obvious that it saved an APK to the strange location `/storage/emulated/0/ApkEditor/tmp/gen_signed.apk`, just move it somewhere if you like to. - -If it works, congratulations! - -# Troubleshooting - -Problem with the project like app crashes: click **More... -> Project -> Refresh Build**. This will clear the project cache and fix problems - -Problem with AIDE: Open System Settings -> Apps and clear data of AIDE app. This will reset everything and you need to install NDK again - -AIDE has a lot of compatibility issues, you need to research a lot and do some trial and errors until you fix something. - -# FAQ - -See: https://github.com/LGLTeam/Android-Mod-Menu#faq - -# Credits/Acknowledgements - -* RAUNAK MODS for help in modding games via phone, and testing the template in AIDE \ No newline at end of file diff --git a/README.md b/README.md index 4947b379..eb02ed43 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ Or download Releases here https://github.com/LGLTeam/Android-Mod-Menu/releases https://github.com/LGLTeam/Android-Mod-Menu/wiki -# Credits/Acknowledgements +# Credits Thanks to the following individuals whose code helped me develop this mod menu * Octowolve/Escanor - Mod menu: https://github.com/z3r0Sec/Substrate-Template-With-Mod-Menu and Hooking: https://github.com/z3r0Sec/Substrate-Hooking-Example @@ -34,3 +34,8 @@ Thanks to the following individuals whose code helped me develop this mod menu # License **GNU General Public License 3** + +# Disclaimer +This project is for Educational Use only. We do not condone this project being used to gain an advantage against other people. This project was made for fun + +While commecial use/selling is allowed, we still strongly refrain you from buying any source codes on Telegram even if the author can be trusted, there is always a risk getting scammed. We will not be responsible for that. This project is always FREE to use \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 97a0d4bb..835eed68 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,13 +1,13 @@ apply plugin: 'com.android.application' android { - compileSdkVersion 30 + compileSdkVersion 32 defaultConfig { applicationId "com.android.support" minSdkVersion 19 - targetSdkVersion 30 + targetSdkVersion 32 versionCode 1 - versionName "2.9" + versionName "3.0" ndk { abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86' } @@ -30,7 +30,6 @@ android { path file('src/main/jni/Android.mk') } } - ndkVersion = '22.0.7026061' } //dependencies must be placed below 'android' brackets to get it work on AIDE diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 1cdfd0e6..ee39f054 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -5,22 +5,24 @@ - + - + diff --git a/app/src/main/ic_launcher-playstore.png b/app/src/main/ic_launcher-playstore.png new file mode 100644 index 00000000..cbc1231e Binary files /dev/null and b/app/src/main/ic_launcher-playstore.png differ diff --git a/app/src/main/java/com/android/support/Launcher.java b/app/src/main/java/com/android/support/Launcher.java new file mode 100644 index 00000000..a8c67160 --- /dev/null +++ b/app/src/main/java/com/android/support/Launcher.java @@ -0,0 +1,69 @@ +package com.android.support; + +import android.app.ActivityManager; +import android.app.Service; +import android.content.Intent; +import android.os.Handler; +import android.os.IBinder; +import android.view.View; + +public class Launcher extends Service { + + Menu menu; + + //When this Class is called the code in this function will be executed + @Override + public void onCreate() { + super.onCreate(); + + menu = new Menu(this); + menu.SetWindowManagerWindowService(); + menu.ShowMenu(); + + //Create a handler for this Class + final Handler handler = new Handler(); + handler.post(new Runnable() { + public void run() { + Thread(); + handler.postDelayed(this, 1000); + } + }); + } + + @Override + public IBinder onBind(Intent intent) { + return null; + } + + //Check if we are still in the game. If now our menu and menu button will dissapear + private boolean isNotInGame() { + ActivityManager.RunningAppProcessInfo runningAppProcessInfo = new ActivityManager.RunningAppProcessInfo(); + ActivityManager.getMyMemoryState(runningAppProcessInfo); + return runningAppProcessInfo.importance != 100; + } + + private void Thread() { + if (isNotInGame()) { + menu.setVisibility(View.INVISIBLE); + } else { + menu.setVisibility(View.VISIBLE); + } + } + + //Destroy our View + public void onDestroy() { + super.onDestroy(); + menu.onDestroy(); + } + + //Same as above so it wont crash in the background and therefore use alot of Battery life + public void onTaskRemoved(Intent intent) { + super.onTaskRemoved(intent); + try { + Thread.sleep(100); + } catch (InterruptedException e) { + e.printStackTrace(); + } + stopSelf(); + } +} diff --git a/app/src/main/java/com/android/support/Logcat.java b/app/src/main/java/com/android/support/Logcat.java deleted file mode 100644 index ae1f70c2..00000000 --- a/app/src/main/java/com/android/support/Logcat.java +++ /dev/null @@ -1,68 +0,0 @@ -package com.android.support; - -import android.content.Context; -import android.os.Build; -import android.util.Log; -import android.widget.Toast; - -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.io.InputStreamReader; - -public class Logcat { - public static void Clear(Context context) { - try { - Runtime.getRuntime().exec("logcat -c"); - Toast.makeText(context, "Logcat cleared", Toast.LENGTH_LONG).show(); - } catch (IOException e) { - Toast.makeText(context, "There was an error saving logcat to file", Toast.LENGTH_LONG).show(); - e.printStackTrace(); - } - } - - public static void Save(Context context) { - File path = null; - try { - Process process = Runtime.getRuntime().exec("logcat -d"); - BufferedReader bufferedReader = new BufferedReader( - new InputStreamReader(process.getInputStream())); - - StringBuilder log = new StringBuilder(); - String line = ""; - while ((line = bufferedReader.readLine()) != null) { - log.append(line + "\n"); - } - long unixTime = System.currentTimeMillis() / 1000L; - if (Build.VERSION.SDK_INT >= 30) { //Android R. AIDE didn't support Build.VERSION_CODES.R - path = new File("/storage/emulated/0/Documents/"); - } else { - path = new File(context.getExternalFilesDir(null) + "/Mod Menu"); - } - - File folder = new File(String.valueOf(path)); - folder.mkdirs(); - - File file = new File(path + "/Mod menu log - " + context.getPackageName() + ".txt"); - file.createNewFile(); - - try { - //BufferedWriter for performance, true to set append to file flag - BufferedWriter buf = new BufferedWriter(new FileWriter(file)); - buf.append(log.toString()); - buf.newLine(); - buf.close(); - Toast.makeText(context, "Logcat saved successfully to: " + file.toString(), Toast.LENGTH_LONG).show(); - Toast.makeText(context, "Logcat saved successfully to: " + file.toString(), Toast.LENGTH_LONG).show(); - } catch (IOException e) { - Toast.makeText(context, "There was an error saving logcat to file: " + e.getLocalizedMessage(), Toast.LENGTH_LONG).show(); - e.printStackTrace(); - } - } catch (IOException e) { - Toast.makeText(context, "There was an error saving logcat to file: " + Log.getStackTraceString(e), Toast.LENGTH_LONG).show(); - e.printStackTrace(); - } - } -} diff --git a/app/src/main/java/com/android/support/Main.java b/app/src/main/java/com/android/support/Main.java new file mode 100644 index 00000000..8d74cc3e --- /dev/null +++ b/app/src/main/java/com/android/support/Main.java @@ -0,0 +1,39 @@ +package com.android.support; + +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.net.Uri; +import android.os.Build; +import android.os.Handler; +import android.provider.Settings; +import android.widget.Toast; + +public class Main { + + //Load lib + static { + // When you change the lib name, change also on Android.mk file + // Both must have same name + System.loadLibrary("MyLibName"); + } + + private static native void CheckOverlayPermission(Context context); + + public static void StartWithoutPermission(Context context) { + + if (context instanceof Activity) { + //Check if context is an Activity. + Menu menu = new Menu(context); + menu.SetWindowManagerActivity(); + menu.ShowMenu(); + } else { + //Anything else, ask for permission + CheckOverlayPermission(context); + } + } + + public static void Start(Context context) { + CheckOverlayPermission(context); + } +} diff --git a/app/src/main/java/com/android/support/MainActivity.java b/app/src/main/java/com/android/support/MainActivity.java index 67105cdc..3aacfcec 100644 --- a/app/src/main/java/com/android/support/MainActivity.java +++ b/app/src/main/java/com/android/support/MainActivity.java @@ -1,14 +1,9 @@ package com.android.support; import android.app.Activity; -import android.content.Context; import android.content.Intent; -import android.net.Uri; -import android.os.Build; import android.os.Bundle; -import android.os.Handler; -import android.provider.Settings; -import android.widget.Toast; +import android.util.Log; public class MainActivity extends Activity { @@ -16,59 +11,28 @@ public class MainActivity extends Activity { public String GameActivity = "com.unity3d.player.UnityPlayerActivity"; public boolean hasLaunched = false; - //Load lib - static { - // When you change the lib name, change also on Android.mk file - // Both must have same name - System.loadLibrary("MyLibName"); - } - //To call onCreate, please refer to README.md @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - //To launch mod menu. - Start(this); - //To launch game activity if (!hasLaunched) { try { //Start service - MainActivity.this.startActivity(new Intent(MainActivity.this, Class.forName(MainActivity.this.GameActivity))); hasLaunched = true; + //Launch mod menu. + MainActivity.this.startActivity(new Intent(MainActivity.this, Class.forName(MainActivity.this.GameActivity))); + Main.Start(this); + return; } catch (ClassNotFoundException e) { - //Uncomment this if you are following METHOD 2 of CHANGING FILES + Log.e("Mod_menu", "Error. Game's main activity does not exist"); + //Uncomment this if you are following METHOD 2 to launch menu //Toast.makeText(MainActivity.this, "Error. Game's main activity does not exist", Toast.LENGTH_LONG).show(); - //e.printStackTrace(); - return; } } - } - public static void Start(final Context context) { - //Check if overlay permission is enabled or not - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !Settings.canDrawOverlays(context)) { - Toast.makeText(context.getApplicationContext(), "Overlay permission is required in order to show mod menu. Restart the game after you allow permission", Toast.LENGTH_LONG).show(); - Toast.makeText(context.getApplicationContext(), "Overlay permission is required in order to show mod menu. Restart the game after you allow permission", Toast.LENGTH_LONG).show(); - context.startActivity(new Intent("android.settings.action.MANAGE_OVERLAY_PERMISSION", - Uri.parse("package:" + context.getPackageName()))); - final Handler handler = new Handler(); - handler.postDelayed(new Runnable() { - @Override - public void run() { - System.exit(1); - } - }, 5000); - return; - } else { - final Handler handler = new Handler(); - handler.postDelayed(new Runnable() { - @Override - public void run() { - context.startService(new Intent(context, Menu.class)); - } - }, 500); - } + //Launch mod menu. + Main.StartWithoutPermission(this); } } diff --git a/app/src/main/java/com/android/support/Menu.java b/app/src/main/java/com/android/support/Menu.java index 4d1b8222..71a77bea 100644 --- a/app/src/main/java/com/android/support/Menu.java +++ b/app/src/main/java/com/android/support/Menu.java @@ -2,22 +2,22 @@ package com.android.support; -import android.app.ActivityManager; -import android.app.ActivityManager.RunningAppProcessInfo; +import android.app.Activity; import android.app.AlertDialog; import android.app.Service; +import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.res.ColorStateList; import android.graphics.BitmapFactory; import android.graphics.Color; +import android.graphics.PixelFormat; import android.graphics.PorterDuff; import android.graphics.Typeface; import android.graphics.drawable.GradientDrawable; import android.net.Uri; import android.os.Build; import android.os.Handler; -import android.os.IBinder; import android.text.Html; import android.text.InputFilter; import android.text.InputType; @@ -62,11 +62,12 @@ import static android.widget.RelativeLayout.ALIGN_PARENT_LEFT; import static android.widget.RelativeLayout.ALIGN_PARENT_RIGHT; -public class Menu extends Service { +public class Menu { //********** Here you can easly change the menu appearance **********// //region Variable public static final String TAG = "Mod_Menu"; //Tag for logcat + int TEXT_COLOR = Color.parseColor("#82CAFD"); int TEXT_COLOR_2 = Color.parseColor("#FFFFFF"); int BTN_COLOR = Color.parseColor("#1C262D"); @@ -74,6 +75,9 @@ public class Menu extends Service { int MENU_FEATURE_BG_COLOR = Color.parseColor("#DD141C22"); //#AARRGGBB int MENU_WIDTH = 290; int MENU_HEIGHT = 210; + int POS_X = 0; + int POS_Y = 100; + float MENU_CORNER = 4f; int ICON_SIZE = 45; //Change both width and height of image float ICON_ALPHA = 0.7f; //Transparent @@ -88,64 +92,45 @@ public class Menu extends Service { int RadioColor = Color.parseColor("#FFFFFF"); String NumberTxtColor = "#41c300"; //********************************************************************// + RelativeLayout mCollapsed, mRootContainer; - LinearLayout mExpanded, patches, mSettings, mCollapse; + LinearLayout mExpanded, mods, mSettings, mCollapse; LinearLayout.LayoutParams scrlLLExpanded, scrlLL; WindowManager mWindowManager; - WindowManager.LayoutParams params; + WindowManager.LayoutParams vmParams; ImageView startimage; FrameLayout rootFrame; ScrollView scrollView; - boolean stopChecking; + Context getContext; //initialize methods from the native library - native void setTitleText(TextView textView); - - native void setHeadingText(TextView textView); + native void Init(Context context, TextView title, TextView subTitle); native String Icon(); native String IconWebViewData(); - native String[] getFeatureList(); - - native String[] settingsList(); + native String[] GetFeatureList(); - native boolean isGameLibLoaded(); - //endregion + native String[] SettingsList(); - //When this Class is called the code in this function will be executed - @Override - public void onCreate() { - super.onCreate(); - Preferences.context = this; - - //Create the menu - initFloating(); - - //Create a handler for this Class - final Handler handler = new Handler(); - handler.post(new Runnable() { - public void run() { - Thread(); - handler.postDelayed(this, 1000); - } - }); - } + native boolean IsGameLibLoaded(); //Here we write the code for our Menu // Reference: https://www.androidhive.info/2016/11/android-floating-widget-like-facebook-chat-head/ - private void initFloating() { - rootFrame = new FrameLayout(this); // Global markup + public Menu(Context context) { + getContext = context; + Preferences.context = context; + rootFrame = new FrameLayout(context); // Global markup rootFrame.setOnTouchListener(onTouchListener()); - mRootContainer = new RelativeLayout(this); // Markup on which two markups of the icon and the menu itself will be placed - mCollapsed = new RelativeLayout(this); // Markup of the icon (when the menu is minimized) + mRootContainer = new RelativeLayout(context); // Markup on which two markups of the icon and the menu itself will be placed + mCollapsed = new RelativeLayout(context); // Markup of the icon (when the menu is minimized) mCollapsed.setVisibility(View.VISIBLE); mCollapsed.setAlpha(ICON_ALPHA); //********** The box of the mod menu ********** - mExpanded = new LinearLayout(this); // Menu markup (when the menu is expanded) + mExpanded = new LinearLayout(context); // Menu markup (when the menu is expanded) mExpanded.setVisibility(View.GONE); mExpanded.setBackgroundColor(MENU_BG_COLOR); mExpanded.setOrientation(LinearLayout.VERTICAL); @@ -158,9 +143,9 @@ private void initFloating() { //mExpanded.setBackground(gdMenuBody); //Apply GradientDrawable to it //********** The icon to open mod menu ********** - startimage = new ImageView(this); + startimage = new ImageView(context); startimage.setLayoutParams(new RelativeLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT)); - int applyDimension = (int) TypedValue.applyDimension(1, ICON_SIZE, getResources().getDisplayMetrics()); //Icon size + int applyDimension = (int) TypedValue.applyDimension(1, ICON_SIZE, context.getResources().getDisplayMetrics()); //Icon size startimage.getLayoutParams().height = applyDimension; startimage.getLayoutParams().width = applyDimension; //startimage.requestLayout(); @@ -178,9 +163,9 @@ public void onClick(View view) { }); //********** The icon in Webview to open mod menu ********** - WebView wView = new WebView(this); //Icon size width=\"50\" height=\"50\" + WebView wView = new WebView(context); //Icon size width=\"50\" height=\"50\" wView.setLayoutParams(new RelativeLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT)); - int applyDimension2 = (int) TypedValue.applyDimension(1, ICON_SIZE, getResources().getDisplayMetrics()); //Icon size + int applyDimension2 = (int) TypedValue.applyDimension(1, ICON_SIZE, context.getResources().getDisplayMetrics()); //Icon size wView.getLayoutParams().height = applyDimension2; wView.getLayoutParams().width = applyDimension2; wView.loadData("" + @@ -195,7 +180,7 @@ public void onClick(View view) { wView.setOnTouchListener(onTouchListener()); //********** Settings icon ********** - TextView settings = new TextView(this); //Android 5 can't show ⚙, instead show other icon instead + TextView settings = new TextView(context); //Android 5 can't show ⚙, instead show other icon instead settings.setText(Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M ? "⚙" : "\uD83D\uDD27"); settings.setTextColor(TEXT_COLOR); settings.setTypeface(Typeface.DEFAULT_BOLD); @@ -211,12 +196,12 @@ public void onClick(View v) { try { settingsOpen = !settingsOpen; if (settingsOpen) { - scrollView.removeView(patches); + scrollView.removeView(mods); scrollView.addView(mSettings); scrollView.scrollTo(0, 0); } else { scrollView.removeView(mSettings); - scrollView.addView(patches); + scrollView.addView(mods); } } catch (IllegalStateException e) { } @@ -224,50 +209,47 @@ public void onClick(View v) { }); //********** Settings ********** - mSettings = new LinearLayout(this); + mSettings = new LinearLayout(context); mSettings.setOrientation(LinearLayout.VERTICAL); - featureList(settingsList(), mSettings); + featureList(SettingsList(), mSettings); - //********** Title text ********** - RelativeLayout titleText = new RelativeLayout(this); + //********** Title ********** + RelativeLayout titleText = new RelativeLayout(context); titleText.setPadding(10, 5, 10, 5); titleText.setVerticalGravity(16); - TextView title = new TextView(this); + TextView title = new TextView(context); title.setTextColor(TEXT_COLOR); title.setTextSize(18.0f); title.setGravity(Gravity.CENTER); RelativeLayout.LayoutParams rl = new RelativeLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT); rl.addRule(RelativeLayout.CENTER_HORIZONTAL); title.setLayoutParams(rl); - setTitleText(title); - - //********** Heading text ********** - TextView heading = new TextView(this); - //heading.setText(Html.fromHtml(Heading())); - heading.setEllipsize(TextUtils.TruncateAt.MARQUEE); - heading.setMarqueeRepeatLimit(-1); - heading.setSingleLine(true); - heading.setSelected(true); - heading.setTextColor(TEXT_COLOR); - heading.setTextSize(10.0f); - heading.setGravity(Gravity.CENTER); - heading.setPadding(0, 0, 0, 5); - setHeadingText(heading); + + //********** Sub title ********** + TextView subTitle = new TextView(context); + subTitle.setEllipsize(TextUtils.TruncateAt.MARQUEE); + subTitle.setMarqueeRepeatLimit(-1); + subTitle.setSingleLine(true); + subTitle.setSelected(true); + subTitle.setTextColor(TEXT_COLOR); + subTitle.setTextSize(10.0f); + subTitle.setGravity(Gravity.CENTER); + subTitle.setPadding(0, 0, 0, 5); //********** Mod menu feature list ********** - scrollView = new ScrollView(this); + scrollView = new ScrollView(context); //Auto size. To set size manually, change the width and height example 500, 500 scrlLL = new LinearLayout.LayoutParams(MATCH_PARENT, dp(MENU_HEIGHT)); scrlLLExpanded = new LinearLayout.LayoutParams(mExpanded.getLayoutParams()); scrlLLExpanded.weight = 1.0f; scrollView.setLayoutParams(Preferences.isExpanded ? scrlLLExpanded : scrlLL); scrollView.setBackgroundColor(MENU_FEATURE_BG_COLOR); - patches = new LinearLayout(this); - patches.setOrientation(LinearLayout.VERTICAL); + mods = new LinearLayout(context); + mods.setOrientation(LinearLayout.VERTICAL); //********** RelativeLayout for buttons ********** - RelativeLayout relativeLayout = new RelativeLayout(this); + RelativeLayout relativeLayout = new RelativeLayout(context); relativeLayout.setPadding(10, 3, 10, 3); relativeLayout.setVerticalGravity(Gravity.CENTER); @@ -275,7 +257,7 @@ public void onClick(View v) { RelativeLayout.LayoutParams lParamsHideBtn = new RelativeLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT); lParamsHideBtn.addRule(ALIGN_PARENT_LEFT); - Button hideBtn = new Button(this); + Button hideBtn = new Button(context); hideBtn.setLayoutParams(lParamsHideBtn); hideBtn.setBackgroundColor(Color.TRANSPARENT); hideBtn.setText("HIDE/KILL (Hold)"); @@ -290,8 +272,9 @@ public void onClick(View view) { }); hideBtn.setOnLongClickListener(new View.OnLongClickListener() { public boolean onLongClick(View view) { - Toast.makeText(view.getContext(), "Menu service killed", Toast.LENGTH_LONG).show(); - Menu.this.stopSelf(); + Toast.makeText(view.getContext(), "Menu killed", Toast.LENGTH_LONG).show(); + rootFrame.removeView(mRootContainer); + mWindowManager.removeView(rootFrame); return false; } }); @@ -300,7 +283,7 @@ public boolean onLongClick(View view) { RelativeLayout.LayoutParams lParamsCloseBtn = new RelativeLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT); lParamsCloseBtn.addRule(ALIGN_PARENT_RIGHT); - Button closeBtn = new Button(this); + Button closeBtn = new Button(context); closeBtn.setLayoutParams(lParamsCloseBtn); closeBtn.setBackgroundColor(Color.TRANSPARENT); closeBtn.setText("MINIMIZE"); @@ -313,16 +296,7 @@ public void onClick(View view) { } }); - //********** Params ********** - //Variable to check later if the phone supports Draw over other apps permission - int iparams = Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O ? 2038 : 2002; - params = new WindowManager.LayoutParams(WRAP_CONTENT, WRAP_CONTENT, iparams, 8, -3); - params.gravity = 51; - params.x = 0; - params.y = 100; - //********** Adding view components ********** - rootFrame.addView(mRootContainer); mRootContainer.addView(mCollapsed); mRootContainer.addView(mExpanded); if (IconWebViewData() != null) { @@ -333,14 +307,18 @@ public void onClick(View view) { titleText.addView(title); titleText.addView(settings); mExpanded.addView(titleText); - mExpanded.addView(heading); - scrollView.addView(patches); + mExpanded.addView(subTitle); + scrollView.addView(mods); mExpanded.addView(scrollView); relativeLayout.addView(hideBtn); relativeLayout.addView(closeBtn); mExpanded.addView(relativeLayout); - mWindowManager = (WindowManager) getSystemService(WINDOW_SERVICE); - mWindowManager.addView(rootFrame, params); + + Init(context, title, subTitle); + } + + public void ShowMenu() { + rootFrame.addView(mRootContainer); final Handler handler = new Handler(); handler.postDelayed(new Runnable() { @@ -350,21 +328,55 @@ public void onClick(View view) { public void run() { //If the save preferences is enabled, it will check if game lib is loaded before starting menu //Comment the if-else code out except startService if you want to run the app and test preferences - if (Preferences.loadPref && !isGameLibLoaded() && !stopChecking) { + if (Preferences.loadPref && !IsGameLibLoaded() && !stopChecking) { if (!viewLoaded) { - patches.addView(Category("Save preferences was been enabled. Waiting for game lib to be loaded...\n\nForce load menu may not apply mods instantly. You would need to reactivate them again")); - patches.addView(Button(-100, "Force load menu")); + Category(mods, "Save preferences was been enabled. Waiting for game lib to be loaded...\n\nForce load menu may not apply mods instantly. You would need to reactivate them again"); + Button(mods, -100, "Force load menu"); viewLoaded = true; } handler.postDelayed(this, 600); } else { - patches.removeAllViews(); - featureList(getFeatureList(), patches); + mods.removeAllViews(); + featureList(GetFeatureList(), mods); } } }, 500); } + public void SetWindowManagerWindowService() { + //Variable to check later if the phone supports Draw over other apps permission + int iparams = Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O ? 2038 : 2002; + vmParams = new WindowManager.LayoutParams(WRAP_CONTENT, WRAP_CONTENT, iparams, 8, -3); + //params = new WindowManager.LayoutParams(WindowManager.LayoutParams.LAST_APPLICATION_WINDOW, 8, -3); + vmParams.gravity = 51; + vmParams.x = POS_X; + vmParams.y = POS_Y; + + mWindowManager = (WindowManager) getContext.getSystemService(getContext.WINDOW_SERVICE); + mWindowManager.addView(rootFrame, vmParams); + } + + public void SetWindowManagerActivity() { + vmParams = new WindowManager.LayoutParams( + WindowManager.LayoutParams.WRAP_CONTENT, + WindowManager.LayoutParams.WRAP_CONTENT, + POS_X,//initialX + POS_Y,//initialy + WindowManager.LayoutParams.TYPE_APPLICATION, + WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | + WindowManager.LayoutParams.FLAG_LAYOUT_IN_OVERSCAN | + WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | + WindowManager.LayoutParams.FLAG_SPLIT_TOUCH, + PixelFormat.TRANSPARENT + ); + vmParams.gravity = 51; + vmParams.x = POS_X; + vmParams.y = POS_Y; + + mWindowManager = ((Activity) getContext).getWindowManager(); + mWindowManager.addView(rootFrame, vmParams); + } + private View.OnTouchListener onTouchListener() { return new View.OnTouchListener() { final View collapsedView = mCollapsed; @@ -375,8 +387,8 @@ private View.OnTouchListener onTouchListener() { public boolean onTouch(View view, MotionEvent motionEvent) { switch (motionEvent.getAction()) { case MotionEvent.ACTION_DOWN: - initialX = params.x; - initialY = params.y; + initialX = vmParams.x; + initialY = vmParams.y; initialTouchX = motionEvent.getRawX(); initialTouchY = motionEvent.getRawY(); return true; @@ -403,10 +415,10 @@ public boolean onTouch(View view, MotionEvent motionEvent) { mExpanded.setAlpha(0.5f); mCollapsed.setAlpha(0.5f); //Calculate the X and Y coordinates of the view. - params.x = initialX + ((int) (motionEvent.getRawX() - initialTouchX)); - params.y = initialY + ((int) (motionEvent.getRawY() - initialTouchY)); + vmParams.x = initialX + ((int) (motionEvent.getRawX() - initialTouchX)); + vmParams.y = initialY + ((int) (motionEvent.getRawY() - initialTouchY)); //Update the layout with new X & Y coordinate - mWindowManager.updateViewLayout(rootFrame, params); + mWindowManager.updateViewLayout(rootFrame, vmParams); return true; default: return false; @@ -449,35 +461,35 @@ private void featureList(String[] listFT, LinearLayout linearLayout) { String[] strSplit = feature.split("_"); switch (strSplit[0]) { case "Toggle": - linearLayout.addView(Switch(featNum, strSplit[1], switchedOn)); + Switch(linearLayout, featNum, strSplit[1], switchedOn); break; case "SeekBar": - linearLayout.addView(SeekBar(featNum, strSplit[1], Integer.parseInt(strSplit[2]), Integer.parseInt(strSplit[3]))); + SeekBar(linearLayout, featNum, strSplit[1], Integer.parseInt(strSplit[2]), Integer.parseInt(strSplit[3])); break; case "Button": - linearLayout.addView(Button(featNum, strSplit[1])); + Button(linearLayout, featNum, strSplit[1]); break; case "ButtonOnOff": - linearLayout.addView(ButtonOnOff(featNum, strSplit[1], switchedOn)); + ButtonOnOff(linearLayout, featNum, strSplit[1], switchedOn); break; case "Spinner": - linearLayout.addView(RichTextView(strSplit[1])); - linearLayout.addView(Spinner(featNum, strSplit[1], strSplit[2])); + TextView(linearLayout, strSplit[1]); + Spinner(linearLayout, featNum, strSplit[1], strSplit[2]); break; case "InputText": - linearLayout.addView(TextField(featNum, strSplit[1], false, 0)); + TextField(linearLayout, featNum, strSplit[1], false, 0); break; case "InputValue": if (strSplit.length == 3) - linearLayout.addView(TextField(featNum, strSplit[2], true, Integer.parseInt(strSplit[1]))); + TextField(linearLayout, featNum, strSplit[2], true, Integer.parseInt(strSplit[1])); if (strSplit.length == 2) - linearLayout.addView(TextField(featNum, strSplit[1], true, 0)); + TextField(linearLayout, featNum, strSplit[1], true, 0); break; case "CheckBox": - linearLayout.addView(CheckBox(featNum, strSplit[1], switchedOn)); + CheckBox(linearLayout, featNum, strSplit[1], switchedOn); break; case "RadioButton": - linearLayout.addView(RadioButton(featNum, strSplit[1], strSplit[2])); + RadioButton(linearLayout, featNum, strSplit[1], strSplit[2]); break; case "Collapse": Collapse(linearLayout, strSplit[1]); @@ -485,26 +497,26 @@ private void featureList(String[] listFT, LinearLayout linearLayout) { break; case "ButtonLink": subFeat++; - linearLayout.addView(ButtonLink(strSplit[1], strSplit[2])); + ButtonLink(linearLayout, strSplit[1], strSplit[2]); break; case "Category": subFeat++; - linearLayout.addView(Category(strSplit[1])); + Category(linearLayout, strSplit[1]); break; case "RichTextView": subFeat++; - linearLayout.addView(RichTextView(strSplit[1])); + TextView(linearLayout, strSplit[1]); break; case "RichWebView": subFeat++; - linearLayout.addView(RichWebView(strSplit[1])); + WebTextView(linearLayout, strSplit[1]); break; } } } - private View Switch(final int featNum, final String featName, boolean swiOn) { - final Switch switchR = new Switch(this); + private void Switch(LinearLayout linLayout, final int featNum, final String featName, boolean swiOn) { + final Switch switchR = new Switch(getContext); ColorStateList buttonStates = new ColorStateList( new int[][]{ new int[]{-android.R.attr.state_enabled}, @@ -519,8 +531,12 @@ private View Switch(final int featNum, final String featName, boolean swiOn) { ); //Set colors of the switch. Comment out if you don't like it if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - switchR.getThumbDrawable().setTintList(buttonStates); - switchR.getTrackDrawable().setTintList(buttonStates); + try { + switchR.getThumbDrawable().setTintList(buttonStates); + switchR.getTrackDrawable().setTintList(buttonStates); + } catch (NullPointerException ex) { + Log.d(TAG, String.valueOf(ex)); + } } switchR.setText(featName); switchR.setTextColor(TEXT_COLOR_2); @@ -542,21 +558,22 @@ public void onCheckedChanged(CompoundButton compoundButton, boolean bool) { } } }); - return switchR; + + linLayout.addView(switchR); } - private View SeekBar(final int featNum, final String featName, final int min, int max) { + private void SeekBar(LinearLayout linLayout, final int featNum, final String featName, final int min, int max) { int loadedProg = Preferences.loadPrefInt(featName, featNum); - LinearLayout linearLayout = new LinearLayout(this); + LinearLayout linearLayout = new LinearLayout(getContext); linearLayout.setPadding(10, 5, 0, 5); linearLayout.setOrientation(LinearLayout.VERTICAL); linearLayout.setGravity(Gravity.CENTER); - final TextView textView = new TextView(this); + final TextView textView = new TextView(getContext); textView.setText(Html.fromHtml(featName + ": " + ((loadedProg == 0) ? min : loadedProg))); textView.setTextColor(TEXT_COLOR_2); - SeekBar seekBar = new SeekBar(this); + SeekBar seekBar = new SeekBar(getContext); seekBar.setPadding(25, 10, 35, 10); seekBar.setMax(max); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) @@ -581,11 +598,11 @@ public void onProgressChanged(SeekBar seekBar, int i, boolean z) { linearLayout.addView(textView); linearLayout.addView(seekBar); - return linearLayout; + linLayout.addView(linearLayout); } - private View Button(final int featNum, final String featName) { - final Button button = new Button(this); + private void Button(LinearLayout linLayout, final int featNum, final String featName) { + final Button button = new Button(getContext); LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT); layoutParams.setMargins(7, 5, 7, 5); button.setLayoutParams(layoutParams); @@ -596,15 +613,10 @@ private View Button(final int featNum, final String featName) { button.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { switch (featNum) { - case -4: - Logcat.Save(getApplicationContext()); - break; - case -5: - Logcat.Clear(getApplicationContext()); - break; + case -6: scrollView.removeView(mSettings); - scrollView.addView(patches); + scrollView.addView(mods); break; case -100: stopChecking = true; @@ -614,11 +626,11 @@ public void onClick(View v) { } }); - return button; + linLayout.addView(button); } - private View ButtonLink(final String featName, final String url) { - final Button button = new Button(this); + private void ButtonLink(LinearLayout linLayout, final String featName, final String url) { + final Button button = new Button(getContext); LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT); layoutParams.setMargins(7, 5, 7, 5); button.setLayoutParams(layoutParams); @@ -631,14 +643,14 @@ public void onClick(View v) { Intent intent = new Intent(Intent.ACTION_VIEW); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.setData(Uri.parse(url)); - startActivity(intent); + getContext.startActivity(intent); } }); - return button; + linLayout.addView(button); } - private View ButtonOnOff(final int featNum, String featName, boolean switchedOn) { - final Button button = new Button(this); + private void ButtonOnOff(LinearLayout linLayout, final int featNum, String featName, boolean switchedOn) { + final Button button = new Button(getContext); LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT); layoutParams.setMargins(7, 5, 7, 5); button.setLayoutParams(layoutParams); @@ -674,27 +686,27 @@ public void onClick(View v) { } } }); - return button; + linLayout.addView(button); } - private View Spinner(final int featNum, final String featName, final String list) { + private void Spinner(LinearLayout linLayout, final int featNum, final String featName, final String list) { Log.d(TAG, "spinner " + featNum + " " + featName + " " + list); final List lists = new LinkedList<>(Arrays.asList(list.split(","))); // Create another LinearLayout as a workaround to use it as a background // to keep the down arrow symbol. No arrow symbol if setBackgroundColor set - LinearLayout linearLayout2 = new LinearLayout(this); + LinearLayout linearLayout2 = new LinearLayout(getContext); LinearLayout.LayoutParams layoutParams2 = new LinearLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT); layoutParams2.setMargins(7, 2, 7, 5); linearLayout2.setOrientation(LinearLayout.VERTICAL); linearLayout2.setBackgroundColor(BTN_COLOR); linearLayout2.setLayoutParams(layoutParams2); - final Spinner spinner = new Spinner(this, Spinner.MODE_DROPDOWN); + final Spinner spinner = new Spinner(getContext, Spinner.MODE_DROPDOWN); spinner.setLayoutParams(layoutParams2); spinner.getBackground().setColorFilter(1, PorterDuff.Mode.SRC_ATOP); //trick to show white down arrow color //Creating the ArrayAdapter instance having the list - ArrayAdapter aa = new ArrayAdapter(this, android.R.layout.simple_spinner_dropdown_item, lists); + ArrayAdapter aa = new ArrayAdapter(getContext, android.R.layout.simple_spinner_dropdown_item, lists); aa.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); //Setting the ArrayAdapter data on the Spinner' spinner.setAdapter(aa); @@ -711,17 +723,17 @@ public void onNothingSelected(AdapterView parent) { } }); linearLayout2.addView(spinner); - return linearLayout2; + linLayout.addView(linearLayout2); } - private View TextField(final int featNum, final String featName, final boolean numOnly, final int maxValue) { + private void TextField(LinearLayout linLayout, final int featNum, final String featName, final boolean numOnly, final int maxValue) { final EditTextString edittextstring = new EditTextString(); final EditTextNum edittextnum = new EditTextNum(); - LinearLayout linearLayout = new LinearLayout(this); + LinearLayout linearLayout = new LinearLayout(getContext); LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT); layoutParams.setMargins(7, 5, 7, 5); - final Button button = new Button(this); + final Button button = new Button(getContext); if (numOnly) { int num = Preferences.loadPrefInt(featName, featNum); edittextnum.setNum((num == 0) ? 1 : num); @@ -738,32 +750,32 @@ private View TextField(final int featNum, final String featName, final boolean n button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { - final AlertDialog alert = new AlertDialog.Builder(getApplicationContext(), 2).create(); + final AlertDialog alert = new AlertDialog.Builder(getContext, 2).create(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { Objects.requireNonNull(alert.getWindow()).setType(Build.VERSION.SDK_INT >= 26 ? 2038 : 2002); } alert.setOnCancelListener(new DialogInterface.OnCancelListener() { public void onCancel(DialogInterface dialog) { - InputMethodManager imm = (InputMethodManager) getSystemService(getApplicationContext().INPUT_METHOD_SERVICE); + InputMethodManager imm = (InputMethodManager) getContext.getSystemService(getContext.INPUT_METHOD_SERVICE); imm.toggleSoftInput(InputMethodManager.HIDE_IMPLICIT_ONLY, 0); } }); //LinearLayout - LinearLayout linearLayout1 = new LinearLayout(getApplicationContext()); + LinearLayout linearLayout1 = new LinearLayout(getContext.getApplicationContext()); linearLayout1.setPadding(5, 5, 5, 5); linearLayout1.setOrientation(LinearLayout.VERTICAL); linearLayout1.setBackgroundColor(MENU_FEATURE_BG_COLOR); //TextView - final TextView TextViewNote = new TextView(getApplicationContext()); + final TextView TextViewNote = new TextView(getContext.getApplicationContext()); TextViewNote.setText("Tap OK to apply changes. Tap outside to cancel"); if (maxValue != 0) - TextViewNote.setText("Tap OK to apply changes. Tap outside to cancel\nMax value: " + maxValue); + TextViewNote.setText("Tap OK to apply changes. Tap outside to cancel\nMax value: " + maxValue); TextViewNote.setTextColor(TEXT_COLOR_2); //Edit text - final EditText edittext = new EditText(getApplicationContext()); + final EditText edittext = new EditText(getContext.getApplicationContext()); edittext.setMaxLines(1); edittext.setWidth(convertDipToPixels(300)); edittext.setTextColor(TEXT_COLOR_2); @@ -779,7 +791,7 @@ public void onCancel(DialogInterface dialog) { edittext.setOnFocusChangeListener(new View.OnFocusChangeListener() { @Override public void onFocusChange(View v, boolean hasFocus) { - InputMethodManager imm = (InputMethodManager) getSystemService(getApplicationContext().INPUT_METHOD_SERVICE); + InputMethodManager imm = (InputMethodManager) getContext.getSystemService(getContext.INPUT_METHOD_SERVICE); if (hasFocus) { imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, InputMethodManager.HIDE_IMPLICIT_ONLY); } else { @@ -790,7 +802,7 @@ public void onFocusChange(View v, boolean hasFocus) { edittext.requestFocus(); //Button - Button btndialog = new Button(getApplicationContext()); + Button btndialog = new Button(getContext); btndialog.setBackgroundColor(BTN_COLOR); btndialog.setTextColor(TEXT_COLOR_2); btndialog.setText("OK"); @@ -801,7 +813,7 @@ public void onClick(View view) { int num; try { num = Integer.parseInt(TextUtils.isEmpty(edittext.getText().toString()) ? "0" : edittext.getText().toString()); - if (maxValue != 0 && num >= maxValue) + if (maxValue != 0 && num >= maxValue) num = maxValue; } catch (NumberFormatException ex) { num = 2147483640; @@ -830,11 +842,11 @@ public void onClick(View view) { }); linearLayout.addView(button); - return linearLayout; + linLayout.addView(linearLayout); } - private View CheckBox(final int featNum, final String featName, boolean switchedOn) { - final CheckBox checkBox = new CheckBox(this); + private void CheckBox(LinearLayout linLayout, final int featNum, final String featName, boolean switchedOn) { + final CheckBox checkBox = new CheckBox(getContext); checkBox.setText(featName); checkBox.setTextColor(TEXT_COLOR_2); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) @@ -850,24 +862,24 @@ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { } } }); - return checkBox; + linLayout.addView(checkBox); } - private View RadioButton(final int featNum, String featName, final String list) { + private void RadioButton(LinearLayout linLayout, final int featNum, String featName, final String list) { //Credit: LoraZalora final List lists = new LinkedList<>(Arrays.asList(list.split(","))); - final TextView textView = new TextView(this); + final TextView textView = new TextView(getContext); textView.setText(featName + ":"); textView.setTextColor(TEXT_COLOR_2); - final RadioGroup radioGroup = new RadioGroup(this); + final RadioGroup radioGroup = new RadioGroup(getContext); radioGroup.setPadding(10, 5, 10, 5); radioGroup.setOrientation(LinearLayout.VERTICAL); radioGroup.addView(textView); for (int i = 0; i < lists.size(); i++) { - final RadioButton Radioo = new RadioButton(this); + final RadioButton Radioo = new RadioButton(getContext); final String finalfeatName = featName, radioName = lists.get(i); View.OnClickListener first_radio_listener = new View.OnClickListener() { public void onClick(View v) { @@ -889,20 +901,19 @@ public void onClick(View v) { textView.setText(Html.fromHtml(featName + ": " + lists.get(index - 1))); ((RadioButton) radioGroup.getChildAt(index)).setChecked(true); } - - return radioGroup; + linLayout.addView(radioGroup); } private void Collapse(LinearLayout linLayout, final String text) { LinearLayout.LayoutParams layoutParamsLL = new LinearLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT); layoutParamsLL.setMargins(0, 5, 0, 0); - LinearLayout collapse = new LinearLayout(this); + LinearLayout collapse = new LinearLayout(getContext); collapse.setLayoutParams(layoutParamsLL); collapse.setVerticalGravity(16); collapse.setOrientation(LinearLayout.VERTICAL); - final LinearLayout collapseSub = new LinearLayout(this); + final LinearLayout collapseSub = new LinearLayout(getContext); collapseSub.setVerticalGravity(16); collapseSub.setPadding(0, 5, 0, 5); collapseSub.setOrientation(LinearLayout.VERTICAL); @@ -910,7 +921,7 @@ private void Collapse(LinearLayout linLayout, final String text) { collapseSub.setVisibility(View.GONE); mCollapse = collapseSub; - final TextView textView = new TextView(this); + final TextView textView = new TextView(getContext); textView.setBackgroundColor(CategoryBG); textView.setText("▽ " + text + " ▽"); textView.setGravity(Gravity.CENTER); @@ -923,8 +934,8 @@ private void Collapse(LinearLayout linLayout, final String text) { @Override public void onClick(View v) { - boolean z = !this.isChecked; - this.isChecked = z; + boolean z = !isChecked; + isChecked = z; if (z) { collapseSub.setVisibility(View.VISIBLE); textView.setText("△ " + text + " △"); @@ -939,32 +950,32 @@ public void onClick(View v) { linLayout.addView(collapse); } - private View Category(String text) { - TextView textView = new TextView(this); + private void Category(LinearLayout linLayout, String text) { + TextView textView = new TextView(getContext); textView.setBackgroundColor(CategoryBG); textView.setText(Html.fromHtml(text)); textView.setGravity(Gravity.CENTER); textView.setTextColor(TEXT_COLOR_2); textView.setTypeface(null, Typeface.BOLD); textView.setPadding(0, 5, 0, 5); - return textView; + linLayout.addView(textView); } - private View RichTextView(String text) { - TextView textView = new TextView(this); + private void TextView(LinearLayout linLayout, String text) { + TextView textView = new TextView(getContext); textView.setText(Html.fromHtml(text)); textView.setTextColor(TEXT_COLOR_2); textView.setPadding(10, 5, 10, 5); - return textView; + linLayout.addView(textView); } - private View RichWebView(String text) { - WebView wView = new WebView(this); + private void WebTextView(LinearLayout linLayout, String text) { + WebView wView = new WebView(getContext); wView.loadData(text, "text/html", "utf-8"); wView.setBackgroundColor(0x00000000); //Transparent wView.setPadding(0, 5, 0, 5); wView.getSettings().setAppCacheEnabled(false); - return wView; + linLayout.addView(wView); } //Override our Start Command so the Service doesnt try to recreate itself when the App is closed @@ -978,50 +989,25 @@ private boolean isViewCollapsed() { //For our image a little converter private int convertDipToPixels(int i) { - return (int) ((((float) i) * getResources().getDisplayMetrics().density) + 0.5f); + return (int) ((((float) i) * getContext.getResources().getDisplayMetrics().density) + 0.5f); } private int dp(int i) { - return (int) TypedValue.applyDimension(1, (float) i, getResources().getDisplayMetrics()); + return (int) TypedValue.applyDimension(1, (float) i, getContext.getResources().getDisplayMetrics()); } - //Check if we are still in the game. If now our menu and menu button will dissapear - private boolean isNotInGame() { - RunningAppProcessInfo runningAppProcessInfo = new RunningAppProcessInfo(); - ActivityManager.getMyMemoryState(runningAppProcessInfo); - return runningAppProcessInfo.importance != 100; + public void setVisibility(int view) { + if (rootFrame != null) { + rootFrame.setVisibility(view); + } } - //Destroy our View public void onDestroy() { - super.onDestroy(); if (rootFrame != null) { mWindowManager.removeView(rootFrame); } } - //Same as above so it wont crash in the background and therefore use alot of Battery life - public void onTaskRemoved(Intent intent) { - super.onTaskRemoved(intent); - try { - Thread.sleep(100); - } catch (InterruptedException e) { - e.printStackTrace(); - } - stopSelf(); - } - - private void Thread() { - if (rootFrame == null) { - return; - } - if (isNotInGame()) { - rootFrame.setVisibility(View.INVISIBLE); - } else { - rootFrame.setVisibility(View.VISIBLE); - } - } - private class EditTextString { private String text; @@ -1046,8 +1032,4 @@ public int getNum() { } } - @Override - public IBinder onBind(Intent intent) { - return null; - } } \ No newline at end of file diff --git a/app/src/main/java/uk/lgl/MainActivity.java b/app/src/main/java/uk/lgl/MainActivity.java deleted file mode 100644 index 1a16e15e..00000000 --- a/app/src/main/java/uk/lgl/MainActivity.java +++ /dev/null @@ -1,78 +0,0 @@ -package uk.lgl; - -import android.app.Activity; -import android.content.Context; -import android.content.Intent; -import android.net.Uri; -import android.os.Build; -import android.os.Bundle; -import android.os.Handler; -import android.provider.Settings; -import android.widget.Toast; - -import uk.lgl.modmenu.FloatingModMenuService; - -public class MainActivity extends Activity { - - //Only if you have changed MainActivity to yours and you wanna call game's activity. - public String GameActivity = "com.unity3d.player.UnityPlayerActivity"; - public boolean hasLaunched = false; - - //Load lib - static { - // When you change the lib name, change also on Android.mk file - // Both must have same name - System.loadLibrary("MyLibName"); - } - - //To call onCreate, please refer to README.md - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_main); - - //To launch mod menu. - Start(this); - - //To launch game activity - if (!hasLaunched) { - try { - //Start service - //MainActivity.this.startActivity(new Intent(MainActivity.this, Class.forName(MainActivity.this.GameActivity))); - MainActivity.this.startActivity(new Intent(MainActivity.this, Class.forName(MainActivity.this.GameActivity))); - hasLaunched = true; - } catch (ClassNotFoundException e) { - //Uncomment this if you are following METHOD 2 of CHANGING FILES - //Toast.makeText(MainActivity.this, "Error. Game's main activity does not exist", Toast.LENGTH_LONG).show(); - e.printStackTrace(); - return; - } - } - } - - public static void Start(final Context context) { - //Check if overlay permission is enabled or not - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !Settings.canDrawOverlays(context)) { - Toast.makeText(context.getApplicationContext(), "Overlay permission is required in order to show mod menu. Restart the game after you allow permission", Toast.LENGTH_LONG).show(); - Toast.makeText(context.getApplicationContext(), "Overlay permission is required in order to show mod menu. Restart the game after you allow permission", Toast.LENGTH_LONG).show(); - context.startActivity(new Intent("android.settings.action.MANAGE_OVERLAY_PERMISSION", - Uri.parse("package:" + context.getPackageName()))); - final Handler handler = new Handler(); - handler.postDelayed(new Runnable() { - @Override - public void run() { - System.exit(1); - } - }, 5000); - return; - } else { - final Handler handler = new Handler(); - handler.postDelayed(new Runnable() { - @Override - public void run() { - context.startService(new Intent(context, FloatingModMenuService.class)); - } - }, 500); - } - } -} diff --git a/app/src/main/java/uk/lgl/modmenu/FloatingModMenuService.java b/app/src/main/java/uk/lgl/modmenu/FloatingModMenuService.java deleted file mode 100644 index 572343eb..00000000 --- a/app/src/main/java/uk/lgl/modmenu/FloatingModMenuService.java +++ /dev/null @@ -1,1055 +0,0 @@ -//Please don't replace listeners with lambda! - -package uk.lgl.modmenu; - -import android.animation.ValueAnimator; -import android.annotation.TargetApi; -import android.app.ActivityManager; -import android.app.ActivityManager.RunningAppProcessInfo; -import android.app.AlertDialog; -import android.app.Service; -import android.content.DialogInterface; -import android.content.Intent; -import android.content.res.ColorStateList; -import android.graphics.BitmapFactory; -import android.graphics.Color; -import android.graphics.PorterDuff; -import android.graphics.Typeface; -import android.graphics.drawable.GradientDrawable; -import android.net.Uri; -import android.os.Build; -import android.os.Handler; -import android.os.IBinder; -import android.text.Html; -import android.text.InputFilter; -import android.text.InputType; -import android.text.TextUtils; -import android.text.method.DigitsKeyListener; -import android.util.Base64; -import android.util.Log; -import android.util.TypedValue; -import android.view.Gravity; -import android.view.MotionEvent; -import android.view.View; -import android.view.ViewGroup; -import android.view.WindowManager; -import android.view.inputmethod.InputMethodManager; -import android.webkit.WebView; -import android.widget.AdapterView; -import android.widget.ArrayAdapter; -import android.widget.Button; -import android.widget.CheckBox; -import android.widget.CompoundButton; -import android.widget.EditText; -import android.widget.FrameLayout; -import android.widget.ImageView; -import android.widget.LinearLayout; -import android.widget.RadioButton; -import android.widget.RadioGroup; -import android.widget.RelativeLayout; -import android.widget.ScrollView; -import android.widget.SeekBar; -import android.widget.Spinner; -import android.widget.Switch; -import android.widget.TextView; -import android.widget.Toast; - -import java.util.Arrays; -import java.util.LinkedList; -import java.util.List; -import java.util.Objects; - -import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; -import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; -import static android.widget.RelativeLayout.ALIGN_PARENT_LEFT; -import static android.widget.RelativeLayout.ALIGN_PARENT_RIGHT; - -public class FloatingModMenuService extends Service { - //********** Here you can easly change the menu appearance **********// - - //region Variable - public static final String TAG = "Mod_Menu"; //Tag for logcat - int TEXT_COLOR = Color.parseColor("#82CAFD"); - int TEXT_COLOR_2 = Color.parseColor("#FFFFFF"); - int BTN_COLOR = Color.parseColor("#1C262D"); - int MENU_BG_COLOR = Color.parseColor("#EE1C2A35"); //#AARRGGBB - int MENU_FEATURE_BG_COLOR = Color.parseColor("#DD141C22"); //#AARRGGBB - int MENU_WIDTH = 290; - int MENU_HEIGHT = 210; - float MENU_CORNER = 4f; - int ICON_SIZE = 45; //Change both width and height of image - float ICON_ALPHA = 0.7f; //Transparent - int ToggleON = Color.GREEN; - int ToggleOFF = Color.RED; - int BtnON = Color.parseColor("#1b5e20"); - int BtnOFF = Color.parseColor("#7f0000"); - int CategoryBG = Color.parseColor("#2F3D4C"); - int SeekBarColor = Color.parseColor("#80CBC4"); - int SeekBarProgressColor = Color.parseColor("#80CBC4"); - int CheckBoxColor = Color.parseColor("#80CBC4"); - int RadioColor = Color.parseColor("#FFFFFF"); - String NumberTxtColor = "#41c300"; - //********************************************************************// - RelativeLayout mCollapsed, mRootContainer; - LinearLayout mExpanded, patches, mSettings, mCollapse; - LinearLayout.LayoutParams scrlLLExpanded, scrlLL; - WindowManager mWindowManager; - WindowManager.LayoutParams params; - ImageView startimage; - FrameLayout rootFrame; - ScrollView scrollView; - - boolean stopChecking; - - //initialize methods from the native library - native void setTitleText(TextView textView); - - native void setHeadingText(TextView textView); - - native String Icon(); - - native String IconWebViewData(); - - native String[] getFeatureList(); - - native String[] settingsList(); - - native boolean isGameLibLoaded(); - //endregion - - //When this Class is called the code in this function will be executed - @Override - public void onCreate() { - super.onCreate(); - Preferences.context = this; - - //Create the menu - initFloating(); - - //Create a handler for this Class - final Handler handler = new Handler(); - handler.post(new Runnable() { - public void run() { - Thread(); - handler.postDelayed(this, 1000); - } - }); - } - - //Here we write the code for our Menu - // Reference: https://www.androidhive.info/2016/11/android-floating-widget-like-facebook-chat-head/ - private void initFloating() { - rootFrame = new FrameLayout(this); // Global markup - rootFrame.setOnTouchListener(onTouchListener()); - mRootContainer = new RelativeLayout(this); // Markup on which two markups of the icon and the menu itself will be placed - mCollapsed = new RelativeLayout(this); // Markup of the icon (when the menu is minimized) - mCollapsed.setVisibility(View.VISIBLE); - mCollapsed.setAlpha(ICON_ALPHA); - - //********** The box of the mod menu ********** - mExpanded = new LinearLayout(this); // Menu markup (when the menu is expanded) - mExpanded.setVisibility(View.GONE); - mExpanded.setBackgroundColor(MENU_BG_COLOR); - mExpanded.setOrientation(LinearLayout.VERTICAL); - // mExpanded.setPadding(1, 1, 1, 1); //So borders would be visible - mExpanded.setLayoutParams(new LinearLayout.LayoutParams(dp(MENU_WIDTH), WRAP_CONTENT)); - GradientDrawable gdMenuBody = new GradientDrawable(); - gdMenuBody.setCornerRadius(MENU_CORNER); //Set corner - gdMenuBody.setColor(MENU_BG_COLOR); //Set background color - gdMenuBody.setStroke(1, Color.parseColor("#32cb00")); //Set border - //mExpanded.setBackground(gdMenuBody); //Apply GradientDrawable to it - - //********** The icon to open mod menu ********** - startimage = new ImageView(this); - startimage.setLayoutParams(new RelativeLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT)); - int applyDimension = (int) TypedValue.applyDimension(1, ICON_SIZE, getResources().getDisplayMetrics()); //Icon size - startimage.getLayoutParams().height = applyDimension; - startimage.getLayoutParams().width = applyDimension; - //startimage.requestLayout(); - startimage.setScaleType(ImageView.ScaleType.FIT_XY); - byte[] decode = Base64.decode(Icon(), 0); - startimage.setImageBitmap(BitmapFactory.decodeByteArray(decode, 0, decode.length)); - ((ViewGroup.MarginLayoutParams) startimage.getLayoutParams()).topMargin = convertDipToPixels(10); - //Initialize event handlers for buttons, etc. - startimage.setOnTouchListener(onTouchListener()); - startimage.setOnClickListener(new View.OnClickListener() { - public void onClick(View view) { - mCollapsed.setVisibility(View.GONE); - mExpanded.setVisibility(View.VISIBLE); - } - }); - - //********** The icon in Webview to open mod menu ********** - WebView wView = new WebView(this); //Icon size width=\"50\" height=\"50\" - wView.setLayoutParams(new RelativeLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT)); - int applyDimension2 = (int) TypedValue.applyDimension(1, ICON_SIZE, getResources().getDisplayMetrics()); //Icon size - wView.getLayoutParams().height = applyDimension2; - wView.getLayoutParams().width = applyDimension2; - wView.loadData("" + - "" + - "" + - "" + - "" + - "", "text/html", "utf-8"); - wView.setBackgroundColor(0x00000000); //Transparent - wView.setAlpha(ICON_ALPHA); - wView.getSettings().setAppCacheEnabled(true); - wView.setOnTouchListener(onTouchListener()); - - //********** Settings icon ********** - TextView settings = new TextView(this); //Android 5 can't show ⚙, instead show other icon instead - settings.setText(Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M ? "⚙" : "\uD83D\uDD27"); - settings.setTextColor(TEXT_COLOR); - settings.setTypeface(Typeface.DEFAULT_BOLD); - settings.setTextSize(20.0f); - RelativeLayout.LayoutParams rlsettings = new RelativeLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT); - rlsettings.addRule(ALIGN_PARENT_RIGHT); - settings.setLayoutParams(rlsettings); - settings.setOnClickListener(new View.OnClickListener() { - boolean settingsOpen; - - @Override - public void onClick(View v) { - try { - settingsOpen = !settingsOpen; - if (settingsOpen) { - scrollView.removeView(patches); - scrollView.addView(mSettings); - scrollView.scrollTo(0, 0); - } else { - scrollView.removeView(mSettings); - scrollView.addView(patches); - } - } catch (IllegalStateException e) { - } - } - }); - - //********** Settings ********** - mSettings = new LinearLayout(this); - mSettings.setOrientation(LinearLayout.VERTICAL); - featureList(settingsList(), mSettings); - - //********** Title text ********** - RelativeLayout titleText = new RelativeLayout(this); - titleText.setPadding(10, 5, 10, 5); - titleText.setVerticalGravity(16); - - TextView title = new TextView(this); - title.setTextColor(TEXT_COLOR); - title.setTextSize(18.0f); - title.setGravity(Gravity.CENTER); - RelativeLayout.LayoutParams rl = new RelativeLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT); - rl.addRule(RelativeLayout.CENTER_HORIZONTAL); - title.setLayoutParams(rl); - setTitleText(title); - - //********** Heading text ********** - TextView heading = new TextView(this); - //heading.setText(Html.fromHtml(Heading())); - heading.setEllipsize(TextUtils.TruncateAt.MARQUEE); - heading.setMarqueeRepeatLimit(-1); - heading.setSingleLine(true); - heading.setSelected(true); - heading.setTextColor(TEXT_COLOR); - heading.setTextSize(10.0f); - heading.setGravity(Gravity.CENTER); - heading.setPadding(0, 0, 0, 5); - setHeadingText(heading); - - //********** Mod menu feature list ********** - scrollView = new ScrollView(this); - //Auto size. To set size manually, change the width and height example 500, 500 - scrlLL = new LinearLayout.LayoutParams(MATCH_PARENT, dp(MENU_HEIGHT)); - scrlLLExpanded = new LinearLayout.LayoutParams(mExpanded.getLayoutParams()); - scrlLLExpanded.weight = 1.0f; - scrollView.setLayoutParams(Preferences.isExpanded ? scrlLLExpanded : scrlLL); - scrollView.setBackgroundColor(MENU_FEATURE_BG_COLOR); - patches = new LinearLayout(this); - patches.setOrientation(LinearLayout.VERTICAL); - - //********** RelativeLayout for buttons ********** - RelativeLayout relativeLayout = new RelativeLayout(this); - relativeLayout.setPadding(10, 3, 10, 3); - relativeLayout.setVerticalGravity(Gravity.CENTER); - - //********** Hide/Kill button ********** - RelativeLayout.LayoutParams lParamsHideBtn = new RelativeLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT); - lParamsHideBtn.addRule(ALIGN_PARENT_LEFT); - - Button hideBtn = new Button(this); - hideBtn.setLayoutParams(lParamsHideBtn); - hideBtn.setBackgroundColor(Color.TRANSPARENT); - hideBtn.setText("HIDE/KILL (Hold)"); - hideBtn.setTextColor(TEXT_COLOR); - hideBtn.setOnClickListener(new View.OnClickListener() { - public void onClick(View view) { - mCollapsed.setVisibility(View.VISIBLE); - mCollapsed.setAlpha(0); - mExpanded.setVisibility(View.GONE); - Toast.makeText(view.getContext(), "Icon hidden. Remember the hidden icon position", Toast.LENGTH_LONG).show(); - } - }); - hideBtn.setOnLongClickListener(new View.OnLongClickListener() { - public boolean onLongClick(View view) { - Toast.makeText(view.getContext(), "Menu service killed", Toast.LENGTH_LONG).show(); - FloatingModMenuService.this.stopSelf(); - return false; - } - }); - - //********** Close button ********** - RelativeLayout.LayoutParams lParamsCloseBtn = new RelativeLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT); - lParamsCloseBtn.addRule(ALIGN_PARENT_RIGHT); - - Button closeBtn = new Button(this); - closeBtn.setLayoutParams(lParamsCloseBtn); - closeBtn.setBackgroundColor(Color.TRANSPARENT); - closeBtn.setText("MINIMIZE"); - closeBtn.setTextColor(TEXT_COLOR); - closeBtn.setOnClickListener(new View.OnClickListener() { - public void onClick(View view) { - mCollapsed.setVisibility(View.VISIBLE); - mCollapsed.setAlpha(ICON_ALPHA); - mExpanded.setVisibility(View.GONE); - } - }); - - //********** Params ********** - //Variable to check later if the phone supports Draw over other apps permission - int iparams = Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O ? 2038 : 2002; - params = new WindowManager.LayoutParams(WRAP_CONTENT, WRAP_CONTENT, iparams, 8, -3); - params.gravity = 51; - params.x = 0; - params.y = 100; - - //********** Adding view components ********** - rootFrame.addView(mRootContainer); - mRootContainer.addView(mCollapsed); - mRootContainer.addView(mExpanded); - if (IconWebViewData() != null) { - mCollapsed.addView(wView); - } else { - mCollapsed.addView(startimage); - } - titleText.addView(title); - titleText.addView(settings); - mExpanded.addView(titleText); - mExpanded.addView(heading); - scrollView.addView(patches); - mExpanded.addView(scrollView); - relativeLayout.addView(hideBtn); - relativeLayout.addView(closeBtn); - mExpanded.addView(relativeLayout); - mWindowManager = (WindowManager) getSystemService(WINDOW_SERVICE); - mWindowManager.addView(rootFrame, params); - - final Handler handler = new Handler(); - handler.postDelayed(new Runnable() { - boolean viewLoaded = false; - - @Override - public void run() { - //If the save preferences is enabled, it will check if game lib is loaded before starting menu - //Comment the if-else code out except startService if you want to run the app and test preferences - if (Preferences.loadPref && !isGameLibLoaded() && !stopChecking) { - if (!viewLoaded) { - patches.addView(Category("Save preferences was been enabled. Waiting for game lib to be loaded...\n\nForce load menu may not apply mods instantly. You would need to reactivate them again")); - patches.addView(Button(-100, "Force load menu")); - viewLoaded = true; - } - handler.postDelayed(this, 600); - } else { - patches.removeAllViews(); - featureList(getFeatureList(), patches); - } - } - }, 500); - } - - private View.OnTouchListener onTouchListener() { - return new View.OnTouchListener() { - final View collapsedView = mCollapsed; - final View expandedView = mExpanded; - private float initialTouchX, initialTouchY; - private int initialX, initialY; - - public boolean onTouch(View view, MotionEvent motionEvent) { - switch (motionEvent.getAction()) { - case MotionEvent.ACTION_DOWN: - initialX = params.x; - initialY = params.y; - initialTouchX = motionEvent.getRawX(); - initialTouchY = motionEvent.getRawY(); - return true; - case MotionEvent.ACTION_UP: - int rawX = (int) (motionEvent.getRawX() - initialTouchX); - int rawY = (int) (motionEvent.getRawY() - initialTouchY); - mExpanded.setAlpha(1f); - mCollapsed.setAlpha(1f); - //The check for Xdiff <10 && YDiff< 10 because sometime elements moves a little while clicking. - //So that is click event. - if (rawX < 10 && rawY < 10 && isViewCollapsed()) { - //When user clicks on the image view of the collapsed layout, - //visibility of the collapsed layout will be changed to "View.GONE" - //and expanded view will become visible. - try { - collapsedView.setVisibility(View.GONE); - expandedView.setVisibility(View.VISIBLE); - } catch (NullPointerException e) { - - } - } - return true; - case MotionEvent.ACTION_MOVE: - mExpanded.setAlpha(0.5f); - mCollapsed.setAlpha(0.5f); - //Calculate the X and Y coordinates of the view. - params.x = initialX + ((int) (motionEvent.getRawX() - initialTouchX)); - params.y = initialY + ((int) (motionEvent.getRawY() - initialTouchY)); - //Update the layout with new X & Y coordinate - mWindowManager.updateViewLayout(rootFrame, params); - return true; - default: - return false; - } - } - }; - } - - private void featureList(String[] listFT, LinearLayout linearLayout) { - //Currently looks messy right now. Let me know if you have improvements - int featNum, subFeat = 0; - LinearLayout llBak = linearLayout; - - for (int i = 0; i < listFT.length; i++) { - boolean switchedOn = false; - //Log.i("featureList", listFT[i]); - String feature = listFT[i]; - if (feature.contains("True_")) { - switchedOn = true; - feature = feature.replaceFirst("True_", ""); - } - - linearLayout = llBak; - if (feature.contains("CollapseAdd_")) { - //if (collapse != null) - linearLayout = mCollapse; - feature = feature.replaceFirst("CollapseAdd_", ""); - } - String[] str = feature.split("_"); - - //Assign feature number - if (TextUtils.isDigitsOnly(str[0]) || str[0].matches("-[0-9]*")) { - featNum = Integer.parseInt(str[0]); - feature = feature.replaceFirst(str[0] + "_", ""); - subFeat++; - } else { - //Subtract feature number. We don't want to count ButtonLink, Category, RichTextView and RichWebView - featNum = i - subFeat; - } - String[] strSplit = feature.split("_"); - switch (strSplit[0]) { - case "Toggle": - linearLayout.addView(Switch(featNum, strSplit[1], switchedOn)); - break; - case "SeekBar": - linearLayout.addView(SeekBar(featNum, strSplit[1], Integer.parseInt(strSplit[2]), Integer.parseInt(strSplit[3]))); - break; - case "Button": - linearLayout.addView(Button(featNum, strSplit[1])); - break; - case "ButtonOnOff": - linearLayout.addView(ButtonOnOff(featNum, strSplit[1], switchedOn)); - break; - case "Spinner": - linearLayout.addView(RichTextView(strSplit[1])); - linearLayout.addView(Spinner(featNum, strSplit[1], strSplit[2])); - break; - case "InputText": - linearLayout.addView(TextField(featNum, strSplit[1], false, 0)); - break; - case "InputValue": - if (strSplit.length == 3) - linearLayout.addView(TextField(featNum, strSplit[2], true, Integer.parseInt(strSplit[1]))); - if (strSplit.length == 2) - linearLayout.addView(TextField(featNum, strSplit[1], true, 0)); - break; - case "CheckBox": - linearLayout.addView(CheckBox(featNum, strSplit[1], switchedOn)); - break; - case "RadioButton": - linearLayout.addView(RadioButton(featNum, strSplit[1], strSplit[2])); - break; - case "Collapse": - Collapse(linearLayout, strSplit[1]); - subFeat++; - break; - case "ButtonLink": - subFeat++; - linearLayout.addView(ButtonLink(strSplit[1], strSplit[2])); - break; - case "Category": - subFeat++; - linearLayout.addView(Category(strSplit[1])); - break; - case "RichTextView": - subFeat++; - linearLayout.addView(RichTextView(strSplit[1])); - break; - case "RichWebView": - subFeat++; - linearLayout.addView(RichWebView(strSplit[1])); - break; - } - } - } - - private View Switch(final int featNum, final String featName, boolean swiOn) { - final Switch switchR = new Switch(this); - ColorStateList buttonStates = new ColorStateList( - new int[][]{ - new int[]{-android.R.attr.state_enabled}, - new int[]{android.R.attr.state_checked}, - new int[]{} - }, - new int[]{ - Color.BLUE, - ToggleON, // ON - ToggleOFF // OFF - } - ); - //Set colors of the switch. Comment out if you don't like it - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - switchR.getThumbDrawable().setTintList(buttonStates); - switchR.getTrackDrawable().setTintList(buttonStates); - } - switchR.setText(featName); - switchR.setTextColor(TEXT_COLOR_2); - switchR.setPadding(10, 5, 0, 5); - switchR.setChecked(Preferences.loadPrefBool(featName, featNum, swiOn)); - switchR.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { - public void onCheckedChanged(CompoundButton compoundButton, boolean bool) { - Preferences.changeFeatureBool(featName, featNum, bool); - switch (featNum) { - case -1: //Save perferences - Preferences.with(switchR.getContext()).writeBoolean(-1, bool); - if (bool == false) - Preferences.with(switchR.getContext()).clear(); //Clear perferences if switched off - break; - case -3: - Preferences.isExpanded = bool; - scrollView.setLayoutParams(bool ? scrlLLExpanded : scrlLL); - break; - } - } - }); - return switchR; - } - - private View SeekBar(final int featNum, final String featName, final int min, int max) { - int loadedProg = Preferences.loadPrefInt(featName, featNum); - LinearLayout linearLayout = new LinearLayout(this); - linearLayout.setPadding(10, 5, 0, 5); - linearLayout.setOrientation(LinearLayout.VERTICAL); - linearLayout.setGravity(Gravity.CENTER); - - final TextView textView = new TextView(this); - textView.setText(Html.fromHtml(featName + ": " + ((loadedProg == 0) ? min : loadedProg))); - textView.setTextColor(TEXT_COLOR_2); - - SeekBar seekBar = new SeekBar(this); - seekBar.setPadding(25, 10, 35, 10); - seekBar.setMax(max); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) - seekBar.setMin(min); //setMin for Oreo and above - seekBar.setProgress((loadedProg == 0) ? min : loadedProg); - seekBar.getThumb().setColorFilter(SeekBarColor, PorterDuff.Mode.SRC_ATOP); - seekBar.getProgressDrawable().setColorFilter(SeekBarProgressColor, PorterDuff.Mode.SRC_ATOP); - seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { - public void onStartTrackingTouch(SeekBar seekBar) { - } - - public void onStopTrackingTouch(SeekBar seekBar) { - } - - public void onProgressChanged(SeekBar seekBar, int i, boolean z) { - //if progress is greater than minimum, don't go below. Else, set progress - seekBar.setProgress(i < min ? min : i); - Preferences.changeFeatureInt(featName, featNum, i < min ? min : i); - textView.setText(Html.fromHtml(featName + ": " + (i < min ? min : i))); - } - }); - linearLayout.addView(textView); - linearLayout.addView(seekBar); - - return linearLayout; - } - - private View Button(final int featNum, final String featName) { - final Button button = new Button(this); - LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT); - layoutParams.setMargins(7, 5, 7, 5); - button.setLayoutParams(layoutParams); - button.setTextColor(TEXT_COLOR_2); - button.setAllCaps(false); //Disable caps to support html - button.setText(Html.fromHtml(featName)); - button.setBackgroundColor(BTN_COLOR); - button.setOnClickListener(new View.OnClickListener() { - public void onClick(View v) { - switch (featNum) { - case -4: - Logcat.Save(getApplicationContext()); - break; - case -5: - Logcat.Clear(getApplicationContext()); - break; - case -6: - scrollView.removeView(mSettings); - scrollView.addView(patches); - break; - case -100: - stopChecking = true; - break; - } - Preferences.changeFeatureInt(featName, featNum, 0); - } - }); - - return button; - } - - private View ButtonLink(final String featName, final String url) { - final Button button = new Button(this); - LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT); - layoutParams.setMargins(7, 5, 7, 5); - button.setLayoutParams(layoutParams); - button.setAllCaps(false); //Disable caps to support html - button.setTextColor(TEXT_COLOR_2); - button.setText(Html.fromHtml(featName)); - button.setBackgroundColor(BTN_COLOR); - button.setOnClickListener(new View.OnClickListener() { - public void onClick(View v) { - Intent intent = new Intent(Intent.ACTION_VIEW); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - intent.setData(Uri.parse(url)); - startActivity(intent); - } - }); - return button; - } - - private View ButtonOnOff(final int featNum, String featName, boolean switchedOn) { - final Button button = new Button(this); - LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT); - layoutParams.setMargins(7, 5, 7, 5); - button.setLayoutParams(layoutParams); - button.setTextColor(TEXT_COLOR_2); - button.setAllCaps(false); //Disable caps to support html - - final String finalfeatName = featName.replace("OnOff_", ""); - boolean isOn = Preferences.loadPrefBool(featName, featNum, switchedOn); - if (isOn) { - button.setText(Html.fromHtml(finalfeatName + ": ON")); - button.setBackgroundColor(BtnON); - isOn = false; - } else { - button.setText(Html.fromHtml(finalfeatName + ": OFF")); - button.setBackgroundColor(BtnOFF); - isOn = true; - } - final boolean finalIsOn = isOn; - button.setOnClickListener(new View.OnClickListener() { - boolean isOn = finalIsOn; - - public void onClick(View v) { - Preferences.changeFeatureBool(finalfeatName, featNum, isOn); - //Log.d(TAG, finalfeatName + " " + featNum + " " + isActive2); - if (isOn) { - button.setText(Html.fromHtml(finalfeatName + ": ON")); - button.setBackgroundColor(BtnON); - isOn = false; - } else { - button.setText(Html.fromHtml(finalfeatName + ": OFF")); - button.setBackgroundColor(BtnOFF); - isOn = true; - } - } - }); - return button; - } - - private View Spinner(final int featNum, final String featName, final String list) { - Log.d(TAG, "spinner " + featNum + " " + featName + " " + list); - final List lists = new LinkedList<>(Arrays.asList(list.split(","))); - - // Create another LinearLayout as a workaround to use it as a background - // to keep the down arrow symbol. No arrow symbol if setBackgroundColor set - LinearLayout linearLayout2 = new LinearLayout(this); - LinearLayout.LayoutParams layoutParams2 = new LinearLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT); - layoutParams2.setMargins(7, 2, 7, 5); - linearLayout2.setOrientation(LinearLayout.VERTICAL); - linearLayout2.setBackgroundColor(BTN_COLOR); - linearLayout2.setLayoutParams(layoutParams2); - - final Spinner spinner = new Spinner(this, Spinner.MODE_DROPDOWN); - spinner.setLayoutParams(layoutParams2); - spinner.getBackground().setColorFilter(1, PorterDuff.Mode.SRC_ATOP); //trick to show white down arrow color - //Creating the ArrayAdapter instance having the list - ArrayAdapter aa = new ArrayAdapter(this, android.R.layout.simple_spinner_dropdown_item, lists); - aa.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); - //Setting the ArrayAdapter data on the Spinner' - spinner.setAdapter(aa); - spinner.setSelection(Preferences.loadPrefInt(featName, featNum)); - spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { - @Override - public void onItemSelected(AdapterView parentView, View selectedItemView, int position, long id) { - Preferences.changeFeatureInt(spinner.getSelectedItem().toString(), featNum, position); - ((TextView) parentView.getChildAt(0)).setTextColor(TEXT_COLOR_2); - } - - @Override - public void onNothingSelected(AdapterView parent) { - } - }); - linearLayout2.addView(spinner); - return linearLayout2; - } - - private View TextField(final int featNum, final String featName, final boolean numOnly, final int maxValue) { - final EditTextString edittextstring = new EditTextString(); - final EditTextNum edittextnum = new EditTextNum(); - LinearLayout linearLayout = new LinearLayout(this); - LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT); - layoutParams.setMargins(7, 5, 7, 5); - - final Button button = new Button(this); - if (numOnly) { - int num = Preferences.loadPrefInt(featName, featNum); - edittextnum.setNum((num == 0) ? 1 : num); - button.setText(Html.fromHtml(featName + ": " + ((num == 0) ? 1 : num) + "")); - } else { - String string = Preferences.loadPrefString(featName, featNum); - edittextstring.setString((string == "") ? "" : string); - button.setText(Html.fromHtml(featName + ": " + string + "")); - } - button.setAllCaps(false); - button.setLayoutParams(layoutParams); - button.setBackgroundColor(BTN_COLOR); - button.setTextColor(TEXT_COLOR_2); - button.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - final AlertDialog alert = new AlertDialog.Builder(getApplicationContext(), 2).create(); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { - Objects.requireNonNull(alert.getWindow()).setType(Build.VERSION.SDK_INT >= 26 ? 2038 : 2002); - } - alert.setOnCancelListener(new DialogInterface.OnCancelListener() { - public void onCancel(DialogInterface dialog) { - InputMethodManager imm = (InputMethodManager) getSystemService(getApplicationContext().INPUT_METHOD_SERVICE); - imm.toggleSoftInput(InputMethodManager.HIDE_IMPLICIT_ONLY, 0); - } - }); - - //LinearLayout - LinearLayout linearLayout1 = new LinearLayout(getApplicationContext()); - linearLayout1.setPadding(5, 5, 5, 5); - linearLayout1.setOrientation(LinearLayout.VERTICAL); - linearLayout1.setBackgroundColor(MENU_FEATURE_BG_COLOR); - - //TextView - final TextView TextViewNote = new TextView(getApplicationContext()); - TextViewNote.setText("Tap OK to apply changes. Tap outside to cancel"); - if (maxValue != 0) - TextViewNote.setText("Tap OK to apply changes. Tap outside to cancel\nMax value: " + maxValue); - TextViewNote.setTextColor(TEXT_COLOR_2); - - //Edit text - final EditText edittext = new EditText(getApplicationContext()); - edittext.setMaxLines(1); - edittext.setWidth(convertDipToPixels(300)); - edittext.setTextColor(TEXT_COLOR_2); - if (numOnly) { - edittext.setInputType(InputType.TYPE_CLASS_NUMBER); - edittext.setKeyListener(DigitsKeyListener.getInstance("0123456789-")); - InputFilter[] FilterArray = new InputFilter[1]; - FilterArray[0] = new InputFilter.LengthFilter(10); - edittext.setFilters(FilterArray); - } else { - edittext.setText(edittextstring.getString()); - } - edittext.setOnFocusChangeListener(new View.OnFocusChangeListener() { - @Override - public void onFocusChange(View v, boolean hasFocus) { - InputMethodManager imm = (InputMethodManager) getSystemService(getApplicationContext().INPUT_METHOD_SERVICE); - if (hasFocus) { - imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, InputMethodManager.HIDE_IMPLICIT_ONLY); - } else { - imm.toggleSoftInput(InputMethodManager.HIDE_IMPLICIT_ONLY, 0); - } - } - }); - edittext.requestFocus(); - - //Button - Button btndialog = new Button(getApplicationContext()); - btndialog.setBackgroundColor(BTN_COLOR); - btndialog.setTextColor(TEXT_COLOR_2); - btndialog.setText("OK"); - btndialog.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - if (numOnly) { - int num; - try { - num = Integer.parseInt(TextUtils.isEmpty(edittext.getText().toString()) ? "0" : edittext.getText().toString()); - if (maxValue != 0 && num >= maxValue) - num = maxValue; - } catch (NumberFormatException ex) { - num = 2147483640; - } - edittextnum.setNum(num); - button.setText(Html.fromHtml(featName + ": " + num + "")); - alert.dismiss(); - Preferences.changeFeatureInt(featName, featNum, num); - } else { - String str = edittext.getText().toString(); - edittextstring.setString(edittext.getText().toString()); - button.setText(Html.fromHtml(featName + ": " + str + "")); - alert.dismiss(); - Preferences.changeFeatureString(featName, featNum, str); - } - edittext.setFocusable(false); - } - }); - - linearLayout1.addView(TextViewNote); - linearLayout1.addView(edittext); - linearLayout1.addView(btndialog); - alert.setView(linearLayout1); - alert.show(); - } - }); - - linearLayout.addView(button); - return linearLayout; - } - - private View CheckBox(final int featNum, final String featName, boolean switchedOn) { - final CheckBox checkBox = new CheckBox(this); - checkBox.setText(featName); - checkBox.setTextColor(TEXT_COLOR_2); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) - checkBox.setButtonTintList(ColorStateList.valueOf(CheckBoxColor)); - checkBox.setChecked(Preferences.loadPrefBool(featName, featNum, switchedOn)); - checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { - @Override - public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { - if (checkBox.isChecked()) { - Preferences.changeFeatureBool(featName, featNum, isChecked); - } else { - Preferences.changeFeatureBool(featName, featNum, isChecked); - } - } - }); - return checkBox; - } - - private View RadioButton(final int featNum, String featName, final String list) { - //Credit: LoraZalora - final List lists = new LinkedList<>(Arrays.asList(list.split(","))); - - final TextView textView = new TextView(this); - textView.setText(featName + ":"); - textView.setTextColor(TEXT_COLOR_2); - - final RadioGroup radioGroup = new RadioGroup(this); - radioGroup.setPadding(10, 5, 10, 5); - radioGroup.setOrientation(LinearLayout.VERTICAL); - radioGroup.addView(textView); - - for (int i = 0; i < lists.size(); i++) { - final RadioButton Radioo = new RadioButton(this); - final String finalfeatName = featName, radioName = lists.get(i); - View.OnClickListener first_radio_listener = new View.OnClickListener() { - public void onClick(View v) { - textView.setText(Html.fromHtml(finalfeatName + ": " + radioName)); - Preferences.changeFeatureInt(finalfeatName, featNum, radioGroup.indexOfChild(Radioo)); - } - }; - System.out.println(lists.get(i)); - Radioo.setText(lists.get(i)); - Radioo.setTextColor(Color.LTGRAY); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) - Radioo.setButtonTintList(ColorStateList.valueOf(RadioColor)); - Radioo.setOnClickListener(first_radio_listener); - radioGroup.addView(Radioo); - } - - int index = Preferences.loadPrefInt(featName, featNum); - if (index > 0) { //Preventing it to get an index less than 1. below 1 = null = crash - textView.setText(Html.fromHtml(featName + ": " + lists.get(index - 1))); - ((RadioButton) radioGroup.getChildAt(index)).setChecked(true); - } - - return radioGroup; - } - - private void Collapse(LinearLayout linLayout, final String text) { - LinearLayout.LayoutParams layoutParamsLL = new LinearLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT); - layoutParamsLL.setMargins(0, 5, 0, 0); - - LinearLayout collapse = new LinearLayout(this); - collapse.setLayoutParams(layoutParamsLL); - collapse.setVerticalGravity(16); - collapse.setOrientation(LinearLayout.VERTICAL); - - final LinearLayout collapseSub = new LinearLayout(this); - collapseSub.setVerticalGravity(16); - collapseSub.setPadding(0, 5, 0, 5); - collapseSub.setOrientation(LinearLayout.VERTICAL); - collapseSub.setBackgroundColor(Color.parseColor("#222D38")); - collapseSub.setVisibility(View.GONE); - mCollapse = collapseSub; - - final TextView textView = new TextView(this); - textView.setBackgroundColor(CategoryBG); - textView.setText("▽ " + text + " ▽"); - textView.setGravity(Gravity.CENTER); - textView.setTextColor(TEXT_COLOR_2); - textView.setTypeface(null, Typeface.BOLD); - textView.setPadding(0, 20, 0, 20); - textView.setOnClickListener(new View.OnClickListener() { - boolean isChecked; - - @Override - public void onClick(View v) { - - boolean z = !this.isChecked; - this.isChecked = z; - if (z) { - collapseSub.setVisibility(View.VISIBLE); - textView.setText("△ " + text + " △"); - return; - } - collapseSub.setVisibility(View.GONE); - textView.setText("▽ " + text + " ▽"); - } - }); - collapse.addView(textView); - collapse.addView(collapseSub); - linLayout.addView(collapse); - } - - private View Category(String text) { - TextView textView = new TextView(this); - textView.setBackgroundColor(CategoryBG); - textView.setText(Html.fromHtml(text)); - textView.setGravity(Gravity.CENTER); - textView.setTextColor(TEXT_COLOR_2); - textView.setTypeface(null, Typeface.BOLD); - textView.setPadding(0, 5, 0, 5); - return textView; - } - - private View RichTextView(String text) { - TextView textView = new TextView(this); - textView.setText(Html.fromHtml(text)); - textView.setTextColor(TEXT_COLOR_2); - textView.setPadding(10, 5, 10, 5); - return textView; - } - - private View RichWebView(String text) { - WebView wView = new WebView(this); - wView.loadData(text, "text/html", "utf-8"); - wView.setBackgroundColor(0x00000000); //Transparent - wView.setPadding(0, 5, 0, 5); - wView.getSettings().setAppCacheEnabled(false); - return wView; - } - - //Override our Start Command so the Service doesnt try to recreate itself when the App is closed - public int onStartCommand(Intent intent, int i, int i2) { - return Service.START_NOT_STICKY; - } - - private boolean isViewCollapsed() { - return rootFrame == null || mCollapsed.getVisibility() == View.VISIBLE; - } - - //For our image a little converter - private int convertDipToPixels(int i) { - return (int) ((((float) i) * getResources().getDisplayMetrics().density) + 0.5f); - } - - private int dp(int i) { - return (int) TypedValue.applyDimension(1, (float) i, getResources().getDisplayMetrics()); - } - - //Check if we are still in the game. If now our menu and menu button will dissapear - private boolean isNotInGame() { - RunningAppProcessInfo runningAppProcessInfo = new RunningAppProcessInfo(); - ActivityManager.getMyMemoryState(runningAppProcessInfo); - return runningAppProcessInfo.importance != 100; - } - - //Destroy our View - public void onDestroy() { - super.onDestroy(); - if (rootFrame != null) { - mWindowManager.removeView(rootFrame); - } - } - - //Same as above so it wont crash in the background and therefore use alot of Battery life - public void onTaskRemoved(Intent intent) { - super.onTaskRemoved(intent); - try { - Thread.sleep(100); - } catch (InterruptedException e) { - e.printStackTrace(); - } - stopSelf(); - } - - private void Thread() { - if (rootFrame == null) { - return; - } - if (isNotInGame()) { - rootFrame.setVisibility(View.INVISIBLE); - } else { - rootFrame.setVisibility(View.VISIBLE); - } - } - - private class EditTextString { - private String text; - - public void setString(String s) { - text = s; - } - - public String getString() { - return text; - } - } - - private class EditTextNum { - private int val; - - public void setNum(int i) { - val = i; - } - - public int getNum() { - return val; - } - } - - @Override - public IBinder onBind(Intent intent) { - return null; - } -} \ No newline at end of file diff --git a/app/src/main/java/uk/lgl/modmenu/Logcat.java b/app/src/main/java/uk/lgl/modmenu/Logcat.java deleted file mode 100644 index 43f1b4ad..00000000 --- a/app/src/main/java/uk/lgl/modmenu/Logcat.java +++ /dev/null @@ -1,68 +0,0 @@ -package uk.lgl.modmenu; - -import android.content.Context; -import android.os.Build; -import android.util.Log; -import android.widget.Toast; - -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.io.InputStreamReader; - -public class Logcat { - public static void Clear(Context context) { - try { - Runtime.getRuntime().exec("logcat -c"); - Toast.makeText(context, "Logcat cleared", Toast.LENGTH_LONG).show(); - } catch (IOException e) { - Toast.makeText(context, "There was an error saving logcat to file", Toast.LENGTH_LONG).show(); - e.printStackTrace(); - } - } - - public static void Save(Context context) { - File path = null; - try { - Process process = Runtime.getRuntime().exec("logcat -d"); - BufferedReader bufferedReader = new BufferedReader( - new InputStreamReader(process.getInputStream())); - - StringBuilder log = new StringBuilder(); - String line = ""; - while ((line = bufferedReader.readLine()) != null) { - log.append(line + "\n"); - } - long unixTime = System.currentTimeMillis() / 1000L; - if (Build.VERSION.SDK_INT >= 30) { //Android R. AIDE didn't support Build.VERSION_CODES.R - path = new File("/storage/emulated/0/Documents/"); - } else { - path = new File(context.getExternalFilesDir(null) + "/Mod Menu"); - } - - File folder = new File(String.valueOf(path)); - folder.mkdirs(); - - File file = new File(path + "/Mod menu log - " + context.getPackageName() + ".txt"); - file.createNewFile(); - - try { - //BufferedWriter for performance, true to set append to file flag - BufferedWriter buf = new BufferedWriter(new FileWriter(file)); - buf.append(log.toString()); - buf.newLine(); - buf.close(); - Toast.makeText(context, "Logcat saved successfully to: " + file.toString(), Toast.LENGTH_LONG).show(); - Toast.makeText(context, "Logcat saved successfully to: " + file.toString(), Toast.LENGTH_LONG).show(); - } catch (IOException e) { - Toast.makeText(context, "There was an error saving logcat to file: " + e.getLocalizedMessage(), Toast.LENGTH_LONG).show(); - e.printStackTrace(); - } - } catch (IOException e) { - Toast.makeText(context, "There was an error saving logcat to file: " + Log.getStackTraceString(e), Toast.LENGTH_LONG).show(); - e.printStackTrace(); - } - } -} diff --git a/app/src/main/java/uk/lgl/modmenu/Preferences.java b/app/src/main/java/uk/lgl/modmenu/Preferences.java deleted file mode 100644 index 1aebc265..00000000 --- a/app/src/main/java/uk/lgl/modmenu/Preferences.java +++ /dev/null @@ -1,488 +0,0 @@ -package uk.lgl.modmenu; - -import android.annotation.TargetApi; -import android.content.Context; -import android.content.SharedPreferences; -import android.preference.PreferenceManager; -import android.util.Log; -import android.os.Build; - -import java.util.LinkedHashSet; -import java.util.Set; - -import static android.preference.PreferenceManager.getDefaultSharedPreferences; - -public class Preferences { - private static SharedPreferences sharedPreferences; - private static Preferences prefsInstance; - public static Context context; - public static boolean loadPref, isExpanded; - - private static final String LENGTH = "_length"; - private static final String DEFAULT_STRING_VALUE = ""; - private static final int DEFAULT_INT_VALUE = 0; //-1 - private static final double DEFAULT_DOUBLE_VALUE = 0d; //-1d - private static final float DEFAULT_FLOAT_VALUE = 0f; //-1f - private static final long DEFAULT_LONG_VALUE = 0L; //-1L - private static final boolean DEFAULT_BOOLEAN_VALUE = false; - - public static native void Changes(Context con, int fNum, String fName, int i, boolean bool, String str); - - public static void changeFeatureInt(String featureName, int featureNum, int value) { - Preferences.with(context).writeInt(featureNum, value); - Changes(context, featureNum, featureName, value, false, null); - } - - public static void changeFeatureString(String featureName, int featureNum, String str) { - Preferences.with(context).writeString(featureNum, str); - Changes(context, featureNum, featureName, 0, false, str); - } - - public static void changeFeatureBool(String featureName, int featureNum, boolean bool) { - Preferences.with(context).writeBoolean(featureNum, bool); - Changes(context, featureNum, featureName, 0, bool, null); - } - - public static int loadPrefInt(String featureName, int featureNum) { - if (loadPref) { - int i = Preferences.with(context).readInt(featureNum); - Changes(context, featureNum, featureName, i, false, null); - return i; - } - return 0; - } - - public static boolean loadPrefBool(String featureName, int featureNum, boolean bDef) { - boolean bool = Preferences.with(context).readBoolean(featureNum, bDef); - if (featureNum == -1) { - loadPref = bool; - } - if (featureNum == -3) { - isExpanded = bool; - } - if (loadPref || featureNum < 0) { - bDef = bool; - } - - Changes(context, featureNum, featureName, 0, bDef, null); - return bDef; - } - - public static String loadPrefString(String featureName, int featureNum) { - if (loadPref || featureNum <= 0) { - String str = Preferences.with(context).readString(featureNum); - Changes(context, featureNum, featureName, 0, false, str); - return str; - } - return ""; - } - - private Preferences(Context context) { - sharedPreferences = context.getApplicationContext().getSharedPreferences( - context.getPackageName() + "_preferences", - Context.MODE_PRIVATE - ); - } - - private Preferences(Context context, String preferencesName) { - sharedPreferences = context.getApplicationContext().getSharedPreferences( - preferencesName, - Context.MODE_PRIVATE - ); - } - - /** - * @param context - * @return Returns a 'Preferences' instance - */ - public static Preferences with(Context context) { - if (prefsInstance == null) { - prefsInstance = new Preferences(context); - } - return prefsInstance; - } - - /** - * @param context - * @param forceInstantiation - * @return Returns a 'Preferences' instance - */ - public static Preferences with(Context context, boolean forceInstantiation) { - if (forceInstantiation) { - prefsInstance = new Preferences(context); - } - return prefsInstance; - } - - /** - * @param context - * @param preferencesName - * @return Returns a 'Preferences' instance - */ - public static Preferences with(Context context, String preferencesName) { - if (prefsInstance == null) { - prefsInstance = new Preferences(context, preferencesName); - } - return prefsInstance; - } - - /** - * @param context - * @param preferencesName - * @param forceInstantiation - * @return Returns a 'Preferences' instance - */ - public static Preferences with(Context context, String preferencesName, - boolean forceInstantiation) { - if (forceInstantiation) { - prefsInstance = new Preferences(context, preferencesName); - } - return prefsInstance; - } - - // String related methods - - /** - * @param what - * @return Returns the stored value of 'what' - */ - public String readString(String what) { - return sharedPreferences.getString(what, DEFAULT_STRING_VALUE); - } - - /** - * @param what - * @return Returns the stored value of 'what' - */ - public String readString(int what) { - try { - return sharedPreferences.getString(String.valueOf(what), DEFAULT_STRING_VALUE); - } catch (java.lang.ClassCastException ex) { - return ""; - } - } - - /** - * @param what - * @param defaultString - * @return Returns the stored value of 'what' - */ - public String readString(String what, String defaultString) { - return sharedPreferences.getString(what, defaultString); - } - - /** - * @param where - * @param what - */ - public void writeString(String where, String what) { - sharedPreferences.edit().putString(where, what).apply(); - } - - /** - * @param where - * @param what - */ - public void writeString(int where, String what) { - sharedPreferences.edit().putString(String.valueOf(where), what).apply(); - } - - // int related methods - - /** - * @param what - * @return Returns the stored value of 'what' - */ - public int readInt(String what) { - return sharedPreferences.getInt(what, DEFAULT_INT_VALUE); - } - - - /** - * @param what - * @return Returns the stored value of 'what' - */ - public int readInt(int what) { - try { - return sharedPreferences.getInt(String.valueOf(what), DEFAULT_INT_VALUE); - } catch (java.lang.ClassCastException ex) { - return 0; - } - } - - /** - * @param what - * @param defaultInt - * @return Returns the stored value of 'what' - */ - public int readInt(String what, int defaultInt) { - return sharedPreferences.getInt(what, defaultInt); - } - - /** - * @param where - * @param what - */ - public void writeInt(String where, int what) { - sharedPreferences.edit().putInt(where, what).apply(); - } - - /** - * @param where - * @param what - */ - public void writeInt(int where, int what) { - sharedPreferences.edit().putInt(String.valueOf(where), what).apply(); - } - - // double related methods - - /** - * @param what - * @return Returns the stored value of 'what' - */ - public double readDouble(String what) { - if (!contains(what)) - return DEFAULT_DOUBLE_VALUE; - return Double.longBitsToDouble(readLong(what)); - } - - /** - * @param what - * @param defaultDouble - * @return Returns the stored value of 'what' - */ - public double readDouble(String what, double defaultDouble) { - if (!contains(what)) - return defaultDouble; - return Double.longBitsToDouble(readLong(what)); - } - - /** - * @param where - * @param what - */ - public void writeDouble(String where, double what) { - writeLong(where, Double.doubleToRawLongBits(what)); - } - - // float related methods - - /** - * @param what - * @return Returns the stored value of 'what' - */ - public float readFloat(String what) { - return sharedPreferences.getFloat(what, DEFAULT_FLOAT_VALUE); - } - - /** - * @param what - * @param defaultFloat - * @return Returns the stored value of 'what' - */ - public float readFloat(String what, float defaultFloat) { - return sharedPreferences.getFloat(what, defaultFloat); - } - - /** - * @param where - * @param what - */ - public void writeFloat(String where, float what) { - sharedPreferences.edit().putFloat(where, what).apply(); - } - - // long related methods - - /** - * @param what - * @return Returns the stored value of 'what' - */ - public long readLong(String what) { - return sharedPreferences.getLong(what, DEFAULT_LONG_VALUE); - } - - /** - * @param what - * @param defaultLong - * @return Returns the stored value of 'what' - */ - public long readLong(String what, long defaultLong) { - return sharedPreferences.getLong(what, defaultLong); - } - - /** - * @param where - * @param what - */ - public void writeLong(String where, long what) { - sharedPreferences.edit().putLong(where, what).apply(); - } - - // boolean related methods - - /** - * @param what - * @return Returns the stored value of 'what' - */ - public boolean readBoolean(String what) { - return sharedPreferences.getBoolean(what, DEFAULT_BOOLEAN_VALUE); - } - - /** - * @param what - * @return Returns the stored value of 'what' - */ - public boolean readBoolean(int what) { - return sharedPreferences.getBoolean(String.valueOf(what), DEFAULT_BOOLEAN_VALUE); - } - - /** - * @param what - * @param defaultBoolean - * @return Returns the stored value of 'what' - */ - public boolean readBoolean(String what, boolean defaultBoolean) { - /*if (defaultBoolean == true && !sharedPreferences.contains(what)) - writeBoolean(what, true);*/ - return sharedPreferences.getBoolean(what, defaultBoolean); - } - - /** - * @param what - * @param defaultBoolean - * @return Returns the stored value of 'what' - */ - public boolean readBoolean(int what, boolean defaultBoolean) { - /*if (defaultBoolean == true && !sharedPreferences.contains(String.valueOf(what))) - writeBoolean(what, true);*/ - try { - return sharedPreferences.getBoolean(String.valueOf(what), defaultBoolean); - } catch (java.lang.ClassCastException ex) { - return defaultBoolean; - } - } - - /** - * @param where - * @param what - */ - public void writeBoolean(String where, boolean what) { - sharedPreferences.edit().putBoolean(where, what).apply(); - } - - /** - * @param where - * @param what - */ - public void writeBoolean(int where, boolean what) { - sharedPreferences.edit().putBoolean(String.valueOf(where), what).apply(); - } - - // String set methods - - /** - * @param key - * @param value - */ - @TargetApi(Build.VERSION_CODES.HONEYCOMB) - public void putStringSet(final String key, final Set value) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { - sharedPreferences.edit().putStringSet(key, value).apply(); - } else { - // Workaround for pre-HC's lack of StringSets - putOrderedStringSet(key, value); - } - } - - /** - * @param key - * @param value - */ - public void putOrderedStringSet(String key, Set value) { - int stringSetLength = 0; - if (sharedPreferences.contains(key + LENGTH)) { - // First read what the value was - stringSetLength = readInt(key + LENGTH); - } - writeInt(key + LENGTH, value.size()); - int i = 0; - for (String aValue : value) { - writeString(key + "[" + i + "]", aValue); - i++; - } - for (; i < stringSetLength; i++) { - // Remove any remaining values - remove(key + "[" + i + "]"); - } - } - - /** - * @param key - * @param defValue - * @return Returns the String Set with HoneyComb compatibility - */ - @TargetApi(Build.VERSION_CODES.HONEYCOMB) - public Set getStringSet(final String key, final Set defValue) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { - return sharedPreferences.getStringSet(key, defValue); - } else { - // Workaround for pre-HC's missing getStringSet - return getOrderedStringSet(key, defValue); - } - } - - /** - * @param key - * @param defValue - * @return Returns the ordered String Set - */ - public Set getOrderedStringSet(String key, final Set defValue) { - if (contains(key + LENGTH)) { - LinkedHashSet set = new LinkedHashSet<>(); - int stringSetLength = readInt(key + LENGTH); - if (stringSetLength >= 0) { - for (int i = 0; i < stringSetLength; i++) { - set.add(readString(key + "[" + i + "]")); - } - } - return set; - } - return defValue; - } - - // end related methods - - /** - * @param key - */ - public void remove(final String key) { - if (contains(key + LENGTH)) { - // Workaround for pre-HC's lack of StringSets - int stringSetLength = readInt(key + LENGTH); - if (stringSetLength >= 0) { - sharedPreferences.edit().remove(key + LENGTH).apply(); - for (int i = 0; i < stringSetLength; i++) { - sharedPreferences.edit().remove(key + "[" + i + "]").apply(); - } - } - } - sharedPreferences.edit().remove(key).apply(); - } - - /** - * @param key - * @return Returns if that key exists - */ - public boolean contains(final String key) { - return sharedPreferences.contains(key); - } - - /** - * Clear all the preferences - */ - public void clear() { - sharedPreferences.edit().clear().apply(); - } -} \ No newline at end of file diff --git a/app/src/main/jni/Android.mk b/app/src/main/jni/Android.mk index 08ef8a51..15ae3254 100644 --- a/app/src/main/jni/Android.mk +++ b/app/src/main/jni/Android.mk @@ -1,5 +1,4 @@ LOCAL_PATH := $(call my-dir) -MAIN_LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) # Here is the name of your lib. @@ -7,18 +6,17 @@ include $(CLEAR_VARS) # Both must have same name LOCAL_MODULE := MyLibName -# Code optimization # -std=c++17 is required to support AIDE app with NDK -LOCAL_CFLAGS := -Wno-error=format-security -fvisibility=hidden -ffunction-sections -fdata-sections -w -LOCAL_CFLAGS += -fno-rtti -fno-exceptions -fpermissive -LOCAL_CPPFLAGS := -Wno-error=format-security -fvisibility=hidden -ffunction-sections -fdata-sections -w -Werror -s -std=c++17 -LOCAL_CPPFLAGS += -Wno-error=c++11-narrowing -fms-extensions -fno-rtti -fno-exceptions -fpermissive -LOCAL_LDFLAGS += -Wl,--gc-sections,--strip-all, -llog +LOCAL_CFLAGS := -w -s -Wno-error=format-security -fvisibility=hidden -fpermissive -fexceptions +LOCAL_CPPFLAGS := -w -s -Wno-error=format-security -fvisibility=hidden -Werror -std=c++17 +LOCAL_CPPFLAGS += -Wno-error=c++11-narrowing -fpermissive -Wall -fexceptions +LOCAL_LDFLAGS += -Wl,--gc-sections,--strip-all,-llog +LOCAL_LDLIBS := -llog -landroid -lEGL -lGLESv2 LOCAL_ARM_MODE := arm -LOCAL_C_INCLUDES += $(MAIN_LOCAL_PATH) +LOCAL_C_INCLUDES += $(LOCAL_PATH) -# Here you add the cpp file +# Here you add the cpp file to compile LOCAL_SRC_FILES := Main.cpp \ Substrate/hde64.c \ Substrate/SubstrateDebug.cpp \ @@ -31,6 +29,4 @@ LOCAL_SRC_FILES := Main.cpp \ KittyMemory/KittyUtils.cpp \ And64InlineHook/And64InlineHook.cpp \ -LOCAL_LDLIBS := -llog -landroid -lGLESv2 - include $(BUILD_SHARED_LIBRARY) diff --git a/app/src/main/jni/Includes/Macros.h b/app/src/main/jni/Includes/Macros.h index 852a0f0e..c36d4c83 100644 --- a/app/src/main/jni/Includes/Macros.h +++ b/app/src/main/jni/Includes/Macros.h @@ -1,71 +1,117 @@ +// thanks to shmoo and joeyjurjens for the usefull stuff under this comment. #ifndef ANDROID_MOD_MENU_MACROS_H #define ANDROID_MOD_MENU_MACROS_H -// thanks to shmoo and joeyjurjens for the usefull stuff under this comment. - #if defined(__aarch64__) //Compile for arm64 lib only #include -#define HOOK(offset, ptr, orig) A64HookFunction((void *)getAbsoluteAddress(targetLibName, string2Offset(OBFUSCATE(offset))), (void *)ptr, (void **)&orig) -#define HOOK_LIB(lib, offset, ptr, orig) A64HookFunction((void *)getAbsoluteAddress(OBFUSCATE(lib), string2Offset(OBFUSCATE(offset))), (void *)ptr, (void **)&orig) - -#define HOOK_NO_ORIG(offset, ptr) A64HookFunction((void *)getAbsoluteAddress(targetLibName, string2Offset(OBFUSCATE(offset))), (void *)ptr, NULL) -#define HOOK_LIB_NO_ORIG(lib, offset, ptr) A64HookFunction((void *)getAbsoluteAddress(OBFUSCATE(lib), string2Offset(OBFUSCATE(offset))), (void *)ptr, NULL) - -#define HOOKSYM(sym, ptr, org) A64HookFunction(dlsym(dlopen(targetLibName, 4), OBFUSCATE(sym)), (void *)ptr, (void **)&org) -#define HOOKSYM_LIB(lib, sym, ptr, org) A64HookFunction(dlsym(dlopen(OBFUSCATE(lib), 4), OBFUSCATE(sym)), (void *)ptr, (void **)&org) - -#define HOOKSYM_NO_ORIG(sym, ptr) A64HookFunction(dlsym(dlopen(targetLibName, 4), OBFUSCATE(sym)), (void *)ptr, NULL) -#define HOOKSYM_LIB_NO_ORIG(lib, sym, ptr) A64HookFunction(dlsym(dlopen(OBFUSCATE(lib), 4), OBFUSCATE(sym)), (void *)ptr, NULL) - #else //Compile for armv7 lib only. Do not worry about greyed out highlighting code, it still works - #include #include -#define HOOK(offset, ptr, orig) MSHookFunction((void *)getAbsoluteAddress(targetLibName, string2Offset(OBFUSCATE(offset))), (void *)ptr, (void **)&orig) -#define HOOK_LIB(lib, offset, ptr, orig) MSHookFunction((void *)getAbsoluteAddress(OBFUSCATE(lib), string2Offset(OBFUSCATE(offset))), (void *)ptr, (void **)&orig) +#endif -#define HOOK_NO_ORIG(offset, ptr) MSHookFunction((void *)getAbsoluteAddress(targetLibName, string2Offset(OBFUSCATE(offset))), (void *)ptr, NULL) -#define HOOK_LIB_NO_ORIG(lib, offset, ptr) MSHookFunction((void *)getAbsoluteAddress(OBFUSCATE(lib), string2Offset(OBFUSCATE(offset))), (void *)ptr, NULL) +void hook(void *offset, void* ptr, void **orig) +{ +#if defined(__aarch64__) + A64HookFunction(offset, ptr, orig); +#else + MSHookFunction(offset, ptr, orig); +#endif +} -#define HOOKSYM(sym, ptr, org) MSHookFunction(dlsym(dlopen(targetLibName, 4), OBFUSCATE(sym)), (void *)ptr, (void **)&org) -#define HOOKSYM_LIB(lib, sym, ptr, org) MSHookFunction(dlsym(dlopen(OBFUSCATE(lib), 4), OBFUSCATE(sym)), (void *)ptr, (void **)&org) +#define HOOK(offset, ptr, orig) hook((void *)getAbsoluteAddress(targetLibName, string2Offset(OBFUSCATE(offset))), (void *)ptr, (void **)&orig) +#define HOOK_LIB(lib, offset, ptr, orig) hook((void *)getAbsoluteAddress(OBFUSCATE(lib), string2Offset(OBFUSCATE(offset))), (void *)ptr, (void **)&orig) -#define HOOKSYM_NO_ORIG(sym, ptr) MSHookFunction(dlsym(dlopen(targetLibName, 4), OBFUSCATE(sym)), (void *)ptr, NULL) -#define HOOKSYM_LIB_NO_ORIG(lib, sym, ptr) MSHookFunction(dlsym(dlopen(OBFUSCATE(lib), 4), OBFUSCATE(sym)), (void *)ptr, NULL) +#define HOOK_NO_ORIG(offset, ptr) hook((void *)getAbsoluteAddress(targetLibName, string2Offset(OBFUSCATE(offset))), (void *)ptr, NULL) +#define HOOK_LIB_NO_ORIG(lib, offset, ptr) hook((void *)getAbsoluteAddress(OBFUSCATE(lib), string2Offset(OBFUSCATE(offset))), (void *)ptr, NULL) -#endif +#define HOOKSYM(sym, ptr, org) hook(dlsym(dlopen(targetLibName, 4), OBFUSCATE(sym)), (void *)ptr, (void **)&org) +#define HOOKSYM_LIB(lib, sym, ptr, org) hook(dlsym(dlopen(OBFUSCATE(lib), 4), OBFUSCATE(sym)), (void *)ptr, (void **)&org) + +#define HOOKSYM_NO_ORIG(sym, ptr) hook(dlsym(dlopen(targetLibName, 4), OBFUSCATE(sym)), (void *)ptr, NULL) +#define HOOKSYM_LIB_NO_ORIG(lib, sym, ptr) hook(dlsym(dlopen(OBFUSCATE(lib), 4), OBFUSCATE(sym)), (void *)ptr, NULL) -// Obfuscate offset -#define OBFUSCATEOFFSET(str) string2Offset(OBFUSCATE(str)) // Encrypt offset +std::vector memoryPatches; +std::vector offsetVector; // Patching a offset without switch. -void patchOffset(const char *fileName, uint64_t offset, std::string hexBytes) { +void patchOffset(const char *fileName, uint64_t offset, std::string hexBytes, bool isOn) { + MemoryPatch patch = MemoryPatch::createWithHex(fileName, offset, hexBytes); - if(!patch.isValid()){ - LOGE(OBFUSCATE("Failing offset: 0x%llu, please re-check the hex you entered."), offset); - return; + + //Check if offset exists in the offsetVector + if (std::find(offsetVector.begin(), offsetVector.end(), offset) != offsetVector.end()) { + //LOGE(OBFUSCATE("Already exists")); + std::vector::iterator itr = std::find(offsetVector.begin(), offsetVector.end(), offset); + patch = memoryPatches[std::distance(offsetVector.begin(), itr)]; //Get index of memoryPatches vector + } else { + memoryPatches.push_back(patch); + offsetVector.push_back(offset); + //LOGI(OBFUSCATE("Added")); } - if(!patch.Modify()) { - LOGE(OBFUSCATE("Something went wrong while patching this offset: 0x%llu"), offset); + + if (!patch.isValid()) { + LOGE(OBFUSCATE("Failing offset: 0x%llu, please re-check the hex"), offset); return; } + if (isOn) { + if (!patch.Modify()) { + LOGE(OBFUSCATE("Something went wrong while patching this offset: 0x%llu"), offset); + } + } else { + if (!patch.Restore()) { + LOGE(OBFUSCATE("Something went wrong while restoring this offset: 0x%llu"), offset); + } + } } -void patchOffset(uint64_t offset, std::string hexBytes) { - MemoryPatch patch = MemoryPatch::createWithHex(targetLibName, offset, hexBytes); - if(!patch.isValid()){ - LOGE(OBFUSCATE("Failing offset: 0x%llu, please re-check the hex you entered."), offset); - return; +void patchOffsetSym(uintptr_t absolute_address, std::string hexBytes, bool isOn) { + + MemoryPatch patch = MemoryPatch::createWithHex(absolute_address, hexBytes); + + //Check if offset exists in the offsetVector + if (std::find(offsetVector.begin(), offsetVector.end(), absolute_address) != offsetVector.end()) { + //LOGE(OBFUSCATE("Already exists")); + std::vector::iterator itr = std::find(offsetVector.begin(), offsetVector.end(), absolute_address); + patch = memoryPatches[std::distance(offsetVector.begin(), itr)]; //Get index of memoryPatches vector + } else { + memoryPatches.push_back(patch); + offsetVector.push_back(absolute_address); + //LOGI(OBFUSCATE("Added")); } - if(!patch.Modify()) { - LOGE(OBFUSCATE("Something went wrong while patching this offset: 0x%llu"), offset); + + if (!patch.isValid()) { + LOGE(OBFUSCATE("Failing offset: 0x%llu, please re-check the hex"), absolute_address); return; } + if (isOn) { + if (!patch.Modify()) { + LOGE(OBFUSCATE("Something went wrong while patching this offset: 0x%llu"), absolute_address); + } + } else { + if (!patch.Restore()) { + LOGE(OBFUSCATE("Something went wrong while restoring this offset: 0x%llu"), absolute_address); + } + } } -#define PATCHOFFSET(offset, hex) patchOffset(string2Offset(OBFUSCATE(offset)), OBFUSCATE(hex)) -#define PATCHOFFSET_LIB(lib, offset, hex) patchOffset(OBFUSCATE(lib), string2Offset(OBFUSCATE(offset)), OBFUSCATE(hex)) +#define PATCH(offset, hex) patchOffset(targetLibName, string2Offset(OBFUSCATE(offset)), OBFUSCATE(hex), true) +#define PATCH_LIB(lib, offset, hex) patchOffset(OBFUSCATE(lib), string2Offset(OBFUSCATE(offset)), OBFUSCATE(hex), true) + +#define PATCH_SYM(sym, hex) patchOffset(dlsym(dlopen(targetLibName, 4), OBFUSCATE(sym)), OBFUSCATE(hex), true) +#define PATCH_LIB_SYM(lib, sym, hex) patchOffset(dlsym(dlopen(lib, 4), OBFUSCATE(sym)), OBFUSCATE(hex), true) + +#define PATCH_SWITCH(offset, hex, boolean) patchOffset(targetLibName, string2Offset(OBFUSCATE(offset)), OBFUSCATE(hex), boolean) +#define PATCH_LIB_SWITCH(lib, offset, hex, boolean) patchOffset(OBFUSCATE(lib), string2Offset(OBFUSCATE(offset)), OBFUSCATE(hex), boolean) + +#define PATCH_SYM_SWITCH(sym, hex, boolean) patchOffsetSym((uintptr_t)dlsym(dlopen(targetLibName, 4), OBFUSCATE(sym)), OBFUSCATE(hex), boolean) +#define PATCH_LIB_SYM_SWITCH(lib, sym, hex, boolean) patchOffsetSym((uintptr_t)dlsym(dlopen(lib, 4), OBFUSCATE(sym)), OBFUSCATE(hex), boolean) + +#define RESTORE(offset) patchOffset(targetLibName, string2Offset(OBFUSCATE(offset)), "", false) +#define RESTORE_LIB(lib, offset) patchOffset(OBFUSCATE(lib), string2Offset(OBFUSCATE(offset)), "", false) + +#define RESTORE_SYM(sym) patchOffsetSym((uintptr_t)dlsym(dlopen(targetLibName, 4), OBFUSCATE(sym)), "", false) +#define RESTORE_LIB_SYM(lib, sym) patchOffsetSym((uintptr_t)dlsym(dlopen(lib, 4), OBFUSCATE(sym)), "", false) -#endif //ANDROID_MOD_MENU_MACROS_H +#endif //ANDROID_MOD_MENU_MACROS_H \ No newline at end of file diff --git a/app/src/main/jni/Includes/Utils.h b/app/src/main/jni/Includes/Utils.h index ffe28090..c7035009 100644 --- a/app/src/main/jni/Includes/Utils.h +++ b/app/src/main/jni/Includes/Utils.h @@ -73,35 +73,6 @@ bool isLibraryLoaded(const char *libraryName) { return false; } -//Credit: Octowolve -void MakeToast(JNIEnv *env, jobject thiz, const char *text, int length) { - //Add our toast in here so it wont be easy to change by simply editing the smali and cant - //be cut out because this method is needed to start the hack (Octowolve is smart) - jstring jstr = env->NewStringUTF(text); //Edit this text to your desired toast message! - jclass toast = env->FindClass(OBFUSCATE("android/widget/Toast")); - jmethodID methodMakeText = - env->GetStaticMethodID( - toast, - OBFUSCATE("makeText"), - OBFUSCATE( - "(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;")); - if (methodMakeText == NULL) { - LOGE(OBFUSCATE("toast.makeText not Found")); - return; - } - //The last int is the length on how long the toast should be displayed - //0 = Short, 1 = Long - jobject toastobj = env->CallStaticObjectMethod(toast, methodMakeText, - thiz, jstr, length); - - jmethodID methodShow = env->GetMethodID(toast, OBFUSCATE("show"), OBFUSCATE("()V")); - if (methodShow == NULL) { - LOGE(OBFUSCATE("toast.show not Found")); - return; - } - env->CallVoidMethod(toastobj, methodShow); -} - uintptr_t string2Offset(const char *c) { int base = 16; // See if this function catches all possibilities. @@ -121,7 +92,7 @@ uintptr_t string2Offset(const char *c) { return strtoull(c, nullptr, base); } -namespace Toast { +namespace ToastLength { inline const int LENGTH_LONG = 1; inline const int LENGTH_SHORT = 0; } diff --git a/app/src/main/jni/Main.cpp b/app/src/main/jni/Main.cpp index bff68534..2a690400 100644 --- a/app/src/main/jni/Main.cpp +++ b/app/src/main/jni/Main.cpp @@ -11,23 +11,15 @@ #include "Includes/Logger.h" #include "Includes/obfuscate.h" #include "Includes/Utils.h" - #include "KittyMemory/MemoryPatch.h" -#include "Menu.h" + +#include "Menu/Register.h" //Target lib here #define targetLibName OBFUSCATE("libFileA.so") #include "Includes/Macros.h" -// fancy struct for patches for kittyMemory -struct My_Patches { - // let's assume we have patches for these functions for whatever game - // like show in miniMap boolean function - MemoryPatch GodMode, GodMode2, SliderExample; - // etc... -} hexPatches; - bool feature1, feature2, featureHookToggle, Health; int sliderValue = 1, level = 0; void *instanceBtn; @@ -88,18 +80,6 @@ void *hack_thread(void *) { LOGI(OBFUSCATE("%s has been loaded"), (const char *) targetLibName); #if defined(__aarch64__) //To compile this code for arm64 lib only. Do not worry about greyed out highlighting code, it still works - // New way to patch hex via KittyMemory without need to specify len. Spaces or without spaces are fine - // ARM64 assembly example - // MOV X0, #0x0 = 00 00 80 D2 - // RET = C0 03 5F D6 - hexPatches.GodMode = MemoryPatch::createWithHex(targetLibName, - string2Offset(OBFUSCATE("0x123456")), - OBFUSCATE("00 00 80 D2 C0 03 5F D6")); - //You can also specify target lib like this - hexPatches.GodMode2 = MemoryPatch::createWithHex("libtargetLibHere.so", - string2Offset(OBFUSCATE("0x222222")), - OBFUSCATE("20 00 80 D2 C0 03 5F D6")); - // Hook example. Comment out if you don't use hook // Strings in macros are automatically obfuscated. No need to obfuscate! HOOK("str", FunctionExample, old_FunctionExample); @@ -112,23 +92,12 @@ void *hack_thread(void *) { HOOKSYM_LIB_NO_ORIG("libFileB.so", "__SymbolNameExample", FunctionExample); // Patching offsets directly. Strings are automatically obfuscated too! - PATCHOFFSET("0x20D3A8", "00 00 A0 E3 1E FF 2F E1"); - PATCHOFFSET_LIB("libFileB.so", "0x20D3A8", "00 00 A0 E3 1E FF 2F E1"); + PATCH("0x20D3A8", "00 00 A0 E3 1E FF 2F E1"); + PATCH_LIB("libFileB.so", "0x20D3A8", "00 00 A0 E3 1E FF 2F E1"); AddMoneyExample = (void(*)(void *,int))getAbsoluteAddress(targetLibName, 0x123456); #else //To compile this code for armv7 lib only. - // New way to patch hex via KittyMemory without need to specify len. Spaces or without spaces are fine - // ARMv7 assembly example - // MOV R0, #0x0 = 00 00 A0 E3 - // BX LR = 1E FF 2F E1 - hexPatches.GodMode = MemoryPatch::createWithHex(targetLibName, //Normal obfuscate - string2Offset(OBFUSCATE("0x123456")), - OBFUSCATE("00 00 A0 E3 1E FF 2F E1")); - //You can also specify target lib like this - hexPatches.GodMode2 = MemoryPatch::createWithHex("libtargetLibHere.so", - string2Offset(OBFUSCATE("0x222222")), - OBFUSCATE("01 00 A0 E3 1E FF 2F E1")); // Hook example. Comment out if you don't use hook // Strings in macros are automatically obfuscated. No need to obfuscate! @@ -142,26 +111,29 @@ void *hack_thread(void *) { HOOKSYM_LIB_NO_ORIG("libFileB.so", "__SymbolNameExample", FunctionExample); // Patching offsets directly. Strings are automatically obfuscated too! - PATCHOFFSET("0x20D3A8", "00 00 A0 E3 1E FF 2F E1"); - PATCHOFFSET_LIB("libFileB.so", "0x20D3A8", "00 00 A0 E3 1E FF 2F E1"); + PATCH("0x20D3A8", "00 00 A0 E3 1E FF 2F E1"); + PATCH_LIB("libFileB.so", "0x20D3A8", "00 00 A0 E3 1E FF 2F E1"); + + //Restore changes to original + RESTORE("0x20D3A8"); + RESTORE_LIB("libFileB.so", "0x20D3A8"); AddMoneyExample = (void (*)(void *, int)) getAbsoluteAddress(targetLibName, 0x123456); LOGI(OBFUSCATE("Done")); #endif - // Anti Leech - sleep(20); - if (!titleValid || !headingValid || !iconValid || !settingsValid) { + //Anti-leech + /*if (!iconValid || !initValid || !settingsValid) { + //Bad function to make it crash + sleep(5); int *p = 0; *p = 0; - } + }*/ return NULL; } -/// -------------------------------------------------------------------- /// - // Do not change or translate the first text unless you know what you are doing // Assigning feature numbers is optional. Without it, it will automatically count for you, starting from 0 // Assigned feature numbers can be like any numbers 1,3,200,10... instead in order 0,1,2,3,4,5... @@ -169,12 +141,9 @@ void *hack_thread(void *) { // Toggle, ButtonOnOff and Checkbox can be switched on by default, if you add True_. Example: CheckBox_True_The Check Box // To learn HTML, go to this page: https://www.w3schools.com/ -jobjectArray getFeatureList(JNIEnv *env, jobject context) { +jobjectArray GetFeatureList(JNIEnv *env, jobject context) { jobjectArray ret; - //Toasts added here so it's harder to remove it - MakeToast(env, context, OBFUSCATE("Modded by LGL"), Toast::LENGTH_LONG); - const char *features[] = { OBFUSCATE("Category_The Category"), //Not counted OBFUSCATE("Toggle_The toggle"), @@ -240,23 +209,25 @@ void Changes(JNIEnv *env, jclass clazz, jobject obj, switch (featNum) { case 0: - feature2 = boolean; - if (feature2) { - // To print bytes you can do this - //if (hexPatches.GodMode.Modify()) { - // LOGD(OBFUSCATE("Current Bytes: %s"), - // hexPatches.GodMode.get_CurrBytes().c_str()); - //} - hexPatches.GodMode.Modify(); - hexPatches.GodMode2.Modify(); - //LOGI(OBFUSCATE("On")); - } else { - hexPatches.GodMode.Restore(); - hexPatches.GodMode2.Restore(); - //LOGI(OBFUSCATE("Off")); - } + // A much simpler way to patch hex via KittyMemory without need to specify the struct and len. Spaces or without spaces are fine + // ARMv7 assembly example + // MOV R0, #0x0 = 00 00 A0 E3 + // BX LR = 1E FF 2F E1 + PATCH_LIB_SWITCH("libil2cpp.so", "0x100000", "00 00 A0 E3 1E FF 2F E1", boolean); break; case 100: + //Reminder that the strings are auto obfuscated + //Switchable patch + PATCH_SWITCH("0x400000", "00 00 A0 E3 1E FF 2F E1", boolean); + PATCH_LIB_SWITCH("libil2cpp.so", "0x200000", "00 00 A0 E3 1E FF 2F E1", boolean); + PATCH_SYM_SWITCH("_SymbolExample", "00 00 A0 E3 1E FF 2F E1", boolean); + PATCH_LIB_SYM_SWITCH("libNativeGame.so", "_SymbolExample", "00 00 A0 E3 1E FF 2F E1", boolean); + + //Restore patched offset to original + RESTORE("0x400000"); + RESTORE_LIB("libil2cpp.so", "0x400000"); + RESTORE_SYM("_SymbolExample"); + RESTORE_LIB_SYM("libil2cpp.so", "_SymbolExample"); break; case 110: break; @@ -269,29 +240,13 @@ void Changes(JNIEnv *env, jclass clazz, jobject obj, switch (value) { //For noobies case 0: - hexPatches.SliderExample = MemoryPatch::createWithHex( - targetLibName, string2Offset( - OBFUSCATE("0x100000")), - OBFUSCATE( - "00 00 A0 E3 1E FF 2F E1")); - hexPatches.SliderExample.Modify(); + RESTORE("0x0"); break; case 1: - hexPatches.SliderExample = MemoryPatch::createWithHex( - targetLibName, string2Offset( - OBFUSCATE("0x100000")), - OBFUSCATE( - "01 00 A0 E3 1E FF 2F E1")); - hexPatches.SliderExample.Modify(); + PATCH("0x0", "01 00 A0 E3 1E FF 2F E1"); break; case 2: - hexPatches.SliderExample = MemoryPatch::createWithHex( - targetLibName, - string2Offset( - OBFUSCATE("0x100000")), - OBFUSCATE( - "02 00 A0 E3 1E FF 2F E1")); - hexPatches.SliderExample.Modify(); + PATCH("0x0", "02 00 A0 E3 1E FF 2F E1"); break; } break; @@ -323,13 +278,14 @@ void Changes(JNIEnv *env, jclass clazz, jobject obj, level = value; break; case 8: - //MakeToast(env, obj, TextInput, Toast::LENGTH_SHORT); break; case 9: break; } } +//No need to use JNI_OnLoad, since we don't use JNIEnv +//We do this to hide OnLoad from disassembler __attribute__((constructor)) void lib_main() { // Create a new thread so it does not block the main thread, means the game would not freeze @@ -340,54 +296,36 @@ void lib_main() { extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) { - JNIEnv *globalEnv; - vm->GetEnv((void **) &globalEnv, JNI_VERSION_1_6); - - // Register your class native methods. Build and ecompile the app and see the signature - // This is to hide function names from disassembler - // See more: https://developer.android.com/training/articles/perf-jni#native-libraries - - //Your menu class - jclass c = globalEnv->FindClass("com/android/support/Menu"); - if (c != nullptr){ - static const JNINativeMethod menuMethods[] = { - {OBFUSCATE("Icon"), OBFUSCATE("()Ljava/lang/String;"), reinterpret_cast(Icon)}, - {OBFUSCATE("IconWebViewData"), OBFUSCATE("()Ljava/lang/String;"), reinterpret_cast(IconWebViewData)}, - {OBFUSCATE("isGameLibLoaded"), OBFUSCATE("()Z"), reinterpret_cast(isGameLibLoaded)}, - {OBFUSCATE("setHeadingText"), OBFUSCATE("(Landroid/widget/TextView;)V"), reinterpret_cast(setHeadingText)}, - {OBFUSCATE("setTitleText"), OBFUSCATE("(Landroid/widget/TextView;)V"), reinterpret_cast(setTitleText)}, - {OBFUSCATE("settingsList"), OBFUSCATE("()[Ljava/lang/String;"), reinterpret_cast(settingsList)}, - {OBFUSCATE("getFeatureList"), OBFUSCATE("()[Ljava/lang/String;"), reinterpret_cast(getFeatureList)}, - }; - - int mm = globalEnv->RegisterNatives(c, menuMethods, sizeof(menuMethods) / sizeof(JNINativeMethod)); - if (mm != JNI_OK) { - LOGE(OBFUSCATE("Menu methods error")); - return mm; - } - } - else{ - LOGE(OBFUSCATE("JNI error")); + JNIEnv *env; + + vm->GetEnv((void **) &env, JNI_VERSION_1_6); + + static const JNINativeMethod menuMethods[] = { + {OBFUSCATE("Icon"), OBFUSCATE("()Ljava/lang/String;"), reinterpret_cast(Icon)}, + {OBFUSCATE("IconWebViewData"), OBFUSCATE("()Ljava/lang/String;"), reinterpret_cast(IconWebViewData)}, + {OBFUSCATE("IsGameLibLoaded"), OBFUSCATE("()Z"), reinterpret_cast(isGameLibLoaded)}, + {OBFUSCATE("Init"), OBFUSCATE("(Landroid/content/Context;Landroid/widget/TextView;Landroid/widget/TextView;)V"), reinterpret_cast(Init)}, + {OBFUSCATE("SettingsList"), OBFUSCATE("()[Ljava/lang/String;"), reinterpret_cast(SettingsList)}, + {OBFUSCATE("GetFeatureList"), OBFUSCATE("()[Ljava/lang/String;"), reinterpret_cast(GetFeatureList)}, + }; + + if (Register(env, "com/android/support/Menu", menuMethods, sizeof(menuMethods) / sizeof(JNINativeMethod)) != 0) return JNI_ERR; - } - jclass p = globalEnv->FindClass( OBFUSCATE("com/android/support/Preferences")); - if (p != nullptr){ - static const JNINativeMethod prefmethods[] = { - { OBFUSCATE("Changes"), OBFUSCATE("(Landroid/content/Context;ILjava/lang/String;IZLjava/lang/String;)V"), reinterpret_cast(Changes)}, - }; + static const JNINativeMethod prefMethods[] = { + { OBFUSCATE("Changes"), OBFUSCATE("(Landroid/content/Context;ILjava/lang/String;IZLjava/lang/String;)V"), reinterpret_cast(Changes)}, + }; - int pm = globalEnv->RegisterNatives(p, prefmethods, sizeof(prefmethods) / sizeof(JNINativeMethod)); - if (pm != JNI_OK){ - LOGE(OBFUSCATE("Preferences methods error")); - return pm; - } - } - else{ - LOGE(OBFUSCATE("JNI error")); + if (Register(env, "com/android/support/Preferences", + prefMethods, sizeof(prefMethods) / sizeof(JNINativeMethod)) != 0) + return JNI_ERR; + + static const JNINativeMethod mainMethods[] = { + { OBFUSCATE("CheckOverlayPermission"), OBFUSCATE("(Landroid/content/Context;)V"), reinterpret_cast(CheckOverlayPermission)}, + }; + + if (Register(env, "com/android/support/Main", mainMethods, sizeof(mainMethods) / sizeof(JNINativeMethod)) != 0) return JNI_ERR; - } return JNI_VERSION_1_6; } - diff --git a/app/src/main/jni/Menu.h b/app/src/main/jni/Menu/Menu.h similarity index 90% rename from app/src/main/jni/Menu.h rename to app/src/main/jni/Menu/Menu.h index 6a066a4b..45293390 100644 --- a/app/src/main/jni/Menu.h +++ b/app/src/main/jni/Menu/Menu.h @@ -1,5 +1,6 @@ -bool titleValid, headingValid, iconValid, settingsValid, isLeeched; +bool iconValid, settingsValid, initValid; +//Big letter cause crash void setText(JNIEnv *env, jobject obj, const char* text){ //https://stackoverflow.com/a/33627640/3763113 //A little JNI calls here. You really really need a great knowledge if you want to play with JNI stuff @@ -16,22 +17,6 @@ void setText(JNIEnv *env, jobject obj, const char* text){ (*env).CallVoidMethod(obj, setText, (*env).CallStaticObjectMethod(html, fromHtml, jstr)); } - -void setTitleText(JNIEnv *env, jobject thiz, jobject obj) { - setText(env, obj, OBFUSCATE("Modded by (yourname)")); - - titleValid = true; -} - -void setHeadingText(JNIEnv *env, jobject thiz, jobject obj) { - setText(env, obj, OBFUSCATE("

" - "

Modded by LGL

| " - "https://github.com/LGLTeam | Lorem Ipsum is simply dummy text of the printing and typesetting

" - "
")); - - headingValid = true; -} - jstring Icon(JNIEnv *env, jobject thiz) { iconValid = true; @@ -57,20 +42,13 @@ jstring IconWebViewData(JNIEnv *env, jobject thiz) { return NULL; } -jobjectArray settingsList(JNIEnv *env, jobject activityObject) { +jobjectArray SettingsList(JNIEnv *env, jobject activityObject) { jobjectArray ret; const char *features[] = { OBFUSCATE("Category_Settings"), OBFUSCATE("-1_Toggle_Save feature preferences"), //-1 is checked on Preferences.java OBFUSCATE("-3_Toggle_Auto size vertically"), - OBFUSCATE("Category_Logcat"), - OBFUSCATE("RichTextView_Save logcat if a bug occured and sent it to the modder. Clear logcat and reproduce bug again if the log file is too large"), - OBFUSCATE("RichTextView_Saving logcat does not need file permission. Logcat location:" - "
Android 11: /storage/emulated/0/Documents/" - "
Android 10 and below: /storage/emulated/0/Android/data/(package name)/files/Mod Menu
"), - OBFUSCATE("-4_Button_Save logcat to file"), - OBFUSCATE("-5_Button_Clear logcat"), OBFUSCATE("Category_Menu"), OBFUSCATE("-6_Button_Close settings"), }; @@ -88,5 +66,3 @@ jobjectArray settingsList(JNIEnv *env, jobject activityObject) { return (ret); } - - diff --git a/app/src/main/jni/Menu/Register.h b/app/src/main/jni/Menu/Register.h new file mode 100644 index 00000000..52b8318d --- /dev/null +++ b/app/src/main/jni/Menu/Register.h @@ -0,0 +1,22 @@ +#include "Menu/Setup.h" +// Register your class native methods. This is to hide function names from disassembler +// See more: https://developer.android.com/training/articles/perf-jni#native-libraries + +jint Register(JNIEnv *globalEnv, const char* classPath, const JNINativeMethod* methods, jint nMethods) { + jclass c = globalEnv->FindClass(classPath); + if (c != nullptr) { + + int mm = globalEnv->RegisterNatives(c, methods, + nMethods); + if (mm != JNI_OK) { + LOGE(OBFUSCATE("%s error"), classPath); + return mm; + } + } else { + LOGE(OBFUSCATE("JNI error")); + return JNI_ERR; + } + + LOGI(OBFUSCATE("Register OK")); + return 0; +} \ No newline at end of file diff --git a/app/src/main/jni/Menu/Setup.h b/app/src/main/jni/Menu/Setup.h new file mode 100644 index 00000000..93e38462 --- /dev/null +++ b/app/src/main/jni/Menu/Setup.h @@ -0,0 +1,122 @@ +#include +#include "Menu/Menu.h" + +//Jni stuff from MrDarkRX https://github.com/MrDarkRXx/DarkMod-Floating +void setDialog(jobject ctx, JNIEnv *env, const char *title, const char *msg){ + jclass Alert = env->FindClass(OBFUSCATE("android/app/AlertDialog$Builder")); + jmethodID AlertCons = env->GetMethodID(Alert, OBFUSCATE(""), OBFUSCATE("(Landroid/content/Context;)V")); + + jobject MainAlert = env->NewObject(Alert, AlertCons, ctx); + + jmethodID setTitle = env->GetMethodID(Alert, OBFUSCATE("setTitle"), OBFUSCATE("(Ljava/lang/CharSequence;)Landroid/app/AlertDialog$Builder;")); + env->CallObjectMethod(MainAlert, setTitle, env->NewStringUTF(title)); + + jmethodID setMsg = env->GetMethodID(Alert, OBFUSCATE("setMessage"), OBFUSCATE("(Ljava/lang/CharSequence;)Landroid/app/AlertDialog$Builder;")); + env->CallObjectMethod(MainAlert, setMsg, env->NewStringUTF(msg)); + + jmethodID setCa = env->GetMethodID(Alert, OBFUSCATE("setCancelable"), OBFUSCATE("(Z)Landroid/app/AlertDialog$Builder;")); + env->CallObjectMethod(MainAlert, setCa, false); + + jmethodID setPB = env->GetMethodID(Alert, OBFUSCATE("setPositiveButton"), OBFUSCATE("(Ljava/lang/CharSequence;Landroid/content/DialogInterface$OnClickListener;)Landroid/app/AlertDialog$Builder;")); + env->CallObjectMethod(MainAlert, setPB, env->NewStringUTF("Ok"), static_cast(NULL)); + + jmethodID create = env->GetMethodID(Alert, OBFUSCATE("create"), OBFUSCATE("()Landroid/app/AlertDialog;")); + jobject creaetob = env->CallObjectMethod(MainAlert, create); + + jclass AlertN = env->FindClass(OBFUSCATE("android/app/AlertDialog")); + + jmethodID show = env->GetMethodID(AlertN, OBFUSCATE("show"), OBFUSCATE("()V")); + env->CallVoidMethod(creaetob, show); +} + +void Toast(JNIEnv *env, jobject thiz, const char *text, int length) { + jstring jstr = env->NewStringUTF(text); + jclass toast = env->FindClass(OBFUSCATE("android/widget/Toast")); + jmethodID methodMakeText =env->GetStaticMethodID(toast,OBFUSCATE("makeText"),OBFUSCATE("(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;")); + jobject toastobj = env->CallStaticObjectMethod(toast, methodMakeText,thiz, jstr, length); + jmethodID methodShow = env->GetMethodID(toast, OBFUSCATE("show"), OBFUSCATE("()V")); + env->CallVoidMethod(toastobj, methodShow); +} + +void startActivityPermisson(JNIEnv *env, jobject ctx){ + jclass native_context = env->GetObjectClass(ctx); + jmethodID startActivity = env->GetMethodID(native_context, OBFUSCATE("startActivity"),OBFUSCATE("(Landroid/content/Intent;)V")); + + jmethodID pack = env->GetMethodID(native_context, OBFUSCATE("getPackageName"),OBFUSCATE("()Ljava/lang/String;")); + jstring packageName = static_cast(env->CallObjectMethod(ctx, pack)); + + const char *pkg = env->GetStringUTFChars(packageName, 0); + + std::stringstream pkgg; + pkgg << OBFUSCATE("package:"); + pkgg << pkg; + std::string pakg = pkgg.str(); + + jclass Uri = env->FindClass(OBFUSCATE("android/net/Uri")); + jmethodID Parce = env->GetStaticMethodID(Uri, OBFUSCATE("parse"), OBFUSCATE("(Ljava/lang/String;)Landroid/net/Uri;")); + jobject UriMethod = env->CallStaticObjectMethod(Uri, Parce, env->NewStringUTF(pakg.c_str())); + + jclass intentclass = env->FindClass(OBFUSCATE("android/content/Intent")); + jmethodID newIntent = env->GetMethodID(intentclass, OBFUSCATE(""), OBFUSCATE("(Ljava/lang/String;Landroid/net/Uri;)V")); + jobject intent = env->NewObject(intentclass,newIntent,env->NewStringUTF(OBFUSCATE("android.settings.action.MANAGE_OVERLAY_PERMISSION")), UriMethod); + + env->CallVoidMethod(ctx, startActivity, intent); +} + +void startService(JNIEnv *env, jobject ctx){ + jclass native_context = env->GetObjectClass(ctx); + jclass intentClass = env->FindClass(OBFUSCATE("android/content/Intent")); + jclass actionString = env->FindClass(OBFUSCATE("com/android/support/Launcher")); + jmethodID newIntent = env->GetMethodID(intentClass, OBFUSCATE(""), OBFUSCATE("(Landroid/content/Context;Ljava/lang/Class;)V")); + jobject intent = env->NewObject(intentClass,newIntent,ctx,actionString); + jmethodID startActivityMethodId = env->GetMethodID(native_context, OBFUSCATE("startService"), OBFUSCATE("(Landroid/content/Intent;)Landroid/content/ComponentName;")); + env->CallObjectMethod(ctx, startActivityMethodId, intent); +} + +void *exit_thread(void *) { + sleep(5); + exit(0); +} + +//Needed jclass parameter because this is a static java method +void CheckOverlayPermission(JNIEnv *env, jclass thiz, jobject ctx){ + //If overlay permission option is greyed out, make sure to add android.permission.SYSTEM_ALERT_WINDOW in manifest + + LOGI(OBFUSCATE("Check overlay permission")); + + jclass Settigs = env->FindClass(OBFUSCATE("android/provider/Settings")); + jmethodID canDraw =env->GetStaticMethodID(Settigs,OBFUSCATE("canDrawOverlays"),OBFUSCATE("(Landroid/content/Context;)Z")); + if (!env->CallStaticBooleanMethod(Settigs, canDraw, ctx)){ + Toast(env,ctx,OBFUSCATE("Overlay permission is required in order to show mod menu."),1); + Toast(env,ctx,OBFUSCATE("Overlay permission is required in order to show mod menu."),1); + startActivityPermisson(env, ctx); + + pthread_t ptid; + pthread_create(&ptid, NULL, exit_thread, NULL); + return; + } + + LOGI(OBFUSCATE("Start service")); + + //StartMod Normal + startService(env, ctx); +} + +void Init(JNIEnv *env, jobject thiz, jobject ctx, jobject title, jobject subtitle){ + //Set sub title + setText(env, title, OBFUSCATE("Modded by (yourname)")); + + //Set sub title + setText(env, subtitle, OBFUSCATE("

" + "

Modded by LGL

| " + "https://github.com/LGLTeam | Lorem Ipsum is simply dummy text of the printing and typesetting

" + "
")); + + //Dialog Example + //setDialog(ctx,env,OBFUSCATE("Title"),OBFUSCATE("Message Example")); + + //Toast Example + Toast(env,ctx,OBFUSCATE("Modded by YOU"),ToastLength::LENGTH_LONG); + + initValid = true; +} \ No newline at end of file diff --git a/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml deleted file mode 100644 index 971add5e..00000000 --- a/app/src/main/res/drawable-v24/ic_launcher_foreground.xml +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - - - - - - diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml deleted file mode 100644 index eed7a425..00000000 --- a/app/src/main/res/drawable/ic_launcher_background.xml +++ /dev/null @@ -1,170 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/drawable/ic_launcher_foreground.xml b/app/src/main/res/drawable/ic_launcher_foreground.xml new file mode 100644 index 00000000..64290327 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_foreground.xml @@ -0,0 +1,15 @@ + + + + + diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 52447413..40c91741 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -5,5 +5,5 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:background="#202020" - tools:context="com.google.com.android.MainActivity"> + tools:context="com.android.support.MainActivity"> \ No newline at end of file diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml index a26f6fbc..1f46878f 100644 --- a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -1,5 +1,5 @@ - - + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml index a26f6fbc..1f46878f 100644 --- a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -1,5 +1,5 @@ - - + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.png b/app/src/main/res/mipmap-hdpi/ic_launcher.png index 4726d538..7c66a39b 100644 Binary files a/app/src/main/res/mipmap-hdpi/ic_launcher.png and b/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/app/src/main/res/mipmap-hdpi/ic_launcher_round.png index dffca360..07fa66dd 100644 Binary files a/app/src/main/res/mipmap-hdpi/ic_launcher_round.png and b/app/src/main/res/mipmap-hdpi/ic_launcher_round.png differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.png b/app/src/main/res/mipmap-mdpi/ic_launcher.png index 97f1be42..0908202d 100644 Binary files a/app/src/main/res/mipmap-mdpi/ic_launcher.png and b/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/app/src/main/res/mipmap-mdpi/ic_launcher_round.png index dae5e082..ce9df107 100644 Binary files a/app/src/main/res/mipmap-mdpi/ic_launcher_round.png and b/app/src/main/res/mipmap-mdpi/ic_launcher_round.png differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/app/src/main/res/mipmap-xhdpi/ic_launcher.png index 6ebcfbd6..d25e23cb 100644 Binary files a/app/src/main/res/mipmap-xhdpi/ic_launcher.png and b/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png index 14ed0af3..33c766d4 100644 Binary files a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png and b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png index 040a07c3..74f9c601 100644 Binary files a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png and b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png index d8ae0315..b4f23ee2 100644 Binary files a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png index 45d47eee..98715ec0 100644 Binary files a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png index beed3cdd..74f9fdef 100644 Binary files a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ diff --git a/app/src/main/res/values/ic_launcher_background.xml b/app/src/main/res/values/ic_launcher_background.xml new file mode 100644 index 00000000..8c40f6a4 --- /dev/null +++ b/app/src/main/res/values/ic_launcher_background.xml @@ -0,0 +1,4 @@ + + + #0277BD + \ No newline at end of file diff --git a/build.gradle b/build.gradle index 3bab362e..958ff6d2 100644 --- a/build.gradle +++ b/build.gradle @@ -7,7 +7,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:7.0.0' + classpath 'com.android.tools.build:gradle:7.1.0' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 70b1d30a..f88d9acc 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-all.zip