├── .gitattributes ├── .gitignore ├── .idea ├── codeStyles │ └── Project.xml ├── compiler.xml ├── gradle.xml ├── jarRepositories.xml ├── misc.xml ├── modules.xml ├── runConfigurations.xml ├── vcs.xml └── workspace.xml ├── LICENSE ├── README.md ├── app ├── .gitignore ├── adb_process │ ├── .idea │ │ ├── artifacts │ │ │ └── adb_process_jar.xml │ │ ├── compiler.xml │ │ ├── description.html │ │ ├── encodings.xml │ │ ├── misc.xml │ │ ├── modules.xml │ │ ├── vcs.xml │ │ └── workspace.xml │ ├── help.md │ ├── jar │ │ ├── adb_process.dex │ │ └── adb_process.jar │ ├── out │ │ └── production │ │ │ └── adb_process │ │ │ └── META-INF │ │ │ └── MANIFEST.MF │ ├── src │ │ ├── META-INF │ │ │ └── MANIFEST.MF │ │ ├── Main.java │ │ └── shell │ │ │ ├── GlobalState.java │ │ │ ├── KeepShell.java │ │ │ ├── KeepShellPublic.java │ │ │ ├── RemoteAPI.java │ │ │ ├── ScreenColor.java │ │ │ └── ShellExecutor.java │ └── steps.txt ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── omarea │ │ └── gesture │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── assets │ │ ├── adb_process.dex │ │ └── up.sh │ ├── java │ │ └── com │ │ │ └── omarea │ │ │ └── gesture │ │ │ ├── AccessibilityServiceGesture.java │ │ │ ├── ActionModel.java │ │ │ ├── AdbProcessExtractor.java │ │ │ ├── AppSwitchActivity.java │ │ │ ├── BatteryReceiver.java │ │ │ ├── DialogAppSwitchExclusive.java │ │ │ ├── DialogFrequentlyAppEdit.java │ │ │ ├── DialogHandlerEX.java │ │ │ ├── EnhancedModeGuide.java │ │ │ ├── FixAppSwitchDelay.java │ │ │ ├── Gesture.java │ │ │ ├── SettingsActivity.java │ │ │ ├── SpfConfig.java │ │ │ ├── SpfConfigEx.java │ │ │ ├── StartActivity.java │ │ │ ├── WhiteBarColor.java │ │ │ ├── fragments │ │ │ ├── Fragment3Section.java │ │ │ ├── FragmentBasic.java │ │ │ ├── FragmentOther.java │ │ │ ├── FragmentSettingsBase.java │ │ │ ├── FragmentSimple.java │ │ │ └── FragmentWhiteBar.java │ │ │ ├── remote │ │ │ └── RemoteAPI.java │ │ │ ├── shell │ │ │ ├── KeepShell.java │ │ │ ├── KeepShellPublic.java │ │ │ └── ShellExecutor.java │ │ │ ├── ui │ │ │ ├── QuickPanel.java │ │ │ ├── ReTouchHelper.java │ │ │ ├── SideGestureBar.java │ │ │ ├── ThreeSectionView.java │ │ │ ├── TouchBarView.java │ │ │ ├── TouchIconCache.java │ │ │ ├── VisualFeedbackView.java │ │ │ ├── iOSTouchBarView.java │ │ │ └── iOSWhiteBar.java │ │ │ └── util │ │ │ ├── AppInfo.java │ │ │ ├── AppLauncher.java │ │ │ ├── AppListHelper.java │ │ │ ├── AppWindowed.java │ │ │ ├── BatteryUtils.java │ │ │ ├── GlobalState.java │ │ │ ├── Handlers.java │ │ │ ├── Memory.java │ │ │ ├── ReceiverLock.java │ │ │ ├── ReceiverLockHandler.java │ │ │ ├── Recents.java │ │ │ ├── ResumeNavBar.java │ │ │ ├── ScreenState.java │ │ │ ├── SystemProperty.java │ │ │ └── UITools.java │ └── res │ │ ├── anim │ │ ├── gesture_app_exit.xml │ │ ├── gesture_app_exit_2.xml │ │ ├── gesture_app_open_enter.xml │ │ ├── gesture_app_open_exit.xml │ │ ├── gesture_back_home.xml │ │ ├── gesture_back_home_2.xml │ │ ├── gesture_next_enter.xml │ │ ├── gesture_next_enter_2.xml │ │ ├── gesture_next_enter_basic.xml │ │ ├── gesture_next_enter_fast.xml │ │ ├── gesture_next_exit.xml │ │ ├── gesture_next_exit_2.xml │ │ ├── gesture_next_exit_basic.xml │ │ ├── gesture_next_exit_fast.xml │ │ ├── gesture_prev_enter.xml │ │ ├── gesture_prev_enter_2.xml │ │ ├── gesture_prev_enter_basic.xml │ │ ├── gesture_prev_enter_fast.xml │ │ ├── gesture_prev_exit.xml │ │ ├── gesture_prev_exit_2.xml │ │ ├── gesture_prev_exit_basic.xml │ │ ├── gesture_prev_exit_fast.xml │ │ ├── gesture_quick_panel_bottom_in.xml │ │ ├── gesture_quick_panel_bottom_out.xml │ │ ├── gesture_quick_panel_left_in.xml │ │ ├── gesture_quick_panel_left_out.xml │ │ ├── gesture_quick_panel_right_in.xml │ │ └── gesture_quick_panel_right_out.xml │ │ ├── drawable │ │ ├── adb_off.png │ │ ├── adb_on.png │ │ ├── bar_background.xml │ │ ├── color_picker_alpha_gradient.xml │ │ ├── color_picker_bg_gradient.xml │ │ ├── color_picker_blue_gradient.xml │ │ ├── color_picker_green_gradient.xml │ │ ├── color_picker_red_gradient.xml │ │ ├── color_picker_seekbar_thumb.xml │ │ ├── frequently_edit_bg.xml │ │ ├── gesture_card_view.xml │ │ ├── gesture_card_view_bottom.xml │ │ ├── gesture_card_view_top.xml │ │ ├── gesture_copy.png │ │ ├── gesture_icon_add.png │ │ ├── gesture_icon_edit.png │ │ ├── gesture_icon_ok.png │ │ ├── gesture_logo.png │ │ ├── gesture_quick_question.png │ │ ├── gesture_tab_apple.png │ │ ├── gesture_tab_edge.png │ │ ├── gesture_tab_lab.png │ │ ├── gesture_tab_settings.png │ │ ├── gesture_tab_switch.png │ │ ├── icon_question.png │ │ ├── landscape_bar_background.xml │ │ ├── power_switch_off.xml │ │ ├── power_switch_on.xml │ │ ├── power_switch_style.xml │ │ ├── quick_panel_bg.xml │ │ ├── quick_panel_bg_bottom.xml │ │ ├── quick_panel_bg_left.xml │ │ ├── quick_panel_bg_right.xml │ │ ├── seekbar_progress_drawable.xml │ │ ├── seekbar_thumb.xml │ │ ├── switch_thumb.xml │ │ ├── switch_track.xml │ │ ├── switch_track_close.xml │ │ ├── switch_track_open.xml │ │ ├── thumb.xml │ │ ├── touch_app.png │ │ ├── touch_app_window.png │ │ ├── touch_arrow_left.png │ │ ├── touch_arrow_right.png │ │ ├── touch_grid.png │ │ ├── touch_home.png │ │ ├── touch_info.png │ │ ├── touch_jump_next.png │ │ ├── touch_jump_previous.png │ │ ├── touch_lock.png │ │ ├── touch_notice.png │ │ ├── touch_power.png │ │ ├── touch_screenshot.png │ │ ├── touch_settings.png │ │ ├── touch_shell.png │ │ ├── touch_split.png │ │ ├── touch_switch.png │ │ ├── touch_tasks.png │ │ └── touch_window.png │ │ ├── layout │ │ ├── enhanced_mode.xml │ │ ├── gesture_color_picker.xml │ │ ├── gesture_fw_ios_touch_bar.xml │ │ ├── gesture_fw_three_section.xml │ │ ├── gesture_fw_vitual_touch_bar.xml │ │ ├── gesture_layout_action_option.xml │ │ ├── gesture_layout_app_option.xml │ │ ├── gesture_layout_app_option2.xml │ │ ├── gesture_layout_ex_shell.xml │ │ ├── gesture_layout_quick_panel_item.xml │ │ ├── gesture_settings.xml │ │ ├── gesture_settings_3section.xml │ │ ├── gesture_settings_basic.xml │ │ ├── gesture_settings_other.xml │ │ ├── gesture_settings_simple.xml │ │ ├── gesture_settings_white_bar.xml │ │ ├── gesture_switch_options.xml │ │ ├── layout_enhanced_mode_guide.xml │ │ ├── layout_frequently_app_edit.xml │ │ ├── layout_quick_panel.xml │ │ ├── layout_quick_panel_add.xml │ │ └── layout_quick_panel_landscape.xml │ │ ├── values │ │ ├── colors.xml │ │ ├── config.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ │ ├── xml-v24 │ │ └── keyevent_accessibility.xml │ │ └── xml │ │ └── keyevent_accessibility.xml │ └── test │ └── java │ └── com │ └── omarea │ └── gesture │ └── ExampleUnitTest.java ├── build.gradle ├── color-polling-apps.txt ├── docs ├── EnhancedMode.md ├── FAQ.md ├── adb_shell.jpg ├── dev-settings.jpg ├── dev-settings2.jpg ├── shell_window.jpg └── success.jpg ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle └── updateLog.log /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/caches 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | app/release_mini/* 10 | app/release/* 11 | .externalNativeBuild 12 | *.class 13 | -------------------------------------------------------------------------------- /.idea/codeStyles/Project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 20 | 21 | 22 | 23 | 25 | 26 | 27 |
28 | 29 | 30 | 31 | xmlns:android 32 | 33 | ^$ 34 | 35 | 36 | 37 |
38 |
39 | 40 | 41 | 42 | xmlns:.* 43 | 44 | ^$ 45 | 46 | 47 | BY_NAME 48 | 49 |
50 |
51 | 52 | 53 | 54 | .*:id 55 | 56 | http://schemas.android.com/apk/res/android 57 | 58 | 59 | 60 |
61 |
62 | 63 | 64 | 65 | .*:name 66 | 67 | http://schemas.android.com/apk/res/android 68 | 69 | 70 | 71 |
72 |
73 | 74 | 75 | 76 | name 77 | 78 | ^$ 79 | 80 | 81 | 82 |
83 |
84 | 85 | 86 | 87 | style 88 | 89 | ^$ 90 | 91 | 92 | 93 |
94 |
95 | 96 | 97 | 98 | .* 99 | 100 | ^$ 101 | 102 | 103 | BY_NAME 104 | 105 |
106 |
107 | 108 | 109 | 110 | .* 111 | 112 | http://schemas.android.com/apk/res/android 113 | 114 | 115 | ANDROID_ATTRIBUTE_ORDER 116 | 117 |
118 |
119 | 120 | 121 | 122 | .* 123 | 124 | .* 125 | 126 | 127 | BY_NAME 128 | 129 |
130 |
131 |
132 |
133 |
134 |
-------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 21 | 22 | -------------------------------------------------------------------------------- /.idea/jarRepositories.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 14 | 15 | 19 | 20 | 24 | 25 | 29 | 30 | 34 | 35 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 【1.2.0】 2 | - 增加横竖屏使用小白条的开关,以及动作和外观自定义选项 3 | - emmm,越来越臃肿了~ 4 | 5 | 【1.1.10】 6 | - 增加横屏时手势区域更换成小白条选项 7 | 8 | 【1.1.9】 9 | - 横屏时缩小底部手势区域降低游戏误触几率 10 | 11 | 【1.1.8】 12 | - 增加三星OneUI独有的优化提示 13 | 14 | 【1.1.7 更新日志】 15 | - 修复了发现的问题 16 | 【1.1.6更新日志】 17 | 18 | - 大幅(35%~90%)降低内存占用 19 | 20 | 21 | 22 | 【1.1.5更新日志】 23 | 24 | - 震动反馈调节加入,根据自己的喜好调节震动强度,把马达耍起来吧! 25 | 26 | 27 | 28 | 【1.1.4 更新日志】 29 | 30 | - 修复 底部热区高度调为0会遮挡全屏的问题 31 | 32 | - 修复 手势动作设置项错位 33 | 34 | - 增加悬停手势触发时长选项 35 | 36 | 37 | 38 | 【1.1.3 更新日志】 39 | 40 | - 诈尸的一天,增加热区灵敏度 41 | 42 | - 允许调整底部热区宽度 43 | 44 | - 进入设置界面时热区高亮显示 45 | 46 | 47 | 48 | 【1.1.2 更新日志】 49 | 50 | - 修复了一些动画细节问题。emmm,似乎对于一款追求轻量的软件来说,差不多可以结束更新了,如果没有重大bug出现的话 51 | 52 | 53 | 54 | 【1.1.0 更新日志】 55 | 56 | - 终于开始做自定义选项了,时间仓促 界面和细节略粗糙,见谅~ 57 | 58 | - 为了方便部分用户锁定后台,改为默认显示桌面图标 59 | 60 | 61 | 62 | 63 | 64 | 【1.0.6 极致精简版 更新日志】 65 | 66 | - 修复在部分设备上偶现的底部手势热区变大 67 | 68 | - 优化悬停手势震动反馈 69 | 70 | 71 | 72 | 【1.0.5 更新日志】 73 | 74 | - 修复在5.0系统上启动失败 75 | 76 | 77 | 78 | 【1.0.4 更新日志】 79 | 80 | - 大幅压缩软件体积 81 | 82 | 83 | 84 | 【1.0.3 更新日志】 85 | 86 | - 为了方便大家锁定后台,增加一个切换启动图标的选项(默认还是不显示启动图标,从辅助服务界面的设置进去,不懂的可以看截图) 87 | 88 | 89 | 90 | 【1.0.2 更新日志】 91 | 92 | - 修复手势动画顶部被截断的问题 93 | 94 | 95 | 96 | 【1.0.1 更新日志】 97 | 98 | - 降低系统版本要求到 Android 5.0 99 | 100 | - 优化手势震动为 仅滑动悬停才震动 101 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | /app/release 3 | /app/release/* -------------------------------------------------------------------------------- /app/adb_process/.idea/artifacts/adb_process_jar.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | $PROJECT_DIR$/jar 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /app/adb_process/.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /app/adb_process/.idea/description.html: -------------------------------------------------------------------------------- 1 | Simple Java application that includes a class with main() method -------------------------------------------------------------------------------- /app/adb_process/.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/adb_process/.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/adb_process/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /app/adb_process/.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/adb_process/help.md: -------------------------------------------------------------------------------- 1 | Demo:https://github.com/zgj224/Android-Demo/tree/master/app_process_exec_java_demo 2 | 栗子: 3 | # am start -n com.android.browser/com.android.browser.BrowserActivity 4 | 这里的am命令是一个可执行文件,查看系统am可以发现其实里面调用的是app_process 5 | # adb root 6 | # adb shell cat /system/bin/am 7 | 8 | #!/system/bin/sh 9 | base=/system 10 | export CLASSPATH=$base/framework/am.jar 11 | exec app_process $base/bin com.android.commands.am.Am "$@" 12 | 13 | 14 | 1.执行jar包里的java可执行文件 15 | 使用app_process启动java文件,其中java里必须有main()方法,这是函数入口。 16 | # adb shell CLASSPATH=/system/framework/Demo.jar exec app_process /system/bin com.example.Demo 17 | 18 | 或在apk里启动一个可执行com.example.helloworld.Console里的main() 19 | # adb shell CLASSPATH=/data/app/com.example.helloworld-1.apk exec app_process /system/bin com.example.helloworld.Console 20 | 注意:/system/bin这个目录可以替换为任意目录 21 | 22 | 2.执行java文件 23 | <1>.Hello.java 24 | public static class Hello { 25 |   public void main(String args[]){ 26 |     System.out.println("Hello Android"); 27 |   } 28 | } 29 | 30 | <2>.编译 31 | # javac Hello.java 32 | 编译出Hello.class文件可以在普通的jvm上运行,要放到android下还需要转换成dex,需要用android sdk中的dx工具进行转换 33 | > 如果出现“错误: 编码GBK的不可映射字符”提示,可使用 `javac Hello.java -encoding UTF-8` 命令编译 34 | 35 | # cd SDK/build-tools //SDK为自己下载的android sdk(例如C:\Users\用户名\AppData\Local\Android\Sdk\build-tools\29.0.2) 36 | # dx --dex --output=Hello.dex Hello.class 37 | 得到Hello.dex 38 | 39 | <3>.Hello.dex push到/sdcard 40 | # adb push Hello.dex /sdcard 41 | 42 | <4>.使用app_process 运行hello.dex 43 | # app_process -Djava.class.path=/sdcard/Hello.dex /sdcard Hello 44 | ———————————————— 45 | 版权声明:本文为CSDN博主「慢慢的燃烧」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。 46 | 原文链接:https://blog.csdn.net/u010164190/article/details/81335727 -------------------------------------------------------------------------------- /app/adb_process/jar/adb_process.dex: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/helloklf/EdgeGesture/fca8d3aaa9552744161eccf582d386802d3d496d/app/adb_process/jar/adb_process.dex -------------------------------------------------------------------------------- /app/adb_process/jar/adb_process.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/helloklf/EdgeGesture/fca8d3aaa9552744161eccf582d386802d3d496d/app/adb_process/jar/adb_process.jar -------------------------------------------------------------------------------- /app/adb_process/out/production/adb_process/META-INF/MANIFEST.MF: -------------------------------------------------------------------------------- 1 | Manifest-Version: 1.0 2 | Main-Class: Main 3 | 4 | -------------------------------------------------------------------------------- /app/adb_process/src/META-INF/MANIFEST.MF: -------------------------------------------------------------------------------- 1 | Manifest-Version: 1.0 2 | Main-Class: Main 3 | 4 | -------------------------------------------------------------------------------- /app/adb_process/src/Main.java: -------------------------------------------------------------------------------- 1 | import shell.RemoteAPI; 2 | 3 | public class Main { 4 | static final Object lock = new Object(); 5 | 6 | public static void main(String[] args) { 7 | /* 8 | try { 9 | new ScreenColor().autoBarColor(); 10 | // System.out.println(KeepShellPublic.doCmdSync("dumpsys activity r | grep mActivityComponent | cut -f2 -d '=' | cut -f1 -d '/'")); 11 | // System.out.println(KeepShellPublic.doCmdSync("screencap > /sdcard/screen")); 12 | } catch (Exception ex) { 13 | System.out.println("错误!" + ex.getMessage()); 14 | } 15 | 16 | if (KeepShellPublic.doCmdSync("pm list packages com.omarea.gesture").contains("com.omarea.gesture")) { 17 | new Thread(new Runnable() { 18 | @Override 19 | public void run() { 20 | try { 21 | wait(2000); 22 | } catch (Exception ignored) { 23 | } 24 | KeepShellPublic.doCmdSync("am broadcast -a com.omarea.gesture.ConfigChanged"); 25 | } 26 | }).start(); 27 | } 28 | */ 29 | 30 | // System.out.println("Gesture ADB Process!"); 31 | 32 | RemoteAPI remoteAPI = new RemoteAPI(); 33 | remoteAPI.start(); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /app/adb_process/src/shell/GlobalState.java: -------------------------------------------------------------------------------- 1 | package shell; 2 | 3 | public class GlobalState { 4 | public static int displayHeight = 2340; 5 | public static int displayWidth = 1080; 6 | public static int lastBarColor = Integer.MIN_VALUE; 7 | public static boolean onBarColorGeting = false; 8 | } -------------------------------------------------------------------------------- /app/adb_process/src/shell/KeepShell.java: -------------------------------------------------------------------------------- 1 | package shell; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.InputStreamReader; 5 | import java.io.OutputStream; 6 | import java.nio.charset.Charset; 7 | import java.util.UUID; 8 | import java.util.concurrent.locks.ReentrantLock; 9 | 10 | /** 11 | * Created by Hello on 2018/01/23. 12 | */ 13 | public class KeepShell { 14 | private Process p = null; 15 | private OutputStream out = null; 16 | private BufferedReader reader = null; 17 | private ReentrantLock mLock = new ReentrantLock(); 18 | private long LOCK_TIMEOUT = 10000L; 19 | private long enterLockTime = 0L; 20 | private byte[] br = "\n\n".getBytes(Charset.defaultCharset()); 21 | 22 | public KeepShell() { 23 | } 24 | 25 | //尝试退出命令行程序 26 | public void tryExit() { 27 | try { 28 | if (out != null) 29 | out.close(); 30 | if (reader != null) 31 | reader.close(); 32 | } catch (Exception ex) { 33 | } 34 | try { 35 | p.destroy(); 36 | } catch (Exception ex) { 37 | } 38 | enterLockTime = 0L; 39 | out = null; 40 | reader = null; 41 | p = null; 42 | } 43 | 44 | private void getRuntimeShell() { 45 | if (p != null) 46 | return; 47 | Thread getSu = new Thread(new Runnable() { 48 | @Override 49 | public void run() { 50 | try { 51 | mLock.lockInterruptibly(); 52 | enterLockTime = System.currentTimeMillis(); 53 | p = ShellExecutor.getRuntime(); 54 | out = p.getOutputStream(); 55 | reader = new BufferedReader(new InputStreamReader(p.getInputStream())); 56 | new Thread(new Runnable() { 57 | @Override 58 | public void run() { 59 | try { 60 | BufferedReader errorReader = new BufferedReader(new InputStreamReader(p.getErrorStream())); 61 | while (true) { 62 | errorReader.readLine(); 63 | } 64 | } catch (Exception ex) { 65 | // System.out.println("Gesture ADB Error " + ex.getMessage()); 66 | } 67 | } 68 | }).start(); 69 | } catch (Exception ex) { 70 | } finally { 71 | enterLockTime = 0L; 72 | mLock.unlock(); 73 | } 74 | } 75 | }); 76 | getSu.start(); 77 | try { 78 | getSu.join(10000); 79 | } catch (InterruptedException e) { 80 | e.printStackTrace(); 81 | } 82 | if (p == null && getSu.getState() != Thread.State.TERMINATED) { 83 | enterLockTime = 0L; 84 | getSu.interrupt(); 85 | } 86 | } 87 | 88 | //执行脚本 89 | public String doCmdSync(String cmd) { 90 | if (mLock.isLocked() && enterLockTime > 0 && System.currentTimeMillis() - enterLockTime > LOCK_TIMEOUT) { 91 | tryExit(); 92 | } 93 | CharSequence uuid = UUID.randomUUID().toString().subSequence(0, 8); 94 | getRuntimeShell(); 95 | if (out != null) { 96 | String startTag = "--start--" + uuid + "--"; 97 | String endTag = "--end--" + uuid + "--"; 98 | // Log.e("shell-lock", cmd) 99 | try { 100 | try { 101 | mLock.lockInterruptibly(); 102 | } catch (InterruptedException e) { 103 | e.printStackTrace(); 104 | return "error"; 105 | } 106 | 107 | OutputStream out = p.getOutputStream(); 108 | if (out != null) { 109 | try { 110 | out.write(br); 111 | out.write(("echo '" + startTag + "'").getBytes(Charset.defaultCharset())); 112 | out.write(br); 113 | out.write(cmd.getBytes(Charset.defaultCharset())); 114 | out.write(br); 115 | out.write("echo \"\"".getBytes(Charset.defaultCharset())); 116 | out.write(br); 117 | out.write(("echo '" + endTag + "'").getBytes(Charset.defaultCharset())); 118 | out.write(br); 119 | out.flush(); 120 | } catch (Exception ex) { 121 | } 122 | 123 | StringBuilder results = new StringBuilder(); 124 | boolean unstart = true; 125 | while (reader != null) { 126 | String line = reader.readLine(); 127 | if (line == null || line.contains("--end--")) { 128 | break; 129 | } else if (line.equals(startTag)) { 130 | unstart = false; 131 | } else if (!unstart) { 132 | results.append(line); 133 | results.append("\n"); 134 | } 135 | } 136 | // Log.e("shell-unlock", cmd) 137 | // Log.d("Shell", cmd.toString() + "\n" + "Result:"+results.toString().trim()) 138 | return results.toString().trim(); 139 | } else { 140 | return "error"; 141 | } 142 | } catch (Exception e) { 143 | tryExit(); 144 | return "error"; 145 | } finally { 146 | enterLockTime = 0L; 147 | mLock.unlock(); 148 | } 149 | } else { 150 | tryExit(); 151 | return "error"; 152 | } 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /app/adb_process/src/shell/KeepShellPublic.java: -------------------------------------------------------------------------------- 1 | package shell; 2 | 3 | /** 4 | * Created by Hello on 2018/01/23. 5 | */ 6 | public class KeepShellPublic { 7 | private static KeepShell keepShell = null; 8 | 9 | //执行脚本 10 | public static String doCmdSync(String cmd) { 11 | if (keepShell == null) { 12 | keepShell = new KeepShell(); 13 | } 14 | return keepShell.doCmdSync(cmd); 15 | } 16 | 17 | public static void tryExit() { 18 | if (keepShell != null) { 19 | keepShell.tryExit(); 20 | keepShell = null; 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /app/adb_process/src/shell/ShellExecutor.java: -------------------------------------------------------------------------------- 1 | package shell; 2 | 3 | import java.io.IOException; 4 | 5 | public class ShellExecutor { 6 | private static Process getProcess(String run) throws IOException { 7 | Runtime runtime = Runtime.getRuntime(); 8 | return runtime.exec(run); 9 | } 10 | 11 | public static Process getRuntime() throws IOException { 12 | return getProcess("sh"); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /app/adb_process/steps.txt: -------------------------------------------------------------------------------- 1 | C:\Users\helloklf\AppData\Local\Android\Sdk\build-tools\28.0.3\dx --dex --output=./jar/adb_process.dex ./jar/adb_process.jar 2 | 3 | adb push ./jar/adb_process.dex /sdcard/adb_process.dex 4 | 5 | adb shell dalvikvm -cp /sdcard/adb_process.dex Main || app_process -Djava.class.path=/sdcard/adb_process.dex /sdcard Main 6 | 7 | 8 | # 直接启动jar也是可以的,但是dalvikvm也可以启动dex文件 9 | adb push ./jar/adb_process.dex /sdcard/adb_process.jar 10 | adb shell dalvikvm -cp /sdcard/adb_process.jar Main 11 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 29 5 | signingConfigs { 6 | omarea_Signing { 7 | keyAlias 'omarea.com' 8 | keyPassword 'asdf1234' 9 | storeFile file('D:/omoarea.jks') 10 | storePassword 'asdf1234' 11 | } 12 | } 13 | defaultConfig { 14 | resConfigs "zh" 15 | applicationId "com.omarea.gesture" 16 | minSdkVersion 21 17 | targetSdkVersion 29 18 | versionCode 104 19 | versionName "1.6.4" 20 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 21 | } 22 | buildTypes { 23 | release_mini { 24 | shrinkResources true 25 | minifyEnabled true 26 | // debuggable true 27 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 28 | } 29 | release { 30 | debuggable true 31 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 32 | } 33 | debug { 34 | // signingConfig signingConfigs.omarea_Signing 35 | minifyEnabled false 36 | debuggable true 37 | jniDebuggable = false 38 | } 39 | } 40 | lintOptions { 41 | checkReleaseBuilds false 42 | // Or, if you prefer, you can continue to check for errors in release builds, 43 | // but continue the build even when errors are found: 44 | abortOnError false 45 | } 46 | } 47 | 48 | dependencies { 49 | implementation fileTree(include: ['*.jar'], dir: 'libs') 50 | testImplementation 'junit:junit:4.13.1' 51 | androidTestImplementation 'androidx.test.ext:junit:1.1.2' 52 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' 53 | } 54 | repositories { 55 | mavenCentral() 56 | } 57 | -------------------------------------------------------------------------------- /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/androidTest/java/com/omarea/gesture/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.omarea.gesture; 2 | 3 | import android.content.Context; 4 | 5 | import org.junit.Test; 6 | import org.junit.runner.RunWith; 7 | 8 | import androidx.test.ext.junit.runners.AndroidJUnit4; 9 | import androidx.test.platform.app.InstrumentationRegistry; 10 | 11 | import static org.junit.Assert.assertEquals; 12 | 13 | /** 14 | * Instrumented test, which will execute on an Android device. 15 | * 16 | * @see Testing documentation 17 | */ 18 | @RunWith(AndroidJUnit4.class) 19 | public class ExampleInstrumentedTest { 20 | @Test 21 | public void useAppContext() { 22 | // Context of the app under test. 23 | Context appContext = InstrumentationRegistry.getTargetContext(); 24 | 25 | assertEquals("com.omarea.sesture", appContext.getPackageName()); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 12 | 15 | 18 | 19 | 20 | 21 | 22 | 32 | 36 | 37 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 99 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /app/src/main/assets/adb_process.dex: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/helloklf/EdgeGesture/fca8d3aaa9552744161eccf582d386802d3d496d/app/src/main/assets/adb_process.dex -------------------------------------------------------------------------------- /app/src/main/assets/up.sh: -------------------------------------------------------------------------------- 1 | file_name="adb_process.dex" 2 | 3 | path1="`dirname $0`/$file_name" 4 | path2="/storage/emulated/0/Android/data/com.omarea.gesture/cache/$file_name" 5 | path3="/sdcard/Android/data/com.omarea.gesture/cache/$file_name" 6 | path4="/data/media/0/Android/data/com.omarea.gesture/cache/$file_name" 7 | 8 | origin_path="" 9 | if [[ -e "$path1" ]];then 10 | origin_path="$path2" 11 | elif [[ -e "$path2" ]]; then 12 | origin_path="$path2" 13 | elif [[ -e "$path3" ]]; then 14 | origin_path="$path3" 15 | elif [[ -e "$path4" ]]; then 16 | origin_path="$path4" 17 | else 18 | echo 'Unknown sdcard !' 19 | exit 1 20 | fi 21 | 22 | cache_dir="/data/local/tmp" 23 | target_path="$cache_dir/gesture_process.dex" 24 | 25 | current_process=`pgrep -f gesture_process.dex` 26 | if [[ ! "$current_process" == "" ]] 27 | then 28 | echo 'Kill Current GestureProcess >>' 29 | kill -9 $current_process 30 | fi 31 | 32 | echo "Origin File: " $origin_path 33 | echo "Target File: " $target_path 34 | echo '' 35 | 36 | cmd package compile -m speed com.omarea.gesture 1 > /dev/null 37 | 38 | if [[ -e $origin_path ]]; then 39 | cp $origin_path $target_path 40 | nohup dalvikvm -cp $target_path Main >/dev/null 2>&1 & 41 | sleep 2 42 | nohup app_process -Djava.class.path=$target_path $cache_dir Main >/dev/null 2>&1 & 43 | sleep 5 44 | am broadcast -a com.omarea.gesture.ConfigChanged 1>/dev/null 45 | am broadcast -a com.omarea.gesture.AdbProcess 46 | else 47 | echo "Gesture's adb_process.dex not found !" 48 | fi 49 | 50 | -------------------------------------------------------------------------------- /app/src/main/java/com/omarea/gesture/ActionModel.java: -------------------------------------------------------------------------------- 1 | package com.omarea.gesture; 2 | 3 | import android.content.SharedPreferences; 4 | 5 | import java.io.Serializable; 6 | 7 | public class ActionModel implements Serializable { 8 | public int actionCode; 9 | public String title; 10 | public String exKey; 11 | public String st; 12 | public String shellCommand; 13 | 14 | private ActionModel(int code) { 15 | this.actionCode = code; 16 | } 17 | 18 | public ActionModel(int code, String title) { 19 | this.actionCode = code; 20 | this.title = title; 21 | } 22 | 23 | public static ActionModel getConfig(SharedPreferences config, String configKey, int defaultAction) { 24 | ActionModel actionModel = new ActionModel(config.getInt(configKey, defaultAction)); 25 | actionModel.exKey = configKey; 26 | 27 | return actionModel; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /app/src/main/java/com/omarea/gesture/AdbProcessExtractor.java: -------------------------------------------------------------------------------- 1 | package com.omarea.gesture; 2 | 3 | import android.content.Context; 4 | 5 | import com.omarea.gesture.remote.RemoteAPI; 6 | import com.omarea.gesture.shell.KeepShellPublic; 7 | import com.omarea.gesture.util.GlobalState; 8 | 9 | import java.io.BufferedReader; 10 | import java.io.File; 11 | import java.io.FileOutputStream; 12 | import java.io.InputStream; 13 | import java.io.InputStreamReader; 14 | 15 | public class AdbProcessExtractor { 16 | private boolean extractFile(Context context, String file) { 17 | try { 18 | File cacheDir = context.getExternalCacheDir(); 19 | cacheDir.mkdirs(); 20 | 21 | cacheDir.setExecutable(true); 22 | cacheDir.setWritable(true); 23 | 24 | InputStream inputStream = context.getAssets().open(file); 25 | File outFile = new File((cacheDir.getAbsolutePath() + "/" + file)); 26 | FileOutputStream fileOutputStream = new FileOutputStream(outFile); 27 | byte[] datas = new byte[10240]; 28 | while (true) { 29 | int len = inputStream.read(datas); 30 | if (len > 0) { 31 | fileOutputStream.write(datas, 0, len); 32 | } else { 33 | break; 34 | } 35 | } 36 | 37 | fileOutputStream.flush(); 38 | fileOutputStream.close(); 39 | inputStream.close(); 40 | 41 | outFile.setExecutable(true, false); 42 | outFile.setReadable(true, false); 43 | outFile.setWritable(true, false); 44 | 45 | return true; 46 | } catch (Exception ex) { 47 | return false; 48 | } 49 | } 50 | 51 | private boolean extractShellScript(Context context, String file) { 52 | try { 53 | File cacheDir = context.getExternalCacheDir(); 54 | cacheDir.mkdirs(); 55 | cacheDir.setExecutable(true); 56 | cacheDir.setWritable(true); 57 | 58 | InputStream inputStream = context.getAssets().open(file); 59 | File outFile = new File((cacheDir.getAbsolutePath() + "/" + file)); 60 | FileOutputStream fileOutputStream = new FileOutputStream(outFile); 61 | BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream)); 62 | StringBuilder stringBuffer = new StringBuilder(); 63 | String line; 64 | do { 65 | line = bufferedReader.readLine(); 66 | if (line == null) { 67 | break; 68 | } else { 69 | stringBuffer.append(line); 70 | stringBuffer.append("\n"); 71 | } 72 | } while (true); 73 | fileOutputStream.write(stringBuffer.toString().replaceAll("\r\n", "\n").replaceAll("\r", "\n").getBytes()); 74 | 75 | fileOutputStream.flush(); 76 | fileOutputStream.close(); 77 | inputStream.close(); 78 | 79 | outFile.setExecutable(true, false); 80 | outFile.setReadable(true, false); 81 | outFile.setWritable(true, false); 82 | 83 | return true; 84 | } catch (Exception ex) { 85 | return false; 86 | } 87 | } 88 | 89 | public String extract(Context context) { 90 | if (extractFile(context, "adb_process.dex") && extractShellScript(context, "up.sh")) { 91 | File cacheDir = context.getExternalCacheDir(); 92 | return cacheDir.getAbsolutePath() + "/up.sh"; 93 | } 94 | return null; 95 | } 96 | 97 | // 尝试连接AdbProcess,或使用root权限激活AdbProcess并连接 98 | public boolean updateAdbProcessState(Context context, boolean useRootStartService) { 99 | // 检测外部程序运行状态或使用root权限主动激活外部进程 100 | boolean rootMode = Gesture.config.getBoolean(SpfConfig.ROOT, SpfConfig.ROOT_DEFAULT); 101 | GlobalState.enhancedMode = RemoteAPI.isOnline(); 102 | if (useRootStartService && rootMode && !GlobalState.enhancedMode) { 103 | String file = extract(context); 104 | if (file != null) { 105 | String shell = "sh " + file + " >/dev/null 2>&1 &"; 106 | KeepShellPublic.doCmdSync(shell); 107 | Gesture.handler.postDelayed(new Runnable() { 108 | @Override 109 | public void run() { 110 | GlobalState.enhancedMode = RemoteAPI.isOnline(); 111 | } 112 | }, 5000); 113 | } 114 | } 115 | return GlobalState.enhancedMode; 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /app/src/main/java/com/omarea/gesture/BatteryReceiver.java: -------------------------------------------------------------------------------- 1 | package com.omarea.gesture; 2 | 3 | import android.content.BroadcastReceiver; 4 | import android.content.Context; 5 | import android.content.Intent; 6 | import android.os.BatteryManager; 7 | 8 | import com.omarea.gesture.util.GlobalState; 9 | 10 | public class BatteryReceiver extends BroadcastReceiver { 11 | private boolean powerConnected = false; 12 | public BatteryReceiver(){} 13 | 14 | public BatteryReceiver(Context context) { 15 | try { 16 | BatteryManager batteryManager = (BatteryManager) context.getSystemService(Context.BATTERY_SERVICE); 17 | GlobalState.batteryCapacity = batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY); 18 | if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { 19 | powerConnected = notCharging(batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_STATUS)); 20 | } 21 | } catch (Exception ignored) { 22 | } 23 | } 24 | 25 | private boolean notCharging(int state) { 26 | return state != BatteryManager.BATTERY_STATUS_NOT_CHARGING && state != BatteryManager.BATTERY_STATUS_DISCHARGING; 27 | } 28 | 29 | @Override 30 | public void onReceive(Context context, Intent intent) { 31 | if (intent == null) { 32 | return; 33 | } 34 | String action = intent.getAction(); 35 | if (action == null) { 36 | return; 37 | } 38 | 39 | int capacity = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1); 40 | switch (action) { 41 | case Intent.ACTION_BATTERY_CHANGED: { 42 | powerConnected = notCharging(intent.getIntExtra(BatteryManager.EXTRA_STATUS, -1)); 43 | break; 44 | } 45 | case Intent.ACTION_POWER_DISCONNECTED: { 46 | powerConnected = false; 47 | break; 48 | } 49 | case Intent.ACTION_POWER_CONNECTED: { 50 | powerConnected = true; 51 | break; 52 | } 53 | } 54 | if (capacity != GlobalState.batteryCapacity) { 55 | GlobalState.batteryCapacity = capacity; 56 | if (GlobalState.updateBar != null) { 57 | GlobalState.updateBar.run(); 58 | } 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /app/src/main/java/com/omarea/gesture/DialogAppSwitchExclusive.java: -------------------------------------------------------------------------------- 1 | package com.omarea.gesture; 2 | 3 | import android.app.AlertDialog; 4 | import android.content.Context; 5 | import android.content.DialogInterface; 6 | import android.content.Intent; 7 | import android.content.SharedPreferences; 8 | 9 | import com.omarea.gesture.util.AppInfo; 10 | import com.omarea.gesture.util.AppListHelper; 11 | 12 | import java.util.ArrayList; 13 | import java.util.Set; 14 | 15 | public class DialogAppSwitchExclusive { 16 | public void openDialog(final Context context) { 17 | AlertDialog.Builder alertDialog = new AlertDialog.Builder(context).setCancelable(false); 18 | 19 | final SharedPreferences configFile = context.getSharedPreferences(SpfConfig.AppSwitchBlackList, Context.MODE_PRIVATE); 20 | final Set inListApps = configFile.getAll().keySet(); 21 | 22 | final ArrayList appInfos = new AppListHelper().loadAppList(context); 23 | final String[] appNames = new String[appInfos.size()]; 24 | final boolean[] status = new boolean[appInfos.size()]; 25 | for (int i = 0; i < appInfos.size(); i++) { 26 | status[i] = inListApps.contains(appInfos.get(i).packageName); 27 | appNames[i] = appInfos.get(i).appName; 28 | } 29 | 30 | alertDialog 31 | .setTitle(context.getString(R.string.exclude_app)) 32 | .setMultiChoiceItems(appNames, 33 | status, new DialogInterface.OnMultiChoiceClickListener() { 34 | @Override 35 | public void onClick(DialogInterface dialog, int which, boolean isChecked) { 36 | status[which] = isChecked; 37 | } 38 | }) 39 | .setPositiveButton(R.string.confirm, new DialogInterface.OnClickListener() { 40 | @Override 41 | public void onClick(DialogInterface dialog, int which) { 42 | final SharedPreferences.Editor config = configFile.edit(); 43 | config.clear(); 44 | for (int i = 0; i < status.length; i++) { 45 | if (status[i]) { 46 | config.putBoolean(appInfos.get(i).packageName, true); 47 | } 48 | } 49 | config.apply(); 50 | try { 51 | Intent intent = new Intent(context.getString(R.string.app_switch_changed)); 52 | context.sendBroadcast(intent); 53 | } catch (Exception ignored) { 54 | } 55 | } 56 | }) 57 | .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { 58 | @Override 59 | public void onClick(DialogInterface dialog, int which) { 60 | } 61 | }) 62 | .show(); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /app/src/main/java/com/omarea/gesture/DialogHandlerEX.java: -------------------------------------------------------------------------------- 1 | package com.omarea.gesture; 2 | 3 | import android.app.AlertDialog; 4 | import android.content.Context; 5 | import android.content.DialogInterface; 6 | import android.content.SharedPreferences; 7 | import android.view.LayoutInflater; 8 | import android.view.View; 9 | import android.view.ViewGroup; 10 | import android.widget.BaseAdapter; 11 | import android.widget.EditText; 12 | import android.widget.TextView; 13 | 14 | import com.omarea.gesture.util.AppInfo; 15 | import com.omarea.gesture.util.AppListHelper; 16 | import com.omarea.gesture.util.Handlers; 17 | 18 | import java.util.ArrayList; 19 | 20 | public class DialogHandlerEX { 21 | public void openDialog(Context context, final String key, int customActionCode) { 22 | AlertDialog.Builder alertDialog = new AlertDialog.Builder(context).setCancelable(false); 23 | 24 | final SharedPreferences configFile = context.getSharedPreferences(SpfConfigEx.configFile, Context.MODE_PRIVATE); 25 | final SharedPreferences.Editor config = configFile.edit(); 26 | config.remove(SpfConfigEx.prefix_app + key); 27 | config.remove(SpfConfigEx.prefix_app_window + key); 28 | config.remove(SpfConfigEx.prefix_shell + key); 29 | 30 | switch (customActionCode) { 31 | case Handlers.CUSTOM_ACTION_APP: 32 | case Handlers.CUSTOM_ACTION_APP_WINDOW: { 33 | final String fullKey = (customActionCode == Handlers.CUSTOM_ACTION_APP ? SpfConfigEx.prefix_app : SpfConfigEx.prefix_app_window) + key; 34 | 35 | final ArrayList appInfos = new AppListHelper().loadAppList(context); 36 | final String currentApp = configFile.getString(fullKey, ""); 37 | alertDialog.setTitle(context.getString(R.string.custom_app)); 38 | int currentIndex = -1; 39 | if (currentApp != null && !currentApp.isEmpty()) { 40 | for (int i = 0; i < appInfos.size(); i++) { 41 | if (appInfos.get(i).packageName.equals(currentApp)) { 42 | currentIndex = i; 43 | break; 44 | } 45 | } 46 | } 47 | 48 | final int finalCurrentIndex = currentIndex; 49 | alertDialog.setSingleChoiceItems( 50 | new BaseAdapter() { 51 | @Override 52 | public int getCount() { 53 | return appInfos.size(); 54 | } 55 | 56 | @Override 57 | public Object getItem(int position) { 58 | return appInfos.get(position); 59 | } 60 | 61 | @Override 62 | public long getItemId(int position) { 63 | return position; 64 | } 65 | 66 | @Override 67 | public View getView(int position, View convertView, ViewGroup parent) { 68 | LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext()); 69 | View view = layoutInflater.inflate(R.layout.gesture_layout_app_option, null); 70 | TextView title = view.findViewById(R.id.item_title); 71 | TextView desc = view.findViewById(R.id.item_desc); 72 | AppInfo appInfo = (AppInfo) getItem(position); 73 | title.setText(appInfo.appName); 74 | desc.setText(appInfo.packageName); 75 | if (position == finalCurrentIndex) { 76 | title.setTextColor(title.getHighlightColor()); 77 | } 78 | 79 | return view; 80 | } 81 | }, 82 | currentIndex, new DialogInterface.OnClickListener() { 83 | @Override 84 | public void onClick(DialogInterface dialog, int which) { 85 | config.putString(fullKey, appInfos.get(which).packageName).apply(); 86 | 87 | dialog.dismiss(); 88 | } 89 | }); 90 | 91 | break; 92 | } 93 | case Handlers.CUSTOM_ACTION_SHELL: { 94 | final String fullKey = SpfConfigEx.prefix_shell + key; 95 | 96 | alertDialog.setTitle(context.getString(R.string.custom_shell)); 97 | View view = LayoutInflater.from(context).inflate(R.layout.gesture_layout_ex_shell, null); 98 | final EditText editText = view.findViewById(R.id.ex_shell); 99 | editText.setText(configFile.getString(fullKey, "")); 100 | 101 | alertDialog.setView(view); 102 | alertDialog.setPositiveButton(R.string.confirm, new DialogInterface.OnClickListener() { 103 | @Override 104 | public void onClick(DialogInterface dialog, int which) { 105 | config.putString(fullKey, editText.getText().toString()).apply(); 106 | } 107 | }); 108 | 109 | break; 110 | } 111 | default: { 112 | return; 113 | } 114 | } 115 | 116 | alertDialog.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { 117 | @Override 118 | public void onClick(DialogInterface dialog, int which) { 119 | } 120 | }); 121 | alertDialog.show(); 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /app/src/main/java/com/omarea/gesture/EnhancedModeGuide.java: -------------------------------------------------------------------------------- 1 | package com.omarea.gesture; 2 | 3 | import android.app.AlertDialog; 4 | import android.content.Context; 5 | import android.content.DialogInterface; 6 | import android.view.LayoutInflater; 7 | import android.view.View; 8 | import android.widget.EditText; 9 | 10 | public class EnhancedModeGuide { 11 | public void show(Context context, String shell) { 12 | View view = LayoutInflater.from(context).inflate(R.layout.layout_enhanced_mode_guide, null); 13 | EditText editText = view.findViewById(R.id.enhanced_mode_shell); 14 | editText.setText("adb -d shell sh " + shell); 15 | 16 | new AlertDialog.Builder(context).setView(view).setPositiveButton(context.getString(R.string.btn_ok), new DialogInterface.OnClickListener() { 17 | @Override 18 | public void onClick(DialogInterface dialog, int which) { 19 | 20 | } 21 | }) 22 | .setOnDismissListener(new DialogInterface.OnDismissListener() { 23 | @Override 24 | public void onDismiss(DialogInterface dialog) { 25 | 26 | } 27 | }) 28 | .create().show(); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /app/src/main/java/com/omarea/gesture/FixAppSwitchDelay.java: -------------------------------------------------------------------------------- 1 | package com.omarea.gesture; 2 | 3 | import android.app.Activity; 4 | import android.os.Bundle; 5 | 6 | public class FixAppSwitchDelay extends Activity { 7 | 8 | @Override 9 | protected void onCreate(Bundle savedInstanceState) { 10 | super.onCreate(savedInstanceState); 11 | finish(); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /app/src/main/java/com/omarea/gesture/Gesture.java: -------------------------------------------------------------------------------- 1 | package com.omarea.gesture; 2 | 3 | import android.annotation.SuppressLint; 4 | import android.app.Application; 5 | import android.content.Context; 6 | import android.content.SharedPreferences; 7 | import android.os.Build; 8 | import android.os.Handler; 9 | import android.os.StrictMode; 10 | import android.os.VibrationEffect; 11 | import android.os.Vibrator; 12 | import android.view.HapticFeedbackConstants; 13 | import android.view.View; 14 | import android.widget.Toast; 15 | 16 | public class Gesture extends Application { 17 | public static final Handler handler = new Handler(); 18 | @SuppressLint("StaticFieldLeak") 19 | public static Context context; 20 | private static Vibrator vibrator; 21 | public static SharedPreferences config; 22 | 23 | public static void vibrate(VibrateMode mode, View view) { 24 | if (vibrator == null) { 25 | vibrator = (Vibrator) (context.getSystemService(Context.VIBRATOR_SERVICE)); 26 | } 27 | 28 | if (vibrator.hasVibrator()) { 29 | if (config.getBoolean(SpfConfig.VIBRATOR_USE_SYSTEM, SpfConfig.VIBRATOR_USE_SYSTEM_DEFAULT)) { 30 | switch (mode) { 31 | case VIBRATE_CLICK: { 32 | view.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY); 33 | return; 34 | } 35 | case VIBRATE_PRESS: { 36 | view.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); 37 | return; 38 | } 39 | case VIBRATE_SLIDE_HOVER: { 40 | view.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); 41 | return; 42 | } 43 | case VIBRATE_SLIDE: { 44 | if (config.getBoolean(SpfConfig.VIBRATOR_QUICK_SLIDE, SpfConfig.VIBRATOR_QUICK_SLIDE_DEFAULT)) { 45 | view.performHapticFeedback(HapticFeedbackConstants.CLOCK_TICK); 46 | } 47 | return; 48 | } 49 | default: { 50 | } 51 | } 52 | } else { 53 | if (mode == VibrateMode.VIBRATE_SLIDE) { 54 | if (!config.getBoolean(SpfConfig.VIBRATOR_QUICK_SLIDE, SpfConfig.VIBRATOR_QUICK_SLIDE_DEFAULT)) { 55 | return; 56 | } 57 | } 58 | 59 | boolean longTime = mode == VibrateMode.VIBRATE_SLIDE_HOVER || mode == VibrateMode.VIBRATE_PRESS; 60 | 61 | vibrator.cancel(); 62 | int time = longTime ? config.getInt(SpfConfig.VIBRATOR_TIME_LONG, SpfConfig.VIBRATOR_TIME_LONG_DEFAULT) : config.getInt(SpfConfig.VIBRATOR_TIME, SpfConfig.VIBRATOR_TIME_DEFAULT); 63 | int amplitude = longTime ? config.getInt(SpfConfig.VIBRATOR_AMPLITUDE_LONG, SpfConfig.VIBRATOR_AMPLITUDE_LONG_DEFAULT) : config.getInt(SpfConfig.VIBRATOR_AMPLITUDE, SpfConfig.VIBRATOR_AMPLITUDE_DEFAULT); 64 | if (time > 0 && amplitude > 0) { 65 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { 66 | vibrator.vibrate(VibrationEffect.createOneShot(time, amplitude)); 67 | } else { 68 | vibrator.vibrate(new long[]{0, time, amplitude}, -1); 69 | } 70 | } 71 | } 72 | } 73 | } 74 | 75 | public static void toast(final String text, final int time) { 76 | handler.post(new Runnable() { 77 | @Override 78 | public void run() { 79 | Toast.makeText(context, text, time).show(); 80 | } 81 | }); 82 | } 83 | 84 | @Override 85 | protected void attachBaseContext(Context base) { 86 | super.attachBaseContext(base); 87 | 88 | config = getSharedPreferences(SpfConfig.ConfigFile, Context.MODE_PRIVATE); 89 | StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build(); 90 | StrictMode.setThreadPolicy(policy); 91 | 92 | context = this; 93 | } 94 | 95 | public static enum VibrateMode { 96 | VIBRATE_CLICK, 97 | VIBRATE_PRESS, 98 | VIBRATE_SLIDE_HOVER, 99 | VIBRATE_SLIDE 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /app/src/main/java/com/omarea/gesture/SettingsActivity.java: -------------------------------------------------------------------------------- 1 | package com.omarea.gesture; 2 | 3 | import android.app.Activity; 4 | import android.app.ActivityManager; 5 | import android.app.UiModeManager; 6 | import android.content.Context; 7 | import android.content.Intent; 8 | import android.os.Build; 9 | import android.os.Bundle; 10 | import android.os.Handler; 11 | import android.os.Looper; 12 | import android.view.View; 13 | import android.view.WindowManager; 14 | import android.widget.TabHost; 15 | 16 | import com.omarea.gesture.fragments.Fragment3Section; 17 | import com.omarea.gesture.fragments.FragmentBasic; 18 | import com.omarea.gesture.fragments.FragmentOther; 19 | import com.omarea.gesture.fragments.FragmentSimple; 20 | import com.omarea.gesture.fragments.FragmentWhiteBar; 21 | import com.omarea.gesture.util.GlobalState; 22 | import com.omarea.gesture.util.Memory; 23 | 24 | 25 | public class SettingsActivity extends Activity { 26 | private boolean inLightMode = false; 27 | 28 | private void setTheme(boolean restart) { 29 | UiModeManager uiModeManager = (UiModeManager) getSystemService(Context.UI_MODE_SERVICE); 30 | boolean isNightMode = uiModeManager.getNightMode() == UiModeManager.MODE_NIGHT_YES; 31 | 32 | if (!isNightMode) { 33 | setTheme(R.style.gestureAppThemeLight); 34 | // 设置白色状态栏 35 | View window = this.getWindow().getDecorView(); 36 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { 37 | window.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR | View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR); 38 | } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 39 | window.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR); 40 | } 41 | } 42 | 43 | if (inLightMode != isNightMode && restart) { 44 | recreate(); 45 | } 46 | inLightMode = isNightMode; 47 | } 48 | 49 | @Override 50 | public void onCreate(Bundle savedInstanceState) { 51 | if (new Memory().getMemorySizeMB(this) > 4096) { 52 | getWindow().setFlags(WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED, WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED); 53 | } 54 | 55 | setTheme(false); 56 | super.onCreate(savedInstanceState); 57 | setContentView(R.layout.gesture_settings); 58 | 59 | try { 60 | final TabHost tabHost = findViewById(R.id.main_tabhost); 61 | tabHost.setup(); 62 | tabHost.addTab(tabHost.newTabSpec("Basic") 63 | .setContent(R.id.main_tab_0).setIndicator("", getDrawable(R.drawable.gesture_tab_switch))); 64 | tabHost.addTab(tabHost.newTabSpec("WhiteBar") 65 | .setContent(R.id.main_tab_1).setIndicator("", getDrawable(R.drawable.gesture_tab_apple))); 66 | tabHost.addTab(tabHost.newTabSpec("Edge") 67 | .setContent(R.id.main_tab_2).setIndicator("", getDrawable(R.drawable.gesture_tab_lab))); 68 | tabHost.addTab(tabHost.newTabSpec("ThreeSection") 69 | .setContent(R.id.main_tab_3).setIndicator("", getDrawable(R.drawable.gesture_tab_edge))); 70 | tabHost.addTab(tabHost.newTabSpec("Other") 71 | .setContent(R.id.main_tab_4).setIndicator("", getDrawable(R.drawable.gesture_tab_settings))); 72 | 73 | getFragmentManager().beginTransaction() 74 | .replace(R.id.main_tab_0, new FragmentBasic()).commit(); 75 | getFragmentManager().beginTransaction() 76 | .replace(R.id.main_tab_1, new FragmentWhiteBar()).commit(); 77 | getFragmentManager().beginTransaction() 78 | .replace(R.id.main_tab_2, new FragmentSimple()).commit(); 79 | getFragmentManager().beginTransaction() 80 | .replace(R.id.main_tab_3, new Fragment3Section()).commit(); 81 | getFragmentManager().beginTransaction() 82 | .replace(R.id.main_tab_4, new FragmentOther()).commit(); 83 | } catch (Exception ex) { 84 | } 85 | } 86 | 87 | private void updateView() { 88 | try { 89 | Intent intent = new Intent(getString(R.string.action_config_changed)); 90 | sendBroadcast(intent); 91 | } catch (Exception ignored) { 92 | } 93 | } 94 | 95 | @Override 96 | protected void onResume() { 97 | super.onResume(); 98 | 99 | GlobalState.testMode = true; 100 | new Handler(Looper.getMainLooper()).postDelayed(new Runnable() { 101 | @Override 102 | public void run() { 103 | updateView(); 104 | } 105 | }, 500); 106 | 107 | setTheme(true); 108 | } 109 | 110 | @Override 111 | protected void onPause() { 112 | super.onPause(); 113 | GlobalState.testMode = false; 114 | new Handler(Looper.getMainLooper()).postDelayed(new Runnable() { 115 | @Override 116 | public void run() { 117 | updateView(); 118 | } 119 | }, 500); 120 | } 121 | 122 | 123 | private void setExcludeFromRecents(boolean excludeFromRecents) { 124 | try { 125 | ActivityManager service = (ActivityManager) this.getSystemService(Context.ACTIVITY_SERVICE); 126 | int taskId = this.getTaskId(); 127 | for (ActivityManager.AppTask task : service.getAppTasks()) { 128 | if (task.getTaskInfo().id == taskId) { 129 | task.setExcludeFromRecents(excludeFromRecents); 130 | } 131 | } 132 | } catch (Exception ex) { 133 | } 134 | } 135 | 136 | @Override 137 | public void onBackPressed() { 138 | setExcludeFromRecents(true); 139 | super.onBackPressed(); 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /app/src/main/java/com/omarea/gesture/SpfConfigEx.java: -------------------------------------------------------------------------------- 1 | package com.omarea.gesture; 2 | 3 | public class SpfConfigEx { 4 | public static final String configFile = "handler_ex"; 5 | public static final String prefix_app = "app_"; 6 | public static final String prefix_app_window = "app_form_"; 7 | public static final String prefix_shell = "shell_"; 8 | public static final String frequently_apps = "frequently_apps3"; 9 | } 10 | -------------------------------------------------------------------------------- /app/src/main/java/com/omarea/gesture/StartActivity.java: -------------------------------------------------------------------------------- 1 | package com.omarea.gesture; 2 | 3 | public class StartActivity extends SettingsActivity { 4 | } 5 | -------------------------------------------------------------------------------- /app/src/main/java/com/omarea/gesture/WhiteBarColor.java: -------------------------------------------------------------------------------- 1 | package com.omarea.gesture; 2 | 3 | import com.omarea.gesture.remote.RemoteAPI; 4 | import com.omarea.gesture.util.GlobalState; 5 | 6 | public class WhiteBarColor { 7 | private static final Object threadRun = ""; 8 | private static ScreenCapThread thread; 9 | private static int nextTimes = 0; 10 | private static boolean notifyed = false; // 是否已经notify过,并且还未进入wait清除notifyed状态,避免多次notify进入队列 11 | 12 | public static void updateBarColorSingle() { 13 | updateBarColor(); 14 | } 15 | 16 | static void updateBarColorMultiple() { 17 | nextTimes = 2; 18 | updateBarColor(); 19 | } 20 | 21 | private static void updateBarColor() { 22 | if (thread != null && thread.isAlive() && !thread.isInterrupted()) { 23 | synchronized (threadRun) { 24 | if (!notifyed && (thread.getState() == Thread.State.WAITING || thread.getState() == Thread.State.TIMED_WAITING)) { 25 | threadRun.notify(); 26 | notifyed = true; 27 | } 28 | } 29 | } else { 30 | thread = new ScreenCapThread(); 31 | thread.start(); 32 | } 33 | } 34 | 35 | public static void updateDisplaySize() { 36 | 37 | } 38 | 39 | static class ScreenCapThread extends Thread { 40 | @Override 41 | public void run() { 42 | do { 43 | int color = RemoteAPI.getBarAutoColor(nextTimes > 0); 44 | if (color != Integer.MIN_VALUE) { 45 | GlobalState.iosBarColor = color; 46 | 47 | if (GlobalState.updateBar != null) { 48 | GlobalState.updateBar.run(); 49 | } 50 | } 51 | notifyed = false; 52 | try { 53 | synchronized (threadRun) { 54 | if (nextTimes > 0) { 55 | threadRun.wait(600); 56 | nextTimes -= 1; 57 | } else { 58 | threadRun.wait(); 59 | } 60 | } 61 | } catch (Exception ex) { 62 | break; 63 | } 64 | } 65 | while (true); 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /app/src/main/java/com/omarea/gesture/fragments/Fragment3Section.java: -------------------------------------------------------------------------------- 1 | package com.omarea.gesture.fragments; 2 | 3 | import android.os.Bundle; 4 | import android.view.LayoutInflater; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | 8 | import com.omarea.gesture.R; 9 | import com.omarea.gesture.SpfConfig; 10 | 11 | public class Fragment3Section extends FragmentSettingsBase { 12 | 13 | @Override 14 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 15 | 16 | return inflater.inflate(R.layout.gesture_settings_3section, container, false); 17 | } 18 | 19 | @Override 20 | public void onResume() { 21 | super.onResume(); 22 | 23 | bindCheckable(R.id.allow_three_section_landscape, SpfConfig.THREE_SECTION_LANDSCAPE, SpfConfig.THREE_SECTION_LANDSCAPE_DEFAULT); 24 | bindCheckable(R.id.allow_three_section_portrait, SpfConfig.THREE_SECTION_PORTRAIT, SpfConfig.THREE_SECTION_PORTRAIT_DEFAULT); 25 | bindSeekBar(R.id.bar_width_three_section, SpfConfig.THREE_SECTION_WIDTH, SpfConfig.THREE_SECTION_WIDTH_DEFAULT, true); 26 | bindSeekBar(R.id.three_section_height, SpfConfig.THREE_SECTION_HEIGHT, SpfConfig.THREE_SECTION_HEIGHT_DEFAULT, true); 27 | 28 | bindHandlerPicker(R.id.three_section_left_slide, SpfConfig.THREE_SECTION_LEFT_SLIDE, SpfConfig.THREE_SECTION_LEFT_SLIDE_DEFAULT); 29 | bindHandlerPicker(R.id.three_section_center_slide, SpfConfig.THREE_SECTION_CENTER_SLIDE, SpfConfig.THREE_SECTION_CENTER_SLIDE_DEFAULT); 30 | bindHandlerPicker(R.id.three_section_right_slide, SpfConfig.THREE_SECTION_RIGHT_SLIDE, SpfConfig.THREE_SECTION_RIGHT_SLIDE_DEFAULT); 31 | bindHandlerPicker(R.id.three_section_left_hover, SpfConfig.THREE_SECTION_LEFT_HOVER, SpfConfig.THREE_SECTION_LEFT_HOVER_DEFAULT); 32 | bindHandlerPicker(R.id.three_section_center_hover, SpfConfig.THREE_SECTION_CENTER_HOVER, SpfConfig.THREE_SECTION_CENTER_HOVER_DEFAULT); 33 | bindHandlerPicker(R.id.three_section_right_hover, SpfConfig.THREE_SECTION_RIGHT_HOVER, SpfConfig.THREE_SECTION_RIGHT_HOVER_DEFAULT); 34 | 35 | bindColorPicker(R.id.bar_color_three_section, SpfConfig.THREE_SECTION_COLOR, SpfConfig.THREE_SECTION_COLOR_DEFAULT, getString(R.string.feedback_color)); 36 | 37 | updateView(); 38 | } 39 | 40 | private void updateView() { 41 | setViewBackground(getActivity().findViewById(R.id.bar_color_three_section), config.getInt(SpfConfig.THREE_SECTION_COLOR, SpfConfig.THREE_SECTION_COLOR_DEFAULT)); 42 | 43 | updateActionText(R.id.three_section_left_slide, SpfConfig.THREE_SECTION_LEFT_SLIDE, SpfConfig.THREE_SECTION_LEFT_SLIDE_DEFAULT); 44 | updateActionText(R.id.three_section_center_slide, SpfConfig.THREE_SECTION_CENTER_SLIDE, SpfConfig.THREE_SECTION_CENTER_SLIDE_DEFAULT); 45 | updateActionText(R.id.three_section_right_slide, SpfConfig.THREE_SECTION_RIGHT_SLIDE, SpfConfig.THREE_SECTION_RIGHT_SLIDE_DEFAULT); 46 | updateActionText(R.id.three_section_left_hover, SpfConfig.THREE_SECTION_LEFT_HOVER, SpfConfig.THREE_SECTION_LEFT_HOVER_DEFAULT); 47 | updateActionText(R.id.three_section_center_hover, SpfConfig.THREE_SECTION_CENTER_HOVER, SpfConfig.THREE_SECTION_CENTER_HOVER_DEFAULT); 48 | updateActionText(R.id.three_section_right_hover, SpfConfig.THREE_SECTION_RIGHT_HOVER, SpfConfig.THREE_SECTION_RIGHT_HOVER_DEFAULT); 49 | } 50 | 51 | @Override 52 | protected void restartService() { 53 | updateView(); 54 | 55 | super.restartService(); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /app/src/main/java/com/omarea/gesture/fragments/FragmentSimple.java: -------------------------------------------------------------------------------- 1 | package com.omarea.gesture.fragments; 2 | 3 | import android.app.Activity; 4 | import android.os.Bundle; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | 9 | import com.omarea.gesture.R; 10 | import com.omarea.gesture.SpfConfig; 11 | 12 | public class FragmentSimple extends FragmentSettingsBase { 13 | @Override 14 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 15 | return inflater.inflate(R.layout.gesture_settings_simple, container, false); 16 | } 17 | 18 | @Override 19 | public void onResume() { 20 | super.onResume(); 21 | 22 | bindColorPicker(R.id.bar_edge_color, SpfConfig.CONFIG_EDGE_COLOR, SpfConfig.CONFIG_EDGE_COLOR_DEFAULT, getString(R.string.feedback_color)); 23 | 24 | bindCheckable(R.id.allow_bottom_landscape, SpfConfig.CONFIG_BOTTOM_ALLOW_LANDSCAPE, SpfConfig.CONFIG_BOTTOM_ALLOW_LANDSCAPE_DEFAULT); 25 | bindCheckable(R.id.allow_bottom_portrait, SpfConfig.CONFIG_BOTTOM_ALLOW_PORTRAIT, SpfConfig.CONFIG_BOTTOM_ALLOW_PORTRAIT_DEFAULT); 26 | bindSeekBar(R.id.bar_width_bottom, SpfConfig.CONFIG_BOTTOM_WIDTH, SpfConfig.CONFIG_BOTTOM_WIDTH_DEFAULT, true); 27 | bindHandlerPicker(R.id.tap_bottom, SpfConfig.CONFIG_BOTTOM_EVENT, SpfConfig.CONFIG_BOTTOM_EVENT_DEFAULT); 28 | bindHandlerPicker(R.id.hover_bottom, SpfConfig.CONFIG_BOTTOM_EVENT_HOVER, SpfConfig.CONFIG_BOTTOM_EVENT_HOVER_DEFAULT); 29 | 30 | bindCheckable(R.id.allow_right_landscape, SpfConfig.CONFIG_RIGHT_ALLOW_LANDSCAPE, SpfConfig.CONFIG_RIGHT_ALLOW_LANDSCAPE_DEFAULT); 31 | bindCheckable(R.id.allow_right_portrait, SpfConfig.CONFIG_RIGHT_ALLOW_PORTRAIT, SpfConfig.CONFIG_RIGHT_ALLOW_PORTRAIT_DEFAULT); 32 | bindSeekBar(R.id.bar_height_right, SpfConfig.CONFIG_RIGHT_HEIGHT, SpfConfig.CONFIG_RIGHT_HEIGHT_DEFAULT, true); 33 | bindHandlerPicker(R.id.tap_right, SpfConfig.CONFIG_RIGHT_EVENT, SpfConfig.CONFIG_RIGHT_EVENT_DEFAULT); 34 | bindHandlerPicker(R.id.hover_right, SpfConfig.CONFIG_RIGHT_EVENT_HOVER, SpfConfig.CONFIG_RIGHT_EVENT_HOVER_DEFAULT); 35 | 36 | bindCheckable(R.id.allow_left_landscape, SpfConfig.CONFIG_LEFT_ALLOW_LANDSCAPE, SpfConfig.CONFIG_LEFT_ALLOW_LANDSCAPE_DEFAULT); 37 | bindCheckable(R.id.allow_left_portrait, SpfConfig.CONFIG_LEFT_ALLOW_PORTRAIT, SpfConfig.CONFIG_LEFT_ALLOW_PORTRAIT_DEFAULT); 38 | bindSeekBar(R.id.bar_height_left, SpfConfig.CONFIG_LEFT_HEIGHT, SpfConfig.CONFIG_LEFT_HEIGHT_DEFAULT, true); 39 | bindHandlerPicker(R.id.tap_left, SpfConfig.CONFIG_LEFT_EVENT, SpfConfig.CONFIG_LEFT_EVENT_DEFAULT); 40 | bindHandlerPicker(R.id.hover_left, SpfConfig.CONFIG_LEFT_EVENT_HOVER, SpfConfig.CONFIG_LEFT_EVENT_HOVER_DEFAULT); 41 | 42 | bindSeekBar(R.id.edge_side_width, SpfConfig.CONFIG_HOT_SIDE_WIDTH, SpfConfig.CONFIG_HOT_SIDE_WIDTH_DEFAULT, true); 43 | bindSeekBar(R.id.edge_bottom_height, SpfConfig.CONFIG_HOT_BOTTOM_HEIGHT, SpfConfig.CONFIG_HOT_BOTTOM_HEIGHT_DEFAULT, true); 44 | 45 | updateView(); 46 | } 47 | 48 | 49 | private void updateView() { 50 | Activity activity = getActivity(); 51 | setViewBackground(activity.findViewById(R.id.bar_edge_color), config.getInt(SpfConfig.CONFIG_EDGE_COLOR, SpfConfig.CONFIG_EDGE_COLOR_DEFAULT)); 52 | 53 | updateActionText(R.id.tap_bottom, SpfConfig.CONFIG_BOTTOM_EVENT, SpfConfig.CONFIG_BOTTOM_EVENT_DEFAULT); 54 | updateActionText(R.id.hover_bottom, SpfConfig.CONFIG_BOTTOM_EVENT_HOVER, SpfConfig.CONFIG_BOTTOM_EVENT_HOVER_DEFAULT); 55 | updateActionText(R.id.tap_left, SpfConfig.CONFIG_LEFT_EVENT, SpfConfig.CONFIG_LEFT_EVENT_DEFAULT); 56 | updateActionText(R.id.hover_left, SpfConfig.CONFIG_LEFT_EVENT_HOVER, SpfConfig.CONFIG_LEFT_EVENT_HOVER_DEFAULT); 57 | updateActionText(R.id.tap_right, SpfConfig.CONFIG_RIGHT_EVENT, SpfConfig.CONFIG_RIGHT_EVENT_DEFAULT); 58 | updateActionText(R.id.hover_right, SpfConfig.CONFIG_RIGHT_EVENT_HOVER, SpfConfig.CONFIG_RIGHT_EVENT_HOVER_DEFAULT); 59 | } 60 | 61 | @Override 62 | protected void restartService() { 63 | updateView(); 64 | 65 | super.restartService(); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /app/src/main/java/com/omarea/gesture/remote/RemoteAPI.java: -------------------------------------------------------------------------------- 1 | package com.omarea.gesture.remote; 2 | 3 | import android.os.Build; 4 | 5 | import com.omarea.gesture.util.GlobalState; 6 | 7 | import java.io.BufferedReader; 8 | import java.io.IOException; 9 | import java.io.InputStreamReader; 10 | import java.net.URL; 11 | import java.net.URLConnection; 12 | import java.net.URLEncoder; 13 | 14 | public class RemoteAPI { 15 | private final static Object networkWaitLock = new Object(); 16 | private static String host = "http://localhost:8906/"; 17 | 18 | public static boolean isOnline() { 19 | String result = loadContent("version"); 20 | return result != null && !result.isEmpty(); 21 | } 22 | 23 | public static String[] getRecents() { 24 | return loadContent((Build.VERSION.SDK_INT <= Build.VERSION_CODES.P) ? "recent-9" : "recent-10").split("\n"); 25 | } 26 | 27 | public static int getBarAutoColor(boolean delayScreenCap) { 28 | // TODO:改为可配置而非自动 29 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { 30 | String isLightColor = loadContent("nav-light-color"); 31 | if (isLightColor != null && isLightColor.equals("true")) { 32 | return 0xFF000000; 33 | } 34 | } 35 | if (delayScreenCap) { 36 | // 延缓截图,以免在动画播放期间过早的截图导致颜色取到的还是黑色背景 37 | try { 38 | Thread.sleep(300); 39 | } catch (Exception ignored) { 40 | } 41 | } 42 | 43 | String colorStr = loadContent("bar-color?" + GlobalState.displayWidth + "x" + GlobalState.displayHeight); 44 | 45 | if (!(colorStr == null || colorStr.isEmpty())) { 46 | try { 47 | return Integer.parseInt(colorStr); 48 | } catch (Exception ignored) { 49 | } 50 | } 51 | return Integer.MIN_VALUE; 52 | } 53 | 54 | private static String loadContent(final String api) { 55 | final String[] result = {""}; 56 | new Thread(new Runnable() { 57 | @Override 58 | public void run() { 59 | synchronized (networkWaitLock) { 60 | try { 61 | URL url = new URL(host + api); 62 | result[0] = readResponse(url.openConnection()); 63 | } catch (Exception ignored) { 64 | } finally { 65 | networkWaitLock.notify(); 66 | } 67 | } 68 | } 69 | }).start(); 70 | try { 71 | synchronized (networkWaitLock) { 72 | networkWaitLock.wait(5000); 73 | } 74 | } catch (Exception ignored) { 75 | } 76 | return result[0]; 77 | } 78 | 79 | public static String getColorPollingApps() { 80 | final String[] results = {""}; 81 | new Thread(new Runnable() { 82 | @Override 83 | public void run() { 84 | synchronized (networkWaitLock) { 85 | try { 86 | URL url = new URL("https://vtools.oss-cn-beijing.aliyuncs.com/EdgeGesture/color-polling-apps.txt"); 87 | results[0] = readResponse(url.openConnection()); 88 | } catch (Exception ignored) { 89 | } finally { 90 | networkWaitLock.notify(); 91 | } 92 | } 93 | } 94 | }).start(); 95 | try { 96 | synchronized (networkWaitLock) { 97 | networkWaitLock.wait(5000); 98 | } 99 | } catch (Exception ignored) { 100 | } 101 | 102 | return results[0]; 103 | } 104 | 105 | private static String readResponse(URLConnection connection) { 106 | try { 107 | connection.setConnectTimeout(500); 108 | connection.setReadTimeout(3000); 109 | 110 | StringBuilder stringBuffer = new StringBuilder(); 111 | BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(connection.getInputStream())); 112 | String line = null; 113 | while (true) { 114 | line = bufferedReader.readLine(); 115 | if (line == null) { 116 | break; 117 | } else { 118 | stringBuffer.append(line); 119 | stringBuffer.append("\n"); 120 | } 121 | } 122 | return stringBuffer.toString().trim(); 123 | } catch (IOException ignored) { 124 | } 125 | return null; 126 | } 127 | 128 | public static void fixDelay() { 129 | new Thread(new Runnable() { 130 | @Override 131 | public void run() { 132 | loadContent("fix-delay"); 133 | } 134 | }).start(); 135 | } 136 | 137 | public static void xiaomiHandymode(final int mode) { 138 | new Thread(new Runnable() { 139 | @Override 140 | public void run() { 141 | loadContent("xiaomi-handymode?" + mode); 142 | } 143 | }).start(); 144 | } 145 | 146 | public static void startActivity(final String params) { 147 | new Thread(new Runnable() { 148 | @Override 149 | public void run() { 150 | try { 151 | StringBuilder paramsBuilder = new StringBuilder("am start -n com.omarea.gesture/.AppSwitchActivity"); 152 | if (params != null) { 153 | paramsBuilder.append(" "); 154 | paramsBuilder.append(params); 155 | } 156 | paramsBuilder.append(" --activity-no-animation --activity-no-history --activity-exclude-from-recents --activity-clear-top --activity-clear-task"); 157 | loadContent("shell?" + URLEncoder.encode(paramsBuilder.toString(), "UTF-8")); 158 | } catch (Exception ignored) { 159 | } 160 | } 161 | }).start(); 162 | } 163 | } 164 | -------------------------------------------------------------------------------- /app/src/main/java/com/omarea/gesture/shell/KeepShellPublic.java: -------------------------------------------------------------------------------- 1 | package com.omarea.gesture.shell; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * Created by Hello on 2018/01/23. 7 | */ 8 | public class KeepShellPublic { 9 | private static KeepShell keepShell = null; 10 | 11 | public static Boolean doCmdSync(List commands) { 12 | StringBuilder stringBuilder = new StringBuilder(); 13 | 14 | for (String cmd : commands) { 15 | stringBuilder.append(cmd); 16 | stringBuilder.append("\n\n"); 17 | } 18 | 19 | return doCmdSync(stringBuilder.toString()) != "error"; 20 | } 21 | 22 | //执行脚本 23 | public static String doCmdSync(String cmd) { 24 | if (keepShell == null) { 25 | keepShell = new KeepShell(); 26 | } 27 | return keepShell.doCmdSync(cmd); 28 | } 29 | 30 | //执行脚本 31 | public static Boolean checkRoot() { 32 | if (keepShell == null) { 33 | keepShell = new KeepShell(); 34 | } 35 | return keepShell.checkRoot(); 36 | } 37 | 38 | public static void tryExit() { 39 | if (keepShell != null) { 40 | keepShell.tryExit(); 41 | keepShell = null; 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /app/src/main/java/com/omarea/gesture/shell/ShellExecutor.java: -------------------------------------------------------------------------------- 1 | package com.omarea.gesture.shell; 2 | 3 | import java.io.IOException; 4 | 5 | public class ShellExecutor { 6 | private static Process getProcess(String run) throws IOException { 7 | return Runtime.getRuntime().exec(run); 8 | } 9 | 10 | public static Process getSuperUserRuntime() throws IOException { 11 | return getProcess("su"); 12 | } 13 | 14 | public static Process getRuntime() throws IOException { 15 | return getProcess("sh"); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /app/src/main/java/com/omarea/gesture/ui/ReTouchHelper.java: -------------------------------------------------------------------------------- 1 | package com.omarea.gesture.ui; 2 | 3 | import android.accessibilityservice.AccessibilityService; 4 | import android.accessibilityservice.GestureDescription; 5 | import android.graphics.Path; 6 | import android.util.Log; 7 | import android.view.View; 8 | import android.view.WindowManager; 9 | 10 | public class ReTouchHelper { 11 | private AccessibilityService mAccessibilityService; 12 | private WindowManager mWindowManager; 13 | private View mView; 14 | private int mFlags; 15 | private boolean running; 16 | final WindowManager.LayoutParams mParams; 17 | public ReTouchHelper(AccessibilityService accessibilityService, WindowManager windowManager, View view) { 18 | mAccessibilityService = accessibilityService; 19 | mWindowManager = windowManager; 20 | mView = view; 21 | mParams = (WindowManager.LayoutParams) view.getLayoutParams(); 22 | mFlags = mParams.flags; 23 | } 24 | 25 | public void dispatchGesture(final Path touchPath) { 26 | if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) { 27 | synchronized (this) { 28 | if (running) { 29 | return; 30 | } 31 | Log.e("@Gesture", "dispatchGesture >>"); 32 | pause(); 33 | mView.postDelayed(new Runnable() { 34 | @Override 35 | public void run() { 36 | try { 37 | final GestureDescription.Builder builder = new GestureDescription.Builder(); 38 | builder.addStroke(new GestureDescription.StrokeDescription(touchPath, 1, 1)); 39 | mAccessibilityService.dispatchGesture(builder.build(), new AccessibilityService.GestureResultCallback() { 40 | @Override 41 | public void onCompleted(GestureDescription gestureDescription) { 42 | resume(); 43 | super.onCompleted(gestureDescription); 44 | } 45 | 46 | public void onCancelled(GestureDescription gestureDescription) { 47 | resume(); 48 | super.onCancelled(gestureDescription); 49 | } 50 | }, null); 51 | } catch (Exception ignored) { 52 | resume(); 53 | } 54 | } 55 | }, 60); 56 | } 57 | } 58 | } 59 | 60 | private void pause() { 61 | running = true; 62 | mParams.flags = mFlags | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE; 63 | mWindowManager.updateViewLayout(mView, mParams); 64 | } 65 | 66 | private void resume() { 67 | mParams.flags = mFlags ; 68 | mWindowManager.updateViewLayout(mView, mParams); 69 | Log.e("@Gesture", "dispatchGesture √"); 70 | mView.postDelayed(new Runnable() { 71 | @Override 72 | public void run() { 73 | running = false; 74 | } 75 | }, 60); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /app/src/main/java/com/omarea/gesture/ui/iOSTouchBarView.java: -------------------------------------------------------------------------------- 1 | package com.omarea.gesture.ui; 2 | 3 | import android.annotation.SuppressLint; 4 | import android.content.Context; 5 | import android.graphics.Canvas; 6 | import android.graphics.Color; 7 | import android.graphics.Paint; 8 | import android.util.AttributeSet; 9 | import android.view.View; 10 | import android.view.ViewGroup; 11 | 12 | import com.omarea.gesture.util.GlobalState; 13 | 14 | public class iOSTouchBarView extends View { 15 | private Context context = getContext(); 16 | 17 | private Paint p = new Paint(); 18 | private float shadowSize = 16f; 19 | private float lineWeight = 16f; 20 | private float strokeWidth = 0f; 21 | private float strokeR = 0f; 22 | private int lineColor = 0; 23 | private int strokeColor = 0; 24 | private float margin = 24f; 25 | 26 | public iOSTouchBarView(Context context) { 27 | super(context); 28 | init(); 29 | } 30 | 31 | public iOSTouchBarView(Context context, AttributeSet attributeSet) { 32 | super(context, attributeSet); 33 | init(); 34 | } 35 | 36 | public iOSTouchBarView(Context context, AttributeSet attributeSet, int defStyleAttr) { 37 | super(context, attributeSet, defStyleAttr); 38 | init(); 39 | } 40 | 41 | private void init() { 42 | p.setAntiAlias(true); 43 | p.setStyle(Paint.Style.FILL); 44 | p.setColor(0xf0f0f0f0); 45 | p.setStrokeWidth(dp2px(context, 8)); 46 | p.setStrokeCap(Paint.Cap.ROUND); 47 | // p.setShadowLayer(dp2px(context, 4), 0, 0, 0x88000000); 48 | 49 | // setLayerType(LAYER_TYPE_SOFTWARE, null); 50 | } 51 | 52 | void setStyle(int widthPx, int heightPx, int color, int shadowColor, int shadowSizeDp, int lineWeightDp, int strokeWidth, int strokeColor) { 53 | this.shadowSize = dp2px(context, shadowSizeDp); 54 | this.lineWeight = dp2px(context, lineWeightDp); 55 | this.strokeWidth = dp2px(context, strokeWidth); 56 | this.strokeR = this.strokeWidth / 2; 57 | this.margin = this.shadowSize + (this.lineWeight / 2f) + this.strokeWidth; 58 | this.lineColor = color; 59 | this.strokeColor = strokeColor; 60 | 61 | if (this.shadowSize > 0) { 62 | p.setShadowLayer(this.shadowSize, 0, 0, shadowColor); 63 | } 64 | 65 | if (this.strokeWidth > 0) { 66 | p.setStrokeWidth(this.strokeWidth); 67 | } else { 68 | p.setStrokeWidth(0); 69 | } 70 | 71 | ViewGroup.LayoutParams lp = this.getLayoutParams(); 72 | int h = heightPx; 73 | int w = widthPx; 74 | if (h < 1) { 75 | h = 1; 76 | } 77 | if (w < 1) { 78 | w = 1; 79 | } 80 | lp.width = w; 81 | lp.height = h; 82 | this.setLayoutParams(lp); 83 | } 84 | 85 | /** 86 | * dp转换成px 87 | */ 88 | private int dp2px(Context context, float dpValue) { 89 | float scale = context.getResources().getDisplayMetrics().density; 90 | return (int) (dpValue * scale + 0.5f); 91 | } 92 | 93 | @Override 94 | @SuppressLint("DrawAllocation") 95 | public void onDraw(Canvas canvas) { 96 | super.onDraw(canvas); 97 | p.setAlpha(255); 98 | if (GlobalState.useBatteryCapacity) { 99 | int capacity = GlobalState.batteryCapacity; 100 | p.setColor(lineColor); 101 | drawLine(canvas, p); 102 | if (capacity > 0) { 103 | if (capacity > 85) { 104 | p.setColor(Color.argb(255, 19, 142, 214)); 105 | } else if (capacity > 75) { 106 | p.setColor(Color.argb(255, 0, 185, 194)); 107 | } else if (capacity > 60) { 108 | p.setColor(Color.argb(255, 0, 213, 217)); 109 | } else if (capacity > 45) { 110 | p.setColor(Color.argb(255, 2, 217, 141)); 111 | } else if (capacity > 35) { 112 | p.setColor(Color.argb(255, 135, 203, 0)); 113 | } else if (capacity > 20) { 114 | p.setColor(Color.argb(255, 252, 138, 27)); 115 | } else { 116 | p.setColor(Color.argb(255, 249, 89, 47)); 117 | } 118 | float totalWidth = getWidth() - (margin * 2); 119 | float outMargin = 0; 120 | canvas.drawRoundRect(margin + outMargin, margin + outMargin, margin + (totalWidth * capacity / 100f) - outMargin, margin + lineWeight - outMargin, 20, 20, p); 121 | 122 | p.setStyle(Paint.Style.FILL); 123 | p.setAlpha(210); 124 | // p.setColor(lineColor); 125 | drawLine(canvas, p); 126 | } 127 | } else { 128 | if (GlobalState.iosBarColor != Integer.MIN_VALUE) { 129 | if (strokeWidth > 0) { 130 | p.setStyle(Paint.Style.STROKE); 131 | if (GlobalState.iosBarColor == Color.WHITE) { 132 | p.setColor(Color.BLACK); 133 | } else { 134 | p.setColor(Color.WHITE); 135 | } 136 | canvas.drawRoundRect(margin - strokeR, margin - strokeR, getWidth() - margin + strokeR, margin + lineWeight + strokeR, 20, 20, p); 137 | } 138 | 139 | p.setStyle(Paint.Style.FILL); 140 | p.setColor(GlobalState.iosBarColor); 141 | drawLine(canvas, p); 142 | } else { 143 | if (strokeWidth > 0) { 144 | p.setStyle(Paint.Style.STROKE); 145 | p.setColor(strokeColor); 146 | canvas.drawRoundRect(margin - strokeR, margin - strokeR, getWidth() - margin + strokeR, margin + lineWeight + strokeR, 20, 20, p); 147 | } 148 | 149 | p.setStyle(Paint.Style.FILL); 150 | p.setColor(lineColor); 151 | drawLine(canvas, p); 152 | } 153 | } 154 | } 155 | 156 | private void drawLine(Canvas canvas, Paint p) { 157 | canvas.drawRoundRect(margin, margin, getWidth() - margin, margin + lineWeight, 20, 20, p); 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /app/src/main/java/com/omarea/gesture/util/AppInfo.java: -------------------------------------------------------------------------------- 1 | package com.omarea.gesture.util; 2 | 3 | public class AppInfo { 4 | public String appName; 5 | public String packageName; 6 | } 7 | -------------------------------------------------------------------------------- /app/src/main/java/com/omarea/gesture/util/AppLauncher.java: -------------------------------------------------------------------------------- 1 | package com.omarea.gesture.util; 2 | 3 | import android.app.ActivityOptions; 4 | import android.content.Context; 5 | import android.content.Intent; 6 | import android.widget.Toast; 7 | 8 | import com.omarea.gesture.Gesture; 9 | 10 | public class AppLauncher { 11 | Intent getAppSwitchIntent(String appPackageName) { 12 | Intent i = Gesture.context.getPackageManager().getLaunchIntentForPackage(appPackageName); 13 | i.setFlags((i.getFlags() & ~Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) | Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_NO_ANIMATION); 14 | i.addFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY); 15 | i.setPackage(null); 16 | return i; 17 | } 18 | 19 | void startActivity(Context context, String targetApp) { 20 | try { 21 | context.startActivity(getAppSwitchIntent(targetApp)); 22 | } catch (Exception ex) { 23 | Gesture.toast("" + ex.getMessage(), Toast.LENGTH_SHORT); 24 | } 25 | } 26 | 27 | public void startActivity(Context context, String targetApp, ActivityOptions activityOptions) { 28 | context.startActivity(getAppSwitchIntent(targetApp), activityOptions.toBundle()); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /app/src/main/java/com/omarea/gesture/util/AppListHelper.java: -------------------------------------------------------------------------------- 1 | package com.omarea.gesture.util; 2 | 3 | import android.content.Context; 4 | import android.content.Intent; 5 | import android.content.pm.PackageManager; 6 | import android.content.pm.ResolveInfo; 7 | 8 | import java.util.ArrayList; 9 | import java.util.List; 10 | 11 | public class AppListHelper { 12 | public ArrayList loadAppList(Context context) { 13 | final PackageManager packageManager = context.getPackageManager(); 14 | Intent queryActIntent = new Intent(Intent.ACTION_MAIN, null); 15 | queryActIntent.addCategory(Intent.CATEGORY_LAUNCHER); 16 | // queryActIntent.setPackage(info.packageName); 17 | List resolveInfoList = packageManager.queryIntentActivities(queryActIntent, 0); 18 | 19 | ArrayList packages = new ArrayList<>(); 20 | for (final ResolveInfo resolveInfo : resolveInfoList) { 21 | String appName = (String) resolveInfo.loadLabel(packageManager); 22 | packages.add(new AppInfo() {{ 23 | appName = (String) resolveInfo.loadLabel(packageManager); 24 | packageName = resolveInfo.activityInfo.packageName; 25 | }}); 26 | } 27 | 28 | return packages; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /app/src/main/java/com/omarea/gesture/util/AppWindowed.java: -------------------------------------------------------------------------------- 1 | package com.omarea.gesture.util; 2 | 3 | import android.app.ActivityOptions; 4 | import android.content.Context; 5 | import android.content.Intent; 6 | import android.os.Bundle; 7 | 8 | import java.lang.reflect.Method; 9 | 10 | public class AppWindowed { 11 | public void switchToFreeForm(Context context, String packageName) { 12 | // ActivityOptions activityOptions = ActivityOptions.makeTaskLaunchBehind(); 13 | // 设置不合理的动画,可能导致切换窗口模式时奔溃,因此去掉动画 14 | ActivityOptions activityOptions = ActivityOptions.makeCustomAnimation(context.getApplicationContext(), 0, 0); 15 | 16 | Intent intent = context.getPackageManager().getLaunchIntentForPackage(packageName); 17 | intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); 18 | // intent.setFlags(Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT | Intent.FLAG_ACTIVITY_NEW_TASK); 19 | try { 20 | Method method = ActivityOptions.class.getMethod("setLaunchWindowingMode", int.class); 21 | method.invoke(activityOptions, 5); 22 | } catch (Exception e) { /* Gracefully fail */ } 23 | 24 | // int left = 50; 25 | // int top = 100; 26 | // int right = 50 + GlobalState.displayWidth / 2; 27 | // int bottom = 100 + (GlobalState.displayWidth / 2 * 16 / 9); 28 | // activityOptions.setLaunchBounds(new Rect(left, top, right, bottom)); 29 | 30 | Bundle bundle = activityOptions.toBundle(); 31 | context.startActivity(intent, bundle); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /app/src/main/java/com/omarea/gesture/util/BatteryUtils.java: -------------------------------------------------------------------------------- 1 | package com.omarea.gesture.util; 2 | 3 | import android.content.Context; 4 | import android.os.BatteryManager; 5 | 6 | public class BatteryUtils { 7 | private BatteryManager batteryManager; 8 | 9 | public BatteryUtils(Context context) { 10 | this.batteryManager = (BatteryManager) context.getSystemService(Context.BATTERY_SERVICE); 11 | } 12 | 13 | public int getCapacity() { 14 | return batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /app/src/main/java/com/omarea/gesture/util/GlobalState.java: -------------------------------------------------------------------------------- 1 | package com.omarea.gesture.util; 2 | 3 | import android.graphics.Bitmap; 4 | 5 | import com.omarea.gesture.ActionModel; 6 | import com.omarea.gesture.ui.VisualFeedbackView; 7 | 8 | public class GlobalState { 9 | // 使用连续动作 10 | public static boolean consecutive = false; 11 | // 连续动作 12 | public static ActionModel consecutiveAction = null; 13 | 14 | // 电池电量 15 | public static int batteryCapacity = -1; 16 | // 小横条是否使用电量 17 | public static boolean useBatteryCapacity = false; 18 | 19 | public static long lastBackHomeTime = 0; 20 | 21 | public static boolean isLandscapf = false; 22 | public static boolean testMode = false; 23 | public static int iosBarColor = Integer.MIN_VALUE; 24 | public static Runnable updateBar; 25 | public static int displayHeight = 2340; 26 | public static int displayWidth = 1080; 27 | // 增强模式(需要Root或者ADB) 28 | public static boolean enhancedMode = false; 29 | 30 | public static VisualFeedbackView visualFeedbackView; 31 | 32 | public static void startEdgeFeedback(float startRawX, float startRawY, int sideMode) { 33 | if (visualFeedbackView != null) { 34 | visualFeedbackView.startEdgeFeedback(startRawX, startRawY, sideMode); 35 | } 36 | } 37 | 38 | public static void updateEdgeFeedback(float currentRawX, float currentRawY) { 39 | if (visualFeedbackView != null) { 40 | visualFeedbackView.updateEdgeFeedback(currentRawX, currentRawY); 41 | } 42 | } 43 | 44 | public static void updateEdgeFeedbackIcon(Bitmap bitmap, boolean oversize) { 45 | if (visualFeedbackView != null) { 46 | visualFeedbackView.updateEdgeFeedbackIcon(bitmap, oversize); 47 | } 48 | } 49 | 50 | public static void clearEdgeFeedback() { 51 | if (visualFeedbackView != null) { 52 | visualFeedbackView.clearEdgeFeedback(); 53 | } 54 | } 55 | 56 | public static void startThreeSectionFeedback(float startRawX, float startRawY) { 57 | if (visualFeedbackView != null) { 58 | visualFeedbackView.startThreeSectionFeedback(startRawX, startRawY); 59 | } 60 | } 61 | 62 | public static void updateThreeSectionFeedback(float currentRawX, float currentRawY) { 63 | if (visualFeedbackView != null) { 64 | visualFeedbackView.updateThreeSectionFeedback(currentRawX, currentRawY); 65 | } 66 | } 67 | 68 | public static void updateThreeSectionFeedbackIcon(Bitmap bitmap, boolean oversize) { 69 | if (visualFeedbackView != null) { 70 | visualFeedbackView.updateThreeSectionFeedbackIcon(bitmap, oversize); 71 | } 72 | } 73 | 74 | public static void finishThreeSectionFeedbackIcon() { 75 | if (visualFeedbackView != null) { 76 | visualFeedbackView.finishThreeSectionFeedbackIcon(); 77 | } 78 | } 79 | 80 | public static void clearThreeSectionFeedback() { 81 | if (visualFeedbackView != null) { 82 | visualFeedbackView.clearThreeSectionFeedback(); 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /app/src/main/java/com/omarea/gesture/util/Memory.java: -------------------------------------------------------------------------------- 1 | package com.omarea.gesture.util; 2 | 3 | import android.app.ActivityManager; 4 | import android.content.Context; 5 | 6 | public class Memory { 7 | public int getMemorySizeMB(Context context) { 8 | //获得ActivityManager服务的对象 9 | ActivityManager mActivityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); 10 | //获得MemoryInfo对象 11 | ActivityManager.MemoryInfo memoryInfo = new ActivityManager.MemoryInfo(); 12 | //获得系统可用内存,保存在MemoryInfo对象上 13 | mActivityManager.getMemoryInfo(memoryInfo); 14 | return (int) (memoryInfo.totalMem / 1024 / 1024); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /app/src/main/java/com/omarea/gesture/util/ReceiverLock.java: -------------------------------------------------------------------------------- 1 | package com.omarea.gesture.util; 2 | 3 | import android.content.BroadcastReceiver; 4 | import android.content.Context; 5 | import android.content.Intent; 6 | import android.content.IntentFilter; 7 | import android.os.Build; 8 | import android.os.Handler; 9 | 10 | /** 11 | * 监听屏幕开关事件 12 | * Created by Hello on 2018/01/23. 13 | */ 14 | 15 | public class ReceiverLock extends BroadcastReceiver { 16 | public static int EVENT_SCREEN_OFF = 8; 17 | public static int EVENT_SCREEN_ON = 10; 18 | private static ReceiverLock receiver = null; 19 | private Handler callbacks; 20 | 21 | public ReceiverLock(Handler callbacks) { 22 | this.callbacks = callbacks; 23 | } 24 | 25 | public static ReceiverLock autoRegister(Context context, Handler callbacks) { 26 | if (receiver != null) { 27 | unRegister(context); 28 | } 29 | 30 | receiver = new ReceiverLock(callbacks); 31 | Context bc = context.getApplicationContext(); 32 | 33 | bc.registerReceiver(receiver, new IntentFilter(Intent.ACTION_SCREEN_OFF)); 34 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { 35 | bc.registerReceiver(receiver, new IntentFilter(Intent.ACTION_USER_UNLOCKED)); 36 | } 37 | bc.registerReceiver(receiver, new IntentFilter(Intent.ACTION_SCREEN_ON)); 38 | bc.registerReceiver(receiver, new IntentFilter(Intent.ACTION_USER_PRESENT)); 39 | 40 | return receiver; 41 | } 42 | 43 | public static void unRegister(Context context) { 44 | if (receiver == null) { 45 | return; 46 | } 47 | context.getApplicationContext().unregisterReceiver(receiver); 48 | receiver = null; 49 | } 50 | 51 | @Override 52 | public void onReceive(final Context p0, Intent p1) { 53 | if (p1 == null) { 54 | return; 55 | } 56 | 57 | String action = p1.getAction(); 58 | if (action != null) { 59 | if (action.equals(Intent.ACTION_SCREEN_OFF)) { 60 | callbacks.sendMessage(callbacks.obtainMessage(EVENT_SCREEN_OFF)); 61 | // } else if (action.equals(Intent.ACTION_USER_PRESENT) || action.equals(Intent.ACTION_USER_UNLOCKED) || action.equals(Intent.ACTION_SCREEN_ON)) { 62 | } else if (action.equals(Intent.ACTION_USER_PRESENT) || action.equals(Intent.ACTION_USER_UNLOCKED)) { 63 | try { 64 | callbacks.postDelayed(new Runnable() { 65 | @Override 66 | public void run() { 67 | if (!new ScreenState(p0).isScreenLocked()) { 68 | callbacks.sendMessage(callbacks.obtainMessage(EVENT_SCREEN_ON)); 69 | } 70 | } 71 | }, 1000); 72 | } catch (Exception ignored) { 73 | } 74 | } else if (action.equals(Intent.ACTION_SCREEN_ON)) { 75 | try { 76 | callbacks.postDelayed(new Runnable() { 77 | @Override 78 | public void run() { 79 | if (!new ScreenState(p0).isScreenLocked()) { 80 | callbacks.sendMessage(callbacks.obtainMessage(EVENT_SCREEN_ON)); 81 | } 82 | } 83 | }, 6000); 84 | } catch (Exception ignored) { 85 | } 86 | } 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /app/src/main/java/com/omarea/gesture/util/ReceiverLockHandler.java: -------------------------------------------------------------------------------- 1 | package com.omarea.gesture.util; 2 | 3 | import android.accessibilityservice.AccessibilityService; 4 | import android.os.Handler; 5 | import android.os.Message; 6 | import android.view.View; 7 | 8 | public class ReceiverLockHandler extends Handler { 9 | private View bar; 10 | private AccessibilityService accessibilityService; 11 | 12 | public ReceiverLockHandler(View bar, AccessibilityService accessibilityService) { 13 | this.bar = bar; 14 | this.accessibilityService = accessibilityService; 15 | } 16 | 17 | @Override 18 | public void handleMessage(Message msg) { 19 | super.handleMessage(msg); 20 | try { 21 | if (bar.isAttachedToWindow()) { 22 | if (msg != null) { 23 | if (msg.what == ReceiverLock.EVENT_SCREEN_ON) { 24 | bar.setVisibility(View.VISIBLE); 25 | } else if (msg.what == ReceiverLock.EVENT_SCREEN_OFF) { 26 | bar.setVisibility(View.INVISIBLE); 27 | } 28 | } 29 | } else { 30 | ReceiverLock.unRegister(accessibilityService); 31 | } 32 | } catch (Exception ignored) { 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /app/src/main/java/com/omarea/gesture/util/Recents.java: -------------------------------------------------------------------------------- 1 | package com.omarea.gesture.util; 2 | 3 | import android.content.Intent; 4 | 5 | import java.util.ArrayList; 6 | 7 | public class Recents { 8 | private final ArrayList recents = new ArrayList<>(); 9 | // TODO:关闭辅助服务时清理以下数据 10 | // 已经确保可以打开的应用 11 | public ArrayList whiteList = new ArrayList<>(); 12 | // 已经可以肯定不是可以打开的应用 13 | public ArrayList blackList = new ArrayList() { 14 | }; 15 | 16 | public ArrayList inputMethods = null; 17 | public ArrayList launcherApps = null; 18 | private int index = -1; 19 | private String currentTop = ""; 20 | 21 | public void clear() { 22 | synchronized (recents) { 23 | recents.clear(); 24 | currentTop = ""; 25 | } 26 | } 27 | 28 | public void addRecent(String packageName) { 29 | if (currentTop.equals(packageName)) { 30 | return; 31 | } 32 | 33 | synchronized (recents) { 34 | int searchResult = recents.indexOf(packageName); 35 | if (searchResult > -1) { 36 | recents.remove(searchResult); 37 | } 38 | 39 | // Intent.CATEGORY_HOME 代步桌面应用,回到桌面时,桌面应该永远应用的后面放 40 | // 因此,在桌面上向后退永远是打开桌面前的上一个应用,而不是上上个应用 41 | if (searchResult > -1 && !Intent.CATEGORY_HOME.equals(packageName)) { 42 | recents.add(index, packageName); 43 | } else { 44 | int indexCurrent = recents.indexOf(currentTop); 45 | if (indexCurrent > -1 && indexCurrent + 1 < recents.size()) { 46 | recents.add(indexCurrent + 1, packageName); 47 | } else { 48 | recents.add(packageName); 49 | } 50 | } 51 | 52 | index = recents.indexOf(packageName); 53 | currentTop = packageName; 54 | 55 | StringBuilder packages = new StringBuilder(); 56 | for (String item : recents) { 57 | packages.append(item); 58 | packages.append(", "); 59 | } 60 | } 61 | } 62 | 63 | void setRecents(ArrayList items) { 64 | synchronized (recents) { 65 | /* 66 | if (recents.size() < 4) { 67 | recents.clear(); 68 | for (String packageName : items) { 69 | if ( 70 | whiteList.indexOf(packageName) > -1 || 71 | (blackList.indexOf(packageName) < 0 && ignoreApps.indexOf(packageName) < 0) 72 | ) { 73 | recents.add(packageName); 74 | } 75 | } 76 | index = recents.indexOf(currentTop); 77 | } else { 78 | ArrayList lostedItems = new ArrayList<>(); 79 | for (String recent : recents) { 80 | if (items.indexOf(recent) < 0) { 81 | lostedItems.add(recent); 82 | } 83 | } 84 | recents.removeAll(lostedItems); 85 | index = recents.indexOf(currentTop); 86 | } 87 | */ 88 | 89 | ArrayList lostedItems = new ArrayList<>(); 90 | for (String recent : recents) { 91 | if (!recent.equals(Intent.CATEGORY_HOME) && items.indexOf(recent) < 0) { 92 | lostedItems.add(recent); 93 | } 94 | } 95 | recents.removeAll(lostedItems); 96 | index = recents.indexOf(currentTop); 97 | } 98 | } 99 | 100 | public boolean notEmpty() { 101 | return this.recents.size() > 1; 102 | } 103 | 104 | String getCurrent() { 105 | return currentTop; 106 | } 107 | 108 | String moveNext() { 109 | String packageName; 110 | synchronized (recents) { 111 | if (index < recents.size() - 1) { 112 | index += 1; 113 | packageName = recents.get(index); 114 | } else if (recents.size() > 0) { 115 | index = 0; 116 | packageName = recents.get(0); 117 | } else { 118 | packageName = null; 119 | } 120 | } 121 | if (Intent.CATEGORY_HOME.equals(packageName) && recents.size() > 1) { 122 | return moveNext(); 123 | } 124 | return packageName; 125 | } 126 | 127 | String movePrevious() { 128 | String packageName; 129 | synchronized (recents) { 130 | if (index > 0) { 131 | index -= 1; 132 | packageName = recents.get(index); 133 | } else if (recents.size() > 0) { 134 | int size = recents.size(); 135 | index = size - 1; 136 | packageName = recents.get(index); 137 | } else { 138 | packageName = null; 139 | } 140 | } 141 | if (Intent.CATEGORY_HOME.equals(packageName) && recents.size() > 1) { 142 | return movePrevious(); 143 | } 144 | 145 | return packageName; 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /app/src/main/java/com/omarea/gesture/util/ResumeNavBar.java: -------------------------------------------------------------------------------- 1 | package com.omarea.gesture.util; 2 | 3 | import android.content.ContentResolver; 4 | import android.provider.Settings; 5 | 6 | public class ResumeNavBar { 7 | private ContentResolver cr = null; 8 | 9 | public ResumeNavBar(ContentResolver contentResolver) { 10 | this.cr = contentResolver; 11 | } 12 | 13 | public void run() { 14 | try { 15 | // oneui 策略取消强制禁用手势(因为锁屏唤醒后底部会触摸失灵,需要重新开关) 16 | Settings.Global.putInt(cr, "navigation_bar_gesture_disabled_by_policy", 0); 17 | } catch (Exception ignored) { 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /app/src/main/java/com/omarea/gesture/util/ScreenState.java: -------------------------------------------------------------------------------- 1 | package com.omarea.gesture.util; 2 | 3 | import android.app.KeyguardManager; 4 | import android.content.Context; 5 | import android.os.Build; 6 | import android.view.Display; 7 | import android.view.WindowManager; 8 | 9 | public class ScreenState { 10 | private Context context; 11 | 12 | public ScreenState(Context context) { 13 | this.context = context; 14 | } 15 | 16 | public boolean isScreenLocked() { 17 | WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); 18 | Display display = windowManager.getDefaultDisplay(); 19 | if (display.getState() == Display.STATE_OFF) { 20 | return true; 21 | } 22 | 23 | KeyguardManager mKeyguardManager = (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE); 24 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { 25 | return mKeyguardManager.isDeviceLocked() || mKeyguardManager.isKeyguardLocked(); 26 | } else { 27 | return mKeyguardManager.inKeyguardRestrictedInputMode() || mKeyguardManager.isDeviceLocked() || mKeyguardManager.isKeyguardLocked(); 28 | } 29 | } 30 | 31 | public boolean isScreenOn() { 32 | return !isScreenLocked(); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /app/src/main/java/com/omarea/gesture/util/SystemProperty.java: -------------------------------------------------------------------------------- 1 | package com.omarea.gesture.util; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.InputStreamReader; 5 | import java.util.Objects; 6 | 7 | class SystemProperty { 8 | String get(String propName) { 9 | String line; 10 | BufferedReader input = null; 11 | try { 12 | Process p = Runtime.getRuntime().exec("getprop " + propName); 13 | input = new BufferedReader(new InputStreamReader(p.getInputStream()), 1024); 14 | line = input.readLine(); 15 | input.close(); 16 | p.destroy(); 17 | } catch (Exception ex) { 18 | return null; 19 | } finally { 20 | if (input != null) { 21 | try { 22 | input.close(); 23 | } catch (Exception ignored) { 24 | } 25 | } 26 | } 27 | return line; 28 | } 29 | 30 | boolean isMiui12() { 31 | try { 32 | // 反射调用私有接口,被Google封杀了 33 | // Object result = Class.forName("android.os.Systemproperties").getMethod("get").invoke(null, "ro.miui.ui.version.name", ""); 34 | // return "V12".equals(result.toString()); 35 | return Objects.equals(get("ro.miui.ui.version.name"), "V12"); 36 | } catch (Exception ex) { 37 | return false; 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /app/src/main/java/com/omarea/gesture/util/UITools.java: -------------------------------------------------------------------------------- 1 | package com.omarea.gesture.util; 2 | 3 | import android.content.Context; 4 | 5 | public class UITools { 6 | /** 7 | * dp转换成px 8 | */ 9 | public static int dp2px(Context context, float dpValue) { 10 | float scale = context.getResources().getDisplayMetrics().density; 11 | int value = (int) (dpValue * scale + 0.5f); 12 | if (value < 1) { 13 | return 1; 14 | } 15 | return value; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /app/src/main/res/anim/gesture_app_exit.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 15 | 20 | -------------------------------------------------------------------------------- /app/src/main/res/anim/gesture_app_exit_2.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/anim/gesture_app_open_enter.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 11 | 17 | 27 | -------------------------------------------------------------------------------- /app/src/main/res/anim/gesture_app_open_exit.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/anim/gesture_back_home.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 15 | 21 | -------------------------------------------------------------------------------- /app/src/main/res/anim/gesture_back_home_2.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 11 | 21 | 27 | -------------------------------------------------------------------------------- /app/src/main/res/anim/gesture_next_enter.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 11 | 21 | -------------------------------------------------------------------------------- /app/src/main/res/anim/gesture_next_enter_2.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 11 | 20 | -------------------------------------------------------------------------------- /app/src/main/res/anim/gesture_next_enter_basic.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/anim/gesture_next_enter_fast.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/anim/gesture_next_exit.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 11 | 20 | -------------------------------------------------------------------------------- /app/src/main/res/anim/gesture_next_exit_2.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 15 | 18 | -------------------------------------------------------------------------------- /app/src/main/res/anim/gesture_next_exit_basic.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/anim/gesture_next_exit_fast.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/anim/gesture_prev_enter.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 11 | 21 | -------------------------------------------------------------------------------- /app/src/main/res/anim/gesture_prev_enter_2.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 14 | 20 | -------------------------------------------------------------------------------- /app/src/main/res/anim/gesture_prev_enter_basic.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/anim/gesture_prev_enter_fast.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/anim/gesture_prev_exit.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 11 | 20 | -------------------------------------------------------------------------------- /app/src/main/res/anim/gesture_prev_exit_2.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 11 | 19 | -------------------------------------------------------------------------------- /app/src/main/res/anim/gesture_prev_exit_basic.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/anim/gesture_prev_exit_fast.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/anim/gesture_quick_panel_bottom_in.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 12 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/anim/gesture_quick_panel_bottom_out.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 12 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/anim/gesture_quick_panel_left_in.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 12 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/anim/gesture_quick_panel_left_out.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 12 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/anim/gesture_quick_panel_right_in.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 12 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/anim/gesture_quick_panel_right_out.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 12 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/adb_off.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/helloklf/EdgeGesture/fca8d3aaa9552744161eccf582d386802d3d496d/app/src/main/res/drawable/adb_off.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/adb_on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/helloklf/EdgeGesture/fca8d3aaa9552744161eccf582d386802d3d496d/app/src/main/res/drawable/adb_on.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/bar_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/color_picker_alpha_gradient.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/color_picker_bg_gradient.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/color_picker_blue_gradient.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/color_picker_green_gradient.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/color_picker_red_gradient.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/color_picker_seekbar_thumb.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/frequently_edit_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/gesture_card_view.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/gesture_card_view_bottom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/gesture_card_view_top.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/gesture_copy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/helloklf/EdgeGesture/fca8d3aaa9552744161eccf582d386802d3d496d/app/src/main/res/drawable/gesture_copy.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/gesture_icon_add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/helloklf/EdgeGesture/fca8d3aaa9552744161eccf582d386802d3d496d/app/src/main/res/drawable/gesture_icon_add.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/gesture_icon_edit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/helloklf/EdgeGesture/fca8d3aaa9552744161eccf582d386802d3d496d/app/src/main/res/drawable/gesture_icon_edit.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/gesture_icon_ok.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/helloklf/EdgeGesture/fca8d3aaa9552744161eccf582d386802d3d496d/app/src/main/res/drawable/gesture_icon_ok.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/gesture_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/helloklf/EdgeGesture/fca8d3aaa9552744161eccf582d386802d3d496d/app/src/main/res/drawable/gesture_logo.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/gesture_quick_question.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/helloklf/EdgeGesture/fca8d3aaa9552744161eccf582d386802d3d496d/app/src/main/res/drawable/gesture_quick_question.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/gesture_tab_apple.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/helloklf/EdgeGesture/fca8d3aaa9552744161eccf582d386802d3d496d/app/src/main/res/drawable/gesture_tab_apple.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/gesture_tab_edge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/helloklf/EdgeGesture/fca8d3aaa9552744161eccf582d386802d3d496d/app/src/main/res/drawable/gesture_tab_edge.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/gesture_tab_lab.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/helloklf/EdgeGesture/fca8d3aaa9552744161eccf582d386802d3d496d/app/src/main/res/drawable/gesture_tab_lab.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/gesture_tab_settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/helloklf/EdgeGesture/fca8d3aaa9552744161eccf582d386802d3d496d/app/src/main/res/drawable/gesture_tab_settings.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/gesture_tab_switch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/helloklf/EdgeGesture/fca8d3aaa9552744161eccf582d386802d3d496d/app/src/main/res/drawable/gesture_tab_switch.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/icon_question.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/helloklf/EdgeGesture/fca8d3aaa9552744161eccf582d386802d3d496d/app/src/main/res/drawable/icon_question.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/landscape_bar_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/power_switch_off.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/power_switch_on.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/power_switch_style.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/quick_panel_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/quick_panel_bg_bottom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/quick_panel_bg_left.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/quick_panel_bg_right.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/seekbar_progress_drawable.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/seekbar_thumb.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/switch_thumb.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/switch_track.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/switch_track_close.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/switch_track_open.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/thumb.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/touch_app.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/helloklf/EdgeGesture/fca8d3aaa9552744161eccf582d386802d3d496d/app/src/main/res/drawable/touch_app.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/touch_app_window.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/helloklf/EdgeGesture/fca8d3aaa9552744161eccf582d386802d3d496d/app/src/main/res/drawable/touch_app_window.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/touch_arrow_left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/helloklf/EdgeGesture/fca8d3aaa9552744161eccf582d386802d3d496d/app/src/main/res/drawable/touch_arrow_left.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/touch_arrow_right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/helloklf/EdgeGesture/fca8d3aaa9552744161eccf582d386802d3d496d/app/src/main/res/drawable/touch_arrow_right.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/touch_grid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/helloklf/EdgeGesture/fca8d3aaa9552744161eccf582d386802d3d496d/app/src/main/res/drawable/touch_grid.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/touch_home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/helloklf/EdgeGesture/fca8d3aaa9552744161eccf582d386802d3d496d/app/src/main/res/drawable/touch_home.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/touch_info.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/helloklf/EdgeGesture/fca8d3aaa9552744161eccf582d386802d3d496d/app/src/main/res/drawable/touch_info.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/touch_jump_next.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/helloklf/EdgeGesture/fca8d3aaa9552744161eccf582d386802d3d496d/app/src/main/res/drawable/touch_jump_next.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/touch_jump_previous.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/helloklf/EdgeGesture/fca8d3aaa9552744161eccf582d386802d3d496d/app/src/main/res/drawable/touch_jump_previous.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/touch_lock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/helloklf/EdgeGesture/fca8d3aaa9552744161eccf582d386802d3d496d/app/src/main/res/drawable/touch_lock.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/touch_notice.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/helloklf/EdgeGesture/fca8d3aaa9552744161eccf582d386802d3d496d/app/src/main/res/drawable/touch_notice.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/touch_power.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/helloklf/EdgeGesture/fca8d3aaa9552744161eccf582d386802d3d496d/app/src/main/res/drawable/touch_power.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/touch_screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/helloklf/EdgeGesture/fca8d3aaa9552744161eccf582d386802d3d496d/app/src/main/res/drawable/touch_screenshot.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/touch_settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/helloklf/EdgeGesture/fca8d3aaa9552744161eccf582d386802d3d496d/app/src/main/res/drawable/touch_settings.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/touch_shell.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/helloklf/EdgeGesture/fca8d3aaa9552744161eccf582d386802d3d496d/app/src/main/res/drawable/touch_shell.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/touch_split.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/helloklf/EdgeGesture/fca8d3aaa9552744161eccf582d386802d3d496d/app/src/main/res/drawable/touch_split.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/touch_switch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/helloklf/EdgeGesture/fca8d3aaa9552744161eccf582d386802d3d496d/app/src/main/res/drawable/touch_switch.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/touch_tasks.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/helloklf/EdgeGesture/fca8d3aaa9552744161eccf582d386802d3d496d/app/src/main/res/drawable/touch_tasks.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/touch_window.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/helloklf/EdgeGesture/fca8d3aaa9552744161eccf582d386802d3d496d/app/src/main/res/drawable/touch_window.png -------------------------------------------------------------------------------- /app/src/main/res/layout/enhanced_mode.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 14 | 15 | 19 | 20 | 26 | 27 | 30 | 31 | 38 | 39 | 40 | 45 | 46 | 47 | 48 | 57 | 58 | 63 | 64 | 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /app/src/main/res/layout/gesture_color_picker.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 16 | 17 | 21 | 22 | 27 | 28 | 39 | 40 | 41 | 45 | 46 | 51 | 52 | 63 | 64 | 65 | 66 | 70 | 71 | 76 | 77 | 88 | 89 | 90 | 94 | 95 | 100 | 101 | 112 | 113 | 114 |