Repository: zhongyi-tong/WeChatLuckyMoney Branch: stable Commit: 54a5201dfba6 Files: 59 Total size: 124.4 KB Directory structure: gitextract_2tar33oo/ ├── .gitignore ├── .idea/ │ ├── compiler.xml │ ├── copyright/ │ │ └── profiles_settings.xml │ ├── encodings.xml │ ├── gradle.xml │ ├── inspectionProfiles/ │ │ └── Project_Default.xml │ ├── misc.xml │ ├── modules.xml │ ├── runConfigurations.xml │ ├── uiDesigner.xml │ └── vcs.xml ├── .travis.yml ├── CHANGELOG.md ├── LICENSE.md ├── README.md ├── README_EN.md ├── WeChatLuckyMoney.iml ├── app/ │ ├── .gitignore │ ├── build.gradle │ ├── proguard-rules.pro │ └── src/ │ └── main/ │ ├── AndroidManifest.xml │ ├── java/ │ │ └── xyz/ │ │ └── monkeytong/ │ │ └── hongbao/ │ │ ├── activities/ │ │ │ ├── MainActivity.java │ │ │ ├── SeekBarPreference.java │ │ │ ├── SettingsActivity.java │ │ │ └── WebViewActivity.java │ │ ├── fragments/ │ │ │ ├── CommentSettingsFragment.java │ │ │ └── GeneralSettingsFragment.java │ │ ├── services/ │ │ │ └── HongbaoService.java │ │ └── utils/ │ │ ├── ConnectivityUtil.java │ │ ├── DownloadUtil.java │ │ ├── HongbaoLogger.java │ │ ├── HongbaoSignature.java │ │ ├── PowerUtil.java │ │ └── UpdateTask.java │ └── res/ │ ├── layout/ │ │ ├── activity_main.xml │ │ ├── activity_preferences.xml │ │ ├── activity_webview.xml │ │ ├── preference_category.xml │ │ ├── preference_checkbox.xml │ │ └── preference_seekbar.xml │ ├── layout-v21/ │ │ ├── activity_preferences.xml │ │ └── activity_webview.xml │ ├── values/ │ │ ├── dimens.xml │ │ └── strings.xml │ ├── values-en/ │ │ └── strings.xml │ ├── values-w820dp/ │ │ ├── dimens.xml │ │ └── strings.xml │ └── xml/ │ ├── accessible_service_config.xml │ ├── comment_preferences.xml │ ├── general_preferences.xml │ └── provider_paths.xml ├── build.gradle ├── gradle/ │ └── wrapper/ │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradle.properties ├── gradlew ├── gradlew.bat ├── monkeytong.jks.enc └── settings.gradle ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ *.imi .gradle /local.properties /.idea/workspace.xml /.idea/libraries .DS_Store /build /captures /.idea/dictionaries /monkeytong.jks /app/release ================================================ FILE: .idea/compiler.xml ================================================ ================================================ FILE: .idea/copyright/profiles_settings.xml ================================================ ================================================ FILE: .idea/encodings.xml ================================================ ================================================ FILE: .idea/gradle.xml ================================================ ================================================ FILE: .idea/inspectionProfiles/Project_Default.xml ================================================ ================================================ FILE: .idea/misc.xml ================================================ ================================================ FILE: .idea/modules.xml ================================================ ================================================ FILE: .idea/runConfigurations.xml ================================================ ================================================ FILE: .idea/uiDesigner.xml ================================================ ================================================ FILE: .idea/vcs.xml ================================================ ================================================ FILE: .travis.yml ================================================ language: android sudo: false jdk: oraclejdk8 env: matrix: - ANDROID_TARGET=android-26 ANDROID_ABI=armeabi-v7a armeabi android: components: - platform-tools - tools - build-tools-26.0.2 - android-N - extra licenses: - android-sdk-license-.+ - .+ before_install: - openssl aes-256-cbc -K $encrypted_6b42a8524af0_key -iv $encrypted_6b42a8524af0_iv -in monkeytong.jks.enc -out monkeytong.jks -d before_script: - mkdir "$ANDROID_HOME/licenses" || true - echo -e "\n8933bad161af4178b1185d1a37fbf41ea5269c55" > "$ANDROID_HOME/licenses/android-sdk-license" - echo -e "\n84831b9409646a918e30573bab4c9c91346d8abd" > "$ANDROID_HOME/licenses/android-sdk-preview-license" - gem install fir-cli script: - ./gradlew assembleRelease deploy: provider: releases api_key: secure: Ookr5Qba+FjvrnlHfA2Gp+9QSua/UhkAq+OtYtLagdC7i1Drd7CANi4zfhCf95xSPDNE8MNJQu2qTR4EkHqno6dBFYbV/+35Ph+3Xnv1GehJmdyVDQSfNwlxzKbCw6rfyoeiMrSORADznRlEx7EfK3b7w2esWS/OAvepbqmUzWlPEA8Xyl1CBiMZacqZJTwyhCCO5dNpXE/+pP4yPrUx32Ts0tYQ5HmsijndbWh/YX2SGeekdAWTXBMr/zUpTEcpk8JYukfuTG3qaNZnUk0OEYHv8/icdaTO+wUuj44m9y/0uoir7iToAjEQP+tEnfUAQYke5Di2N2Pa9dpuc2kvmHi2l4wpPDhwrSSAPkI73r1eM8AAl7U2d2G/qG7UGAmXoI4NnDozkCGrHDH4VLH/uSpoJPdsVSOPRZX7lWPIM6xBoz+3AW0mtZbRsduvwvqR24B/xEs9jy02RJin3VQw1qlVYATUvThrNqMUz45AgVvjx00llX6i5As7xkWwLjZSEpr6FWEjOtPg1ZHWBxD/dCHWpcL7nnGAWi2INTUT6NgN9ZpuU0tgHMMMx/7bfUM1EVEpJKjKLyaX8XmsRmztPUYOhRN/m2uEoiiOu54QoD9oszszIlEqT5jneu8LQ1Ie9ICaGF1Mj2CgbWB0hTvKSTPTP1hXF0FHtwmaTDwKKVE= file: app/build/outputs/apk/app-release.apk skip_cleanup: true on: repo: geeeeeeeeek/WeChatLuckyMoney branch: stable tags: true notifications: webhooks: urls: - https://webhooks.gitter.im/e/d83cc8365de0abdd097e on_success: always on_failure: always on_start: always ================================================ FILE: CHANGELOG.md ================================================ # 更新日志 **[v4.0 (2017.01.27)](https://github.com/geeeeeeeeek/WeChatLuckyMoney/releases/tag/v4.0)** - 新年快乐! - 新增 多语言支持,目前支持中文和英文两种语言 - 新增 适配部分Android 7.0机型(进行中,华为等部分机型仍不可用) - 优化 UI - 优化 性能改进 - 修复 Uber与滴滴合并后优惠链接失效的问题 - 修复 Bugly高优先级的问题 - 移除 自动回复功能 **[v3.0 (2016.08.02)](https://github.com/geeeeeeeeek/WeChatLuckyMoney/releases/tag/v3.0.1)** - 优化 重新设计UI,风格更加简洁明快。提升“社区”和“设置”的视觉优先级,开启插件更顺手。 - 新增 Uber免费乘车优惠。 - 新增 适配微信6.3.22。 - 新增 Android N (牛轧糖) 适配(预计v3.1完成) - 修复 Bugly高优先级的问题。 **[v2.3 (2016.02.07)](https://github.com/geeeeeeeeek/WeChatLuckyMoney/releases/tag/v2.3)** - 优化 不打开拜年红包 - 紧急修复了Bugly上几个高优先级的问题,减少Crash出现 **[v2.2 (2016.02.04)](https://github.com/geeeeeeeeek/WeChatLuckyMoney/releases/tag/v2.2)** - 新增 延时拆开红包的可选项 - 新增 跳转至浏览器打开的入口 - 新增 接入腾讯Bugly - 新增 自动回复的可选项(实验中) - 优化 手动拆开的红包不返回 - 优化 适配三星等坑爹机型 (感谢 [@firesunCN](https://github.com/firesunCN) 对这项修改的贡献) - 修复 拆开红包后的多次返回问题 **[v2.1 (2016.01.30)](https://github.com/geeeeeeeeek/WeChatLuckyMoney/releases/tag/v2.1.1)** - 新增 屏蔽指定红包文字的可选项 - 新增 息屏抢红包的可选项 - 新增 不拆开自己发的红包的可选项 - 新增 内置红包攻略 - 新增 所有链接默认用内置WebView打开 - 优化 仅在WiFi环境下回到应用时检测更新 - 优化 抢红包的逻辑流程,减少了一些误判情形 - 优化 适配了Lollipop以上版本的透明Status Bar - 修复 插件开启后按钮仍然显示“开启插件” - 修复 监听SharedPreferences变化无效的问题 (感谢 @act262 对这项修改的贡献) - 修复 在其他界面会做额外的操作的问题 (感谢 @sxyy 对这项修改的贡献) - 修复 响应Notification进入聊天后,可能误判不抢的问题 (感谢 @tttony3 对这项修改的贡献) **[v2.0.1 (2016.01.23)](https://github.com/geeeeeeeeek/WeChatLuckyMoney/releases/tag/v2.0.1)** - 修复了用户第一次使用,偏好设置未加载导致的插件失效。 Fix issue #50, #51. **[v2.0 (2016.01.23)](https://github.com/geeeeeeeeek/WeChatLuckyMoney/releases/tag/v2.0)** - 更自由的监视选项. Give user the freedom to choose what to watch, chat/list/notifications available at choices. - 更优化的重复红包判定. Optimize algorithm for duplicate hongbao detection. - 自动更新机制. Add auto update module. - 更新UI设计、应用图标. Update UI and app icon. - 增加辅助服务的说明. Add description for accessibility service. - 增加了反馈issue的快捷方式. Add quick link to Github issues. - 替换包名. Substitute the original package name. 详细的release notes请见https://github.com/geeeeeeeeek/WeChatLuckyMoney/issues/48。 **[v1.4 (2016.01.16)](https://github.com/geeeeeeeeek/WeChatLuckyMoney/releases/tag/v1.4)** - 修复了微信新版(6.3.9.48_refecd3e)红包UI调整导致的功能失效。Fix failure caused by new WeChat Hongbao UI. Related issue #41. **[v1.3 (2015.12.29)](https://github.com/geeeeeeeeek/WeChatLuckyMoney/releases/tag/v1.3)** - 修复了红包频繁点击的bug。Fix repeatedly opening envelopes. Related issue #27 . - 并入了从通知栏进入抢红包的代码(#28),充分测试后加入下一个版本。Add watch for WeChat notification, from which enter the chat activity. This feature will not be available in this version, until well tested. **[v1.2 (2015.12.17)](https://github.com/geeeeeeeeek/WeChatLuckyMoney/releases/tag/v1.2)** 该版本的红包识别代码存在Bug,会出现频繁点击,建议跳过该版本。 - 增加了微信语言 英语 的支持,修复了由此导致的一系列问题. Add support for the English language. Fix related issues. - 修改了红包重复判断的逻辑,戳“名称与缓存不一致的红包”和“名称一致且间隔大于5秒”的红包。Change the logic of detecting duplicate red envelopes. Only those name unmatched with cached or those name matched but with a duration > 5 secs will be touched. **[v1.1 (2015.10.28)](https://github.com/geeeeeeeeek/WeChatLuckyMoney/releases/tag/v1.1)** - 服务运行时防止息屏。Keep screen on when service is running. **[v1.0 (2015.10.07)](https://github.com/geeeeeeeeek/WeChatLuckyMoney/releases/tag/v1.0)** - 从dev分支并入了新版UI和红包节点的hash算法。 - 增加了红包重复判断,不再不停点击最新的红包,极大优化了性能和体验。 **[Preview (2015.08.17)](https://github.com/geeeeeeeeek/WeChatLuckyMoney/releases/tag/v1-beta1)** - 对源码进行了少量修改。 ================================================ FILE: LICENSE.md ================================================ **The MIT License (MIT)** Copyright (c) 2016 Zhongyi Tong ([geeeeeeeeek@Github](https://github.com/geeeeeeeeek)) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.md ================================================ # 微信红包 [![Gitter](https://badges.gitter.im/geeeeeeeeek/WeChatLuckyMoney.svg)](https://gitter.im/geeeeeeeeek/WeChatLuckyMoney?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=body_badge) [![Build Status](https://travis-ci.org/geeeeeeeeek/WeChatLuckyMoney.svg?branch=stable)](https://travis-ci.org/geeeeeeeeek/WeChatLuckyMoney) [![Docs](https://img.shields.io/badge/Docs-English-blue.svg)](https://github.com/geeeeeeeeek/WeChatLuckyMoney/blob/stable/README_EN.md) 一个帮助你在微信抢红包时战无不胜的Android应用。自动检测并且拆开红包,速度超乎你的想象。 支持中英文。前往[**Release**](https://github.com/geeeeeeeeek/WeChatLuckyMoney/releases/)下载最新版本。已下载用户可直接在设置里面更新。 ### 特性 - **监视选项任意组合,满足多样化的使用需求**[[?]](https://github.com/geeeeeeeeek/WeChatLuckyMoney/issues/48) 提供了`系统通知`/`聊天列表`/`聊天页面`三档选项,无论是想要谨慎不被察觉,还是想要高效志在必得,这个插件如你所愿。 - **不仅快人一步,红包识别更加智能** 多种特征标识,聊天时不再重复点击红包。智能过滤红包关键字[[?]](https://github.com/geeeeeeeeek/WeChatLuckyMoney/issues/97),避免落入“专属红包”、“抢到翻倍”的陷阱。还可以设置延时抢红包和自动回复感谢语[[?]](https://github.com/geeeeeeeeek/WeChatLuckyMoney/issues/118)。 - **紧跟微信更新** 第一时间适配最新版本微信,应用内即可一键更新。 - **轻量、安全、值得信赖** 安装包仅1M,无需ROOT,下载即用。代码公开透明,活跃的社区讨论,数万用户下载,值得你的信赖。 ### 使用方法 1. 打开『微信红包』应用,开启插件。 2. 做你想做的事。 3. 坐等红包进账。 ### 实现原理 请见[技术文档](https://github.com/geeeeeeeeek/WeChatLuckyMoney/blob/dev/README.md),注意文档描述的是dev分支(已弃用)的具体实现,而不是stable分支。若有疑问,请在[ISSUES](https://github.com/geeeeeeeeek/WeChatLuckyMoney/issues)中提出。 ### 更新日志 完整的更新日志请见[CHANGELOG](https://github.com/geeeeeeeeek/WeChatLuckyMoney/blob/stable/CHANGELOG.md)。 ### **版权及免责声明** 本项目源自小米去年秋季发布会时演示的MIUI 7抢红包测试[代码](https://github.com/XiaoMi/LuckyMoneyTool)。 插件可能会在一定程度上改变微信的交互方式。使用本项目中包含的代码及其生成物时,使用者自行承担随之而来的各种风险,包括但不限于“禁用红包功能”、“微信封号”。 本项目使用[MIT许可证](https://github.com/geeeeeeeeek/WeChatLuckyMoney/blob/stable/LICENSE.md)。 ### 应用截图 ![wechatimg159](https://cloud.githubusercontent.com/assets/7262715/22361931/999cc8e0-e499-11e6-91ae-ce6973f722f0.png) ![wechatimg160](https://cloud.githubusercontent.com/assets/7262715/22361932/99b0181e-e499-11e6-8547-d366f9c4cfd9.jpeg) ================================================ FILE: README_EN.md ================================================ # WeChat Lucky Money [![Gitter](https://badges.gitter.im/geeeeeeeeek/WeChatLuckyMoney.svg)](https://gitter.im/geeeeeeeeek/WeChatLuckyMoney?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=body_badge) [![Build Status](https://travis-ci.org/geeeeeeeeek/WeChatLuckyMoney.svg?branch=stable)](https://travis-ci.org/geeeeeeeeek/WeChatLuckyMoney) [![Docs](https://img.shields.io/badge/文档-中文-blue.svg)](https://github.com/geeeeeeeeek/WeChatLuckyMoney/blob/stable/README.md) This Android app helps you snatch red envelopes in WeChat. It detects red envelopes automatically, and clicks to open them faster than your imagination. Available in English and Chinese. Please goto the [**Release**](https://github.com/geeeeeeeeek/WeChatLuckyMoney/releases/) page to download the latest version. ### Spotlights - **What to watch is at your choice**[[?]](https://github.com/geeeeeeeeek/WeChatLuckyMoney/issues/48) Three levels of watch options: `notification`/`chat list`/`chat page`. Whatever a coutious man or an ambitious one you wanna be, the choice is at yours. - **More intelligent algorithm** Multiple features used to identify a red envelope. No more repeated clickings. Anti-anti-plugin strategies are protecting the app from disability. - **Auto update checking** Work with the latest version of WeChat. Update available inside your app. - **Light, safe, and trustful** Tha package is as light as 1Mb. With code open sourced, active community discussions, tens of thousands of downloads, it's worth your trust. ### How to use 1. Open the app, turn on the service. 2. Do whatever you wanna do. 3. Wait for the lucky money comes in your pocket. ### Implementation See the [document](https://github.com/geeeeeeeeek/WeChatLuckyMoney/blob/dev/README.md), which is targeted at the dev branch (deprecated) and is IN CHINESE. If it bothers you, leave your message in the [ISSUES](https://github.com/geeeeeeeeek/WeChatLuckyMoney/issues). ### Update history For full history, see [CHANGELOG](https://github.com/geeeeeeeeek/WeChatLuckyMoney/blob/stable/CHANGELOG.md). ### License The project was heavily inspired by the [app](https://github.com/XiaoMi/LuckyMoneyTool) demonstrated on XiaoMi's news conference for its phone product last autumn. This app might alter the natural way of interactions with WeChat. When you are using the code and its accessories, you are fully responsible for any possible consequences. The project is licensed to the [MIT](https://github.com/geeeeeeeeek/WeChatLuckyMoney/blob/stable/LICENSE.md). ### Snapshots ![wechatimg157](https://cloud.githubusercontent.com/assets/7262715/22361930/999aecdc-e499-11e6-91f6-c8c44b9ccc55.png) ![wechatimg158](https://cloud.githubusercontent.com/assets/7262715/22361929/99998126-e499-11e6-93bc-e97ea263db47.jpeg) ================================================ FILE: WeChatLuckyMoney.iml ================================================ ================================================ FILE: app/.gitignore ================================================ # Built application files *.apk *.ap_ # Files for the ART/Dalvik VM *.dex # Java class files *.class # Generated files bin/ gen/ out/ # Gradle files .gradle/ build/ # Local configuration file (sdk path, etc) local.properties # Proguard folder generated by Eclipse proguard/ # Log Files *.log # Android Studio Navigation editor temp files .navigation/ # Android Studio captures folder captures/ # Intellij *.iml .idea/ # Keystore files *.jks ================================================ FILE: app/build.gradle ================================================ apply plugin: 'com.android.application' android { compileSdkVersion 25 buildToolsVersion "26.0.2" useLibrary 'org.apache.http.legacy' defaultConfig { applicationId "xyz.monkeytong.hongbao" minSdkVersion 19 targetSdkVersion 25 versionCode 7 versionName "v5.0.0" ndk { //设置支持的SO库架构 abiFilters 'armeabi', 'armeabi-v7a' //, 'x86', 'armeabi-v7a', 'x86_64', 'arm64-v8a' } } signingConfigs { releaseConfig { storeFile file("../monkeytong.jks") storePassword project.hasProperty("KEYSTORE_PASS") ? KEYSTORE_PASS : System.getenv("KEYSTORE_PASS") keyAlias project.hasProperty("ALIAS_NAME") ? ALIAS_NAME : System.getenv("ALIAS_NAME") keyPassword project.hasProperty("ALIAS_PASS") ? ALIAS_PASS : System.getenv("ALIAS_PASS") } } buildTypes { release { minifyEnabled true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' signingConfig signingConfigs.releaseConfig } } } dependencies { compile fileTree(include: ['*.jar'], dir: 'libs') compile 'com.tencent.bugly:crashreport_upgrade:latest.release' //其中latest.release指代最新版本号,也可以指定明确的版本号,例如1.0.1 compile 'com.tencent.bugly:nativecrashreport:latest.release' //其中latest.release指代最新版本号,也可以指定明确的版本号,例如2.2.0 compile 'com.android.support:support-v4:25.4.0' compile 'com.android.support:appcompat-v7:25.4.0' } ================================================ FILE: app/proguard-rules.pro ================================================ # Add project specific ProGuard rules here. # By default, the flags in this file are appended to flags specified # in /home/nian/Android/Sdk/tools/proguard/proguard-android.txt # You can edit the include path and order by changing the proguardFiles # directive in build.gradle. # # For more details, see # http://developer.android.com/guide/developing/tools/proguard.html # Add any project specific keep options here: # If your project uses WebView with JS, uncomment the following # and specify the fully qualified class name to the JavaScript interface # class: #-keepclassmembers class fqcn.of.javascript.interface.for.webview { # public *; #} -dontwarn com.tencent.bugly.** -keep public class com.tencent.bugly.**{*;} -keep class android.support.**{*;} ================================================ FILE: app/src/main/AndroidManifest.xml ================================================ ================================================ FILE: app/src/main/java/xyz/monkeytong/hongbao/activities/MainActivity.java ================================================ package xyz.monkeytong.hongbao.activities; import android.accessibilityservice.AccessibilityServiceInfo; import android.annotation.TargetApi; import android.app.Activity; import android.content.Context; import android.content.Intent; import android.os.Build; import android.os.Bundle; import android.preference.PreferenceManager; import android.provider.Settings; import android.view.View; import android.view.Window; import android.view.WindowManager; import android.view.accessibility.AccessibilityManager; import android.widget.ImageView; import android.widget.TextView; import android.widget.Toast; import com.tencent.bugly.Bugly; import xyz.monkeytong.hongbao.R; import xyz.monkeytong.hongbao.utils.ConnectivityUtil; import xyz.monkeytong.hongbao.utils.UpdateTask; import java.util.List; public class MainActivity extends Activity implements AccessibilityManager.AccessibilityStateChangeListener { //开关切换按钮 private TextView pluginStatusText; private ImageView pluginStatusIcon; //AccessibilityService 管理 private AccessibilityManager accessibilityManager; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //CrashReport.initCrashReport(getApplicationContext(), "900019352", false); Bugly.init(getApplicationContext(), "900019352", false); setContentView(R.layout.activity_main); pluginStatusText = (TextView) findViewById(R.id.layout_control_accessibility_text); pluginStatusIcon = (ImageView) findViewById(R.id.layout_control_accessibility_icon); handleMaterialStatusBar(); explicitlyLoadPreferences(); //监听AccessibilityService 变化 accessibilityManager = (AccessibilityManager) getSystemService(Context.ACCESSIBILITY_SERVICE); accessibilityManager.addAccessibilityStateChangeListener(this); updateServiceStatus(); } private void explicitlyLoadPreferences() { PreferenceManager.setDefaultValues(this, R.xml.general_preferences, false); } /** * 适配MIUI沉浸状态栏 */ @TargetApi(Build.VERSION_CODES.LOLLIPOP) private void handleMaterialStatusBar() { // Not supported in APK level lower than 21 if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) return; Window window = this.getWindow(); window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); window.setStatusBarColor(0xffE46C62); } @Override protected void onPause() { super.onPause(); } @Override protected void onResume() { super.onResume(); updateServiceStatus(); // Check for update when WIFI is connected or on first time. if (ConnectivityUtil.isWifi(this) || UpdateTask.count == 0) new UpdateTask(this, false).update(); } @Override protected void onDestroy() { //移除监听服务 accessibilityManager.removeAccessibilityStateChangeListener(this); super.onDestroy(); } public void openAccessibility(View view) { try { Toast.makeText(this, getString(R.string.turn_on_toast) + pluginStatusText.getText(), Toast.LENGTH_SHORT).show(); Intent accessibleIntent = new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS); startActivity(accessibleIntent); } catch (Exception e) { Toast.makeText(this, getString(R.string.turn_on_error_toast), Toast.LENGTH_LONG).show(); e.printStackTrace(); } } public void openGitHub(View view) { Intent webViewIntent = new Intent(this, WebViewActivity.class); webViewIntent.putExtra("title", getString(R.string.webview_github_title)); webViewIntent.putExtra("url", "https://github.com/geeeeeeeeek/WeChatLuckyMoney"); startActivity(webViewIntent); } public void openUber(View view) { Intent webViewIntent = new Intent(this, WebViewActivity.class); webViewIntent.putExtra("title", getString(R.string.webview_alipay_title)); String[] couponList = new String[]{"https://render.alipay.com/p/f/fd-j6lzqrgm/guiderofmklvtvw.html?shareId=2088422430692204&campStr=p1j%2BdzkZl018zOczaHT4Z5CLdPVCgrEXq89JsWOx1gdt05SIDMPg3PTxZbdPw9dL&sign=DEqbE64SUB0qjRQGtu%2F0BPXN9YsSXM2zqLHT1X2ufDs%3D&scene=offlinePaymentNewSns"}; startActivity(webViewIntent); } public void openSettings(View view) { Intent settingsIntent = new Intent(this, SettingsActivity.class); settingsIntent.putExtra("title", getString(R.string.preference)); settingsIntent.putExtra("frag_id", "GeneralSettingsFragment"); startActivity(settingsIntent); } @Override public void onAccessibilityStateChanged(boolean enabled) { updateServiceStatus(); } /** * 更新当前 HongbaoService 显示状态 */ private void updateServiceStatus() { if (isServiceEnabled()) { pluginStatusText.setText(R.string.service_off); pluginStatusIcon.setBackgroundResource(R.mipmap.ic_stop); } else { pluginStatusText.setText(R.string.service_on); pluginStatusIcon.setBackgroundResource(R.mipmap.ic_start); } } /** * 获取 HongbaoService 是否启用状态 * * @return */ private boolean isServiceEnabled() { List accessibilityServices = accessibilityManager.getEnabledAccessibilityServiceList(AccessibilityServiceInfo.FEEDBACK_GENERIC); for (AccessibilityServiceInfo info : accessibilityServices) { if (info.getId().equals(getPackageName() + "/.services.HongbaoService")) { return true; } } return false; } } ================================================ FILE: app/src/main/java/xyz/monkeytong/hongbao/activities/SeekBarPreference.java ================================================ package xyz.monkeytong.hongbao.activities; import android.content.Context; import android.content.SharedPreferences; import android.preference.DialogPreference; import android.util.AttributeSet; import android.view.View; import android.widget.SeekBar; import android.widget.TextView; import xyz.monkeytong.hongbao.R; /** * Created by Zhongyi on 2/3/16. */ public class SeekBarPreference extends DialogPreference { private SeekBar seekBar; private TextView textView; private String hintText, prefKind; public SeekBarPreference(Context context, AttributeSet attrs) { super(context, attrs); setDialogLayoutResource(R.layout.preference_seekbar); for (int i = 0; i < attrs.getAttributeCount(); i++) { String attr = attrs.getAttributeName(i); if (attr.equalsIgnoreCase("pref_kind")) { prefKind = attrs.getAttributeValue(i); break; } } if (prefKind.equals("pref_open_delay")) { hintText = getContext().getString(R.string.delay_open); } else if (prefKind.equals("pref_comment_delay")) { hintText = "发送回复(暂不支持延时)"; } } @Override protected void onBindDialogView(View view) { super.onBindDialogView(view); SharedPreferences pref = getSharedPreferences(); int delay = pref.getInt(prefKind, 0); this.seekBar = (SeekBar) view.findViewById(R.id.delay_seekBar); this.seekBar.setProgress(delay); if (prefKind.equals("pref_comment_delay")) { this.seekBar.setEnabled(false); } this.textView = (TextView) view.findViewById(R.id.pref_seekbar_textview); setHintText(0); this.seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { @Override public void onProgressChanged(SeekBar seekBar, int i, boolean b) { setHintText(i); } @Override public void onStartTrackingTouch(SeekBar seekBar) { } @Override public void onStopTrackingTouch(SeekBar seekBar) { } }); } @Override protected void onDialogClosed(boolean positiveResult) { if (positiveResult) { SharedPreferences.Editor editor = getEditor(); editor.putInt(prefKind, this.seekBar.getProgress()); editor.commit(); } super.onDialogClosed(positiveResult); } private void setHintText(int delay) { if (delay == 0) { this.textView.setText(getContext().getString(R.string.delay_instantly) + hintText); } else { this.textView.setText(getContext().getString(R.string.delay_delay) + delay + getContext().getString(R.string.delay_sec) + getContext().getString(R.string.delay_then) + hintText); } } } ================================================ FILE: app/src/main/java/xyz/monkeytong/hongbao/activities/SettingsActivity.java ================================================ package xyz.monkeytong.hongbao.activities; import android.annotation.TargetApi; import android.app.Activity; import android.app.Fragment; import android.app.FragmentManager; import android.app.FragmentTransaction; import android.content.Intent; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.os.Parcelable; import android.preference.Preference; import android.preference.PreferenceActivity; import android.preference.PreferenceManager; import android.provider.Settings; import android.support.v4.app.FragmentActivity; import android.view.View; import android.view.Window; import android.view.WindowManager; import android.widget.TextView; import android.widget.Toast; import org.w3c.dom.Text; import xyz.monkeytong.hongbao.R; import xyz.monkeytong.hongbao.fragments.CommentSettingsFragment; import xyz.monkeytong.hongbao.fragments.GeneralSettingsFragment; import xyz.monkeytong.hongbao.utils.UpdateTask; /** * Created by Zhongyi on 1/19/16. * Settings page. */ public class SettingsActivity extends FragmentActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_preferences); loadUI(); prepareSettings(); } private void prepareSettings() { String title, fragId; Bundle bundle = getIntent().getExtras(); if (bundle != null) { title = bundle.getString("title"); fragId = bundle.getString("frag_id"); } else { title = getString(R.string.preference); fragId = "GeneralSettingsFragment"; } TextView textView = (TextView) findViewById(R.id.settings_bar); textView.setText(title); FragmentManager fragmentManager = getFragmentManager(); FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); if ("GeneralSettingsFragment".equals(fragId)) { fragmentTransaction.replace(R.id.preferences_fragment, new GeneralSettingsFragment()); } else if ("CommentSettingsFragment".equals(fragId)) { fragmentTransaction.replace(R.id.preferences_fragment, new CommentSettingsFragment()); } fragmentTransaction.commit(); } @TargetApi(Build.VERSION_CODES.LOLLIPOP) private void loadUI() { if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) return; Window window = this.getWindow(); window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); window.setStatusBarColor(0xffE46C62); } @Override protected void onResume() { super.onResume(); } public void performBack(View view) { super.onBackPressed(); } public void enterAccessibilityPage(View view) { Toast.makeText(this, getString(R.string.turn_on_toast), Toast.LENGTH_SHORT).show(); Intent mAccessibleIntent = new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS); startActivity(mAccessibleIntent); } } ================================================ FILE: app/src/main/java/xyz/monkeytong/hongbao/activities/WebViewActivity.java ================================================ package xyz.monkeytong.hongbao.activities; import android.annotation.TargetApi; import android.app.Activity; import android.content.Intent; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.view.KeyEvent; import android.view.View; import android.view.Window; import android.view.WindowManager; import android.webkit.CookieSyncManager; import android.webkit.WebSettings; import android.webkit.WebView; import android.webkit.WebViewClient; import android.widget.TextView; import android.widget.Toast; import xyz.monkeytong.hongbao.R; import xyz.monkeytong.hongbao.utils.DownloadUtil; /** * Created by Zhongyi on 1/19/16. * Settings page. */ public class WebViewActivity extends Activity { private WebView webView; private String webViewUrl, webViewTitle; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); loadUI(); Bundle bundle = getIntent().getExtras(); if (bundle != null && !bundle.isEmpty()) { webViewTitle = bundle.getString("title"); webViewUrl = bundle.getString("url"); final TextView webViewBar = (TextView) findViewById(R.id.webview_bar); webViewBar.setText(webViewTitle); webView = (WebView) findViewById(R.id.webView); webView.getSettings().setBuiltInZoomControls(false); webView.getSettings().setJavaScriptEnabled(true); webView.getSettings().setDomStorageEnabled(true); webView.getSettings().setCacheMode(WebSettings.LOAD_DEFAULT); webView.setWebViewClient(new WebViewClient() { @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { if (url.contains("apk")) { Toast.makeText(getApplicationContext(), getString(R.string.download_backend), Toast.LENGTH_SHORT).show(); (new DownloadUtil()).enqueue(url, getApplicationContext()); return true; } else if (!url.contains("http")) { Toast.makeText(getApplicationContext(), getString(R.string.download_redirect), Toast.LENGTH_LONG).show(); webViewBar.setText(getString(R.string.download_hint)); return false; } else { view.loadUrl(url); return false; } } @Override public void onPageFinished(WebView view, String url) { CookieSyncManager.getInstance().sync(); } }); webView.loadUrl(webViewUrl); } } @Override protected void onPause() { super.onPause(); } @Override protected void onResume() { super.onResume(); } @Override protected void onDestroy() { super.onDestroy(); } @TargetApi(Build.VERSION_CODES.LOLLIPOP) private void loadUI() { setContentView(R.layout.activity_webview); if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) return; Window window = this.getWindow(); window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); window.setStatusBarColor(0xffE46C62); } public void performBack(View view) { super.onBackPressed(); } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if (event.getAction() == KeyEvent.ACTION_DOWN) { switch (keyCode) { case KeyEvent.KEYCODE_BACK: if (webView.canGoBack()) { webView.goBack(); } else { finish(); } return true; } } return super.onKeyDown(keyCode, event); } public void openLink(View view) { Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(this.webViewUrl)); startActivity(intent); } } ================================================ FILE: app/src/main/java/xyz/monkeytong/hongbao/fragments/CommentSettingsFragment.java ================================================ package xyz.monkeytong.hongbao.fragments; import android.os.Build; import android.os.Bundle; import android.preference.Preference; import android.preference.PreferenceFragment; import android.preference.PreferenceManager; import android.widget.Toast; import xyz.monkeytong.hongbao.R; /** * Created by Zhongyi on 2/4/16. */ public class CommentSettingsFragment extends PreferenceFragment { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); addPreferencesFromResource(R.xml.comment_preferences); setPrefListeners(); } private void setPrefListeners() { Preference updatePref = findPreference("pref_comment_switch"); if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { updatePref.setEnabled(false); } Toast.makeText(getActivity(), "该功能尚处于实验中,只能自动填充感谢语,无法直接发送.", Toast.LENGTH_LONG).show(); Preference commentWordsPref = findPreference("pref_comment_words"); String summary = getResources().getString(R.string.pref_comment_words_summary); String value = PreferenceManager.getDefaultSharedPreferences(getActivity()).getString("pref_comment_words", ""); if (value.length() > 0) commentWordsPref.setSummary(summary + ":" + value); commentWordsPref.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { @Override public boolean onPreferenceChange(Preference preference, Object o) { String summary = getResources().getString(R.string.pref_comment_words_summary); if (o != null && o.toString().length() > 0) { preference.setSummary(summary + ":" + o.toString()); } else { preference.setSummary(summary); } return true; } }); } } ================================================ FILE: app/src/main/java/xyz/monkeytong/hongbao/fragments/GeneralSettingsFragment.java ================================================ package xyz.monkeytong.hongbao.fragments; import android.content.Intent; import android.os.Bundle; import android.preference.Preference; import android.preference.PreferenceFragment; import android.preference.PreferenceManager; import xyz.monkeytong.hongbao.R; import xyz.monkeytong.hongbao.activities.WebViewActivity; import xyz.monkeytong.hongbao.utils.UpdateTask; /** * Created by Zhongyi on 2/4/16. */ public class GeneralSettingsFragment extends PreferenceFragment { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); addPreferencesFromResource(R.xml.general_preferences); setPrefListeners(); } private void setPrefListeners() { // Check for updates Preference updatePref = findPreference("pref_etc_check_update"); updatePref.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { public boolean onPreferenceClick(Preference preference) { new UpdateTask(getActivity().getApplicationContext(), true).update(); return false; } }); // Open issue Preference issuePref = findPreference("pref_etc_issue"); issuePref.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { public boolean onPreferenceClick(Preference preference) { Intent webViewIntent = new Intent(getActivity(), WebViewActivity.class); webViewIntent.putExtra("title", "GitHub Issues"); webViewIntent.putExtra("url", getString(R.string.url_github_issues)); webViewIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(webViewIntent); return false; } }); Preference excludeWordsPref = findPreference("pref_watch_exclude_words"); String summary = getResources().getString(R.string.pref_watch_exclude_words_summary); String value = PreferenceManager.getDefaultSharedPreferences(getActivity()).getString("pref_watch_exclude_words", ""); if (value.length() > 0) excludeWordsPref.setSummary(summary + ":" + value); excludeWordsPref.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { @Override public boolean onPreferenceChange(Preference preference, Object o) { String summary = getResources().getString(R.string.pref_watch_exclude_words_summary); if (o != null && o.toString().length() > 0) { preference.setSummary(summary + ":" + o.toString()); } else { preference.setSummary(summary); } return true; } }); } } ================================================ FILE: app/src/main/java/xyz/monkeytong/hongbao/services/HongbaoService.java ================================================ package xyz.monkeytong.hongbao.services; import android.accessibilityservice.AccessibilityService; import android.accessibilityservice.GestureDescription; import android.app.Notification; import android.app.PendingIntent; import android.content.ComponentName; import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.graphics.Rect; import android.os.Bundle; import android.os.Parcelable; import android.graphics.Path; import android.preference.PreferenceManager; import android.util.Log; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityNodeInfo; import android.util.DisplayMetrics; import xyz.monkeytong.hongbao.utils.HongbaoSignature; import xyz.monkeytong.hongbao.utils.PowerUtil; import java.util.List; public class HongbaoService extends AccessibilityService implements SharedPreferences.OnSharedPreferenceChangeListener { private static final String TAG = "HongbaoService"; private static final String WECHAT_DETAILS_EN = "Details"; private static final String WECHAT_DETAILS_CH = "红包详情"; private static final String WECHAT_BETTER_LUCK_EN = "Better luck next time!"; private static final String WECHAT_BETTER_LUCK_CH = "手慢了"; private static final String WECHAT_EXPIRES_CH = "已超过24小时"; private static final String WECHAT_VIEW_SELF_CH = "查看红包"; private static final String WECHAT_VIEW_OTHERS_CH = "领取红包"; private static final String WECHAT_NOTIFICATION_TIP = "[微信红包]"; private static final String WECHAT_LUCKMONEY_RECEIVE_ACTIVITY = ".plugin.luckymoney.ui";//com.tencent.mm/.plugin.luckymoney.ui.En_fba4b94f com.tencent.mm/com.tencent.mm.plugin.luckymoney.ui.LuckyMoneyReceiveUI private static final String WECHAT_LUCKMONEY_DETAIL_ACTIVITY = "LuckyMoneyDetailUI"; private static final String WECHAT_LUCKMONEY_GENERAL_ACTIVITY = "LauncherUI"; private static final String WECHAT_LUCKMONEY_CHATTING_ACTIVITY = "ChattingUI"; private String currentActivityName = WECHAT_LUCKMONEY_GENERAL_ACTIVITY; private AccessibilityNodeInfo rootNodeInfo, mReceiveNode, mUnpackNode; private boolean mLuckyMoneyPicked, mLuckyMoneyReceived; private int mUnpackCount = 0; private boolean mMutex = false, mListMutex = false, mChatMutex = false; private HongbaoSignature signature = new HongbaoSignature(); private PowerUtil powerUtil; private SharedPreferences sharedPreferences; /** * AccessibilityEvent * * @param event 事件 */ @Override public void onAccessibilityEvent(AccessibilityEvent event) { if (sharedPreferences == null) return; setCurrentActivityName(event); /* 检测通知消息 */ if (!mMutex) { if (sharedPreferences.getBoolean("pref_watch_notification", false) && watchNotifications(event)) return; if (sharedPreferences.getBoolean("pref_watch_list", false) && watchList(event)) return; mListMutex = false; } if (!mChatMutex) { mChatMutex = true; if (sharedPreferences.getBoolean("pref_watch_chat", false)) watchChat(event); mChatMutex = false; } } private void watchChat(AccessibilityEvent event) { this.rootNodeInfo = getRootInActiveWindow(); if (rootNodeInfo == null) return; mReceiveNode = null; mUnpackNode = null; checkNodeInfo(event.getEventType()); /* 如果已经接收到红包并且还没有戳开 */ Log.d(TAG, "watchChat mLuckyMoneyReceived:" + mLuckyMoneyReceived + " mLuckyMoneyPicked:" + mLuckyMoneyPicked + " mReceiveNode:" + mReceiveNode); if (mLuckyMoneyReceived && (mReceiveNode != null)) { mMutex = true; mReceiveNode.getParent().performAction(AccessibilityNodeInfo.ACTION_CLICK); mLuckyMoneyReceived = false; mLuckyMoneyPicked = true; } /* 如果戳开但还未领取 */ Log.d(TAG, "戳开红包!" + " mUnpackCount: " + mUnpackCount + " mUnpackNode: " + mUnpackNode); if (mUnpackCount >= 1 && (mUnpackNode != null)) { int delayFlag = sharedPreferences.getInt("pref_open_delay", 0) * 1000; new android.os.Handler().postDelayed( new Runnable() { public void run() { try { openPacket(); } catch (Exception e) { mMutex = false; mLuckyMoneyPicked = false; mUnpackCount = 0; } } }, delayFlag); } } private void openPacket() { DisplayMetrics metrics = getResources().getDisplayMetrics(); float dpi = metrics.densityDpi; Log.d(TAG, "openPacket!" + dpi); if (android.os.Build.VERSION.SDK_INT <= 23) { mUnpackNode.performAction(AccessibilityNodeInfo.ACTION_CLICK); } else { if (android.os.Build.VERSION.SDK_INT > 23) { Path path = new Path(); if (640 == dpi) { //1440 path.moveTo(720, 1575); } else if(320 == dpi){//720p path.moveTo(355, 780); }else if(480 == dpi){//1080p path.moveTo(533, 1115); } GestureDescription.Builder builder = new GestureDescription.Builder(); GestureDescription gestureDescription = builder.addStroke(new GestureDescription.StrokeDescription(path, 450, 50)).build(); dispatchGesture(gestureDescription, new GestureResultCallback() { @Override public void onCompleted(GestureDescription gestureDescription) { Log.d(TAG, "onCompleted"); mMutex = false; super.onCompleted(gestureDescription); } @Override public void onCancelled(GestureDescription gestureDescription) { Log.d(TAG, "onCancelled"); mMutex = false; super.onCancelled(gestureDescription); } }, null); } } } private void setCurrentActivityName(AccessibilityEvent event) { if (event.getEventType() != AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) { return; } try { ComponentName componentName = new ComponentName( event.getPackageName().toString(), event.getClassName().toString() ); getPackageManager().getActivityInfo(componentName, 0); currentActivityName = componentName.flattenToShortString(); } catch (PackageManager.NameNotFoundException e) { currentActivityName = WECHAT_LUCKMONEY_GENERAL_ACTIVITY; } } private boolean watchList(AccessibilityEvent event) { if (mListMutex) return false; mListMutex = true; AccessibilityNodeInfo eventSource = event.getSource(); // Not a message if (event.getEventType() != AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED || eventSource == null) return false; List nodes = eventSource.findAccessibilityNodeInfosByText(WECHAT_NOTIFICATION_TIP); //增加条件判断currentActivityName.contains(WECHAT_LUCKMONEY_GENERAL_ACTIVITY) //避免当订阅号中出现标题为“[微信红包]拜年红包”(其实并非红包)的信息时误判 if (!nodes.isEmpty() && currentActivityName.contains(WECHAT_LUCKMONEY_GENERAL_ACTIVITY)) { AccessibilityNodeInfo nodeToClick = nodes.get(0); if (nodeToClick == null) return false; CharSequence contentDescription = nodeToClick.getContentDescription(); if (contentDescription != null && !signature.getContentDescription().equals(contentDescription)) { nodeToClick.performAction(AccessibilityNodeInfo.ACTION_CLICK); signature.setContentDescription(contentDescription.toString()); return true; } } return false; } private boolean watchNotifications(AccessibilityEvent event) { // Not a notification if (event.getEventType() != AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED) return false; // Not a hongbao String tip = event.getText().toString(); if (!tip.contains(WECHAT_NOTIFICATION_TIP)) return true; Parcelable parcelable = event.getParcelableData(); if (parcelable instanceof Notification) { Notification notification = (Notification) parcelable; try { /* 清除signature,避免进入会话后误判 */ signature.cleanSignature(); notification.contentIntent.send(); } catch (PendingIntent.CanceledException e) { e.printStackTrace(); } } return true; } @Override public void onInterrupt() { } private AccessibilityNodeInfo findOpenButton(AccessibilityNodeInfo node) { if (node == null) return null; //非layout元素 if (node.getChildCount() == 0) { if ("android.widget.Button".equals(node.getClassName())) return node; else return null; } //layout元素,遍历找button AccessibilityNodeInfo button; for (int i = 0; i < node.getChildCount(); i++) { button = findOpenButton(node.getChild(i)); if (button != null) return button; } return null; } private void checkNodeInfo(int eventType) { if (this.rootNodeInfo == null) return; if (signature.commentString != null) { sendComment(); signature.commentString = null; } /* 聊天会话窗口,遍历节点匹配“领取红包”和"查看红包" */ AccessibilityNodeInfo node1 = (sharedPreferences.getBoolean("pref_watch_self", false)) ? this.getTheLastNode(WECHAT_VIEW_OTHERS_CH, WECHAT_VIEW_SELF_CH) : this.getTheLastNode(WECHAT_VIEW_OTHERS_CH); if (node1 != null && (currentActivityName.contains(WECHAT_LUCKMONEY_CHATTING_ACTIVITY) || currentActivityName.contains(WECHAT_LUCKMONEY_GENERAL_ACTIVITY))) { String excludeWords = sharedPreferences.getString("pref_watch_exclude_words", ""); if (this.signature.generateSignature(node1, excludeWords)) { mLuckyMoneyReceived = true; mReceiveNode = node1; Log.d("sig", this.signature.toString()); } return; } /* 戳开红包,红包还没抢完,遍历节点匹配“拆红包” */ AccessibilityNodeInfo node2 = findOpenButton(this.rootNodeInfo); Log.d(TAG, "checkNodeInfo node2 " + node2); if (node2 != null && "android.widget.Button".equals(node2.getClassName()) && currentActivityName.contains(WECHAT_LUCKMONEY_RECEIVE_ACTIVITY) && (mUnpackNode == null || mUnpackNode != null && !mUnpackNode.equals(node2))) { mUnpackNode = node2; mUnpackCount += 1; return; } /* 戳开红包,红包已被抢完,遍历节点匹配“红包详情”和“手慢了” */ boolean hasNodes = this.hasOneOfThoseNodes( WECHAT_BETTER_LUCK_CH, WECHAT_DETAILS_CH, WECHAT_BETTER_LUCK_EN, WECHAT_DETAILS_EN, WECHAT_EXPIRES_CH); Log.d(TAG, "checkNodeInfo hasNodes:" + hasNodes + " mMutex:"+ mMutex); if ( eventType == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED && hasNodes && (currentActivityName.contains(WECHAT_LUCKMONEY_DETAIL_ACTIVITY) || currentActivityName.contains(WECHAT_LUCKMONEY_RECEIVE_ACTIVITY))) { mMutex = false; mLuckyMoneyPicked = false; mUnpackCount = 0; performGlobalAction(GLOBAL_ACTION_BACK); signature.commentString = generateCommentString(); } } private void sendComment() { try { AccessibilityNodeInfo outNode = getRootInActiveWindow().getChild(0).getChild(0); AccessibilityNodeInfo nodeToInput = outNode.getChild(outNode.getChildCount() - 1).getChild(0).getChild(1); if ("android.widget.EditText".equals(nodeToInput.getClassName())) { Bundle arguments = new Bundle(); arguments.putCharSequence(AccessibilityNodeInfo .ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, signature.commentString); nodeToInput.performAction(AccessibilityNodeInfo.ACTION_SET_TEXT, arguments); } } catch (Exception e) { // Not supported } } private boolean hasOneOfThoseNodes(String... texts) { List nodes; for (String text : texts) { if (text == null) continue; nodes = this.rootNodeInfo.findAccessibilityNodeInfosByText(text); if (nodes != null && !nodes.isEmpty()) return true; } return false; } private AccessibilityNodeInfo getTheLastNode(String... texts) { int bottom = 0; AccessibilityNodeInfo lastNode = null, tempNode; List nodes; for (String text : texts) { if (text == null) continue; nodes = this.rootNodeInfo.findAccessibilityNodeInfosByText(text); if (nodes != null && !nodes.isEmpty()) { tempNode = nodes.get(nodes.size() - 1); if (tempNode == null) return null; Rect bounds = new Rect(); tempNode.getBoundsInScreen(bounds); if (bounds.bottom > bottom) { bottom = bounds.bottom; lastNode = tempNode; signature.others = text.equals(WECHAT_VIEW_OTHERS_CH); } } } return lastNode; } @Override public void onServiceConnected() { super.onServiceConnected(); this.watchFlagsFromPreference(); } private void watchFlagsFromPreference() { sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this); sharedPreferences.registerOnSharedPreferenceChangeListener(this); this.powerUtil = new PowerUtil(this); Boolean watchOnLockFlag = sharedPreferences.getBoolean("pref_watch_on_lock", false); this.powerUtil.handleWakeLock(watchOnLockFlag); } @Override public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { if (key.equals("pref_watch_on_lock")) { Boolean changedValue = sharedPreferences.getBoolean(key, false); this.powerUtil.handleWakeLock(changedValue); } } @Override public void onDestroy() { this.powerUtil.handleWakeLock(false); super.onDestroy(); } private String generateCommentString() { if (!signature.others) return null; Boolean needComment = sharedPreferences.getBoolean("pref_comment_switch", false); if (!needComment) return null; String[] wordsArray = sharedPreferences.getString("pref_comment_words", "").split(" +"); if (wordsArray.length == 0) return null; Boolean atSender = sharedPreferences.getBoolean("pref_comment_at", false); if (atSender) { return "@" + signature.sender + " " + wordsArray[(int) (Math.random() * wordsArray.length)]; } else { return wordsArray[(int) (Math.random() * wordsArray.length)]; } } } ================================================ FILE: app/src/main/java/xyz/monkeytong/hongbao/utils/ConnectivityUtil.java ================================================ package xyz.monkeytong.hongbao.utils; import android.content.Context; import android.net.ConnectivityManager; import android.net.NetworkInfo; /** * Created by Zhongyi on 1/29/16. */ public class ConnectivityUtil { public static boolean isWifi(Context context) { ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo activeNetwork = cm.getActiveNetworkInfo(); return activeNetwork != null && activeNetwork.isConnectedOrConnecting() && activeNetwork.getType() == ConnectivityManager.TYPE_WIFI; } } ================================================ FILE: app/src/main/java/xyz/monkeytong/hongbao/utils/DownloadUtil.java ================================================ package xyz.monkeytong.hongbao.utils; import android.app.DownloadManager; import android.content.Context; import android.net.Uri; import android.os.Environment; import java.net.URI; import static android.content.Context.DOWNLOAD_SERVICE; /** * Created by Zhongyi on 8/1/16. */ public class DownloadUtil { public void enqueue(String url, Context context) { DownloadManager.Request r = new DownloadManager.Request(Uri.parse(url)); r.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, "Uber.apk"); r.allowScanningByMediaScanner(); r.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED); DownloadManager dm = (DownloadManager) context.getSystemService(DOWNLOAD_SERVICE); dm.enqueue(r); } } ================================================ FILE: app/src/main/java/xyz/monkeytong/hongbao/utils/HongbaoLogger.java ================================================ package xyz.monkeytong.hongbao.utils; import android.content.Context; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; /** * Created by Zhongyi on 1/22/16. */ public class HongbaoLogger { private Context context; private SQLiteDatabase database; private static final int DATABASE_VERSION = 1; private static final String DATABASE_NAME = "WeChatLuckyMoney.db"; private static final String createDatabaseSQL = "CREATE TABLE IF NOT EXISTS HongbaoLog (id INTEGER PRIMARY KEY AUTOINCREMENT, sender TEXT, content TEXT, time TEXT, amount TEXT);"; public HongbaoLogger(final Context context) { this.context = context; this.initSchemaAndDatabase(); } private void initSchemaAndDatabase() { this.database = context.openOrCreateDatabase("WeChatLuckyMoney", context.MODE_PRIVATE, null); this.database.beginTransaction(); this.database.execSQL(createDatabaseSQL); this.database.endTransaction(); } public void writeHongbaoLog(String sender, String content, String amount) { } public void getAllLogs() { } } ================================================ FILE: app/src/main/java/xyz/monkeytong/hongbao/utils/HongbaoSignature.java ================================================ package xyz.monkeytong.hongbao.utils; import android.graphics.Rect; import android.view.accessibility.AccessibilityNodeInfo; /** * Created by Zhongyi on 1/21/16. */ public class HongbaoSignature { public String sender, content, time, contentDescription = "", commentString; public boolean others; public boolean generateSignature(AccessibilityNodeInfo node, String excludeWords) { try { /* The hongbao container node. It should be a LinearLayout. By specifying that, we can avoid text messages. */ AccessibilityNodeInfo hongbaoNode = node.getParent(); if (!"android.widget.LinearLayout".equals(hongbaoNode.getClassName())) return false; /* The text in the hongbao. Should mean something. */ String hongbaoContent = hongbaoNode.getChild(0).getText().toString(); if (hongbaoContent == null || "查看红包".equals(hongbaoContent)) return false; /* Check the user's exclude words list. */ String[] excludeWordsArray = excludeWords.split(" +"); for (String word : excludeWordsArray) { if (word.length() > 0 && hongbaoContent.contains(word)) return false; } /* The container node for a piece of message. It should be inside the screen. Or sometimes it will get opened twice while scrolling. */ AccessibilityNodeInfo messageNode = hongbaoNode.getParent(); Rect bounds = new Rect(); messageNode.getBoundsInScreen(bounds); if (bounds.top < 0) return false; /* The sender and possible timestamp. Should mean something too. */ String[] hongbaoInfo = getSenderContentDescriptionFromNode(messageNode); if (this.getSignature(hongbaoInfo[0], hongbaoContent, hongbaoInfo[1]).equals(this.toString())) return false; /* So far we make sure it's a valid new coming hongbao. */ this.sender = hongbaoInfo[0]; this.time = hongbaoInfo[1]; this.content = hongbaoContent; return true; } catch (Exception e) { e.printStackTrace(); return false; } } @Override public String toString() { return this.getSignature(this.sender, this.content, this.time); } private String getSignature(String... strings) { String signature = ""; for (String str : strings) { if (str == null) return null; signature += str + "|"; } return signature.substring(0, signature.length() - 1); } public String getContentDescription() { return this.contentDescription; } public void setContentDescription(String description) { this.contentDescription = description; } private String[] getSenderContentDescriptionFromNode(AccessibilityNodeInfo node) { int count = node.getChildCount(); String[] result = {"unknownSender", "unknownTime"}; for (int i = 0; i < count; i++) { AccessibilityNodeInfo thisNode = node.getChild(i); if ("android.widget.ImageView".equals(thisNode.getClassName()) && "unknownSender".equals(result[0])) { CharSequence contentDescription = thisNode.getContentDescription(); if (contentDescription != null) result[0] = contentDescription.toString().replaceAll("头像$", ""); } else if ("android.widget.TextView".equals(thisNode.getClassName()) && "unknownTime".equals(result[1])) { CharSequence thisNodeText = thisNode.getText(); if (thisNodeText != null) result[1] = thisNodeText.toString(); } } return result; } public void cleanSignature() { this.content = ""; this.time = ""; this.sender = ""; } } ================================================ FILE: app/src/main/java/xyz/monkeytong/hongbao/utils/PowerUtil.java ================================================ package xyz.monkeytong.hongbao.utils; import android.app.KeyguardManager; import android.content.Context; import android.os.PowerManager; /** * Created by Zhongyi on 1/29/16. */ public class PowerUtil { private PowerManager.WakeLock wakeLock; private KeyguardManager.KeyguardLock keyguardLock; public PowerUtil(Context context) { PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE); wakeLock = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, "HongbaoWakelock"); KeyguardManager km = (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE); keyguardLock = km.newKeyguardLock("HongbaoKeyguardLock"); } private void acquire() { wakeLock.acquire(1800000); keyguardLock.disableKeyguard(); } private void release() { if (wakeLock.isHeld()) { wakeLock.release(); keyguardLock.reenableKeyguard(); } } public void handleWakeLock(boolean isWake) { if (isWake) { this.acquire(); } else { this.release(); } } } ================================================ FILE: app/src/main/java/xyz/monkeytong/hongbao/utils/UpdateTask.java ================================================ package xyz.monkeytong.hongbao.utils; import android.content.Context; import android.content.Intent; import android.content.pm.PackageInfo; import android.net.Uri; import android.os.AsyncTask; import android.widget.Toast; import org.apache.http.HttpResponse; import org.apache.http.StatusLine; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.DefaultHttpClient; import org.json.JSONObject; import xyz.monkeytong.hongbao.R; import xyz.monkeytong.hongbao.activities.SettingsActivity; import xyz.monkeytong.hongbao.activities.WebViewActivity; import java.io.ByteArrayOutputStream; import java.io.IOException; /** * Created by Zhongyi on 1/20/16. * Util for app update task. */ public class UpdateTask extends AsyncTask { public static int count = 0; private Context context; private boolean isUpdateOnRelease; public static final String updateUrl = "https://api.github.com/repos/geeeeeeeeek/WeChatLuckyMoney/releases/latest"; public UpdateTask(Context context, boolean needUpdate) { this.context = context; this.isUpdateOnRelease = needUpdate; if (this.isUpdateOnRelease) Toast.makeText(context, context.getString(R.string.checking_new_version), Toast.LENGTH_SHORT).show(); } @Override protected String doInBackground(String... uri) { HttpClient httpclient = new DefaultHttpClient(); HttpResponse response; String responseString = null; try { response = httpclient.execute(new HttpGet(uri[0])); StatusLine statusLine = response.getStatusLine(); if (statusLine.getStatusCode() == 200) { ByteArrayOutputStream out = new ByteArrayOutputStream(); response.getEntity().writeTo(out); responseString = out.toString(); out.close(); } else { // Close the connection. response.getEntity().getContent().close(); throw new IOException(statusLine.getReasonPhrase()); } } catch (Exception e) { return null; } return responseString; } @Override protected void onPostExecute(String result) { super.onPostExecute(result); try { count += 1; JSONObject release = new JSONObject(result); // Get current version PackageInfo pInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0); String version = pInfo.versionName; String latestVersion = release.getString("tag_name"); boolean isPreRelease = release.getBoolean("prerelease"); if (!isPreRelease && version.compareToIgnoreCase(latestVersion) >= 0) { // Your version is ahead of or same as the latest. if (this.isUpdateOnRelease) Toast.makeText(context, R.string.update_already_latest, Toast.LENGTH_SHORT).show(); } else { if (!isUpdateOnRelease) { Toast.makeText(context, context.getString(R.string.update_new_seg1) + latestVersion + context.getString(R.string.update_new_seg3), Toast.LENGTH_LONG).show(); return; } // Need update. String downloadUrl = release.getJSONArray("assets").getJSONObject(0).getString("browser_download_url"); // Give up on the fucking DownloadManager. The downloaded apk got renamed and unable to install. Fuck. Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(downloadUrl)); browserIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); context.startActivity(browserIntent); Toast.makeText(context, context.getString(R.string.update_new_seg1) + latestVersion + context.getString(R.string.update_new_seg2), Toast.LENGTH_LONG).show(); } } catch (Exception e) { e.printStackTrace(); if (this.isUpdateOnRelease) Toast.makeText(context, R.string.update_error, Toast.LENGTH_LONG).show(); } } public void update() { super.execute(updateUrl); } } ================================================ FILE: app/src/main/res/layout/activity_main.xml ================================================ ================================================ FILE: app/src/main/res/layout/activity_preferences.xml ================================================ ================================================ FILE: app/src/main/res/layout/activity_webview.xml ================================================ ================================================ FILE: app/src/main/res/layout/preference_category.xml ================================================ ================================================ FILE: app/src/main/res/layout/preference_checkbox.xml ================================================ ================================================ FILE: app/src/main/res/layout/preference_seekbar.xml ================================================ ================================================ FILE: app/src/main/res/layout-v21/activity_preferences.xml ================================================ ================================================ FILE: app/src/main/res/layout-v21/activity_webview.xml ================================================ ================================================ FILE: app/src/main/res/values/dimens.xml ================================================ 16dp 16dp ================================================ FILE: app/src/main/res/values/strings.xml ================================================ 微信红包 v5.0 ∠( ᐛ 」∠)_使用指南∠( ᐛ 」∠)_\n\n ○ 狠戳插件开关\n ○ 回到微信聊天\n ○ 坐等红包进账\n\n 遇到问题, 欢迎通过 GitHub Issue 反馈~\n https://github.com/geeeeeeeeek/WeChatLuckyMoney 偏好设置 遇到一些问题,请前往GitHub手动更新喵(ฅ´ω`ฅ) 发现新版本( ),正在为您准备下载( /) V (\\ ) ),请进入设置完成更新(ฅ´ω`ฅ) 已经是最新版本了(❁´▽`❁) 关闭插件 开启插件 不拆开包含这些文字的红包(空格间隔) 随机选择下列感谢语(空格间隔) https://github.com/geeeeeeeeek/WeChatLuckyMoney/issues ca-app-pub-8428619221469478/4736153346 ca-app-pub-8428619221469478/4163694548 社区 设置 立即获得红包!人人可领!天天可领! 在 GitHub 上 本项目,支持应用开源 Star 点击「微信红包」 遇到一些问题,请手动打开系统设置>无障碍服务>微信红包(ฅ´ω`ฅ) GitHub 项目主页 支付宝红包 正在后台下载 正在前往下载页面 点击\"普通下载\"获取 Uber 监视选项 监视系统通知 读取新消息通知中的红包提示并进入聊天页 监视聊天列表 读取聊天列表中的红包提示并进入聊天页 防封号选项 自动拆开红包 延时拆开红包 拆开自己发的红包 屏蔽红包文字 关于应用 检查新版本 帮助与反馈 前往GitHub项目主页提交issue 实验功能 息屏抢红包 保持30分钟后台活跃,可能会极大增加电量消耗,请谨慎使用 拆开红包后自动回复 正在检查新版本…… 立即 延迟 拆开红包 然后 延迟0秒拆开红包 TODO ================================================ FILE: app/src/main/res/values-en/strings.xml ================================================ Lucky Money v5.0 ∠( ᐛ 」∠)_ Instructions ∠( ᐛ 」∠)_\n\n ○ Turn on the Accessibility switch\n ○ Go back to WeChat\n ○ Wait for money comes in\n\n Please submit your feedback on GitHub Issues Page~\n https://github.com/geeeeeeeeek/WeChatLuckyMoney Preferences An error occurred. Please manually update from GitHub Release Page. (ฅ´ω`ฅ) New version found.( )Preparing download for you. ( /) V (\\ ) )Please go to Settings to finish update. (ฅ´ω`ฅ) You\'re using the latest version! (❁´▽`❁) Turn Off Turn On Skip red packets with these phrases (separated by space) Randomly choose reply from these phrases (separated by space) https://github.com/geeeeeeeeek/WeChatLuckyMoney/issues ca-app-pub-8428619221469478/4736153346 ca-app-pub-8428619221469478/4163694548 Community Settings Get Luckymoney Now this app on GitHub to support us Star Click 「WeChat Lucky Money」  An error occurred. Please manually open System Settings > Accessibility > WeChat Lucky Money. (ฅ´ω`ฅ) Project Homepage on GitHub Get Luckymoney Downloading… Redirecting to download page… Download Uber by clicking \"普通下载\" Watch Level Watch system notifications Enter chat when a red packet is detected from WeChat notifications Watch chat list Enter chat when a red packet is detected from chat list Anti-block Options Open red packets automatically Open red packets with a delay Open red packets I gave out Skip red packets by words in the message About Check for updates Help and feedback Submit issues on GitHub homepage Labs Snatch red packets on lock screen Will keep the app active in backend for 30 min. Please proceed with caution, since this might greatly increase your battery usage. Auto reply Checking for updates… Instantly  Delay for  open red packets.  seconds  and then  延迟0秒拆开红包 TODO ================================================ FILE: app/src/main/res/values-w820dp/dimens.xml ================================================ 64dp ================================================ FILE: app/src/main/res/values-w820dp/strings.xml ================================================ 延迟0秒拆开红包 TODO ================================================ FILE: app/src/main/res/xml/accessible_service_config.xml ================================================ ================================================ FILE: app/src/main/res/xml/comment_preferences.xml ================================================ ================================================ FILE: app/src/main/res/xml/general_preferences.xml ================================================ ================================================ FILE: app/src/main/res/xml/provider_paths.xml ================================================ ================================================ FILE: build.gradle ================================================ // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { repositories { jcenter() maven { url 'https://maven.google.com/' name 'Google' } } dependencies { classpath 'com.android.tools.build:gradle:2.3.3' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files } } allprojects { repositories { jcenter() google() } } ================================================ FILE: gradle/wrapper/gradle-wrapper.properties ================================================ #Sat Jan 27 19:41:50 CST 2018 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip ================================================ FILE: gradle.properties ================================================ ## Project-wide Gradle settings. # # For more details on how to configure your build environment visit # http://www.gradle.org/docs/current/userguide/build_environment.html # # Specifies the JVM arguments used for the daemon process. # The setting is particularly useful for tweaking memory settings. # Default value: -Xmx1024m -XX:MaxPermSize=256m # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 # # When configured, Gradle will run in incubating parallel mode. # This option should only be used with decoupled projects. More details, visit # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects # org.gradle.parallel=true #Sat Jan 27 19:37:03 CST 2018 systemProp.http.proxyHost=127.0.0.1 systemProp.http.proxyPort=1087 android.useDeprecatedNdk=true ================================================ FILE: gradlew ================================================ #!/usr/bin/env bash ############################################################################## ## ## Gradle start up script for UN*X ## ############################################################################## # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS="" APP_NAME="Gradle" APP_BASE_NAME=`basename "$0"` # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD="maximum" warn ( ) { echo "$*" } die ( ) { echo echo "$*" echo exit 1 } # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false case "`uname`" in CYGWIN* ) cygwin=true ;; Darwin* ) darwin=true ;; MINGW* ) msys=true ;; esac # For Cygwin, ensure paths are in UNIX format before anything is touched. if $cygwin ; then [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` fi # Attempt to set APP_HOME # Resolve links: $0 may be a link PRG="$0" # Need this for relative symlinks. while [ -h "$PRG" ] ; do ls=`ls -ld "$PRG"` link=`expr "$ls" : '.*-> \(.*\)$'` if expr "$link" : '/.*' > /dev/null; then PRG="$link" else PRG=`dirname "$PRG"`"/$link" fi done SAVED="`pwd`" cd "`dirname \"$PRG\"`/" >&- APP_HOME="`pwd -P`" cd "$SAVED" >&- CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD="$JAVA_HOME/jre/sh/java" else JAVACMD="$JAVA_HOME/bin/java" fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD="java" which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi # Increase the maximum file descriptors if we can. if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then MAX_FD_LIMIT=`ulimit -H -n` if [ $? -eq 0 ] ; then if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then MAX_FD="$MAX_FD_LIMIT" fi ulimit -n $MAX_FD if [ $? -ne 0 ] ; then warn "Could not set maximum file descriptor limit: $MAX_FD" fi else warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" fi fi # For Darwin, add options to specify how the application appears in the dock if $darwin; then GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" fi # For Cygwin, switch paths to Windows format before running java if $cygwin ; then APP_HOME=`cygpath --path --mixed "$APP_HOME"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` # We build the pattern for arguments to be converted via cygpath ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` SEP="" for dir in $ROOTDIRSRAW ; do ROOTDIRS="$ROOTDIRS$SEP$dir" SEP="|" done OURCYGPATTERN="(^($ROOTDIRS))" # Add a user-defined pattern to the cygpath arguments if [ "$GRADLE_CYGPATTERN" != "" ] ; then OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" fi # Now convert the arguments - kludge to limit ourselves to /bin/sh i=0 for arg in "$@" ; do CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` else eval `echo args$i`="\"$arg\"" fi i=$((i+1)) done case $i in (0) set -- ;; (1) set -- "$args0" ;; (2) set -- "$args0" "$args1" ;; (3) set -- "$args0" "$args1" "$args2" ;; (4) set -- "$args0" "$args1" "$args2" "$args3" ;; (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; esac fi # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules function splitJvmOpts() { JVM_OPTS=("$@") } eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" ================================================ FILE: gradlew.bat ================================================ @if "%DEBUG%" == "" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS= set DIRNAME=%~dp0 if "%DIRNAME%" == "" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if "%ERRORLEVEL%" == "0" goto init echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto init echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :init @rem Get command-line arguments, handling Windowz variants if not "%OS%" == "Windows_NT" goto win9xME_args if "%@eval[2+2]" == "4" goto 4NT_args :win9xME_args @rem Slurp the command line arguments. set CMD_LINE_ARGS= set _SKIP=2 :win9xME_args_slurp if "x%~1" == "x" goto execute set CMD_LINE_ARGS=%* goto execute :4NT_args @rem Get arguments from the 4NT Shell from JP Software set CMD_LINE_ARGS=%$ :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% :end @rem End local scope for the variables with windows NT shell if "%ERRORLEVEL%"=="0" goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 exit /b 1 :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: settings.gradle ================================================ include ':app'