.
675 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # XposedHider
2 |
3 | [从酷安下载](https://www.coolapk.com/apk/190274)
4 | 尽可能完美地隐藏Xposed。目前仍然处于实验性阶段,欢迎测试与发Issues。
5 |
6 | ---
7 | [Download from CoolApk](https://www.coolapk.com/apk/190274)
8 | This module will hide your xposed as perfectly as possible.It's in an experimental stage at the moment and welcomes testing and issues.
9 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 | /debug
3 | /release
4 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | import java.text.SimpleDateFormat
2 |
3 | apply plugin: 'com.android.application'
4 |
5 | android {
6 | compileSdkVersion 28
7 | defaultConfig {
8 | applicationId 'com.yaerin.xposed.hide'
9 | minSdkVersion 21
10 | targetSdkVersion 28
11 | versionCode getMyVersionCode()
12 | versionName getMyVersionName()
13 | }
14 | buildTypes {
15 | release {
16 | minifyEnabled false
17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
18 | }
19 | }
20 | compileOptions {
21 | sourceCompatibility JavaVersion.VERSION_1_8
22 | targetCompatibility JavaVersion.VERSION_1_8
23 | }
24 | }
25 |
26 | dependencies {
27 | implementation fileTree(include: ['*.jar'], dir: 'libs')
28 | implementation 'com.android.support:support-annotations:27.1.1'
29 | implementation 'com.google.code.gson:gson:2.8.5'
30 | compileOnly 'de.robv.android.xposed:api:82'
31 | compileOnly 'de.robv.android.xposed:api:82:sources'
32 | }
33 |
34 | static def getMyVersionCode() {
35 | return Integer.parseInt(new SimpleDateFormat("yyMMdd").format(new Date()))
36 | }
37 |
38 | static def getMyVersionName() {
39 | return "1.4.2." + "git describe --always".execute().getText().trim()
40 | }
41 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
14 |
17 |
20 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/app/src/main/assets/xposed_init:
--------------------------------------------------------------------------------
1 | com.yaerin.xposed.hider.InitInjector
--------------------------------------------------------------------------------
/app/src/main/java/com/yaerin/xposed/hider/App.java:
--------------------------------------------------------------------------------
1 | package com.yaerin.xposed.hider;
2 |
3 | import android.app.Application;
4 |
5 | import com.yaerin.xposed.hider.util.Crashlytics;
6 |
7 | public class App extends Application {
8 | @Override
9 | public void onCreate() {
10 | super.onCreate();
11 | Thread.setDefaultUncaughtExceptionHandler(new Crashlytics(this));
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yaerin/xposed/hider/C.java:
--------------------------------------------------------------------------------
1 | package com.yaerin.xposed.hider;
2 |
3 | public class C {
4 | public static final String KW_XPOSED = "xposed";
5 |
6 | public static final String PREF_SHOW_SYSTEM_APP = "pref_show_system_app";
7 | }
8 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yaerin/xposed/hider/InitInjector.java:
--------------------------------------------------------------------------------
1 | package com.yaerin.xposed.hider;
2 |
3 | import android.app.Application;
4 | import android.content.Context;
5 | import android.content.pm.PackageManager;
6 | import android.support.annotation.Keep;
7 |
8 | import java.io.File;
9 | import java.lang.reflect.Method;
10 |
11 | import dalvik.system.PathClassLoader;
12 | import de.robv.android.xposed.IXposedHookLoadPackage;
13 | import de.robv.android.xposed.XC_MethodHook;
14 | import de.robv.android.xposed.XC_MethodReplacement;
15 | import de.robv.android.xposed.XposedBridge;
16 | import de.robv.android.xposed.XposedHelpers;
17 | import de.robv.android.xposed.callbacks.XC_LoadPackage;
18 |
19 | /**
20 | * Created by w568w on 18-3-2.
21 | *
22 | * So we do not need to reboot, but it'll run slower.
23 | *
24 | * @author w568w
25 | * @author shuihuadx
26 | */
27 | @Keep
28 | public class InitInjector implements IXposedHookLoadPackage {
29 | public InitInjector() {
30 | super();
31 | }
32 |
33 | @Override
34 | @Keep
35 | public void handleLoadPackage(final XC_LoadPackage.LoadPackageParam loadPackageParam) {
36 | // XposedBridge.log("-----------handleLoadPackage--------------"+loadPackageParam.packageName);
37 |
38 | if (loadPackageParam.packageName.equals(BuildConfig.APPLICATION_ID)) {
39 | XposedHelpers.findAndHookMethod(
40 | "com.yaerin.xposed.hider.ui.MainActivity", loadPackageParam.classLoader,
41 | "isEnabled", XC_MethodReplacement.returnConstant(true)
42 | );
43 | }
44 | //这里是为了解决app多dex进行hook的问题,Xposed默认是hook主dex
45 | XposedHelpers.findAndHookMethod(Application.class, "attach", Context.class, new XC_MethodHook() {
46 | @Override
47 | protected void afterHookedMethod(MethodHookParam param) throws Throwable {
48 | // super.afterHookedMethod(param);
49 | Context context = (Context) param.args[0];
50 | // XposedBridge.log("==================="+context.getPackageName());
51 | if (context != null) {
52 | loadPackageParam.classLoader = context.getClassLoader();
53 | try {
54 | invokeHandleHookMethod(
55 | context, BuildConfig.APPLICATION_ID,
56 | BuildConfig.APPLICATION_ID + "r.XposedHook",
57 | "handleLoadPackage", loadPackageParam);
58 | } catch (Throwable error) {
59 | error.printStackTrace();
60 | }
61 | }
62 | }
63 | });
64 | }
65 |
66 | private void invokeHandleHookMethod(
67 | Context context,
68 | String modulePackageName,
69 | String handleHookClass,
70 | String handleHookMethod,
71 | XC_LoadPackage.LoadPackageParam loadPackageParam
72 | ) throws Throwable {
73 | // 原来的两种方式不是很好,改用这种新的方式
74 | File apkFile = findApkFile(context, modulePackageName);
75 | if (apkFile == null) {
76 | throw new RuntimeException("Cannot find the module APK.");
77 | }
78 | // 加载指定的hook逻辑处理类,并调用它的handleHook方法
79 | PathClassLoader pathClassLoader =
80 | new PathClassLoader(apkFile.getAbsolutePath(), ClassLoader.getSystemClassLoader());
81 | Class> cls = Class.forName(handleHookClass, true, pathClassLoader);
82 | Object instance = cls.newInstance();
83 |
84 | Method method = cls.getDeclaredMethod(handleHookMethod,
85 | Context.class, XC_LoadPackage.LoadPackageParam.class);
86 | method.invoke(instance, context, loadPackageParam);
87 | }
88 |
89 | /**
90 | * 根据包名构建目标Context,并调用getPackageCodePath()来定位apk
91 | *
92 | * @param context context参数
93 | * @param modulePackageName 当前模块包名
94 | * @return return apk file
95 | */
96 | private File findApkFile(Context context, String modulePackageName) {
97 | if (context == null) {
98 | return null;
99 | }
100 | try {
101 | Context moduleContext = context.createPackageContext(
102 | modulePackageName,
103 | Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY);
104 | String apkPath = moduleContext.getPackageCodePath();
105 | return new File(apkPath);
106 | } catch (PackageManager.NameNotFoundException e) {
107 | e.printStackTrace();
108 | }
109 | return null;
110 | }
111 |
112 | }
113 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yaerin/xposed/hider/XposedHook.java:
--------------------------------------------------------------------------------
1 | package com.yaerin.xposed.hider;
2 |
3 | import android.app.ActivityManager;
4 | import android.content.Context;
5 | import android.content.pm.ApplicationInfo;
6 | import android.content.pm.PackageInfo;
7 | import android.content.pm.PackageManager;
8 | import android.os.Bundle;
9 | import android.os.Environment;
10 | import android.support.annotation.Keep;
11 | import android.util.Log;
12 |
13 | import com.yaerin.xposed.hider.util.ConfigUtils;
14 |
15 | import java.io.BufferedReader;
16 | import java.io.File;
17 | import java.io.IOException;
18 | import java.io.InputStream;
19 | import java.lang.reflect.Modifier;
20 | import java.util.ArrayList;
21 | import java.util.Arrays;
22 | import java.util.List;
23 | import java.util.Map;
24 |
25 | import de.robv.android.xposed.XC_MethodHook;
26 | import de.robv.android.xposed.XposedBridge;
27 | import de.robv.android.xposed.XposedHelpers;
28 | import de.robv.android.xposed.callbacks.XC_LoadPackage;
29 | import top.fols.box.io.FilterXpInputStream;
30 |
31 | /**
32 | * helpful link: https://github.com/w568w/XposedChecker
33 | */
34 | @Keep
35 | @SuppressWarnings("unchecked")
36 | public class XposedHook {
37 |
38 | private String mSdcard;
39 |
40 | private static boolean isXposedModule(Context context, ApplicationInfo applicationInfo) {
41 | Bundle bundle = null;
42 | try {
43 | bundle = context.getPackageManager()
44 | .getApplicationInfo(applicationInfo.packageName, PackageManager.GET_META_DATA)
45 | .metaData;
46 | } catch (PackageManager.NameNotFoundException e) {
47 | e.printStackTrace();
48 | }
49 | return bundle != null && bundle.getBoolean("xposedmodule", false);
50 | }
51 |
52 | @Keep
53 | public void handleLoadPackage(Context context, XC_LoadPackage.LoadPackageParam lpparam) {
54 | mSdcard = Environment.getExternalStorageDirectory().getPath();
55 | if (!isXposedModule(context, lpparam.appInfo)) {
56 | next(lpparam);
57 | }
58 | }
59 |
60 | private void next(XC_LoadPackage.LoadPackageParam lpparam) {
61 | XposedBridge.log("=========="+lpparam.packageName);
62 |
63 | if (!"ml.w568w.checkxposed".equals(lpparam.packageName)){
64 | return;
65 | }
66 | // if (!"com.alibaba.android.rimet".equals(lpparam.packageName)){
67 | // return;
68 | // }
69 |
70 | // if ((lpparam.classLoader == null) || !ConfigUtils.get().contains(lpparam.packageName)) {
71 | // return;
72 | // }
73 | Log.i("xposed", "-------------------[I/XposedHider] Handle package " + lpparam.packageName);
74 | XposedBridge.log("-------------------[I/XposedHider] Handle package " + lpparam.packageName);
75 |
76 | XC_MethodHook hookClass = new XC_MethodHook() {
77 | @Override
78 | protected void beforeHookedMethod(MethodHookParam param) {
79 | Log.i("xposed","xposed1");
80 | String packageName = (String) param.args[0];
81 | if (packageName.matches("de\\.robv\\.android\\.xposed\\.Xposed+.+")) {
82 | Log.i("xposed","de\\.robv\\.android\\.xposed\\.Xposed+.+");
83 | param.setThrowable(new ClassNotFoundException(packageName));
84 | }
85 | }
86 | };
87 | // FIXME: 18-6-23 w568w: It's very dangerous to hook these methods, thinking to replace them.
88 | XposedHelpers.findAndHookMethod(
89 | ClassLoader.class,
90 | "loadClass",
91 | String.class,
92 | boolean.class,
93 | hookClass
94 | );
95 | XposedHelpers.findAndHookMethod(
96 | Class.class,
97 | "forName",
98 | String.class,
99 | boolean.class,
100 | ClassLoader.class,
101 | hookClass
102 | );
103 |
104 | // XposedHelpers.findAndHookConstructor(
105 | // File.class,
106 | // String.class,
107 | // new XC_MethodHook() {
108 | // @Override
109 | // protected void beforeHookedMethod(MethodHookParam param) {
110 | // Log.i("xposed","xposed2");
111 | //
112 | // String path = (String) param.args[0];
113 | // boolean shouldDo = path.matches("/proc/[0-9]+/maps") ||
114 | // (path.toLowerCase().contains(C.KW_XPOSED) &&
115 | // !path.startsWith(mSdcard) && !path.contains("fkzhang"));
116 | // if (shouldDo) {
117 | // param.args[0] = "/system/build.prop";
118 | // }
119 | // }
120 | // }
121 | // );
122 |
123 | XposedHelpers.findAndHookMethod(BufferedReader.class, "readLine", new XC_MethodHook() {
124 | @Override
125 | protected void afterHookedMethod(MethodHookParam param) throws Throwable {
126 | String result = (String) param.getResult();
127 | if(result != null) {
128 | if (result.contains("XposedBridge")) {
129 | param.setResult("");new File("").lastModified();
130 | }
131 | }
132 |
133 | super.afterHookedMethod(param);
134 | }
135 | });
136 |
137 | XC_MethodHook hookStack = new XC_MethodHook() {
138 | @Override
139 | protected void afterHookedMethod(MethodHookParam param) {
140 | Log.i("xposed","xposed3");
141 |
142 | StackTraceElement[] elements = (StackTraceElement[]) param.getResult();
143 | List clone = new ArrayList<>();
144 | for (StackTraceElement element : elements) {
145 | if (!element.getClassName().toLowerCase().contains(C.KW_XPOSED)) {
146 | clone.add(element);
147 | }
148 | }
149 | param.setResult(clone.toArray(new StackTraceElement[0]));
150 | }
151 | };
152 | XposedHelpers.findAndHookMethod(
153 | Throwable.class,
154 | "getStackTrace",
155 | hookStack
156 | );
157 | XposedHelpers.findAndHookMethod(
158 | Thread.class,
159 | "getStackTrace",
160 | hookStack
161 | );
162 |
163 | XposedHelpers.findAndHookMethod(
164 | "android.app.ApplicationPackageManager",
165 | lpparam.classLoader,
166 | "getInstalledPackages",
167 | int.class,
168 | new XC_MethodHook() {
169 | @Override
170 | protected void afterHookedMethod(MethodHookParam param) {
171 | Log.i("xposed","xposed4");
172 |
173 | List apps = (List) param.getResult();
174 | List clone = new ArrayList<>();
175 | // foreach is very slow.
176 | final int len = apps.size();
177 | for (int i = 0; i < len; i++) {
178 | PackageInfo app = apps.get(i);
179 | if (!app.packageName.toLowerCase().contains(C.KW_XPOSED)) {
180 | clone.add(app);
181 | }
182 | }
183 | param.setResult(clone);
184 | }
185 | }
186 | );
187 |
188 | XposedHelpers.findAndHookMethod(
189 | "android.app.ApplicationPackageManager",
190 | lpparam.classLoader,
191 | "getInstalledApplications",
192 | int.class,
193 | new XC_MethodHook() {
194 | @Override
195 | protected void afterHookedMethod(MethodHookParam param) {
196 | Log.i("xposed","xposed5");
197 |
198 | List apps = (List) param.getResult();
199 | List clone = new ArrayList<>();
200 | final int len = apps.size();
201 | for (int i = 0; i < len; i++) {
202 | ApplicationInfo app = apps.get(i);
203 | boolean shouldRemove = app.metaData != null && app.metaData.getBoolean("xposedmodule") ||
204 | app.packageName != null && app.packageName.toLowerCase().contains(C.KW_XPOSED) ||
205 | app.className != null && app.className.toLowerCase().contains(C.KW_XPOSED) ||
206 | app.processName != null && app.processName.toLowerCase().contains(C.KW_XPOSED);
207 | if (!shouldRemove) {
208 | clone.add(app);
209 | }
210 | }
211 | param.setResult(clone);
212 | }
213 | }
214 | );
215 |
216 | XposedHelpers.findAndHookMethod(
217 | Modifier.class,
218 | "isNative",
219 | int.class,
220 | new XC_MethodHook() {
221 | @Override
222 | protected void afterHookedMethod(MethodHookParam param) {
223 | Log.i("xposed","xposed6");
224 |
225 | param.setResult(false);
226 | }
227 | }
228 | );
229 |
230 | XposedHelpers.findAndHookMethod(
231 | System.class,
232 | "getProperty",
233 | String.class,
234 | new XC_MethodHook() {
235 | @Override
236 | protected void afterHookedMethod(MethodHookParam param) {
237 | Log.i("xposed","xposed7");
238 |
239 | if ("vxp".equals(param.args[0])) {
240 | param.setResult(null);
241 | }
242 | }
243 | }
244 | );
245 |
246 | XposedHelpers.findAndHookMethod(
247 | File.class,
248 | "list",
249 | new XC_MethodHook() {
250 | @Override
251 | protected void afterHookedMethod(MethodHookParam param) {
252 | Log.i("xposed","xposed8");
253 |
254 | String[] fs = (String[]) param.getResult();
255 | if (fs == null) {
256 | return;
257 | }
258 | List list = new ArrayList<>();
259 | for (String f : fs) {
260 | if (!f.toLowerCase().contains(C.KW_XPOSED) && !f.equals("su")) {
261 | list.add(f);
262 | }
263 | }
264 | param.setResult(list.toArray(new String[0]));
265 | }
266 | }
267 | );
268 |
269 | Class> clazz = null;
270 | try {
271 | clazz = Runtime.getRuntime().exec("echo").getClass();
272 | } catch (IOException ignore) {
273 | XposedBridge.log("[W/XposedHider] Cannot hook Process#getInputStream");
274 | }
275 | if (clazz != null) {
276 | XposedHelpers.findAndHookMethod(
277 | clazz,
278 | "getInputStream",
279 | new XC_MethodHook() {
280 | @Override
281 | protected void afterHookedMethod(MethodHookParam param) {
282 | Log.i("xposed","xposed9");
283 |
284 | InputStream is = (InputStream) param.getResult();
285 | if (is instanceof FilterXpInputStream) {
286 | param.setResult(is);
287 | } else {
288 | param.setResult(new FilterXpInputStream(is));
289 | }
290 | }
291 | }
292 | );
293 | }
294 |
295 | XposedBridge.hookAllMethods(System.class, "getenv",
296 | new XC_MethodHook() {
297 | @Override
298 | protected void afterHookedMethod(MethodHookParam param) {
299 | Log.i("xposed","xposed10");
300 |
301 | if (param.args.length == 0) {
302 | Map res = (Map) param.getResult();
303 | String classpath = res.get("CLASSPATH");
304 | param.setResult(filter(classpath));
305 | } else if ("CLASSPATH".equals(param.args[0])) {
306 | String classpath = (String) param.getResult();
307 | param.setResult(filter(classpath));
308 | }
309 | }
310 |
311 | private String filter(String s) {
312 | List list = Arrays.asList(s.split(":"));
313 | List clone = new ArrayList<>();
314 | for (int i = 0; i < list.size(); i++) {
315 | if (!list.get(i).toLowerCase().contains(C.KW_XPOSED)) {
316 | clone.add(list.get(i));
317 | }
318 | }
319 | StringBuilder res = new StringBuilder();
320 | for (int i = 0; i < clone.size(); i++) {
321 | res.append(clone);
322 | if (i != clone.size() - 1) {
323 | res.append(":");
324 | }
325 | }
326 | return res.toString();
327 | }
328 | }
329 | );
330 |
331 | XposedHelpers.findAndHookMethod("android.app.ApplicationPackageManager", lpparam.classLoader, "getPackageInfo", String.class, int.class, new XC_MethodHook() {
332 |
333 | @Override
334 | protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
335 | String packageName = (String) param.args[0];
336 | XposedBridge.log("ApplicationPackageManager: " + packageName);
337 | if(packageName.equals("de.robv.android.xposed.installer")){
338 | param.args[0]="de.robv.android.Xposed.installer";
339 | }
340 |
341 | }
342 |
343 | // @Override
344 | // protected void afterHookedMethod(MethodHookParam param) throws Throwable {
345 | // String packageName = (String) param.args[0];
346 | // XposedBridge.log("ApplicationPackageManager: " + packageName);
347 | // if(packageName.equals("de.robv.android.xposed.installer")){
348 | // param.setResult( new PackageManager.NameNotFoundException("de.robv.android.xposed.installer"));
349 | // }
350 | //
351 | // }
352 | });
353 | XposedHelpers.findAndHookMethod("android.app.ApplicationPackageManager", lpparam.classLoader, "getApplicationInfo", String.class, int.class, new XC_MethodHook() {
354 | @Override
355 | protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
356 | String packageName = (String) param.args[0];
357 | if (isTarget(packageName)) {
358 | XposedBridge.log("packageName: " + packageName);
359 | }
360 | }
361 | });
362 | XposedHelpers.findAndHookMethod("android.app.ActivityManager", lpparam.classLoader, "getRunningServices", int.class, new XC_MethodHook() {
363 | @Override
364 | protected void afterHookedMethod(MethodHookParam param) throws Throwable {
365 | List serviceInfoList = (List) param.getResult();
366 | List resultList = new ArrayList<>();
367 |
368 | for (ActivityManager.RunningServiceInfo runningServiceInfo : serviceInfoList) {
369 | String serviceName = runningServiceInfo.process;
370 | if (isTarget(serviceName)) {
371 | XposedBridge.log("serviceName: " + serviceName);
372 | } else {
373 | resultList.add(runningServiceInfo);
374 | }
375 | }
376 | param.setResult(resultList);
377 | }
378 | });
379 | XposedHelpers.findAndHookMethod("android.app.ActivityManager", lpparam.classLoader, "getRunningTasks", int.class, new XC_MethodHook() {
380 | @Override
381 | protected void afterHookedMethod(MethodHookParam param) throws Throwable {
382 | List serviceInfoList = (List) param.getResult();
383 | List resultList = new ArrayList<>();
384 |
385 | for (ActivityManager.RunningTaskInfo runningTaskInfo : serviceInfoList) {
386 | String taskName = runningTaskInfo.baseActivity.flattenToString();
387 | if (isTarget(taskName)) {
388 | XposedBridge.log("taskName: " + taskName);
389 | } else {
390 | resultList.add(runningTaskInfo);
391 | }
392 | }
393 | param.setResult(resultList);
394 | }
395 | });
396 | XposedHelpers.findAndHookMethod("android.app.ActivityManager", lpparam.classLoader, "getRunningAppProcesses", new XC_MethodHook() {
397 | @Override
398 | protected void afterHookedMethod(MethodHookParam param) throws Throwable {
399 | List runningAppProcessInfos = (List) param.getResult();
400 | List resultList = new ArrayList<>();
401 |
402 | for (ActivityManager.RunningAppProcessInfo runningAppProcessInfo : runningAppProcessInfos) {
403 | String processName = runningAppProcessInfo.processName;
404 | if (isTarget(processName)) {
405 | XposedBridge.log("processName: " + processName);
406 | } else {
407 | resultList.add(runningAppProcessInfo);
408 | }
409 | }
410 | param.setResult(resultList);
411 | }
412 | });
413 | }
414 | private static boolean isTarget(String name) {
415 | return name.contains("Hu") || name.contains("xposed");
416 | }
417 | }
418 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yaerin/xposed/hider/adapter/AppsAdapter.java:
--------------------------------------------------------------------------------
1 | package com.yaerin.xposed.hider.adapter;
2 |
3 | import android.content.Context;
4 | import android.view.View;
5 | import android.view.ViewGroup;
6 | import android.widget.BaseAdapter;
7 |
8 | import com.yaerin.xposed.hider.bean.AppInfo;
9 | import com.yaerin.xposed.hider.widget.AppView;
10 |
11 | import java.util.ArrayList;
12 | import java.util.List;
13 |
14 | public class AppsAdapter extends BaseAdapter {
15 |
16 | private Context mContext;
17 | private List mApps;
18 |
19 | public AppsAdapter(Context context, List apps) {
20 | mContext = context;
21 | mApps = apps == null ? new ArrayList<>() : apps;
22 | }
23 |
24 | @Override
25 | public int getCount() {
26 | return mApps.size();
27 | }
28 |
29 | @Override
30 | public AppInfo getItem(int position) {
31 | return mApps.get(position);
32 | }
33 |
34 | @Override
35 | public long getItemId(int position) {
36 | return position;
37 | }
38 |
39 | @Override
40 | public View getView(int position, View convertView, ViewGroup parent) {
41 | if (convertView == null) {
42 | convertView = new AppView(mContext, mApps.get(position));
43 | } else {
44 | ((AppView) convertView).setAppInfo(mApps.get(position));
45 | }
46 | return convertView;
47 | }
48 |
49 | public void add(AppInfo app) {
50 | mApps.add(app);
51 | }
52 |
53 | public void remove(int index) {
54 | mApps.remove(index);
55 | }
56 |
57 | public List getAppList() {
58 | return mApps;
59 | }
60 |
61 | public void setAppList(List apps) {
62 | mApps = apps;
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yaerin/xposed/hider/bean/AppInfo.java:
--------------------------------------------------------------------------------
1 | package com.yaerin.xposed.hider.bean;
2 |
3 | import android.graphics.drawable.Drawable;
4 |
5 | public class AppInfo {
6 |
7 | private String packageName;
8 | private String label;
9 | private int flags;
10 | private Drawable icon;
11 |
12 | public AppInfo() {
13 | }
14 |
15 | public AppInfo(String packageName, String label, int flags, Drawable icon) {
16 | this.packageName = packageName;
17 | this.label = label;
18 | this.flags = flags;
19 | this.icon = icon;
20 | }
21 |
22 | public AppInfo(AppInfo from) {
23 | this.packageName = from.packageName;
24 | this.label = from.label;
25 | this.icon = from.icon;
26 | }
27 |
28 | public String getPackageName() {
29 | return packageName;
30 | }
31 |
32 | public void setPackageName(String packageName) {
33 | this.packageName = packageName;
34 | }
35 |
36 | public String getLabel() {
37 | return label;
38 | }
39 |
40 | public void setLabel(String label) {
41 | this.label = label;
42 | }
43 |
44 | public int getFlags() {
45 | return flags;
46 | }
47 |
48 | public void setFlags(int flags) {
49 | this.flags = flags;
50 | }
51 |
52 | public Drawable getIcon() {
53 | return icon;
54 | }
55 |
56 | public void setIcon(Drawable icon) {
57 | this.icon = icon;
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yaerin/xposed/hider/ui/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.yaerin.xposed.hider.ui;
2 |
3 | import android.app.Activity;
4 | import android.content.Intent;
5 | import android.content.SharedPreferences;
6 | import android.os.Bundle;
7 | import android.preference.PreferenceManager;
8 | import android.util.SparseBooleanArray;
9 | import android.view.Menu;
10 | import android.view.MenuItem;
11 | import android.view.View;
12 | import android.view.inputmethod.EditorInfo;
13 | import android.widget.ListView;
14 | import android.widget.SearchView;
15 |
16 | import com.yaerin.xposed.hider.R;
17 | import com.yaerin.xposed.hider.adapter.AppsAdapter;
18 | import com.yaerin.xposed.hider.bean.AppInfo;
19 | import com.yaerin.xposed.hider.util.ConfigUtils;
20 |
21 | import java.util.ArrayList;
22 | import java.util.HashSet;
23 | import java.util.List;
24 | import java.util.Set;
25 | import java.util.concurrent.ExecutorService;
26 | import java.util.concurrent.Executors;
27 |
28 | import static com.yaerin.xposed.hider.C.PREF_SHOW_SYSTEM_APP;
29 | import static com.yaerin.xposed.hider.util.Utilities.getAppList;
30 |
31 | public class MainActivity extends Activity {
32 |
33 | private ListView mAppsView;
34 |
35 | private AppsAdapter mAdapter;
36 |
37 | private SharedPreferences mPreferences;
38 |
39 | private List mApps = new ArrayList<>();
40 | private List mMatches = new ArrayList<>();
41 | private ExecutorService mExecutor = Executors.newSingleThreadExecutor();
42 | private Set mConfig = ConfigUtils.get() != null ? ConfigUtils.get() : new HashSet<>();
43 | private boolean mShowSystemApp = false;
44 |
45 | public static boolean isEnabled() {
46 | return false;
47 | }
48 |
49 | private void setCheckedItems() {
50 | List apps = mAdapter.getAppList();
51 | for (int i = 0; i < apps.size(); i++) {
52 | mAppsView.setItemChecked(i, mConfig.contains(apps.get(i).getPackageName()));
53 | }
54 | }
55 |
56 | @Override
57 | protected void onCreate(Bundle savedInstanceState) {
58 | super.onCreate(savedInstanceState);
59 | setContentView(R.layout.activity_main);
60 | mAppsView = findViewById(R.id.apps);
61 | if (isEnabled()) {
62 | findViewById(R.id.tip_reboot).setVisibility(View.GONE);
63 | }
64 |
65 | mPreferences = PreferenceManager.getDefaultSharedPreferences(this);
66 | mShowSystemApp = mPreferences.getBoolean(PREF_SHOW_SYSTEM_APP, false);
67 |
68 | mAppsView.setOnItemClickListener((parent, view, position, id) -> {
69 | if (mAppsView.isItemChecked(position)) {
70 | mConfig.add(mAdapter.getAppList().get(position).getPackageName());
71 | } else {
72 | mConfig.remove(mAdapter.getAppList().get(position).getPackageName());
73 | }
74 | });
75 | mAppsView.setAdapter(mAdapter = new AppsAdapter(this, mApps));
76 | }
77 |
78 | @Override
79 | public boolean onCreateOptionsMenu(Menu menu) {
80 | getMenuInflater().inflate(R.menu.main, menu);
81 | SearchView sv = (SearchView) menu.findItem(R.id.menu_search).getActionView();
82 | sv.setInputType(EditorInfo.TYPE_CLASS_TEXT);
83 | sv.setImeOptions(EditorInfo.IME_ACTION_SEARCH);
84 | sv.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
85 | @Override
86 | public boolean onQueryTextSubmit(String query) {
87 | return false;
88 | }
89 |
90 | @Override
91 | public boolean onQueryTextChange(String newText) {
92 | mMatches.clear();
93 | newText = newText.toLowerCase();
94 | for (AppInfo app : mApps) {
95 | if (app.getLabel().toLowerCase().contains(newText) || app.getPackageName().contains(newText)) {
96 | mMatches.add(app);
97 | }
98 | }
99 | if (mAdapter.getAppList().equals(mApps)) {
100 | mAdapter.setAppList(mMatches);
101 | }
102 | mAdapter.notifyDataSetChanged();
103 | setCheckedItems();
104 | return true;
105 | }
106 | });
107 | sv.setOnCloseListener(() -> {
108 | mAdapter.setAppList(mApps);
109 | mAdapter.notifyDataSetChanged();
110 | setCheckedItems();
111 | return false;
112 | });
113 | return true;
114 | }
115 |
116 | @Override
117 | public boolean onOptionsItemSelected(MenuItem item) {
118 | switch (item.getItemId()) {
119 | case R.id.menu_settings: {
120 | startActivity(new Intent(this, SettingsActivity.class));
121 | return true;
122 | }
123 | default:
124 | break;
125 | }
126 | return false;
127 | }
128 |
129 | @Override
130 | protected void onResume() {
131 | super.onResume();
132 | boolean b = mPreferences.getBoolean(PREF_SHOW_SYSTEM_APP, false);
133 | if (mShowSystemApp != b || mApps.isEmpty()) {
134 | mShowSystemApp = b;
135 | mApps.clear();
136 | mAdapter.notifyDataSetChanged();
137 | findViewById(R.id.progress).setVisibility(View.VISIBLE);
138 | mExecutor.submit(() -> {
139 | mApps.addAll(getAppList(this, mShowSystemApp));
140 | runOnUiThread(() -> {
141 | mAdapter.notifyDataSetChanged();
142 | setCheckedItems();
143 | findViewById(R.id.progress).setVisibility(View.GONE);
144 | });
145 | });
146 | }
147 | }
148 |
149 | @Override
150 | protected void onPause() {
151 | SparseBooleanArray arr = mAppsView.getCheckedItemPositions();
152 | List apps = mAdapter.getAppList();
153 | for (int i = 0; i < arr.size(); i++) {
154 | if (i >= apps.size()) {
155 | continue;
156 | }
157 | String name = apps.get(i).getPackageName();
158 | if (arr.get(i)) {
159 | mConfig.add(name);
160 | } else {
161 | mConfig.remove(name);
162 | }
163 | }
164 | ConfigUtils.put(this, mConfig);
165 | super.onPause();
166 | }
167 | }
168 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yaerin/xposed/hider/ui/SettingsActivity.java:
--------------------------------------------------------------------------------
1 | package com.yaerin.xposed.hider.ui;
2 |
3 | import android.app.Activity;
4 | import android.os.Bundle;
5 | import android.support.annotation.Nullable;
6 |
7 | import com.yaerin.xposed.hider.R;
8 |
9 | public class SettingsActivity extends Activity {
10 | @Override
11 | protected void onCreate(@Nullable Bundle savedInstanceState) {
12 | super.onCreate(savedInstanceState);
13 | setContentView(R.layout.activity_settings);
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yaerin/xposed/hider/ui/SettingsFragment.java:
--------------------------------------------------------------------------------
1 | package com.yaerin.xposed.hider.ui;
2 |
3 | import android.os.Bundle;
4 | import android.preference.PreferenceFragment;
5 | import android.support.annotation.Nullable;
6 |
7 | import com.yaerin.xposed.hider.R;
8 |
9 | public class SettingsFragment extends PreferenceFragment {
10 | @Override
11 | public void onCreate(@Nullable Bundle savedInstanceState) {
12 | super.onCreate(savedInstanceState);
13 | addPreferencesFromResource(R.xml.settings);
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yaerin/xposed/hider/util/ConfigUtils.java:
--------------------------------------------------------------------------------
1 | package com.yaerin.xposed.hider.util;
2 |
3 | import android.annotation.SuppressLint;
4 | import android.content.Context;
5 | import android.util.Log;
6 |
7 | import com.google.gson.Gson;
8 | import com.google.gson.reflect.TypeToken;
9 | import com.yaerin.xposed.hider.BuildConfig;
10 |
11 | import java.io.BufferedReader;
12 | import java.io.DataOutputStream;
13 | import java.io.File;
14 | import java.io.FileInputStream;
15 | import java.io.FileOutputStream;
16 | import java.io.IOException;
17 | import java.io.InputStreamReader;
18 | import java.lang.reflect.Method;
19 | import java.util.Set;
20 |
21 | import de.robv.android.xposed.XposedBridge;
22 |
23 | /**
24 | * Create by Yaerin on 2018/6/23
25 | *
26 | * @author Yaerin
27 | */
28 | public class ConfigUtils {
29 |
30 | private static final String PATH = "rules";
31 | private static final String FILE = "list.json";
32 | private static boolean chmod=false;
33 |
34 | public static void put(Context context, Set apps) {
35 | File path = context.getDir(PATH, Context.MODE_PRIVATE);
36 | File file = new File(path, FILE);
37 | if (!path.exists()) {
38 | path.mkdirs();
39 | setFilePermissions(path, 0777, -1, -1);
40 | }
41 | try {
42 | FileOutputStream fos = new FileOutputStream(file);
43 | fos.write(new Gson().toJson(apps).getBytes());
44 | fos.close();
45 | setFilePermissions(file, 0777, -1, -1);
46 | } catch (IOException e) {
47 | Log.i("Xposed", Log.getStackTraceString(e));
48 | }
49 | }
50 |
51 | public static Set get() {
52 | StringBuilder s = new StringBuilder();
53 | String file_path="/data/data/" + BuildConfig.APPLICATION_ID + "/app_rules";
54 | String fi=file_path+"/"+FILE;
55 |
56 | if (chmod){
57 | chmod=true;
58 | Process process = null;
59 | DataOutputStream dataOutputStream = null;
60 |
61 | try {
62 | process = Runtime.getRuntime().exec("su");
63 | dataOutputStream = new DataOutputStream(process.getOutputStream());
64 | dataOutputStream.writeBytes("chmod 777 "+fi+"\n");
65 | dataOutputStream.writeBytes("exit\n");
66 | dataOutputStream.flush();
67 | process.waitFor();
68 | } catch (Exception e) {
69 |
70 | } finally {
71 | try {
72 | if (dataOutputStream != null) {
73 | dataOutputStream.close();
74 | }
75 | process.destroy();
76 | } catch (Exception e) {
77 | }
78 | }
79 | }
80 |
81 |
82 |
83 | File path = new File(file_path);
84 | // Log.i("Xposed", "[W/XposedHider] " + path.exists());
85 | File file = new File(path, FILE);
86 | // int code=setFilePermissions(file, 0777, -1, -1);
87 | Log.i("Xposed", "[W/XposedHider] " + file.exists()+file.canRead());
88 | if (file.exists() && file.canRead()) {
89 | try {
90 | InputStreamReader isr = new InputStreamReader(new FileInputStream(file));
91 | BufferedReader bufReader = new BufferedReader(isr);
92 | String line;
93 | while ((line = bufReader.readLine()) != null) {
94 | s.append("\n").append(line);
95 | }
96 | bufReader.close();
97 | isr.close();
98 | } catch (Exception e) {
99 | Log.i("Xposed", Log.getStackTraceString(e));
100 | }
101 | } else {
102 | String t = file.exists() ? "Cannot read config file." : "Config file does not exists.";
103 | Log.i("Xposed", "[W/XposedHider] " + t);
104 | }
105 | return new Gson().fromJson(s.toString(), new TypeToken>() {
106 | }.getType());
107 | }
108 |
109 | @SuppressLint("PrivateApi")
110 | public static int setFilePermissions(File path, int chmod, int uid, int gid) {
111 | Class> cls;
112 | try {
113 | cls = Class.forName("android.os.FileUtils");
114 | Method method = cls.getMethod("setPermissions", File.class, int.class, int.class, int.class);
115 | return (int) method.invoke(null, path, chmod, uid, gid);
116 | } catch (Exception e) {
117 | Log.i("Xposed", Log.getStackTraceString(e));
118 | return 1;
119 | }
120 | }
121 | }
122 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yaerin/xposed/hider/util/Crashlytics.java:
--------------------------------------------------------------------------------
1 | package com.yaerin.xposed.hider.util;
2 |
3 | import android.content.Context;
4 | import android.content.pm.PackageManager;
5 | import android.os.Build;
6 | import android.os.Process;
7 |
8 | import java.io.File;
9 | import java.io.FileOutputStream;
10 | import java.io.IOException;
11 | import java.io.PrintWriter;
12 | import java.io.StringWriter;
13 | import java.io.Writer;
14 | import java.text.SimpleDateFormat;
15 | import java.util.Date;
16 | import java.util.Locale;
17 |
18 | public class Crashlytics implements Thread.UncaughtExceptionHandler {
19 |
20 | private Context mContext;
21 |
22 | public Crashlytics(Context context) {
23 | this.mContext = context;
24 | }
25 |
26 | @Override
27 | public void uncaughtException(Thread t, Throwable e) {
28 | e.printStackTrace();
29 | String crashTime =
30 | new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS", Locale.getDefault())
31 | .format(new Date());
32 | String env =
33 | "########RuntimeEnviormentInormation#######\n" +
34 | "crashTime = " + crashTime + "\n" +
35 | "model = " + Build.MODEL + "\n" +
36 | "android = " + Build.VERSION.RELEASE + "(" + Build.VERSION.SDK_INT + ")\n" +
37 | "brand = " + Build.BRAND + "\n" +
38 | "manufacturer = " + Build.MANUFACTURER + "\n" +
39 | "board = " + Build.BOARD + "\n" +
40 | "hardware = " + Build.HARDWARE + "\n" +
41 | "device = " + Build.DEVICE + "\n" +
42 | "version = " + getVersionName() + "(" + getVersionCode() + ")\n" +
43 | "supportAbis = " + getSupportAbis() + "\n" +
44 | "display = " + Build.DISPLAY + "\n";
45 | Writer writer = new StringWriter();
46 | PrintWriter printWriter = new PrintWriter(writer);
47 | e.printStackTrace(printWriter);
48 | Throwable cause = e.getCause();
49 | while (cause != null) {
50 | cause.printStackTrace(printWriter);
51 | cause = cause.getCause();
52 | }
53 | printWriter.close();
54 | String stack = "############ForceCloseCrashLog############\n" + writer.toString();
55 | String message = env + stack;
56 | try {
57 | String name = "error_log_" + crashTime + ".log";
58 | FileOutputStream fos =
59 | new FileOutputStream(new File(mContext.getExternalFilesDir("logs"), name));
60 | fos.write(message.getBytes());
61 | fos.close();
62 | } catch (IOException ex) {
63 | ex.printStackTrace();
64 | }
65 |
66 | Process.killProcess(Process.myPid());
67 | System.exit(1);
68 | }
69 |
70 | private String getVersionName() {
71 | String versionName = "unknown";
72 | try {
73 | versionName = mContext.getPackageManager()
74 | .getPackageInfo(mContext.getPackageName(), 0).versionName;
75 | } catch (PackageManager.NameNotFoundException e) {
76 | e.printStackTrace();
77 | }
78 | return versionName;
79 | }
80 |
81 | private int getVersionCode() {
82 | int versionCode = -1;
83 | try {
84 | versionCode = mContext.getPackageManager()
85 | .getPackageInfo(mContext.getPackageName(), 0).versionCode;
86 | } catch (PackageManager.NameNotFoundException e) {
87 | e.printStackTrace();
88 | }
89 | return versionCode;
90 | }
91 |
92 | private String getSupportAbis() {
93 | String[] abis = Build.SUPPORTED_ABIS;
94 | StringBuilder abi = new StringBuilder();
95 | for (int i = 0; i < abis.length; i++) {
96 | if (i == 0) {
97 | abi.append(abis[i]);
98 | } else {
99 | abi.append(" & ").append(abis[i]);
100 | }
101 | }
102 | return abi.toString();
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yaerin/xposed/hider/util/Utilities.java:
--------------------------------------------------------------------------------
1 | package com.yaerin.xposed.hider.util;
2 |
3 | import android.content.Context;
4 | import android.content.pm.ApplicationInfo;
5 | import android.content.pm.PackageManager;
6 |
7 | import com.yaerin.xposed.hider.bean.AppInfo;
8 |
9 | import java.util.ArrayList;
10 | import java.util.List;
11 |
12 |
13 | public class Utilities {
14 |
15 | public static boolean isSystemApp(int flags) {
16 | return (flags & ApplicationInfo.FLAG_SYSTEM) != 0;
17 | }
18 |
19 | public static List getAppList(Context context, boolean sys) {
20 | PackageManager pm = context.getPackageManager();
21 | List apps = pm.getInstalledApplications(0);
22 | List newList = new ArrayList<>();
23 | for (int i = 0; i < apps.size(); i++) {
24 | ApplicationInfo info = apps.get(i);
25 | if (!isSystemApp(info.flags) || sys) {
26 | newList.add(new AppInfo(
27 | info.packageName, info.loadLabel(pm).toString(), info.flags, info.loadIcon(pm)
28 | ));
29 | }
30 | }
31 | return newList;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/app/src/main/java/com/yaerin/xposed/hider/widget/AppView.java:
--------------------------------------------------------------------------------
1 | package com.yaerin.xposed.hider.widget;
2 |
3 | import android.content.Context;
4 | import android.graphics.drawable.ColorDrawable;
5 | import android.util.AttributeSet;
6 | import android.view.LayoutInflater;
7 | import android.widget.Checkable;
8 | import android.widget.ImageView;
9 | import android.widget.RelativeLayout;
10 | import android.widget.TextView;
11 |
12 | import com.yaerin.xposed.hider.R;
13 | import com.yaerin.xposed.hider.bean.AppInfo;
14 | import com.yaerin.xposed.hider.util.ConfigUtils;
15 |
16 | public class AppView extends RelativeLayout implements Checkable {
17 |
18 | private AppInfo mAppInfo;
19 |
20 | private ImageView mIcon;
21 | private TextView mName;
22 | private TextView mPackage;
23 |
24 | private boolean mChecked;
25 |
26 | public AppView(Context context, AppInfo info) {
27 | super(context);
28 | LayoutInflater.from(context).inflate(R.layout.view_app, this, true);
29 | mIcon = findViewById(R.id.app_icon);
30 | mName = findViewById(R.id.app_name);
31 | mPackage = findViewById(R.id.app_package);
32 | setAppInfo(info);
33 | }
34 |
35 | public AppView(Context context) {
36 | super(context);
37 | }
38 |
39 | public AppView(Context context, AttributeSet attrs) {
40 | super(context, attrs);
41 | }
42 |
43 | public AppView(Context context, AttributeSet attrs, int defStyleAttr) {
44 | super(context, attrs, defStyleAttr);
45 | }
46 |
47 | public AppInfo getAppInfo() {
48 | return mAppInfo;
49 | }
50 |
51 | public void setAppInfo(AppInfo info) {
52 | mAppInfo = info;
53 | mIcon.setImageDrawable(info.getIcon());
54 | mName.setText(info.getLabel());
55 | mPackage.setText(info.getPackageName());
56 | }
57 |
58 | @Override
59 | public boolean isChecked() {
60 | return mChecked;
61 | }
62 |
63 | @Override
64 | public void setChecked(boolean checked) {
65 | mChecked = checked;
66 | setBackground(checked ? new ColorDrawable(0xFFE1A7A2) : null);
67 | }
68 |
69 | @Override
70 | public void toggle() {
71 | setChecked(!isChecked());
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/app/src/main/java/top/fols/box/io/ByteArrayOutputStreamUtils.java:
--------------------------------------------------------------------------------
1 | package top.fols.box.io;
2 |
3 | import java.io.IOException;
4 | import java.io.OutputStream;
5 | import java.io.UnsupportedEncodingException;
6 | import java.util.Arrays;
7 |
8 | public class ByteArrayOutputStreamUtils extends OutputStream {
9 | // 将“字节数组输出流”转换成字节数组。
10 | private static final byte[] mNullByteArray = new byte[0];
11 | // 保存“字节数组输出流”数据的数组
12 | private byte[] mBuffer;
13 | // “字节数组输出流”的计数
14 | private int mCount;
15 |
16 | // 构造函数:默认创建的字节数组大小是32。
17 | public ByteArrayOutputStreamUtils() {
18 | this(32);
19 | }
20 |
21 | // 构造函数:创建指定数组大小的“字节数组输出流”
22 | public ByteArrayOutputStreamUtils(int size) {
23 | if (size < 0) {
24 | throw new IllegalArgumentException("Negative initial size: " + size);
25 | }
26 | mBuffer = new byte[size];
27 | }
28 |
29 | public static int indexOf(byte[] array, byte b, int start, int indexRange) {
30 | if (array == null || array.length == 0 || start >= indexRange) {
31 | return -1;
32 | } else if (start < 0) {
33 | start = 0;
34 | }
35 | if (indexRange > array.length) {
36 | indexRange = array.length;
37 | }
38 | while (start < indexRange) {
39 | if (array[start] == b) {
40 | return start;
41 | }
42 | start++;
43 | }
44 | return -1;
45 | }
46 |
47 | public static int lastIndexOf(byte[] array, byte b, int startIndex, int indexRange) {
48 | if (array == null || array.length == 0 || indexRange > startIndex) {
49 | return -1;
50 | } else if (indexRange < 0) {
51 | indexRange = 0;
52 | }
53 | if (startIndex > array.length - 1) {
54 | startIndex = array.length - 1;
55 | }
56 | while (startIndex >= indexRange) {
57 | if (array[startIndex] == b) {
58 | return startIndex;
59 | }
60 | startIndex--;
61 | }
62 | return -1;
63 | }
64 |
65 | public static int indexOf(byte[] array, byte[] b, int start, int indexRange) {
66 | if (array == null || array.length == 0 || start > indexRange || b == null || b.length > array.length || b.length == 0 || indexRange - start + 1 < b.length) {
67 | return -1;
68 | } else if (start < 0) {
69 | start = 0;
70 | }
71 | if (indexRange > array.length) {
72 | indexRange = array.length;
73 | }
74 | int i, i2;
75 | for (i = start; i < indexRange; i++) {
76 | if (array[i] == b[0]) {
77 | if (indexRange - i < b.length) {
78 | break;
79 | }
80 | for (i2 = 1; i2 < b.length; i2++) {
81 | if (array[i + i2] != b[i2]) {
82 | break;
83 | }
84 | }
85 | if (i2 == b.length) {
86 | return i;
87 | }
88 | }
89 | }
90 | return -1;
91 | }
92 |
93 | public static int lastIndexOf(byte[] array, byte[] b, int startIndex, int indexRange) {
94 | if (array == null || array.length == 0 || indexRange > startIndex || b == null || b.length > array.length || b.length == 0 || startIndex - indexRange + 1 < b.length) {
95 | return -1;
96 | } else if (indexRange < 0) {
97 | indexRange = 0;
98 | }
99 | if (startIndex > array.length) {
100 | startIndex = array.length;
101 | }
102 | int i, i2;
103 | for (i = startIndex == array.length ? array.length - 1 : startIndex; i >= indexRange; i--) {
104 | if (array[i] == b[0]) {
105 | if (i + b.length > startIndex) {
106 | continue;
107 | }
108 | for (i2 = 1; i2 < b.length; i2++) {
109 | if (array[i + i2] != b[i2]) {
110 | break;
111 | }
112 | }
113 | if (i2 == b.length) {
114 | return i;
115 | }
116 | }
117 | }
118 | return -1;
119 | }
120 |
121 | public int getSize() {
122 | return mCount;
123 | }
124 |
125 | public void setSize(int size) {
126 | if (size > mBuffer.length) {
127 | size = mBuffer.length;
128 | }
129 | mCount = size;
130 | }
131 |
132 | public int getBuffSize() {
133 | return mBuffer.length;
134 | }
135 |
136 | // 确认“容量”。
137 | // 若“实际容量 < minCapacity”,则增加“字节数组输出流”的容量
138 | private void ensureCapacity(int minCapacity) {
139 | // overflow-conscious code
140 | if (minCapacity - mBuffer.length > 0) {
141 | grow(minCapacity);
142 | }
143 | }
144 |
145 | // 增加“容量”。
146 | private void grow(int minCapacity) {
147 | int oldCapacity = mBuffer.length;
148 | // “新容量”的初始化 = “旧容量”x2
149 | int newCapacity = oldCapacity << 1;
150 | // 比较“新容量”和“minCapacity”的大小,并选取其中较大的数为“新的容量”。
151 | if (newCapacity - minCapacity < 0) {
152 | newCapacity = minCapacity;
153 | }
154 | if (newCapacity < 0) {
155 | if (minCapacity < 0) {
156 | // overflow
157 | throw new OutOfMemoryError();
158 | }
159 | newCapacity = Integer.MAX_VALUE;
160 | }
161 | mBuffer = Arrays.copyOf(mBuffer, newCapacity);
162 | }
163 |
164 | // 写入一个字节b到“字节数组输出流”中,并将计数+1
165 | public void write(int b) {
166 | ensureCapacity(mCount + 1);
167 | mBuffer[mCount] = (byte) b;
168 | mCount += 1;
169 | }
170 |
171 | // 写入字节数组b到“字节数组输出流”中。off是“写入字节数组b的起始位置”,len是写入的长度
172 | @Override
173 | public void write(byte b[], int off, int len) {
174 | if ((off < 0) || (off > b.length) || (len < 0) ||
175 | ((off + len) - b.length > 0)) {
176 | throw new IndexOutOfBoundsException();
177 | }
178 | ensureCapacity(mCount + len);
179 | System.arraycopy(b, off, mBuffer, mCount, len);
180 | mCount += len;
181 | }
182 |
183 | // 写入输出流outb到“字节数组输出流”中。
184 | public void writeTo(OutputStream out) throws IOException {
185 | out.write(mBuffer, 0, mCount);
186 | }
187 |
188 | // 重置“字节数组输出流”的计数。
189 | public void reset() {
190 | mCount = 0;
191 | }
192 |
193 | public byte toByteArray()[] {
194 | if (mCount == 0) {
195 | return mNullByteArray;
196 | }
197 | return Arrays.copyOf(mBuffer, mCount);
198 | }
199 |
200 | // 返回“字节数组输出流”当前计数值
201 | public int size() {
202 | return mCount;
203 | }
204 |
205 | public String toString() {
206 | return new String(mBuffer, 0, mCount);
207 | }
208 |
209 | public String toString(String charsetName) throws UnsupportedEncodingException {
210 | return new String(mBuffer, 0, mCount, charsetName);
211 | }
212 |
213 | @Deprecated
214 | public String toString(int hibyte) {
215 | return new String(mBuffer, hibyte, 0, mCount);
216 | }
217 |
218 | public void close() {
219 | }
220 |
221 | public void releaseCache() {
222 | mBuffer = mNullByteArray;
223 | mCount = 0;
224 | }
225 |
226 | public byte[] getBuff() {
227 | return mBuffer;
228 | }
229 |
230 | public void seekIndex(int index) {
231 | setSize(index);
232 | }
233 |
234 | public int getIndex() {
235 | return mCount;
236 | }
237 |
238 | public int indexOfBuff(byte b, int start) {
239 | return indexOf(mBuffer, b, start, mBuffer.length);
240 | }
241 |
242 | public int indexOfBuff(byte[] b, int start) {
243 | return indexOf(mBuffer, b, start, mBuffer.length);
244 | }
245 |
246 | public int indexOfBuff(byte b, int start, int end) {
247 | return indexOf(mBuffer, b, start, end);
248 | }
249 |
250 | public int indexOfBuff(byte[] b, int start, int end) {
251 | return indexOf(mBuffer, b, start, end);
252 | }
253 |
254 | public int lastIndexOfBuff(byte b, int start) {
255 | return lastIndexOf(mBuffer, b, 0, start);
256 | }
257 |
258 | public int lastIndexOfBuff(byte[] b, int start) {
259 | return lastIndexOf(mBuffer, b, 0, start);
260 | }
261 |
262 | public int lastIndexOfBuff(byte b, int start, int end) {
263 | return lastIndexOf(mBuffer, b, start, end);
264 | }
265 |
266 | public int lastIndexOfBuff(byte[] b, int start, int end) {
267 | return lastIndexOf(mBuffer, b, start, end);
268 | }
269 |
270 | }
271 |
--------------------------------------------------------------------------------
/app/src/main/java/top/fols/box/io/FilterXpInputStream.java:
--------------------------------------------------------------------------------
1 | package top.fols.box.io;
2 |
3 | import android.support.annotation.NonNull;
4 |
5 | import java.io.InputStream;
6 | import java.util.Arrays;
7 |
8 | public class FilterXpInputStream extends InputStream {
9 | private final byte[] mXposedBytes = "xposed".getBytes(); // {120, 112, 111, 115, 101, 100}
10 | private final byte[] mReadBuffer = new byte[6];
11 | private final ByteArrayOutputStreamUtils mBuffer = new ByteArrayOutputStreamUtils();
12 | private final InputStream mStream;
13 |
14 | public FilterXpInputStream(InputStream stream) {
15 | this.mStream = stream;
16 | }
17 |
18 | @Override
19 | public int read() throws java.io.IOException {
20 | int read = mStream.read();
21 | if (read != -1) {
22 | byte b = (byte) read;
23 | mReadBuffer[0] = mReadBuffer[1];
24 | mReadBuffer[1] = mReadBuffer[2];
25 | mReadBuffer[2] = mReadBuffer[3];
26 | mReadBuffer[3] = mReadBuffer[4];
27 | mReadBuffer[4] = mReadBuffer[5];
28 | mReadBuffer[5] = b;
29 | if (Arrays.equals(mReadBuffer, mXposedBytes)) {
30 | return 'a';
31 | }
32 | }
33 | return read;
34 | }
35 |
36 | @Override
37 | public int read(@NonNull byte[] b, int off, int len) throws java.io.IOException {
38 | int read = mStream.read(b, off, len);
39 | if (read != -1) {
40 | int index;
41 | mBuffer.write(mReadBuffer);
42 | mBuffer.write(b, 0, read);
43 | int l = 0;
44 | while ((index = mBuffer.indexOfBuff(mXposedBytes, l, mBuffer.size())) > -1) {
45 | l = index + mXposedBytes.length;
46 | byte random = 'x';
47 | mBuffer.getBuff()[index] = random;
48 | mBuffer.getBuff()[index + 1] = random;
49 | mBuffer.getBuff()[index + 2] = random;
50 | mBuffer.getBuff()[index + 3] = random;
51 | mBuffer.getBuff()[index + 4] = random;
52 | mBuffer.getBuff()[index + 5] = random;
53 | }
54 | if (read == 1) {
55 | mReadBuffer[0] = mReadBuffer[1];
56 | mReadBuffer[1] = mReadBuffer[2];
57 | mReadBuffer[2] = mReadBuffer[3];
58 | mReadBuffer[3] = mReadBuffer[4];
59 | mReadBuffer[4] = mReadBuffer[5];
60 | mReadBuffer[5] = b[read - 1];
61 | } else if (read == 2) {
62 | mReadBuffer[0] = mReadBuffer[2];
63 | mReadBuffer[1] = mReadBuffer[3];
64 | mReadBuffer[2] = mReadBuffer[4];
65 | mReadBuffer[3] = mReadBuffer[5];
66 | mReadBuffer[4] = b[read - 2];
67 | mReadBuffer[5] = b[read - 1];
68 | } else if (read == 3) {
69 | mReadBuffer[0] = mReadBuffer[3];
70 | mReadBuffer[1] = mReadBuffer[4];
71 | mReadBuffer[2] = mReadBuffer[5];
72 | mReadBuffer[3] = b[read - 3];
73 | mReadBuffer[4] = b[read - 2];
74 | mReadBuffer[5] = b[read - 1];
75 | } else if (read == 4) {
76 | mReadBuffer[0] = mReadBuffer[4];
77 | mReadBuffer[1] = mReadBuffer[5];
78 | mReadBuffer[2] = b[read - 4];
79 | mReadBuffer[3] = b[read - 3];
80 | mReadBuffer[4] = b[read - 2];
81 | mReadBuffer[5] = b[read - 1];
82 | } else if (read == 5) {
83 | mReadBuffer[0] = mReadBuffer[5];
84 | mReadBuffer[1] = b[read - 5];
85 | mReadBuffer[2] = b[read - 4];
86 | mReadBuffer[3] = b[read - 3];
87 | mReadBuffer[4] = b[read - 2];
88 | mReadBuffer[5] = b[read - 1];
89 | } else if (read == 6 || read > 6) {
90 | mReadBuffer[0] = b[read - 6];
91 | mReadBuffer[1] = b[read - 5];
92 | mReadBuffer[2] = b[read - 4];
93 | mReadBuffer[3] = b[read - 3];
94 | mReadBuffer[4] = b[read - 2];
95 | mReadBuffer[5] = b[read - 1];
96 | }
97 |
98 | read = mBuffer.size() - 6;
99 | System.out.println(read);
100 | if (read > 0) {
101 | System.arraycopy(mBuffer.getBuff(), 6, b, 0, read);
102 | }
103 | }
104 | mBuffer.releaseCache();
105 | return read;
106 | }
107 |
108 | @Override
109 | public long skip(long n) throws java.io.IOException {
110 | return mStream.skip(n);
111 | }
112 |
113 | @Override
114 | public int available() throws java.io.IOException {
115 | return mStream.available();
116 | }
117 |
118 | @Override
119 | public void close() throws java.io.IOException {
120 | mStream.close();
121 | }
122 |
123 | @Override
124 | public synchronized void mark(int readlimit) {
125 | mStream.mark(readlimit);
126 | }
127 |
128 | @Override
129 | public synchronized void reset() throws java.io.IOException {
130 | mStream.reset();
131 | }
132 |
133 | @Override
134 | public boolean markSupported() {
135 | return mStream.markSupported();
136 | }
137 | }
138 |
139 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
11 |
12 |
17 |
18 |
32 |
33 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/view_app.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
13 |
14 |
24 |
25 |
35 |
36 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/main.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/langgithub/XposedHider/472bcc2d68d641402628d78f5bf39592a279e7f0/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/langgithub/XposedHider/472bcc2d68d641402628d78f5bf39592a279e7f0/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/langgithub/XposedHider/472bcc2d68d641402628d78f5bf39592a279e7f0/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/values-zh/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Xposed Hider
4 |
5 | 模块未启用
6 |
7 | 搜索
8 | 关于
9 | 设置
10 | 捐赠
11 | 显示系统应用
12 |
13 | 尽可能完美地隐藏Xposed
14 | 点击跳转至微信二维码
15 |
16 | Copyright © 2017–2018 Yaerin All rights reserved.
17 |
18 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #00BCD4
4 | #0097A7
5 | #00E5FF
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Xposed Hider
4 |
5 | Module is NOT enabled
6 |
7 | Search
8 | About
9 | Settings
10 | Donate
11 | Show System APP
12 |
13 | This module will hide your Xposed as apparently as possible.
14 | Click to view WeChat QR code.
15 |
16 | Copyright © 2017–2018 Yaerin All rights reserved.
17 |
18 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
9 |
12 |
15 |
16 |
17 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 |
5 | repositories {
6 | google()
7 | jcenter()
8 | }
9 | dependencies {
10 | classpath 'com.android.tools.build:gradle:3.2.1'
11 |
12 |
13 | // NOTE: Do not place your application dependencies here; they belong
14 | // in the individual module build.gradle files
15 | }
16 | }
17 |
18 | allprojects {
19 | repositories {
20 | google()
21 | jcenter()
22 | }
23 | }
24 |
25 | task clean(type: Delete) {
26 | delete rootProject.buildDir
27 | }
28 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx1536m
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
14 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/langgithub/XposedHider/472bcc2d68d641402628d78f5bf39592a279e7f0/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS=""
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn () {
37 | echo "$*"
38 | }
39 |
40 | die () {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Escape application args
158 | save () {
159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
160 | echo " "
161 | }
162 | APP_ARGS=$(save "$@")
163 |
164 | # Collect all arguments for the java command, following the shell quoting and substitution rules
165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
166 |
167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
169 | cd "$(dirname "$0")"
170 | fi
171 |
172 | exec "$JAVACMD" "$@"
173 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------