├── .github ├── ISSUE_TEMPLATE │ └── bug_report.md └── workflows │ └── lock-issue-and-delete-comment.yml ├── .gitignore ├── AppIdMap.txt ├── LICENSE ├── README.md ├── app ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── assets │ └── xposed_init │ ├── java │ └── pansong291 │ │ └── xposed │ │ └── quickenergy │ │ ├── AntCooperate.java │ │ ├── AntFarm.java │ │ ├── AntForest.java │ │ ├── AntForestNotification.java │ │ ├── AntForestToast.java │ │ ├── AntMember.java │ │ ├── AntSports.java │ │ ├── KBMember.java │ │ ├── hook │ │ ├── AntCooperateRpcCall.java │ │ ├── AntFarmRpcCall.java │ │ ├── AntForestRpcCall.java │ │ ├── AntMemberRpcCall.java │ │ ├── AntSportsRpcCall.java │ │ ├── ClassMember.java │ │ ├── KBMemberRpcCall.java │ │ ├── RpcCall.java │ │ └── XposedHook.java │ │ ├── ui │ │ ├── AlipayCooperate.java │ │ ├── AlipayId.java │ │ ├── AlipayUser.java │ │ ├── ChoiceDialog.java │ │ ├── EditDialog.java │ │ ├── HtmlViewerActivity.java │ │ ├── ListAdapter.java │ │ ├── ListDialog.java │ │ ├── MainActivity.java │ │ ├── MyWebView.java │ │ ├── OptionsAdapter.java │ │ └── SettingsActivity.java │ │ └── util │ │ ├── Config.java │ │ ├── CooperationIdMap.java │ │ ├── FileUtils.java │ │ ├── FriendIdMap.java │ │ ├── Log.java │ │ ├── RandomUtils.java │ │ └── Statistics.java │ └── res │ ├── drawable │ └── button.xml │ ├── layout │ ├── activity_html_viewer.xml │ ├── activity_main.xml │ ├── activity_settings.xml │ ├── dialog_list.xml │ ├── include_settings.xml │ └── list_item.xml │ ├── values-v21 │ └── styles.xml │ └── values │ ├── arrays.xml │ ├── strings.xml │ └── styles.xml ├── build.gradle └── settings.gradle /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug 反馈 / Bug report 3 | about: Create a report to help us improve 4 | title: 这是标题!This is the title! 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | [或许你遇到的问题已经在 wiki 里有说明了](https://github.com/pansong291/XQuickEnergy/wiki) 11 | 12 | [请先阅读此反馈 BUG 的注意事项,再提交](https://github.com/pansong291/XQuickEnergy/issues/25) 13 | -------------------------------------------------------------------------------- /.github/workflows/lock-issue-and-delete-comment.yml: -------------------------------------------------------------------------------- 1 | name: Lock Issue And Delete Comment 2 | 3 | on: 4 | issues: 5 | types: [opened, edited, reopened] 6 | issue_comment: 7 | types: [created, edited] 8 | workflow_dispatch: 9 | 10 | jobs: 11 | lock-and-delete: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - name: lock issue and delete comment 15 | uses: pansong291/issue-interceptor-action@main 16 | with: 17 | test-regex: ${{ secrets.REGEX_ISSUE_INTERCEPTOR }} 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Built application files 2 | *.apk 3 | *.ap_ 4 | 5 | # Files for the ART/Dalvik VM 6 | *.dex 7 | 8 | # Java class files 9 | *.class 10 | 11 | # Generated files 12 | bin/ 13 | gen/ 14 | out/ 15 | 16 | # Gradle files 17 | .gradle/ 18 | build/ 19 | 20 | # Local configuration file (sdk path, etc) 21 | local.properties 22 | 23 | # Proguard folder generated by Eclipse 24 | proguard/ 25 | 26 | # Log Files 27 | *.log 28 | 29 | # Android Studio Navigation editor temp files 30 | .navigation/ 31 | 32 | # Android Studio captures folder 33 | captures/ 34 | 35 | # IntelliJ 36 | *.iml 37 | .idea/workspace.xml 38 | .idea/tasks.xml 39 | .idea/gradle.xml 40 | .idea/assetWizardSettings.xml 41 | .idea/dictionaries 42 | .idea/libraries 43 | .idea/caches 44 | 45 | # Keystore files 46 | # Uncomment the following line if you do not want to check your keystore files in. 47 | #*.jks 48 | 49 | # External native build folder generated in Android Studio 2.2 and later 50 | .externalNativeBuild 51 | 52 | # Google Services (e.g. APIs or Firebase) 53 | google-services.json 54 | 55 | # Freeline 56 | freeline.py 57 | freeline/ 58 | freeline_project_description.json 59 | 60 | # fastlane 61 | fastlane/report.xml 62 | fastlane/Preview.html 63 | fastlane/screenshots 64 | fastlane/test_output 65 | fastlane/readme.md 66 | -------------------------------------------------------------------------------- /AppIdMap.txt: -------------------------------------------------------------------------------- 1 | 10000003:充值中心 2 | 10000009:爱心捐赠 3 | 20000001:null 4 | 20000003:账单 5 | 20000014:我的银行卡 6 | 20000019:余额 7 | 20000032:余额宝 8 | 20000033:余额提现 9 | 20000038:关联账户认证/身份认证 10 | 20000042:null 11 | 20000047:null 12 | 20000067:? 13 | 20000076:账单 14 | 20000111:? 15 | 20000120:饿了么外卖 16 | 20000123:个人收钱 17 | 20000134:股票 18 | 20000142:娱乐宝 19 | 20000160:支付宝会员 20 | 20000165:理财 21 | 20000180:借呗 22 | 20000193:生活缴费 23 | 20000199:花呗 24 | 20000218:黄金 25 | 20000241:车险服务 26 | 20000691:我的客服 27 | 20000725:设置 28 | 20000754:我的快递 29 | 20000793:基金 30 | 20000909:args error 31 | 20000936:蚂蚁保险 32 | 20001045:args error 33 | 60000002:蚂蚁森林 34 | 60000010:? 35 | 60000071:天天有料 36 | 60000081:商家服务 37 | 60000123:args error 38 | 60000127:args error 39 | 60000148:财富号 40 | 60000161:支付宝会员周周乐 41 | 63300018:? 42 | 66666673:风险测试/风险类型 43 | 66666674:蚂蚁庄园 44 | 66666698:标签系统/标签和随笔 45 | 66666708:余利宝 46 | 66666721:财富有料 47 | 66666735:基金组合 48 | 66666741:上证指数讨论区 49 | 66666755:好医保 50 | 66666783:爱攒油加油站 51 | 66666819:还贷管家 52 | 66666823:? 53 | 66666825:财富标签页/我的理财标签 54 | 66666828:知识课堂 55 | 66666866:收益曲线 56 | 66666883:网商贷 57 | 66666886:蚂蚁森林合种 58 | 66666897:工资理财 59 | 68686987:网贷 60 | 68687015:办理赔 61 | 68687031:智能理财助理 62 | 68687049:蚂蚁心愿 63 | 68687058:null 64 | 68687109:null 65 | 68687129:行走积分赛 66 | 68687131:养老金 67 | 68687158:支付宝积分猜涨跌 68 | 68687197:null 69 | 68687233:股票工具 70 | 68687242:尊享理财 71 | 68687249:大盘晴雨表 72 | 68687279:null 73 | 68687357:null 74 | 77700124:余额宝 75 | 77700126:互相宝 76 | 77700130:花呗账单 77 | 77700144:扫码点单 78 | 77700152:信用卡还款 79 | 77700173:标注高德地图(在高德地图上标注我的商铺) 80 | 77700174:财富王者 81 | 77700199:财富SHOW 82 | 77700223:笔笔攒 83 | 77700234:模拟炒股 84 | 77700252:市场投资情绪 85 | 77700253:资金管理 86 | 77700257:收钱有奖 87 | 77700279:校园生活 88 | 77700292:收入统计 89 | 77700296:? 90 | 98000012:? 91 | 2013062600000474:new 92 | 2016122804685366:new 93 | 2017081908285290:new 94 | 2018030502317554:new 95 | 2018040402504128:new 96 | 2018051160096372:new 97 | 2018052460226391:new 98 | 2018071160524903:new 99 | 2018091361395351:new 100 | 2018110662035452:new 101 | 2018110762040932:new 102 | 2018112962211021:new 103 | 2018122762703259:new 104 | 2019010462802084:new 105 | 2019012963182381:new 106 | 2019021363229455:new 107 | 2019030863479637:new 108 | 2019031563521845:new 109 | 2019032763709372:new 110 | 2019032863733398:new 111 | 2019040963856084:new 112 | 2019042364288308:new 113 | 2019060465478294:new 114 | 2019060565481471:new 115 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # XQuickEnergy 2 | 3 | [![License](https://img.shields.io/github/license/pansong291/XQuickEnergy.svg)](LICENSE) 4 | [![Latest Release](https://img.shields.io/github/release/pansong291/XQuickEnergy.svg)](../../releases) 5 | [![All Releases Download](https://img.shields.io/github/downloads/pansong291/XQuickEnergy/total.svg)](../../releases) 6 | 7 | 快速收取蚂蚁森林能量 8 | 进入界面快速收取,非自动收取 9 | 更多详情请见[Wiki](../../wiki) 10 | 11 | 原地址:[https://github.com/yongjun925/autocollectenergy](https://github.com/yongjun925/autocollectenergy) 12 | 感谢编码美丽的四哥(@尼古拉斯·赵四) 13 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 21 5 | buildToolsVersion "21.1.0" 6 | 7 | defaultConfig { 8 | applicationId "pansong291.xposed.quickenergy" 9 | minSdkVersion 14 10 | targetSdkVersion 21 11 | versionCode 20191130 12 | versionName "1.2.7-temp.1" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | 22 | dependencies { 23 | compile fileTree(dir: 'libs', include: ['*.jar']) 24 | } 25 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in C:\tools\adt-bundle-windows-x86_64-20131030\sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 13 | 14 | 17 | 18 | 21 | 22 | 25 | 26 | 29 | 30 | 32 | 34 | 35 | 36 | 37 | 41 | 42 | 44 | 46 | 47 | 48 | 49 | 52 | 53 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /app/src/main/assets/xposed_init: -------------------------------------------------------------------------------- 1 | pansong291.xposed.quickenergy.hook.XposedHook 2 | -------------------------------------------------------------------------------- /app/src/main/java/pansong291/xposed/quickenergy/AntCooperate.java: -------------------------------------------------------------------------------- 1 | package pansong291.xposed.quickenergy; 2 | 3 | import org.json.JSONArray; 4 | import org.json.JSONObject; 5 | import pansong291.xposed.quickenergy.hook.AntCooperateRpcCall; 6 | import pansong291.xposed.quickenergy.util.Config; 7 | import pansong291.xposed.quickenergy.util.CooperationIdMap; 8 | import pansong291.xposed.quickenergy.util.FriendIdMap; 9 | import pansong291.xposed.quickenergy.util.Log; 10 | import pansong291.xposed.quickenergy.util.RandomUtils; 11 | import pansong291.xposed.quickenergy.util.Statistics; 12 | 13 | public class AntCooperate 14 | { 15 | private static final String TAG = AntCooperate.class.getCanonicalName(); 16 | 17 | public static void start(ClassLoader loader, int times) 18 | { 19 | if(!Config.cooperateWater() || times != 0) 20 | return; 21 | new Thread() 22 | { 23 | private ClassLoader loader; 24 | 25 | public Thread setData(ClassLoader cl) 26 | { 27 | loader = cl; 28 | return this; 29 | } 30 | 31 | @Override 32 | public void run() 33 | { 34 | try 35 | { 36 | while(FriendIdMap.currentUid == null || FriendIdMap.currentUid.isEmpty()) 37 | Thread.sleep(100); 38 | String s = AntCooperateRpcCall.rpcCall_queryUserCooperatePlantList(loader); 39 | if(s == null) 40 | { 41 | Thread.sleep(RandomUtils.delay()); 42 | s = AntCooperateRpcCall.rpcCall_queryUserCooperatePlantList(loader); 43 | } 44 | JSONObject jo = new JSONObject(s); 45 | if(jo.getString("resultCode").equals("SUCCESS")) 46 | { 47 | int userCurrentEnergy = jo.getInt("userCurrentEnergy"); 48 | JSONArray ja = jo.getJSONArray("cooperatePlants"); 49 | for(int i = 0; i < ja.length(); i++) 50 | { 51 | jo = ja.getJSONObject(i); 52 | String cooperationId = jo.getString("cooperationId"); 53 | if(!jo.has("name")) 54 | { 55 | s = AntCooperateRpcCall.rpcCall_queryCooperatePlant(loader, cooperationId); 56 | jo = new JSONObject(s).getJSONObject("cooperatePlant"); 57 | } 58 | String name = jo.getString("name"); 59 | int waterDayLimit = jo.getInt("waterDayLimit"); 60 | CooperationIdMap.putIdMap(cooperationId, name); 61 | if(!Statistics.canCooperateWaterToday(FriendIdMap.currentUid, cooperationId)) 62 | continue; 63 | int index = -1; 64 | for(int j = 0; j < Config.getCooperateWaterList().size(); j++) 65 | { 66 | if(Config.getCooperateWaterList().get(j).equals(cooperationId)) 67 | { 68 | index = j; 69 | break; 70 | } 71 | } 72 | if(index >= 0) 73 | { 74 | int num = Config.getcooperateWaterNumList().get(index); 75 | if(num > waterDayLimit) 76 | num = waterDayLimit; 77 | if(num > userCurrentEnergy) 78 | num = userCurrentEnergy; 79 | if(num > 0) 80 | cooperateWater(loader, FriendIdMap.currentUid, cooperationId, num, name); 81 | } 82 | } 83 | }else 84 | { 85 | Log.i(TAG, jo.getString("resultDesc")); 86 | } 87 | }catch(Throwable t) 88 | { 89 | Log.i(TAG, "start.run err:"); 90 | Log.printStackTrace(TAG, t); 91 | } 92 | CooperationIdMap.saveIdMap(); 93 | } 94 | }.setData(loader).start(); 95 | } 96 | 97 | private static void cooperateWater(ClassLoader loader, String uid, String coopId, int count, String name) 98 | { 99 | try 100 | { 101 | String s = AntCooperateRpcCall.rpcCall_cooperateWater(loader, uid, coopId, count); 102 | JSONObject jo = new JSONObject(s); 103 | if(jo.getString("resultCode").equals("SUCCESS")) 104 | { 105 | Log.forest("合种【" + name + "】" + jo.getString("barrageText")); 106 | Statistics.cooperateWaterToday(FriendIdMap.currentUid, coopId); 107 | }else 108 | { 109 | Log.i(TAG, jo.getString("resultDesc")); 110 | } 111 | }catch(Throwable t) 112 | { 113 | Log.i(TAG, "cooperateWater err:"); 114 | Log.printStackTrace(TAG, t); 115 | } 116 | } 117 | 118 | } 119 | -------------------------------------------------------------------------------- /app/src/main/java/pansong291/xposed/quickenergy/AntForest.java: -------------------------------------------------------------------------------- 1 | package pansong291.xposed.quickenergy; 2 | 3 | import org.json.JSONArray; 4 | import org.json.JSONObject; 5 | import pansong291.xposed.quickenergy.AntFarm.TaskStatus; 6 | import pansong291.xposed.quickenergy.AntForestNotification; 7 | import pansong291.xposed.quickenergy.hook.AntForestRpcCall; 8 | import pansong291.xposed.quickenergy.util.Config; 9 | import pansong291.xposed.quickenergy.util.FriendIdMap; 10 | import pansong291.xposed.quickenergy.util.Log; 11 | import pansong291.xposed.quickenergy.util.RandomUtils; 12 | import pansong291.xposed.quickenergy.util.Statistics; 13 | 14 | public class AntForest 15 | { 16 | private static final String TAG = AntForest.class.getCanonicalName(); 17 | private static String selfId; 18 | private static int collectedEnergy = 0; 19 | private static int helpCollectedEnergy = 0; 20 | private static int totalCollected = 0; 21 | private static int totalHelpCollected = 0; 22 | private static int collectTaskCount = 0; 23 | public enum CollectStatus 24 | { AVAILABLE, WAITING, INSUFFICIENT, ROBBED } 25 | public enum TaskAwardType 26 | { 27 | BUBBLE_BOOST, DRESS; 28 | public static final CharSequence[] nickNames = 29 | {"时光加速器","装扮"}; 30 | public CharSequence nickName() 31 | { 32 | return nickNames[ordinal()]; 33 | } 34 | } 35 | 36 | private static long serverTime = -1; 37 | private static long offsetTime = -1; 38 | private static long laterTime = -1; 39 | 40 | private static void queryEnergyRanking(ClassLoader loader, String startPoint) 41 | { 42 | boolean hasMore = false; 43 | try 44 | { 45 | String s; 46 | JSONObject jo; 47 | do 48 | { 49 | s = AntForestRpcCall.rpcCall_queryEnergyRanking(loader, startPoint); 50 | jo = new JSONObject(s); 51 | if(jo.getString("resultCode").equals("SUCCESS")) 52 | { 53 | hasMore = jo.getBoolean("hasMore"); 54 | startPoint = jo.getString("nextStartPoint"); 55 | JSONArray jaFriendRanking = jo.getJSONArray("friendRanking"); 56 | for(int i = 0; i < jaFriendRanking.length(); i++) 57 | { 58 | jo = jaFriendRanking.getJSONObject(i); 59 | boolean optBoolean = jo.getBoolean("canCollectEnergy") 60 | || jo.getBoolean("canHelpCollect") || jo.getLong("canCollectLaterTime") > 0; 61 | String userId = jo.getString("userId"); 62 | if(optBoolean && !userId.equals(selfId)) 63 | { 64 | canCollectEnergy(loader, userId, true); 65 | }else 66 | { 67 | FriendIdMap.getNameById(userId); 68 | } 69 | } 70 | }else 71 | { 72 | Log.recordLog(jo.getString("resultDesc"), s); 73 | } 74 | }while(hasMore); 75 | }catch(Throwable t) 76 | { 77 | Log.i(TAG, "queryEnergyRanking err:"); 78 | Log.printStackTrace(TAG, t); 79 | } 80 | onForestEnd(loader); 81 | } 82 | 83 | private static void canCollectSelfEnergy(ClassLoader loader, int times) 84 | { 85 | try 86 | { 87 | while(FriendIdMap.currentUid == null || FriendIdMap.currentUid.isEmpty()) 88 | Thread.sleep(100); 89 | long start = System.currentTimeMillis(); 90 | String s = AntForestRpcCall.rpcCall_queryNextAction(loader, FriendIdMap.currentUid); 91 | long end = System.currentTimeMillis(); 92 | if(s == null) 93 | { 94 | Thread.sleep(RandomUtils.delay()); 95 | start = System.currentTimeMillis(); 96 | s = AntForestRpcCall.rpcCall_queryNextAction(loader, FriendIdMap.currentUid); 97 | end = System.currentTimeMillis(); 98 | } 99 | JSONObject jo = new JSONObject(s); 100 | if(jo.getString("resultCode").equals("SUCCESS")) 101 | { 102 | serverTime = jo.getLong("now"); 103 | offsetTime = (start + end) / 2 - serverTime; 104 | Log.i(TAG, "服务器时间:" + serverTime + ",本地减服务器时间差:" + offsetTime); 105 | JSONArray jaBubbles = jo.getJSONArray("bubbles"); 106 | jo = jo.getJSONObject("userEnergy"); 107 | selfId = jo.getString("userId"); 108 | FriendIdMap.currentUid = selfId; 109 | String selfName = jo.getString("displayName"); 110 | if(selfName == null || selfName.isEmpty()) 111 | selfName = "我"; 112 | FriendIdMap.putIdMap(selfId, selfName); 113 | Log.recordLog("进入【" + selfName + "】的蚂蚁森林", ""); 114 | FriendIdMap.saveIdMap(); 115 | if(Config.collectEnergy()) 116 | for(int i = 0; i < jaBubbles.length(); i++) 117 | { 118 | jo = jaBubbles.getJSONObject(i); 119 | long bubbleId = jo.getLong("id"); 120 | switch(CollectStatus.valueOf(jo.getString("collectStatus"))) 121 | { 122 | case AVAILABLE: 123 | if(Config.getDontCollectList().contains(selfId)) 124 | Log.recordLog("不偷取【" + selfName + "】", ", userId=" + selfId); 125 | else 126 | collectedEnergy += collectEnergy(loader, selfId, bubbleId, selfName, null); 127 | break; 128 | 129 | case WAITING: 130 | if(Config.getDontCollectList().contains(selfId)) 131 | break; 132 | long produceTime = jo.getLong("produceTime"); 133 | if(produceTime - serverTime < Config.checkInterval()) 134 | execute(loader, selfName, selfId, null, bubbleId, produceTime); 135 | else 136 | setLaterTime(produceTime); 137 | break; 138 | } 139 | } 140 | }else 141 | { 142 | Log.recordLog(jo.getString("resultDesc"), s); 143 | } 144 | if(times == 0) 145 | { 146 | receiveTaskAward(loader); 147 | for(int i = 0; i < Config.getWaterFriendList().size(); i++) 148 | { 149 | String uid = Config.getWaterFriendList().get(i); 150 | if(selfId.equals(uid)) continue; 151 | int waterCount = Config.getWaterCountList().get(i); 152 | if(waterCount <= 0) continue; 153 | if(waterCount > 3) waterCount = 3; 154 | if(Statistics.canWaterFriendToday(uid, waterCount)) 155 | waterFriendEnergy(loader, uid, waterCount); 156 | } 157 | checkUnknownId(loader); 158 | } 159 | }catch(Throwable t) 160 | { 161 | Log.i(TAG, "canCollectSelfEnergy err:"); 162 | Log.printStackTrace(TAG, t); 163 | } 164 | } 165 | 166 | private static void canCollectEnergy(ClassLoader loader, String userId, boolean laterCollect) 167 | { 168 | try 169 | { 170 | long start = System.currentTimeMillis(); 171 | String s = AntForestRpcCall.rpcCall_queryNextAction(loader, userId); 172 | long end = System.currentTimeMillis(); 173 | JSONObject jo = new JSONObject(s); 174 | if(jo.getString("resultCode").equals("SUCCESS")) 175 | { 176 | serverTime = jo.getLong("now"); 177 | offsetTime = (start + end) / 2 - serverTime; 178 | Log.i(TAG, "服务器时间:" + serverTime + ",本地减服务器时间差:" + offsetTime); 179 | String bizNo = jo.getString("bizNo"); 180 | JSONArray jaProps = jo.getJSONArray("usingUserProps"); 181 | JSONArray jaBubbles = jo.getJSONArray("bubbles"); 182 | jo = jo.getJSONObject("userEnergy"); 183 | String userName = jo.getString("displayName"); 184 | if(userName == null || userName.isEmpty()) 185 | userName = "*null*"; 186 | String loginId = userName; 187 | if(jo.has("loginId")) 188 | loginId += "(" + jo.getString("loginId") + ")"; 189 | FriendIdMap.putIdMap(userId, loginId); 190 | Log.recordLog("进入【" + loginId + "】的蚂蚁森林", ""); 191 | FriendIdMap.saveIdMap(); 192 | for(int i = 0; i < jaProps.length(); i++) 193 | { 194 | JSONObject joProps = jaProps.getJSONObject(i); 195 | if("energyShield".equals(joProps.getString("type"))) 196 | { 197 | if(joProps.getLong("endTime") > serverTime) 198 | { 199 | Log.recordLog("【" + userName + "】被能量罩保护着哟", ""); 200 | return; 201 | } 202 | } 203 | } 204 | int collected = 0; 205 | int helped = 0; 206 | for(int i = 0; i < jaBubbles.length(); i++) 207 | { 208 | jo = jaBubbles.getJSONObject(i); 209 | long bubbleId = jo.getLong("id"); 210 | switch(CollectStatus.valueOf(jo.getString("collectStatus"))) 211 | { 212 | case AVAILABLE: 213 | if(Config.getDontCollectList().contains(userId)) 214 | Log.recordLog("不偷取【" + userName + "】", ", userId=" + userId); 215 | else 216 | collected += collectEnergy(loader, userId, bubbleId, userName, bizNo); 217 | break; 218 | 219 | case WAITING: 220 | if(!laterCollect || Config.getDontCollectList().contains(userId)) 221 | break; 222 | long produceTime = jo.getLong("produceTime"); 223 | if(produceTime - serverTime < Config.checkInterval()) 224 | execute(loader, userName, userId, bizNo, bubbleId, produceTime); 225 | else 226 | setLaterTime(produceTime); 227 | break; 228 | } 229 | if(jo.getBoolean("canHelpCollect")) 230 | { 231 | if(Config.helpFriendCollect()) 232 | { 233 | if(Config.getDontHelpCollectList().contains(userId)) 234 | Log.recordLog("不帮收【" + userName + "】", ", userId=" + userId); 235 | else 236 | helped += forFriendCollectEnergy(loader, userId, bubbleId, userName); 237 | }else 238 | Log.recordLog("不帮收【" + userName + "】", ", userId=" + userId); 239 | } 240 | } 241 | if(helped > 0) 242 | { 243 | canCollectEnergy(loader, userId, false); 244 | } 245 | collectedEnergy += collected; 246 | }else 247 | { 248 | Log.recordLog(jo.getString("resultDesc"), s); 249 | } 250 | }catch(Throwable t) 251 | { 252 | Log.i(TAG, "canCollectEnergy err:"); 253 | Log.printStackTrace(TAG, t); 254 | } 255 | } 256 | 257 | private static int collectEnergy(ClassLoader loader, String userId, long bubbleId, String userName, String bizNo) 258 | { 259 | int collected = 0; 260 | try 261 | { 262 | String s = AntForestRpcCall.rpcCall_collectEnergy(loader, userId, bubbleId); 263 | JSONObject jo = new JSONObject(s); 264 | if(jo.getString("resultCode").equals("SUCCESS")) 265 | { 266 | JSONArray jaBubbles = jo.getJSONArray("bubbles"); 267 | for(int i = 0; i < jaBubbles.length(); i++) 268 | { 269 | jo = jaBubbles.getJSONObject(i); 270 | collected += jo.getInt("collectedEnergy"); 271 | } 272 | if(collected > 0) 273 | { 274 | totalCollected += collected; 275 | Statistics.addData(Statistics.DataType.COLLECTED, collected); 276 | String str = "偷取【" + userName + "】的能量【" + collected + "克】"; 277 | Log.forest(str); 278 | AntForestToast.show(str); 279 | }else 280 | { 281 | Log.recordLog("偷取【" + userName + "】的能量失败", ",UserID:" + userId + ",BubbleId:" + bubbleId); 282 | } 283 | if(bizNo == null || bizNo.isEmpty()) 284 | return collected; 285 | int returnCount = 0; 286 | if(Config.returnWater30() > 0 && collected >= Config.returnWater30()) 287 | returnCount = 3; 288 | else if(Config.returnWater20() > 0 && collected >= Config.returnWater20()) 289 | returnCount = 2; 290 | else if(Config.returnWater10() > 0 && collected >= Config.returnWater10()) 291 | returnCount = 1; 292 | if(returnCount > 0) 293 | returnFriendWater(loader, userId, userName, bizNo, returnCount); 294 | }else 295 | { 296 | Log.recordLog("【" + userName + "】" + jo.getString("resultDesc"), s); 297 | } 298 | }catch(Throwable t) 299 | { 300 | Log.i(TAG, "collectEnergy err:"); 301 | Log.printStackTrace(TAG, t); 302 | } 303 | return collected; 304 | } 305 | 306 | private static int forFriendCollectEnergy(ClassLoader loader, String targetUserId, long bubbleId, String userName) 307 | { 308 | int helped = 0; 309 | try 310 | { 311 | String s = AntForestRpcCall.rpcCall_forFriendCollectEnergy(loader, targetUserId, bubbleId); 312 | JSONObject jo = new JSONObject(s); 313 | if(jo.getString("resultCode").equals("SUCCESS")) 314 | { 315 | JSONArray jaBubbles = jo.getJSONArray("bubbles"); 316 | for(int i = 0; i < jaBubbles.length(); i++) 317 | { 318 | jo = jaBubbles.getJSONObject(i); 319 | helped += jo.getInt("collectedEnergy"); 320 | } 321 | if(helped > 0) 322 | { 323 | Log.forest("帮【" + userName + "】收取【" + helped + "克】"); 324 | helpCollectedEnergy += helped; 325 | totalHelpCollected += helped; 326 | Statistics.addData(Statistics.DataType.HELPED, helped); 327 | }else 328 | { 329 | Log.recordLog("帮【" + userName + "】收取失败", ",UserID:" + targetUserId + ",BubbleId" + bubbleId); 330 | } 331 | }else 332 | { 333 | Log.recordLog("【" + userName + "】" + jo.getString("resultDesc"), s); 334 | } 335 | }catch(Throwable t) 336 | { 337 | Log.i(TAG, "forFriendCollectEnergy err:"); 338 | Log.printStackTrace(TAG, t); 339 | } 340 | return helped; 341 | } 342 | 343 | private static void waterFriendEnergy(ClassLoader loader, String userId, int count) 344 | { 345 | try 346 | { 347 | String s = AntForestRpcCall.rpcCall_queryNextAction(loader, userId); 348 | JSONObject jo = new JSONObject(s); 349 | if(jo.getString("resultCode").equals("SUCCESS")) 350 | { 351 | String bizNo = jo.getString("bizNo"); 352 | jo = jo.getJSONObject("userEnergy"); 353 | String userName = jo.getString("displayName"); 354 | count = returnFriendWater(loader, userId, userName, bizNo, count); 355 | if(count > 0) Statistics.waterFriendToday(userId, count); 356 | }else 357 | { 358 | Log.recordLog(jo.getString("resultDesc"), s); 359 | } 360 | }catch(Throwable t) 361 | { 362 | Log.i(TAG, "waterFriendEnergy err:"); 363 | Log.printStackTrace(TAG, t); 364 | } 365 | } 366 | 367 | private static int returnFriendWater(ClassLoader loader, String userId, String userName, String bizNo, int count) 368 | { 369 | if(bizNo == null || bizNo.isEmpty()) return 0; 370 | int wateredTimes = 0; 371 | try 372 | { 373 | String s; 374 | JSONObject jo; 375 | for(int waterCount = 1; waterCount <= count; waterCount++) 376 | { 377 | s = AntForestRpcCall.rpcCall_transferEnergy(loader, userId, bizNo, waterCount); 378 | jo = new JSONObject(s); 379 | s = jo.getString("resultCode"); 380 | if(s.equals("SUCCESS")) 381 | { 382 | s = jo.getJSONObject("treeEnergy").getString("currentEnergy"); 383 | Log.forest("给【" + userName + "】浇水成功,剩余能量【" + s + "克】"); 384 | wateredTimes++; 385 | Statistics.addData(Statistics.DataType.WATERED, 10); 386 | }else if(s.equals("WATERING_TIMES_LIMIT")) 387 | { 388 | Log.recordLog("今日给【" + userName + "】浇水已达上限", ""); 389 | wateredTimes = 3; 390 | break; 391 | }else 392 | { 393 | Log.recordLog(jo.getString("resultDesc"), jo.toString()); 394 | } 395 | Thread.sleep(2000); 396 | } 397 | }catch(Throwable t) 398 | { 399 | Log.i(TAG, "returnFriendWater err:"); 400 | Log.printStackTrace(TAG, t); 401 | } 402 | return wateredTimes; 403 | } 404 | 405 | private static void receiveTaskAward(ClassLoader loader) 406 | { 407 | try 408 | { 409 | String s = AntForestRpcCall.rpcCall_queryTaskList(loader); 410 | JSONObject jo = new JSONObject(s); 411 | if(jo.getString("resultCode").equals("SUCCESS")) 412 | { 413 | JSONArray jaForestTaskVOList = jo.getJSONArray("forestTaskVOList"); 414 | for(int i = 0; i < jaForestTaskVOList.length(); i++) 415 | { 416 | jo = jaForestTaskVOList.getJSONObject(i); 417 | if(TaskStatus.FINISHED.name().equals(jo.getString("taskStatus"))) 418 | { 419 | String taskAwardTypeStr = jo.getString("awardType"); 420 | String awardName = null; 421 | if(taskAwardTypeStr.endsWith(TaskAwardType.DRESS.name())) 422 | { 423 | awardName = TaskAwardType.DRESS.nickName().toString(); 424 | }else if(TaskAwardType.BUBBLE_BOOST.name().equals(taskAwardTypeStr)) 425 | { 426 | awardName = TaskAwardType.BUBBLE_BOOST.nickName().toString(); 427 | } 428 | int awardCount = jo.getInt("awardCount"); 429 | s = AntForestRpcCall.rpcCall_receiveTaskAward(loader, jo.getString("taskType")); 430 | jo = new JSONObject(s); 431 | s = jo.getString("desc"); 432 | if(s.equals("SUCCESS")) 433 | Log.forest("已领取【" + awardCount + "个】【" + awardName + "】"); 434 | else 435 | Log.recordLog("领取失败," + s, jo.toString()); 436 | } 437 | } 438 | }else 439 | { 440 | Log.recordLog(jo.getString("resultDesc"), s); 441 | } 442 | }catch(Throwable t) 443 | { 444 | Log.i(TAG, "receiveTaskAward err:"); 445 | Log.printStackTrace(TAG, t); 446 | } 447 | } 448 | 449 | private static void queryPropList(ClassLoader loader) 450 | { 451 | try 452 | { 453 | String s = AntForestRpcCall.rpcCall_queryTaskList(loader); 454 | JSONObject jo = new JSONObject(s); 455 | if(jo.getString("resultCode").equals("SUCCESS")) 456 | { 457 | JSONArray jaForestPropVOList = jo.getJSONArray("forestPropVOList"); 458 | for(int i = 0; i < jaForestPropVOList.length(); i++) 459 | { 460 | jo = jaForestPropVOList.getJSONObject(i); 461 | if(TaskStatus.FINISHED.name().equals(jo.getString("taskStatus"))) 462 | { 463 | String taskType = jo.getString("taskType"); 464 | 465 | } 466 | } 467 | }else 468 | { 469 | Log.recordLog(jo.getString("resultDesc"), s); 470 | } 471 | }catch(Throwable t) 472 | { 473 | Log.i(TAG, "queryTaskList err:"); 474 | Log.printStackTrace(TAG, t); 475 | } 476 | } 477 | 478 | private static void setLaterTime(long time) 479 | { 480 | Log.i(TAG, "能量成熟时间:" + time); 481 | if(time > serverTime && serverTime > 0 482 | && (laterTime < 0 || time < laterTime)) 483 | { 484 | laterTime = time; 485 | Log.i(TAG, laterTime - serverTime + "ms 后能量成熟"); 486 | } 487 | } 488 | 489 | private static void onForestEnd(ClassLoader loader) 490 | { 491 | Log.recordLog( 492 | "收【" + collectedEnergy + "克】,帮【" 493 | + helpCollectedEnergy + "克】," 494 | + collectTaskCount + "个蹲点任务", ""); 495 | FriendIdMap.saveIdMap(); 496 | collectedEnergy = 0; 497 | helpCollectedEnergy = 0; 498 | if(Config.collectEnergy()) 499 | { 500 | StringBuilder sb = new StringBuilder(); 501 | sb.append(" 收:" + totalCollected + ",帮:" + totalHelpCollected); 502 | if(laterTime > 0) 503 | { 504 | sb.append(",下个:"); 505 | long second = (laterTime - serverTime) / 1000; 506 | long minute = second / 60; 507 | second %= 60; 508 | long hour = minute / 60; 509 | minute %= 60; 510 | if(hour > 0) sb.append(hour + "时"); 511 | if(minute > 0) sb.append(minute + "分"); 512 | sb.append(second + "秒"); 513 | } 514 | Log.recordLog(sb.toString(), ""); 515 | AntForestNotification.setContentText(Log.getFormatTime() + sb.toString()); 516 | } 517 | laterTime = -1; 518 | } 519 | 520 | public static void checkEnergyRanking(ClassLoader loader, int times) 521 | { 522 | Log.recordLog("定时检测开始", ""); 523 | new Thread() 524 | { 525 | ClassLoader loader; 526 | int times; 527 | 528 | public Thread setData(ClassLoader cl, int i) 529 | { 530 | loader = cl; 531 | times = i; 532 | return this; 533 | } 534 | 535 | @Override 536 | public void run() 537 | { 538 | canCollectSelfEnergy(loader, times); 539 | if(Config.collectEnergy()) 540 | queryEnergyRanking(loader, "1"); 541 | } 542 | }.setData(loader, times).start(); 543 | } 544 | 545 | public static void checkUnknownId(ClassLoader loader) 546 | { 547 | String[] unknownIds = FriendIdMap.getUnknownIds(); 548 | if(unknownIds != null) 549 | { 550 | new Thread() 551 | { 552 | ClassLoader loader; 553 | String[] unknownIds; 554 | public Thread setData(ClassLoader cl, String[] ss) 555 | { 556 | loader = cl;unknownIds = ss; 557 | return this; 558 | } 559 | 560 | @Override 561 | public void run() 562 | { 563 | try 564 | { 565 | Log.i(TAG, "开始检查" + unknownIds.length + "个未知id"); 566 | for(int i = 0; i < unknownIds.length; i++) 567 | { 568 | long start = System.currentTimeMillis(); 569 | String s = AntForestRpcCall.rpcCall_queryNextAction(loader, unknownIds[i]); 570 | long end = System.currentTimeMillis(); 571 | JSONObject jo = new JSONObject(s); 572 | if(jo.getString("resultCode").equals("SUCCESS")) 573 | { 574 | serverTime = jo.getLong("now"); 575 | offsetTime = (start + end) / 2 - serverTime; 576 | Log.i(TAG, "服务器时间:" + serverTime + ",本地减服务器时间差:" + offsetTime); 577 | jo = jo.getJSONObject("userEnergy"); 578 | String userName = jo.getString("displayName"); 579 | if(userName == null || userName.isEmpty()) 580 | userName = "*null*"; 581 | String loginId = userName; 582 | if(jo.has("loginId")) 583 | loginId += "(" + jo.getString("loginId") + ")"; 584 | FriendIdMap.putIdMap(unknownIds[i], loginId); 585 | Log.recordLog("进入【" + loginId + "】的蚂蚁森林", ""); 586 | FriendIdMap.saveIdMap(); 587 | } 588 | } 589 | }catch(Throwable t) 590 | { 591 | Log.i(TAG, "checkUnknownId.run err:"); 592 | Log.printStackTrace(TAG, t); 593 | } 594 | } 595 | }.setData(loader, unknownIds).start(); 596 | } 597 | } 598 | 599 | public static void execute(ClassLoader loader, String userName, String userId, String bizNo, long bubbleId, long produceTime) 600 | { 601 | for(int i = Config.threadCount(); i > 0; i--) 602 | { 603 | BubbleTimerTask btt = new BubbleTimerTask(loader, userName, userId, bizNo, bubbleId, produceTime); 604 | long delay = btt.getDelayTime(); 605 | btt.start(); 606 | collectTaskCount++; 607 | Log.recordLog(delay / 1000 + "秒后尝试收取能量", ""); 608 | } 609 | } 610 | 611 | public static class BubbleTimerTask extends Thread 612 | { 613 | ClassLoader loader; 614 | String userName; 615 | String userId; 616 | String bizNo; 617 | long bubbleId; 618 | long produceTime; 619 | long sleep = 0; 620 | 621 | BubbleTimerTask(ClassLoader cl, String un, String ui, String bn, long bi, long pt) 622 | { 623 | loader = cl; 624 | userName = un; 625 | bizNo = bn; 626 | userId = ui; 627 | bubbleId = bi; 628 | produceTime = pt; 629 | } 630 | 631 | public long getDelayTime() 632 | { 633 | sleep = produceTime + offsetTime - System.currentTimeMillis() - Config.advanceTime(); 634 | return sleep; 635 | } 636 | 637 | @Override 638 | public void run() 639 | { 640 | try 641 | { 642 | if(sleep > 0) sleep(sleep); 643 | Log.recordLog("【" + userName + "】蹲点收取开始" + collectTaskCount, ""); 644 | collectTaskCount--; 645 | long time = System.currentTimeMillis(); 646 | int collected = 0; 647 | while(System.currentTimeMillis() - time < Config.collectTimeout()) 648 | { 649 | collected = collectEnergy(loader, userId, bubbleId, userName, bizNo); 650 | if(collected > 0) break; 651 | if(Config.collectInterval() > 0) 652 | sleep(Config.collectInterval()); 653 | } 654 | }catch(Throwable t) 655 | { 656 | Log.i(TAG, "BubbleTimerTask.run err:"); 657 | Log.printStackTrace(TAG, t); 658 | } 659 | String s = " 收:" + totalCollected + ",帮:" + totalHelpCollected; 660 | Log.recordLog(s, ""); 661 | AntForestNotification.setContentText(Log.getFormatTime() + s); 662 | } 663 | 664 | } 665 | 666 | } 667 | -------------------------------------------------------------------------------- /app/src/main/java/pansong291/xposed/quickenergy/AntForestNotification.java: -------------------------------------------------------------------------------- 1 | package pansong291.xposed.quickenergy; 2 | 3 | import android.app.Notification; 4 | import android.app.NotificationChannel; 5 | import android.app.NotificationManager; 6 | import android.app.PendingIntent; 7 | import android.app.Service; 8 | import android.content.Context; 9 | import android.content.Intent; 10 | import android.net.Uri; 11 | import android.os.Build; 12 | 13 | public class AntForestNotification 14 | { 15 | public static final int ANTFOREST_NOTIFICATION_ID = 46; 16 | private static NotificationManager mNotifyManager; 17 | public static final String CHANNEL_ID = "pansong291.xposed.quickenergy.ANTFOREST_NOTIFY_CHANNEL"; 18 | private static Notification mNotification; 19 | private static Notification.Builder builder; 20 | private static boolean isStart = false; 21 | 22 | private AntForestNotification() 23 | {} 24 | 25 | public static boolean isStart() 26 | { 27 | return isStart; 28 | } 29 | 30 | public static void start(Context context) 31 | { 32 | initNotification(context); 33 | if(!isStart) 34 | { 35 | if(context instanceof Service) 36 | ((Service)context).startForeground(ANTFOREST_NOTIFICATION_ID, mNotification); 37 | else 38 | getNotificationManager(context).notify(ANTFOREST_NOTIFICATION_ID, mNotification); 39 | isStart = true; 40 | } 41 | } 42 | 43 | public static void setContentText(CharSequence cs) 44 | { 45 | if(isStart) 46 | { 47 | mNotification = builder.setContentText(cs).build(); 48 | if(mNotifyManager != null) 49 | mNotifyManager.notify(ANTFOREST_NOTIFICATION_ID, mNotification); 50 | } 51 | } 52 | 53 | public static void stop(Context context, boolean remove) 54 | { 55 | if(isStart) 56 | { 57 | if(context instanceof Service) 58 | ((Service)context).stopForeground(remove); 59 | else 60 | getNotificationManager(context).cancel(ANTFOREST_NOTIFICATION_ID); 61 | isStart = false; 62 | } 63 | } 64 | 65 | private static void initNotification(Context context) 66 | { 67 | if(mNotification == null) 68 | { 69 | Intent it = new Intent(Intent.ACTION_VIEW); 70 | it.setData(Uri.parse("alipays://platformapi/startapp?appId=")); 71 | PendingIntent pi = PendingIntent.getActivity(context, 0, it, PendingIntent.FLAG_UPDATE_CURRENT); 72 | 73 | if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) 74 | { 75 | NotificationChannel notificationChannel = new NotificationChannel(CHANNEL_ID, "XQuickEnergy能量提醒", NotificationManager.IMPORTANCE_LOW); 76 | notificationChannel.enableLights(false); 77 | notificationChannel.enableVibration(false); 78 | notificationChannel.setShowBadge(false); 79 | getNotificationManager(context).createNotificationChannel(notificationChannel); 80 | builder = new Notification.Builder(context, CHANNEL_ID); 81 | }else 82 | { 83 | getNotificationManager(context); 84 | builder = new Notification.Builder(context) 85 | .setPriority(Notification.PRIORITY_LOW); 86 | } 87 | mNotification = builder 88 | .setSmallIcon(android.R.drawable.sym_def_app_icon) 89 | .setContentTitle("XQuickEnergy") 90 | .setContentText("开始检测能量") 91 | .setAutoCancel(false) 92 | .setContentIntent(pi) 93 | .build(); 94 | } 95 | } 96 | 97 | private static NotificationManager getNotificationManager(Context context) 98 | { 99 | if(mNotifyManager == null) 100 | mNotifyManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); 101 | return mNotifyManager; 102 | } 103 | 104 | } 105 | -------------------------------------------------------------------------------- /app/src/main/java/pansong291/xposed/quickenergy/AntForestToast.java: -------------------------------------------------------------------------------- 1 | package pansong291.xposed.quickenergy; 2 | 3 | import android.content.Context; 4 | import android.widget.Toast; 5 | import pansong291.xposed.quickenergy.util.Config; 6 | import pansong291.xposed.quickenergy.util.Log; 7 | import pansong291.xposed.quickenergy.hook.XposedHook; 8 | 9 | public class AntForestToast 10 | { 11 | private static final String TAG = AntForestToast.class.getCanonicalName(); 12 | public static Context context; 13 | 14 | public static void show(CharSequence cs) 15 | { 16 | try 17 | { 18 | if(context != null && Config.showToast()) 19 | { 20 | XposedHook.handler.post( 21 | new Runnable() 22 | { 23 | CharSequence cs; 24 | 25 | public Runnable setData(CharSequence c) 26 | { 27 | cs = c; 28 | return this; 29 | } 30 | 31 | @Override 32 | public void run() 33 | { 34 | try 35 | { 36 | Toast.makeText(context, cs, 0).show(); 37 | }catch(Throwable t) 38 | { 39 | Log.i(TAG, "show.run err:"); 40 | Log.printStackTrace(TAG, t); 41 | } 42 | } 43 | }.setData(cs)); 44 | } 45 | }catch(Throwable t) 46 | { 47 | Log.i(TAG, "show err:"); 48 | Log.printStackTrace(TAG, t); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /app/src/main/java/pansong291/xposed/quickenergy/AntMember.java: -------------------------------------------------------------------------------- 1 | package pansong291.xposed.quickenergy; 2 | 3 | import org.json.JSONArray; 4 | import org.json.JSONObject; 5 | import pansong291.xposed.quickenergy.hook.AntMemberRpcCall; 6 | import pansong291.xposed.quickenergy.util.Log; 7 | import pansong291.xposed.quickenergy.util.Statistics; 8 | import pansong291.xposed.quickenergy.util.Config; 9 | 10 | public class AntMember 11 | { 12 | public static final String TAG = AntMember.class.getCanonicalName(); 13 | 14 | public static void receivePoint(ClassLoader loader, int times) 15 | { 16 | if(!Config.receivePoint() || times != 0) 17 | return; 18 | 19 | new Thread() 20 | { 21 | ClassLoader loader; 22 | 23 | public Thread setData(ClassLoader cl) 24 | { 25 | loader = cl; 26 | return this; 27 | } 28 | 29 | @Override 30 | public void run() 31 | { 32 | try 33 | { 34 | if(Statistics.canMemberSignInToday()) 35 | { 36 | String s = AntMemberRpcCall.rpcCall_memberSignin(loader); 37 | JSONObject jo = new JSONObject(s); 38 | if(jo.getString("resultCode").equals("SUCCESS")) 39 | { 40 | Log.other( 41 | "领取〈每日签到〉〈" + jo.getString("signinPoint") + 42 | "积分〉,已签到〈" + jo.getString("signinSumDay") + "天〉"); 43 | Statistics.memberSignInToday(); 44 | }else 45 | { 46 | Log.recordLog(jo.getString("resultDesc"), s); 47 | } 48 | } 49 | queryPointCert(loader, 1, 8); 50 | claimFamilyPoint(loader); 51 | }catch(Throwable t) 52 | { 53 | Log.i(TAG, "receivePoint.run err:"); 54 | Log.printStackTrace(TAG, t); 55 | } 56 | } 57 | }.setData(loader).start(); 58 | } 59 | 60 | private static void queryPointCert(ClassLoader loader, int page, int pageSize) 61 | { 62 | try 63 | { 64 | String s = AntMemberRpcCall.rpcCall_queryPointCert(loader, page, pageSize); 65 | JSONObject jo = new JSONObject(s); 66 | if(jo.getString("resultCode").equals("SUCCESS")) 67 | { 68 | boolean hasNextPage = jo.getBoolean("hasNextPage"); 69 | JSONArray jaCertList = jo.getJSONArray("certList"); 70 | for(int i = 0; i < jaCertList.length(); i++) 71 | { 72 | jo = jaCertList.getJSONObject(i); 73 | String bizTitle = jo.getString("bizTitle"); 74 | String id = jo.getString("id"); 75 | int pointAmount = jo.getInt("pointAmount"); 76 | s = AntMemberRpcCall.rpcCall_receivePointByUser(loader, id); 77 | jo = new JSONObject(s); 78 | if(jo.getString("resultCode").equals("SUCCESS")) 79 | { 80 | Log.other("领取〈" + bizTitle + "〉〈" + pointAmount + "积分〉"); 81 | }else 82 | { 83 | Log.recordLog(jo.getString("resultDesc"), s); 84 | } 85 | } 86 | if(hasNextPage) 87 | queryPointCert(loader, page + 1, pageSize); 88 | }else 89 | { 90 | Log.recordLog(jo.getString("resultDesc"), s); 91 | } 92 | }catch(Throwable t) 93 | { 94 | Log.i(TAG, "queryPointCert err:"); 95 | Log.printStackTrace(TAG, t); 96 | } 97 | } 98 | 99 | private static void claimFamilyPoint(ClassLoader loader) 100 | { 101 | try 102 | { 103 | String s = AntMemberRpcCall.rpcCall_familySignin(loader); 104 | s = AntMemberRpcCall.rpcCall_familyHomepage(loader); 105 | JSONObject jo = new JSONObject(s); 106 | if(jo.getBoolean("success")) 107 | { 108 | jo = jo.getJSONObject("data"); 109 | if(jo.getBoolean("success")) 110 | { 111 | jo = jo.getJSONObject("familyInfoView"); 112 | String familyId = jo.getString("familyId"); 113 | s = AntMemberRpcCall.rpcCall_queryFamilyPointCert(loader, familyId); 114 | jo = new JSONObject(s); 115 | if(jo.getBoolean("success")) 116 | { 117 | JSONArray ja = jo.getJSONArray("familyPointCertInfos"); 118 | for(int i = 0; i < ja.length(); i++) 119 | { 120 | jo = ja.getJSONObject(i); 121 | String bizTitle = jo.getString("bizTitle"); 122 | long certId = jo.getLong("certId"); 123 | s = AntMemberRpcCall.rpcCall_claimFamilyPointCert(loader, certId, familyId); 124 | jo = new JSONObject(s); 125 | if(jo.getBoolean("success")) 126 | { 127 | Log.other("领取〈" + bizTitle + "〉〈" + jo.getInt("realPoint") + "家庭积分〉"); 128 | }else 129 | { 130 | Log.recordLog(jo.getString("resultDesc"), s); 131 | } 132 | } 133 | }else 134 | { 135 | Log.recordLog(jo.getString("resultDesc"), s); 136 | } 137 | } 138 | } 139 | }catch(Throwable t) 140 | { 141 | Log.i(TAG, "claimFamilyPoint err:"); 142 | Log.printStackTrace(TAG, t); 143 | } 144 | } 145 | 146 | } 147 | -------------------------------------------------------------------------------- /app/src/main/java/pansong291/xposed/quickenergy/AntSports.java: -------------------------------------------------------------------------------- 1 | package pansong291.xposed.quickenergy; 2 | 3 | import org.json.JSONArray; 4 | import org.json.JSONObject; 5 | import pansong291.xposed.quickenergy.hook.AntSportsRpcCall; 6 | import pansong291.xposed.quickenergy.util.Config; 7 | import pansong291.xposed.quickenergy.util.FriendIdMap; 8 | import pansong291.xposed.quickenergy.util.Log; 9 | import pansong291.xposed.quickenergy.util.RandomUtils; 10 | import pansong291.xposed.quickenergy.util.Statistics; 11 | 12 | public class AntSports 13 | { 14 | private static final String TAG = AntSports.class.getCanonicalName(); 15 | 16 | public static void start(ClassLoader loader, int times) 17 | { 18 | new Thread() 19 | { 20 | ClassLoader loader; 21 | int times; 22 | 23 | public Thread setData(ClassLoader cl, int i) 24 | { 25 | loader = cl; 26 | times = i; 27 | return this; 28 | } 29 | 30 | @Override 31 | public void run() 32 | { 33 | try 34 | { 35 | if(Config.openTreasureBox()) 36 | queryMyHomePage(loader); 37 | if(Config.donateCharityCoin()) 38 | queryProjectList(loader); 39 | if(Config.minExchangeCount() > 0 && Statistics.canExchangeToday() && times == 0) 40 | queryWalkStep(loader); 41 | }catch(Throwable t) 42 | { 43 | Log.i(TAG, "start.run err:"); 44 | Log.printStackTrace(TAG, t); 45 | } 46 | } 47 | }.setData(loader, times).start(); 48 | } 49 | 50 | private static void queryMyHomePage(ClassLoader loader) 51 | { 52 | try 53 | { 54 | String s = AntSportsRpcCall.rpcCall_queryMyHomePage(loader); 55 | JSONObject jo = new JSONObject(s); 56 | if(jo.getString("resultCode").equals("SUCCESS")) 57 | { 58 | s = jo.getString("pathJoinStatus"); 59 | if(s.equals("GOING")) 60 | { 61 | FriendIdMap.currentUid = jo.getJSONObject("myPositionModel").getString("userId"); 62 | String rankCacheKey = jo.getString("rankCacheKey"); 63 | JSONArray ja = jo.getJSONArray("treasureBoxModelList"); 64 | for(int i = 0; i < ja.length(); i++) 65 | { 66 | parseTreasureBoxModel(loader, ja.getJSONObject(i), rankCacheKey); 67 | } 68 | JSONObject joPathRender = jo.getJSONObject("pathRenderModel"); 69 | String title = joPathRender.getString("title"); 70 | int minGoStepCount = joPathRender.getInt("minGoStepCount"); 71 | jo = jo.getJSONObject("dailyStepModel"); 72 | int consumeQuantity = jo.getInt("consumeQuantity"); 73 | int produceQuantity = jo.getInt("produceQuantity"); 74 | String day = jo.getString("day"); 75 | int canMoveStepCount = produceQuantity - consumeQuantity; 76 | if(canMoveStepCount >= minGoStepCount) 77 | { 78 | go(loader, day, rankCacheKey, canMoveStepCount, title); 79 | } 80 | }else if(s.equals("NOT_JOIN")) 81 | { 82 | JSONArray ja = jo.getJSONArray("allPathBaseInfoList"); 83 | for(int i = ja.length() - 1; i >= 0; i--) 84 | { 85 | jo = ja.getJSONObject(i); 86 | if(jo.getBoolean("unlocked")) 87 | break; 88 | } 89 | String title = jo.getString("title"); 90 | String pathId = jo.getString("pathId"); 91 | join(loader, pathId, title); 92 | } 93 | }else 94 | { 95 | Log.i(TAG, jo.getString("resultDesc")); 96 | } 97 | }catch(Throwable t) 98 | { 99 | Log.i(TAG, "queryMyHomePage err:"); 100 | Log.printStackTrace(TAG, t); 101 | } 102 | } 103 | 104 | private static void join(ClassLoader loader, String pathId, String title) 105 | { 106 | try 107 | { 108 | String s = AntSportsRpcCall.rpcCall_join(loader, pathId); 109 | JSONObject jo = new JSONObject(s); 110 | if(jo.getString("resultCode").equals("SUCCESS")) 111 | { 112 | Log.other("成功加入〈" + title + "〉路线"); 113 | queryMyHomePage(loader); 114 | }else 115 | { 116 | Log.i(TAG, jo.getString("resultDesc")); 117 | } 118 | }catch(Throwable t) 119 | { 120 | Log.i(TAG, "join err:"); 121 | Log.printStackTrace(TAG, t); 122 | } 123 | } 124 | 125 | private static void go(ClassLoader loader, String day, String rankCacheKey, int stepCount, String title) 126 | { 127 | try 128 | { 129 | String s = AntSportsRpcCall.rpcCall_go(loader, day, rankCacheKey, stepCount); 130 | JSONObject jo = new JSONObject(s); 131 | if(jo.getString("resultCode").equals("SUCCESS")) 132 | { 133 | Log.other("〈" + title + "〉路线前进了〈" + jo.getInt("goStepCount") + "步〉"); 134 | boolean completed = jo.getString("completeStatus").equals("COMPLETED"); 135 | JSONArray ja = jo.getJSONArray("allTreasureBoxModelList"); 136 | for(int i = 0; i < ja.length(); i++) 137 | { 138 | parseTreasureBoxModel(loader, ja.getJSONObject(i), rankCacheKey); 139 | } 140 | if(completed) 141 | { 142 | Log.other("〈" + title + "〉路线已完成"); 143 | queryMyHomePage(loader); 144 | } 145 | }else 146 | { 147 | Log.i(TAG, jo.getString("resultDesc")); 148 | } 149 | }catch(Throwable t) 150 | { 151 | Log.i(TAG, "go err:"); 152 | Log.printStackTrace(TAG, t); 153 | } 154 | } 155 | 156 | private static void parseTreasureBoxModel(ClassLoader loader, JSONObject jo, String rankCacheKey) 157 | { 158 | try 159 | { 160 | String canOpenTime = jo.getString("canOpenTime"); 161 | String issueTime = jo.getString("issueTime"); 162 | String boxNo = jo.getString("boxNo"); 163 | String userId = jo.getString("userId"); 164 | if(canOpenTime.equals(issueTime)) 165 | { 166 | openTreasureBox(loader, boxNo, userId); 167 | }else 168 | { 169 | long cot = Long.parseLong(canOpenTime); 170 | long now = Long.parseLong(rankCacheKey); 171 | long delay = cot - now; 172 | Log.recordLog("还有 " + delay + "ms 才能开宝箱", ""); 173 | if(delay < Config.checkInterval()) 174 | { 175 | new Thread() 176 | { 177 | long delay; 178 | ClassLoader loader; 179 | String boxNo; 180 | String userId; 181 | 182 | public Thread setData(long l, ClassLoader cl, String bN, String uid) 183 | { 184 | delay = l - 1000; 185 | loader = cl; 186 | boxNo = bN; 187 | userId = uid; 188 | return this; 189 | } 190 | 191 | @Override 192 | public void run() 193 | { 194 | try 195 | { 196 | if(delay > 0) sleep(delay); 197 | Log.recordLog("蹲点开箱开始", ""); 198 | long startTime = System.currentTimeMillis(); 199 | while(System.currentTimeMillis() - startTime < 5_000) 200 | { 201 | if(openTreasureBox(loader, boxNo, userId) > 0) 202 | break; 203 | sleep(200); 204 | } 205 | }catch(Throwable t) 206 | { 207 | Log.i(TAG, "parseTreasureBoxModel.run err:"); 208 | Log.printStackTrace(TAG, t); 209 | } 210 | } 211 | 212 | }.setData(delay, loader, boxNo, userId).start(); 213 | } 214 | } 215 | }catch(Throwable t) 216 | { 217 | Log.i(TAG, "parseTreasureBoxModel err:"); 218 | Log.printStackTrace(TAG, t); 219 | } 220 | } 221 | 222 | private static int openTreasureBox(ClassLoader loader, String boxNo, String userId) 223 | { 224 | try 225 | { 226 | String s = AntSportsRpcCall.rpcCall_openTreasureBox(loader, boxNo, userId); 227 | JSONObject jo = new JSONObject(s); 228 | if(jo.getString("resultCode").equals("SUCCESS")) 229 | { 230 | JSONArray ja = jo.getJSONArray("treasureBoxAwards"); 231 | int num = 0; 232 | for(int i = 0; i < ja.length(); i++) 233 | { 234 | jo = ja.getJSONObject(i); 235 | num += jo.getInt("num"); 236 | Log.other("开宝箱获得〈" + num + jo.getString("name") + "〉"); 237 | } 238 | return num; 239 | }else 240 | { 241 | Log.recordLog(jo.getString("resultDesc"), ""); 242 | } 243 | }catch(Throwable t) 244 | { 245 | Log.i(TAG, "openTreasureBox err:"); 246 | Log.printStackTrace(TAG, t); 247 | } 248 | return 0; 249 | } 250 | 251 | private static boolean queryProjectList(ClassLoader loader) 252 | { 253 | boolean haveMore = false; 254 | try 255 | { 256 | String s = AntSportsRpcCall.rpcCall_queryProjectList(loader, 0); 257 | JSONObject jo = new JSONObject(s); 258 | if(jo.getString("resultCode").equals("SUCCESS")) 259 | { 260 | int charityCoinCount = jo.getInt("charityCoinCount"); 261 | if(charityCoinCount < 10) return false; 262 | jo = jo.getJSONObject("projectPage"); 263 | haveMore = jo.getBoolean("haveMore"); 264 | JSONArray ja = jo.getJSONArray("data"); 265 | for(int i = 0; i < ja.length(); i++) 266 | { 267 | jo = ja.getJSONObject(i).getJSONObject("basicModel"); 268 | if(jo.getString("footballFieldStatus").equals("OPENING_DONATE")) 269 | { 270 | donate(loader, charityCoinCount / 10 * 10, jo.getString("projectId"), jo.getString("title")); 271 | break; 272 | } 273 | } 274 | }else 275 | { 276 | Log.recordLog(TAG, jo.getString("resultDesc")); 277 | } 278 | }catch(Throwable t) 279 | { 280 | Log.i(TAG, "queryProjectList err:"); 281 | Log.printStackTrace(TAG, t); 282 | } 283 | return haveMore; 284 | } 285 | 286 | private static void donate(ClassLoader loader, int donateCharityCoin, String projectId, String title) 287 | { 288 | try 289 | { 290 | String s = AntSportsRpcCall.rpcCall_donate(loader, donateCharityCoin, projectId); 291 | JSONObject jo = new JSONObject(s); 292 | if(jo.getString("resultCode").equals("SUCCESS")) 293 | { 294 | Log.other("捐赠〈" + title + "〉〈" + donateCharityCoin + "运动币〉"); 295 | }else 296 | { 297 | Log.i(TAG, jo.getString("resultDesc")); 298 | } 299 | }catch(Throwable t) 300 | { 301 | Log.i(TAG, "donate err:"); 302 | Log.printStackTrace(TAG, t); 303 | } 304 | } 305 | 306 | private static void queryWalkStep(ClassLoader loader) 307 | { 308 | try 309 | { 310 | String s = AntSportsRpcCall.rpcCall_queryWalkStep(loader); 311 | JSONObject jo = new JSONObject(s); 312 | if(jo.getString("resultCode").equals("SUCCESS")) 313 | { 314 | jo = jo.getJSONObject("dailyStepModel"); 315 | int produceQuantity = jo.getInt("produceQuantity"); 316 | int hour = Integer.parseInt(Log.getFormatTime().split(":")[0]); 317 | if(produceQuantity >= Config.minExchangeCount() || hour >= Config.latestExchangeTime()) 318 | { 319 | s = AntSportsRpcCall.rpcCall_exchange(loader, produceQuantity, 3); 320 | jo = new JSONObject(s); 321 | if(jo.getBoolean("isSuccess")) 322 | { 323 | s = AntSportsRpcCall.rpcCall_exchange_success(loader, jo.getString("exchangeId")); 324 | jo = new JSONObject(s); 325 | if(jo.getBoolean("isSuccess")) 326 | { 327 | int userCount = jo.getInt("userCount"); 328 | double amount = jo.getJSONObject("userAmount").getDouble("amount"); 329 | Log.other("捐出〈" + userCount + "步〉,兑换〈" + amount + "元〉公益金"); 330 | Statistics.exchangeToday(); 331 | }else 332 | { 333 | Log.i(TAG, jo.getString("resultDesc")); 334 | } 335 | }else if(s.contains("已捐步")) 336 | { 337 | Statistics.exchangeToday(); 338 | }else 339 | { 340 | Log.i(TAG, jo.getString("resultDesc")); 341 | } 342 | } 343 | }else 344 | { 345 | Log.i(TAG, jo.getString("resultDesc")); 346 | } 347 | }catch(Throwable t) 348 | { 349 | Log.i(TAG, "queryWalkStep err:"); 350 | Log.printStackTrace(TAG, t); 351 | } 352 | } 353 | } 354 | -------------------------------------------------------------------------------- /app/src/main/java/pansong291/xposed/quickenergy/KBMember.java: -------------------------------------------------------------------------------- 1 | package pansong291.xposed.quickenergy; 2 | 3 | import org.json.JSONObject; 4 | import pansong291.xposed.quickenergy.hook.KBMemberRpcCall; 5 | import pansong291.xposed.quickenergy.util.Config; 6 | import pansong291.xposed.quickenergy.util.Log; 7 | import pansong291.xposed.quickenergy.util.Statistics; 8 | 9 | public class KBMember 10 | { 11 | private static final String TAG = KBMember.class.getCanonicalName(); 12 | 13 | public static void start(ClassLoader loader) 14 | { 15 | if(!Config.kbSginIn() || !Statistics.canKbSignInToday()) 16 | return; 17 | new Thread() 18 | { 19 | private ClassLoader loader; 20 | 21 | public Thread setData(ClassLoader cl) 22 | { 23 | loader = cl; 24 | return this; 25 | } 26 | 27 | @Override 28 | public void run() 29 | { 30 | try 31 | { 32 | signIn(loader); 33 | }catch(Throwable t) 34 | { 35 | Log.i(TAG, "start.run err:"); 36 | Log.printStackTrace(TAG, t); 37 | } 38 | } 39 | }.setData(loader).start(); 40 | } 41 | 42 | private static void signIn(ClassLoader loader) 43 | { 44 | try 45 | { 46 | String s = KBMemberRpcCall.rpcCall_signIn(loader); 47 | JSONObject jo = new JSONObject(s); 48 | if(jo.getBoolean("success")) 49 | { 50 | jo = jo.getJSONObject("data"); 51 | Log.other("口碑签到〈第" + jo.getString("dayNo") + "天〉,获得〈" + jo.getString("value") + "积分〉"); 52 | Statistics.KbSignInToday(); 53 | }else if(s.contains("\"HAS_SIGN_IN\"")) 54 | { 55 | Statistics.KbSignInToday(); 56 | }else 57 | { 58 | Log.i(TAG, jo.getString("errorMessage")); 59 | } 60 | }catch(Throwable t) 61 | { 62 | Log.i(TAG, "signIn err:"); 63 | Log.printStackTrace(TAG, t); 64 | } 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /app/src/main/java/pansong291/xposed/quickenergy/hook/AntCooperateRpcCall.java: -------------------------------------------------------------------------------- 1 | package pansong291.xposed.quickenergy.hook; 2 | 3 | import pansong291.xposed.quickenergy.util.Log; 4 | 5 | public class AntCooperateRpcCall 6 | { 7 | private static final String TAG = AntCooperateRpcCall.class.getCanonicalName(); 8 | 9 | public static String rpcCall_queryUserCooperatePlantList(ClassLoader loader) 10 | { 11 | try 12 | { 13 | String args1 = "[{}]"; 14 | return RpcCall.invoke(loader, "alipay.antmember.forest.h5.queryUserCooperatePlantList", args1); 15 | }catch(Throwable t) 16 | { 17 | Log.i(TAG, "rpcCall_queryUserCooperatePlantList err:"); 18 | Log.printStackTrace(TAG, t); 19 | } 20 | return null; 21 | } 22 | 23 | public static String rpcCall_queryCooperatePlant(ClassLoader loader, String coopId) 24 | { 25 | try 26 | { 27 | String args1 = "[{\"cooperationId\":\"" + coopId + "\"}]"; 28 | return RpcCall.invoke(loader, "alipay.antmember.forest.h5.queryCooperatePlant", args1); 29 | }catch(Throwable t) 30 | { 31 | Log.i(TAG, "rpcCall_queryCooperatePlant err:"); 32 | Log.printStackTrace(TAG, t); 33 | } 34 | return null; 35 | } 36 | 37 | public static String rpcCall_cooperateWater(ClassLoader loader, String uid, String coopId, int count) 38 | { 39 | try 40 | { 41 | String args1 = "[{\"bizNo\":\"" + uid + "_" + coopId + "_" + System.currentTimeMillis() 42 | + "\",\"cooperationId\":\"" + coopId + "\",\"energyCount\":" + count + "}]"; 43 | return RpcCall.invoke(loader, "alipay.antmember.forest.h5.cooperateWater", args1); 44 | }catch(Throwable t) 45 | { 46 | Log.i(TAG, "rpcCall_cooperateWater err:"); 47 | Log.printStackTrace(TAG, t); 48 | } 49 | return null; 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /app/src/main/java/pansong291/xposed/quickenergy/hook/AntFarmRpcCall.java: -------------------------------------------------------------------------------- 1 | package pansong291.xposed.quickenergy.hook; 2 | 3 | import pansong291.xposed.quickenergy.util.Log; 4 | 5 | public class AntFarmRpcCall 6 | { 7 | private static final String TAG = AntFarmRpcCall.class.getCanonicalName(); 8 | 9 | private static final String cityAdCode = "000000", 10 | districtAdCode = "000000", version = "1.0.1910171156.41"; 11 | 12 | public static String rpcCall_enterFarm(ClassLoader loader, String farmId, String userId) 13 | { 14 | try 15 | { 16 | String args1 = "[{\"animalId\":\"\",\"cityAdCode\":\"" + cityAdCode + "\",\"districtAdCode\":\"" + districtAdCode + "\",\"farmId\":\"" + farmId + 17 | "\",\"masterFarmId\":\"\",\"recall\":false,\"requestType\":\"NORMAL\",\"sceneCode\":\"ANTFARM\",\"source\":\"H5\",\"touchRecordId\":\"\",\"userId\":\"" 18 | + userId + "\",\"version\":\"" + version + "\"}]"; 19 | return RpcCall.invoke(loader, "com.alipay.antfarm.enterFarm", args1); 20 | }catch(Throwable t) 21 | { 22 | Log.i(TAG, "rpcCall_enterFarm err:"); 23 | Log.printStackTrace(TAG, t); 24 | } 25 | return null; 26 | } 27 | 28 | public static String rpcCall_syncAnimalStatus(ClassLoader loader, String farmId) 29 | { 30 | try 31 | { 32 | String args1 = "[{\"farmId\":\"" + farmId + 33 | "\",\"operType\":\"FEEDSYNC\",\"queryFoodStockInfo\":false,\"recall\":false,\"requestType\":\"NORMAL\",\"sceneCode\":\"ANTFARM\",\"source\":\"H5\",\"userId\":\"" 34 | + farmId2UserId(farmId) + "\",\"version\":\"" + version + "\"}]"; 35 | return RpcCall.invoke(loader, "com.alipay.antfarm.syncAnimalStatus", args1); 36 | }catch(Throwable t) 37 | { 38 | Log.i(TAG, "rpcCall_syncAnimalStatus err:"); 39 | Log.printStackTrace(TAG, t); 40 | } 41 | return null; 42 | } 43 | 44 | public static String rpcCall_rewardFriend(ClassLoader loader, String consistencyKey, String friendId, String productNum, String time) 45 | { 46 | try 47 | { 48 | String args1 = "[{\"canMock\":true,\"consistencyKey\":\"" + consistencyKey 49 | + "\",\"friendId\":\"" + friendId + "\",\"operType\":\"1\",\"productNum\":" + productNum + 50 | ",\"requestType\":\"NORMAL\",\"sceneCode\":\"ANTFARM\",\"source\":\"H5\",\"time\":" 51 | + time + ",\"version\":\"" + version + "\"}]"; 52 | return RpcCall.invoke(loader, "com.alipay.antfarm.rewardFriend", args1); 53 | }catch(Throwable t) 54 | { 55 | Log.i(TAG, "rpcCall_rewardFriend err:"); 56 | Log.printStackTrace(TAG, t); 57 | } 58 | return null; 59 | } 60 | 61 | public static String rpcCall_recallAnimal(ClassLoader loader, String animalId, String currentFarmId, String masterFarmId) 62 | { 63 | try 64 | { 65 | String args1 = "[{\"animalId\":\"" + animalId + "\",\"currentFarmId\":\"" 66 | + currentFarmId + "\",\"masterFarmId\":\"" + masterFarmId + 67 | "\",\"requestType\":\"NORMAL\",\"sceneCode\":\"ANTFARM\",\"source\":\"H5\",\"version\":\"" 68 | + version + "\"}]"; 69 | return RpcCall.invoke(loader, "com.alipay.antfarm.recallAnimal", args1); 70 | }catch(Throwable t) 71 | { 72 | Log.i(TAG, "rpcCall_recallAnimal err:"); 73 | Log.printStackTrace(TAG, t); 74 | } 75 | return null; 76 | } 77 | 78 | public static String rpcCall_sendBackAnimal(ClassLoader loader, String sendType, String animalId, String currentFarmId, String masterFarmId) 79 | { 80 | try 81 | { 82 | String args1 = "[{\"animalId\":\"" + animalId + "\",\"currentFarmId\":\"" 83 | + currentFarmId + "\",\"masterFarmId\":\"" + masterFarmId + 84 | "\",\"requestType\":\"NORMAL\",\"sceneCode\":\"ANTFARM\",\"sendType\":\"" 85 | + sendType + "\",\"source\":\"H5\",\"version\":\"" 86 | + version + "\"}]"; 87 | return RpcCall.invoke(loader, "com.alipay.antfarm.sendBackAnimal", args1); 88 | }catch(Throwable t) 89 | { 90 | Log.i(TAG, "rpcCall_sendBackAnimal err:"); 91 | Log.printStackTrace(TAG, t); 92 | } 93 | return null; 94 | } 95 | 96 | public static String rpcCall_harvestProduce(ClassLoader loader, String farmId) 97 | { 98 | try 99 | { 100 | String args1 = "[{\"canMock\":true,\"farmId\":\"" + farmId + 101 | "\",\"giftType\":\"\",\"requestType\":\"NORMAL\",\"sceneCode\":\"ANTFARM\",\"source\":\"H5\",\"version\":\"" 102 | + version + "\"}]"; 103 | return RpcCall.invoke(loader, "com.alipay.antfarm.harvestProduce", args1); 104 | }catch(Throwable t) 105 | { 106 | Log.i(TAG, "rpcCall_harvestProduce err:"); 107 | Log.printStackTrace(TAG, t); 108 | } 109 | return null; 110 | } 111 | 112 | public static String rpcCall_listActivityInfo(ClassLoader loader) 113 | { 114 | try 115 | { 116 | String args1 = "[{\"requestType\":\"NORMAL\",\"sceneCode\":\"ANTFARM\",\"source\":\"H5\",\"version\":\"" 117 | + version + "\"}]"; 118 | return RpcCall.invoke(loader, "com.alipay.antfarm.listActivityInfo", args1); 119 | }catch(Throwable t) 120 | { 121 | Log.i(TAG, "rpcCall_listActivityInfo err:"); 122 | Log.printStackTrace(TAG, t); 123 | } 124 | return null; 125 | } 126 | 127 | public static String rpcCall_donation(ClassLoader loader, String activityId) 128 | { 129 | try 130 | { 131 | String args1 = "[{\"activityId\":\"" + activityId + 132 | "\",\"donationAmount\":5,\"requestType\":\"NORMAL\",\"sceneCode\":\"ANTFARM\",\"source\":\"H5\",\"version\":\"" 133 | + version + "\"}]"; 134 | return RpcCall.invoke(loader, "com.alipay.antfarm.donation", args1); 135 | }catch(Throwable t) 136 | { 137 | Log.i(TAG, "rpcCall_donation err:"); 138 | Log.printStackTrace(TAG, t); 139 | } 140 | return null; 141 | } 142 | 143 | public static String rpcCall_listFarmTask(ClassLoader loader) 144 | { 145 | try 146 | { 147 | String args1 = "[{\"requestType\":\"NORMAL\",\"sceneCode\":\"ANTFARM\",\"source\":\"H5\",\"version\":\"" 148 | + version + "\"}]"; 149 | return RpcCall.invoke(loader, "com.alipay.antfarm.listFarmTask", args1); 150 | }catch(Throwable t) 151 | { 152 | Log.i(TAG, "rpcCall_listFarmTask err:"); 153 | Log.printStackTrace(TAG, t); 154 | } 155 | return null; 156 | } 157 | 158 | public static String rpcCall_getAnswerInfo(ClassLoader loader) 159 | { 160 | try 161 | { 162 | String args1 = "[{\"answerSource\":\"foodTask\",\"requestType\":\"NORMAL\",\"sceneCode\":\"ANTFARM\",\"source\":\"H5\",\"version\":\"" 163 | + version + "\"}]"; 164 | return RpcCall.invoke(loader, "com.alipay.antfarm.getAnswerInfo", args1); 165 | }catch(Throwable t) 166 | { 167 | Log.i(TAG, "rpcCall_getAnswerInfo err:"); 168 | Log.printStackTrace(TAG, t); 169 | } 170 | return null; 171 | } 172 | 173 | public static String rpcCall_answerQuestion(ClassLoader loader, String quesId, int answer) 174 | { 175 | try 176 | { 177 | String args1 = "[{\"answers\":\"[{\\\"questionId\\\":\\\"" + quesId + "\\\",\\\"answers\\\":[" + answer + 178 | "]}]\",\"bizkey\":\"ANSWER\",\"requestType\":\"NORMAL\",\"sceneCode\":\"ANTFARM\",\"source\":\"H5\",\"version\":\"" 179 | + version + "\"}]"; 180 | return RpcCall.invoke(loader, "com.alipay.antfarm.doFarmTask", args1); 181 | }catch(Throwable t) 182 | { 183 | Log.i(TAG, "rpcCall_answerQuestion err:"); 184 | Log.printStackTrace(TAG, t); 185 | } 186 | return null; 187 | } 188 | 189 | public static String rpcCall_receiveFarmTaskAward(ClassLoader loader, String taskId) 190 | { 191 | try 192 | { 193 | String args1 = "[{\"requestType\":\"NORMAL\",\"sceneCode\":\"ANTFARM\",\"source\":\"H5\",\"taskId\":\"" 194 | + taskId + "\",\"version\":\"" + version + "\"}]"; 195 | return RpcCall.invoke(loader, "com.alipay.antfarm.receiveFarmTaskAward", args1); 196 | }catch(Throwable t) 197 | { 198 | Log.i(TAG, "rpcCall_receiveFarmTaskAward err:"); 199 | Log.printStackTrace(TAG, t); 200 | } 201 | return null; 202 | } 203 | 204 | public static String rpcCall_listToolTaskDetails(ClassLoader loader) 205 | { 206 | try 207 | { 208 | String args1 = "[{\"requestType\":\"NORMAL\",\"sceneCode\":\"ANTFARM\",\"source\":\"H5\",\"version\":\"" 209 | + version + "\"}]"; 210 | return RpcCall.invoke(loader, "com.alipay.antfarm.listToolTaskDetails", args1); 211 | }catch(Throwable t) 212 | { 213 | Log.i(TAG, "rpcCall_listToolTaskDetails err:"); 214 | Log.printStackTrace(TAG, t); 215 | } 216 | return null; 217 | } 218 | 219 | public static String rpcCall_receiveToolTaskReward(ClassLoader loader, String awardType, int rewardCount, String taskType) 220 | { 221 | try 222 | { 223 | String args1 = "[{\"awardType\":\"" + awardType + 224 | "\",\"ignoreLimit\":false,\"requestType\":\"NORMAL\",\"rewardCount\":" 225 | + rewardCount + ",\"rewardType\":\"" + awardType + 226 | "\",\"sceneCode\":\"ANTFARM\",\"source\":\"H5\",\"taskType\":\"" 227 | + taskType + "\",\"version\":\"" + version + "\"}]"; 228 | return RpcCall.invoke(loader, "com.alipay.antfarm.receiveToolTaskReward", args1); 229 | }catch(Throwable t) 230 | { 231 | Log.i(TAG, "rpcCall_receiveToolTaskReward err:"); 232 | Log.printStackTrace(TAG, t); 233 | } 234 | return null; 235 | } 236 | 237 | public static String rpcCall_feedAnimal(ClassLoader loader, String farmId) 238 | { 239 | try 240 | { 241 | String args1 = "[{\"animalType\":\"CHICK\",\"canMock\":true,\"farmId\":\"" + farmId + 242 | "\",\"requestType\":\"NORMAL\",\"sceneCode\":\"ANTFARM\",\"source\":\"H5\",\"version\":\"" 243 | + version + "\"}]"; 244 | return RpcCall.invoke(loader, "com.alipay.antfarm.feedAnimal", args1); 245 | }catch(Throwable t) 246 | { 247 | Log.i(TAG, "rpcCall_feedAnimal err:"); 248 | Log.printStackTrace(TAG, t); 249 | } 250 | return null; 251 | } 252 | 253 | public static String rpcCall_listFarmTool(ClassLoader loader) 254 | { 255 | try 256 | { 257 | String args1 = "[{\"requestType\":\"NORMAL\",\"sceneCode\":\"ANTFARM\",\"source\":\"H5\",\"version\":\"" 258 | + version + "\"}]"; 259 | return RpcCall.invoke(loader, "com.alipay.antfarm.listFarmTool", args1); 260 | }catch(Throwable t) 261 | { 262 | Log.i(TAG, "rpcCall_listFarmTool err:"); 263 | Log.printStackTrace(TAG, t); 264 | } 265 | return null; 266 | } 267 | 268 | public static String rpcCall_useFarmTool(ClassLoader loader, String targetFarmId, String toolId, String toolType) 269 | { 270 | try 271 | { 272 | String args1 = "[{\"requestType\":\"NORMAL\",\"sceneCode\":\"ANTFARM\",\"source\":\"H5\",\"targetFarmId\":\"" 273 | + targetFarmId + "\",\"toolId\":\"" + toolId + "\",\"toolType\":\"" + toolType + "\",\"version\":\"" + version + "\"}]"; 274 | return RpcCall.invoke(loader, "com.alipay.antfarm.useFarmTool", args1); 275 | }catch(Throwable t) 276 | { 277 | Log.i(TAG, "rpcCall_useFarmTool err:"); 278 | Log.printStackTrace(TAG, t); 279 | } 280 | return null; 281 | } 282 | 283 | public static String rpcCall_rankingList(ClassLoader loader, int pageStartSum) 284 | { 285 | try 286 | { 287 | String args1 = "[{\"pageSize\":20,\"requestType\":\"NORMAL\",\"sceneCode\":\"ANTFARM\",\"source\":\"H5\",\"startNum\":" 288 | + pageStartSum + ",\"version\":\"" + version + "\"}]"; 289 | return RpcCall.invoke(loader, "com.alipay.antfarm.rankingList", args1); 290 | }catch(Throwable t) 291 | { 292 | Log.i(TAG, "rpcCall_rankingList err:"); 293 | Log.printStackTrace(TAG, t); 294 | } 295 | return null; 296 | } 297 | 298 | public static String rpcCall_notifyFriend(ClassLoader loader, String animalId, String notifiedFarmId) 299 | { 300 | try 301 | { 302 | String args1 = "[{\"animalId\":\"" + animalId + 303 | "\",\"animalType\":\"CHICK\",\"canBeGuest\":true,\"notifiedFarmId\":\"" + notifiedFarmId + 304 | "\",\"requestType\":\"NORMAL\",\"sceneCode\":\"ANTFARM\",\"source\":\"H5\",\"version\":\"" 305 | + version + "\"}]"; 306 | return RpcCall.invoke(loader, "com.alipay.antfarm.notifyFriend", args1); 307 | }catch(Throwable t) 308 | { 309 | Log.i(TAG, "rpcCall_notifyFriend err:"); 310 | Log.printStackTrace(TAG, t); 311 | } 312 | return null; 313 | } 314 | 315 | public static String rpcCall_feedFriendAnimal(ClassLoader loader, String friendFarmId) 316 | { 317 | try 318 | { 319 | String args1 = "[{\"animalType\":\"CHICK\",\"canMock\":true,\"friendFarmId\":\"" + friendFarmId + 320 | "\",\"requestType\":\"NORMAL\",\"sceneCode\":\"ANTFARM\",\"source\":\"H5\",\"version\":\"" 321 | + version + "\"}]"; 322 | return RpcCall.invoke(loader, "com.alipay.antfarm.feedFriendAnimal", args1); 323 | }catch(Throwable t) 324 | { 325 | Log.i(TAG, "rpcCall_feedFriendAnimal err:"); 326 | Log.printStackTrace(TAG, t); 327 | } 328 | return null; 329 | } 330 | 331 | public static String farmId2UserId(String farmId) 332 | { 333 | int l = farmId.length() / 2; 334 | return farmId.substring(l); 335 | } 336 | 337 | } 338 | -------------------------------------------------------------------------------- /app/src/main/java/pansong291/xposed/quickenergy/hook/AntForestRpcCall.java: -------------------------------------------------------------------------------- 1 | package pansong291.xposed.quickenergy.hook; 2 | 3 | import pansong291.xposed.quickenergy.util.Log; 4 | 5 | public class AntForestRpcCall 6 | { 7 | private static final String TAG = AntForestRpcCall.class.getCanonicalName(); 8 | 9 | public static String rpcCall_queryEnergyRanking(ClassLoader loader, String startPoint) 10 | { 11 | try 12 | { 13 | String args1 = "[{\"av\":\"5\",\"ct\":\"android\",\"pageSize\":20,\"startPoint\":\"" 14 | + startPoint + "\"}]"; 15 | return RpcCall.invoke(loader, "alipay.antmember.forest.h5.queryEnergyRanking", args1); 16 | }catch(Throwable t) 17 | { 18 | Log.i(TAG, "rpcCall_queryEnergyRanking err:"); 19 | Log.printStackTrace(TAG, t); 20 | } 21 | return null; 22 | } 23 | 24 | public static String rpcCall_queryNextAction(ClassLoader loader, String userId) 25 | { 26 | try 27 | { 28 | String args1 = "[{\"canRobFlags\":\"F,F,F\",\"source\":\"_NO_SOURCE_\",\"userId\":\"" 29 | + userId + "\",\"version\":\"20181220\"}]"; 30 | String res = RpcCall.invoke(loader, "alipay.antmember.forest.h5.queryNextAction", args1); 31 | 32 | // args1 = "[{\"av\":\"5\",\"ct\":\"android\",\"pageSize\":3,\"startIndex\":0,\"userId\":\"" 33 | // + userId + "\"}]"; 34 | // RpcCall.invoke(loader, "alipay.antmember.forest.h5.pageQueryDynamics", args1); 35 | 36 | return res; 37 | }catch(Throwable t) 38 | { 39 | Log.i(TAG, "rpcCall_queryNextAction err:"); 40 | Log.printStackTrace(TAG, t); 41 | } 42 | return null; 43 | } 44 | 45 | public static String rpcCall_collectEnergy(ClassLoader loader, String userId, long bubbleId) 46 | { 47 | try 48 | { 49 | String args1 = "[{\"bubbleIds\":[" + bubbleId + "],\"userId\":\"" + userId + "\"}]"; 50 | return RpcCall.invoke(loader, "alipay.antmember.forest.h5.collectEnergy", args1); 51 | }catch(Throwable t) 52 | { 53 | Log.i(TAG, "rpcCall_collectEnergy err:"); 54 | Log.printStackTrace(TAG, t); 55 | } 56 | return null; 57 | } 58 | 59 | public static String rpcCall_transferEnergy(ClassLoader loader, String targetUser, String bizNo, int ordinal) 60 | { 61 | try 62 | { 63 | String args1 = "[{\"bizNo\":\"" + bizNo + ordinal + "\",\"targetUser\":\"" 64 | + targetUser + "\",\"transferType\":\"WATERING\",\"version\":\"20181217\"}]";// 65 | return RpcCall.invoke(loader, "alipay.antmember.forest.h5.transferEnergy", args1); 66 | }catch(Throwable t) 67 | { 68 | Log.i(TAG, "rpcCall_transferEnergy err:"); 69 | Log.printStackTrace(TAG, t); 70 | } 71 | return null; 72 | } 73 | 74 | public static String rpcCall_forFriendCollectEnergy(ClassLoader loader, String targetUserId, long bubbleId) 75 | { 76 | try 77 | { 78 | String args1 = "[{\"bubbleIds\":[" + bubbleId + "],\"targetUserId\":\"" + targetUserId + "\"}]"; 79 | return RpcCall.invoke(loader, "alipay.antmember.forest.h5.forFriendCollectEnergy", args1); 80 | }catch(Throwable t) 81 | { 82 | Log.i(TAG, "rpcCall_forFriendCollectEnergy err:"); 83 | Log.printStackTrace(TAG, t); 84 | } 85 | return null; 86 | } 87 | 88 | public static String rpcCall_queryTaskList(ClassLoader loader) 89 | { 90 | try 91 | { 92 | String args1 = "[{\"version\":\"20191010\"}]"; // 93 | return RpcCall.invoke(loader, "alipay.antforest.forest.h5.queryTaskList", args1); 94 | }catch(Throwable t) 95 | { 96 | Log.i(TAG, "rpcCall_queryTaskList err:"); 97 | Log.printStackTrace(TAG, t); 98 | } 99 | return null; 100 | } 101 | 102 | public static String rpcCall_receiveTaskAward(ClassLoader loader, String taskType) 103 | { 104 | try 105 | { 106 | String args1 = 107 | "[{\"ignoreLimit\":false,\"requestType\":\"H5\",\"sceneCode\":\"ANTFOREST_TASK\",\"source\":\"ANTFOREST\",\"taskType\":\"" 108 | + taskType + "\"}]"; 109 | return RpcCall.invoke(loader, "com.alipay.antiep.receiveTaskAward", args1); 110 | }catch(Throwable t) 111 | { 112 | Log.i(TAG, "rpcCall_receiveTaskAward err:"); 113 | Log.printStackTrace(TAG, t); 114 | } 115 | return null; 116 | } 117 | 118 | private static String rpcCall_queryPropList(ClassLoader loader) 119 | { 120 | try 121 | { 122 | String args1 = "[{\"version\":\"\"}]"; //20181217 123 | return RpcCall.invoke(loader, "alipay.antforest.forest.h5.queryPropList", args1); 124 | }catch(Throwable t) 125 | { 126 | Log.i(TAG, "rpcCall_queryPropList err:"); 127 | Log.printStackTrace(TAG, t); 128 | } 129 | return null; 130 | } 131 | 132 | } 133 | -------------------------------------------------------------------------------- /app/src/main/java/pansong291/xposed/quickenergy/hook/AntMemberRpcCall.java: -------------------------------------------------------------------------------- 1 | package pansong291.xposed.quickenergy.hook; 2 | 3 | import pansong291.xposed.quickenergy.util.Log; 4 | 5 | public class AntMemberRpcCall 6 | { 7 | private static final String TAG = AntMemberRpcCall.class.getCanonicalName(); 8 | 9 | private static final String appVersion = "3.0.0"; 10 | 11 | /* ant member point */ 12 | public static String rpcCall_queryPointCert(ClassLoader loader, int page, int pageSize) 13 | { 14 | try 15 | { 16 | String args1 = "[{\"page\":" + page + ",\"pageSize\":" + pageSize + "}]"; 17 | return RpcCall.invoke(loader, "alipay.antmember.biz.rpc.member.h5.queryPointCert", args1); 18 | }catch(Throwable t) 19 | { 20 | Log.i(TAG, "rpcCall_queryPointCert err:"); 21 | Log.printStackTrace(TAG, t); 22 | } 23 | return null; 24 | } 25 | 26 | public static String rpcCall_receivePointByUser(ClassLoader loader, String certId) 27 | { 28 | try 29 | { 30 | String args1 = "[{\"certId\":" + certId + "}]"; 31 | return RpcCall.invoke(loader, "alipay.antmember.biz.rpc.member.h5.receivePointByUser", args1); 32 | }catch(Throwable t) 33 | { 34 | Log.i(TAG, "rpcCall_receivePointByUser err:"); 35 | Log.printStackTrace(TAG, t); 36 | } 37 | return null; 38 | } 39 | 40 | public static String rpcCall_queryPoint(ClassLoader loader) 41 | { 42 | try 43 | { 44 | String args1 = "[{}]"; 45 | return RpcCall.invoke(loader, "alipay.antmember.h5.queryPoint", args1); 46 | }catch(Throwable t) 47 | { 48 | Log.i(TAG, "rpcCall_queryPoint err:"); 49 | Log.printStackTrace(TAG, t); 50 | } 51 | return null; 52 | } 53 | 54 | public static String rpcCall_memberSignin(ClassLoader loader) 55 | { 56 | try 57 | { 58 | String args1 = "[{}]"; 59 | return RpcCall.invoke(loader, "alipay.antmember.biz.rpc.member.h5.memberSignin", args1); 60 | }catch(Throwable t) 61 | { 62 | Log.i(TAG, "rpcCall_memberSignin err:"); 63 | Log.printStackTrace(TAG, t); 64 | } 65 | return null; 66 | } 67 | 68 | /* family point*/ 69 | public static String rpcCall_familySignin(ClassLoader loader) 70 | { 71 | try 72 | { 73 | String args1 = "[{\"appVersion\": \"" + appVersion + 74 | "\",\"clientTraceId\": \"\",\"source\": \"JTHYJGW\"}]"; 75 | return RpcCall.invoke(loader, "alipay.peerpayprod.family.signin", args1); 76 | }catch(Throwable t) 77 | { 78 | Log.i(TAG, "rpcCall_familySignin err:"); 79 | Log.printStackTrace(TAG, t); 80 | } 81 | return null; 82 | } 83 | 84 | public static String rpcCall_familyHomepage(ClassLoader loader) 85 | { 86 | try 87 | { 88 | String args1 = "[{\"appVersion\": \"" + appVersion + 89 | "\",\"clientTraceId\": \"\",\"source\": \"JTHYJGW\"}]"; 90 | return RpcCall.invoke(loader, "alipay.peerpayprod.family.homepage", args1); 91 | }catch(Throwable t) 92 | { 93 | Log.i(TAG, "rpcCall_familyHomepage err:"); 94 | Log.printStackTrace(TAG, t); 95 | } 96 | return null; 97 | } 98 | 99 | public static String rpcCall_queryFamilyPointCert(ClassLoader loader, String familyId) 100 | { 101 | try 102 | { 103 | String args1 = "[{\"familyId\":\"" + familyId + 104 | "\",\"limit\":20,\"needQueryOtherMemberCert\":false}]"; 105 | return RpcCall.invoke(loader, "com.alipay.alipaymember.biz.rpc.family.h5.queryFamilyPointCert", args1); 106 | }catch(Throwable t) 107 | { 108 | Log.i(TAG, "rpcCall_queryFamilyPointCert err:"); 109 | Log.printStackTrace(TAG, t); 110 | } 111 | return null; 112 | } 113 | 114 | public static String rpcCall_claimFamilyPointCert(ClassLoader loader, long certId, String familyId) 115 | { 116 | try 117 | { 118 | String args1 = "[{\"certId\":" + certId + ",\"familyId\":\"" 119 | + familyId + "\"}]"; 120 | return RpcCall.invoke(loader, "com.alipay.alipaymember.biz.rpc.family.h5.claimFamilyPointCert", args1); 121 | }catch(Throwable t) 122 | { 123 | Log.i(TAG, "rpcCall_claimFamilyPointCert err:"); 124 | Log.printStackTrace(TAG, t); 125 | } 126 | return null; 127 | } 128 | 129 | } 130 | -------------------------------------------------------------------------------- /app/src/main/java/pansong291/xposed/quickenergy/hook/AntSportsRpcCall.java: -------------------------------------------------------------------------------- 1 | package pansong291.xposed.quickenergy.hook; 2 | 3 | import pansong291.xposed.quickenergy.util.Log; 4 | 5 | public class AntSportsRpcCall 6 | { 7 | private static final String TAG = AntSportsRpcCall.class.getCanonicalName(); 8 | private static final String chInfo = "antsports-account", 9 | timeZone = "Asia\\/Shanghai", version = "3.0.1.2"; 10 | 11 | public static String rpcCall_queryMyHomePage(ClassLoader loader) 12 | { 13 | try 14 | { 15 | String args1 = "[{\"chInfo\":\"" + chInfo 16 | + "\",\"pathListUsePage\":true,\"timeZone\":\"" + timeZone + "\"}]"; 17 | return RpcCall.invoke(loader, "alipay.antsports.walk.map.queryMyHomePage", args1); 18 | }catch(Throwable t) 19 | { 20 | Log.i(TAG, "rpcCall_queryMyHomePage err:"); 21 | Log.printStackTrace(TAG, t); 22 | } 23 | return null; 24 | } 25 | 26 | public static String rpcCall_join(ClassLoader loader, String pathId) 27 | { 28 | try 29 | { 30 | String args1 = "[{\"chInfo\":\"" + chInfo 31 | + "\",\"pathId\":\"" + pathId + "\"}]"; 32 | return RpcCall.invoke(loader, "alipay.antsports.walk.map.join", args1); 33 | }catch(Throwable t) 34 | { 35 | Log.i(TAG, "rpcCall_join err:"); 36 | Log.printStackTrace(TAG, t); 37 | } 38 | return null; 39 | } 40 | 41 | public static String rpcCall_go(ClassLoader loader, String day, String rankCacheKey, int stepCount) 42 | { 43 | try 44 | { 45 | String args1 = "[{\"chInfo\":\"" + chInfo + "\",\"day\":\"" + day 46 | + "\",\"needAllBox\":true,\"rankCacheKey\":\"" + rankCacheKey 47 | + "\",\"timeZone\":\"" + timeZone + "\",\"useStepCount\":" + stepCount + "}]"; 48 | return RpcCall.invoke(loader, "alipay.antsports.walk.map.go", args1); 49 | }catch(Throwable t) 50 | { 51 | Log.i(TAG, "rpcCall_go err:"); 52 | Log.printStackTrace(TAG, t); 53 | } 54 | return null; 55 | } 56 | 57 | public static String rpcCall_openTreasureBox(ClassLoader loader, String boxNo, String userId) 58 | { 59 | try 60 | { 61 | String args1 = "[{\"boxNo\":\"" + boxNo + "\",\"chInfo\":\"" 62 | + chInfo + "\",\"userId\":\"" + userId + "\"}]"; 63 | return RpcCall.invoke(loader, "alipay.antsports.walk.treasureBox.openTreasureBox", args1); 64 | }catch(Throwable t) 65 | { 66 | Log.i(TAG, "rpcCall_openTreasureBox err:"); 67 | Log.printStackTrace(TAG, t); 68 | } 69 | return null; 70 | } 71 | 72 | public static String rpcCall_queryProjectList(ClassLoader loader, int index) 73 | { 74 | try 75 | { 76 | String args1 = "[{\"chInfo\":\"" + chInfo + "\",\"index\":" 77 | + index + ",\"projectListUseVertical\":true}]"; 78 | return RpcCall.invoke(loader, "alipay.antsports.walk.charity.queryProjectList", args1); 79 | }catch(Throwable t) 80 | { 81 | Log.i(TAG, "rpcCall_queryProjectList err:"); 82 | Log.printStackTrace(TAG, t); 83 | } 84 | return null; 85 | } 86 | 87 | public static String rpcCall_donate(ClassLoader loader, int donateCharityCoin, String projectId) 88 | { 89 | try 90 | { 91 | String args1 = "[{\"chInfo\":\"" + chInfo + "\",\"donateCharityCoin\":" 92 | + donateCharityCoin + ",\"projectId\":\"" + projectId + "\"}]"; 93 | return RpcCall.invoke(loader, "alipay.antsports.walk.charity.donate", args1); 94 | }catch(Throwable t) 95 | { 96 | Log.i(TAG, "rpcCall_queryProjectList err:"); 97 | Log.printStackTrace(TAG, t); 98 | } 99 | return null; 100 | } 101 | 102 | public static String rpcCall_queryWalkStep(ClassLoader loader) 103 | { 104 | try 105 | { 106 | String args1 = "[{\"timeZone\":\"" + timeZone + "\"}]"; 107 | return RpcCall.invoke(loader, "alipay.antsports.walk.user.queryWalkStep", args1); 108 | }catch(Throwable t) 109 | { 110 | Log.i(TAG, "rpcCall_queryWalkStep err:"); 111 | Log.printStackTrace(TAG, t); 112 | } 113 | return null; 114 | } 115 | 116 | public static String rpcCall_exchange(ClassLoader loader, int count, int ver) 117 | { 118 | try 119 | { 120 | String args1 = "[{\"actId\":\"\",\"count\":" + count 121 | + ",\"timezone\":\"" + timeZone + "\",\"ver\":" 122 | + ver + ",\"version\":\"" + version + "\"}]"; 123 | return RpcCall.invoke(loader, "alipay.charity.mobile.donate.exchange", args1); 124 | }catch(Throwable t) 125 | { 126 | Log.i(TAG, "rpcCall_exchange err:"); 127 | Log.printStackTrace(TAG, t); 128 | } 129 | return null; 130 | } 131 | 132 | public static String rpcCall_exchange_success(ClassLoader loader, String exchangeId) 133 | { 134 | try 135 | { 136 | String args1 = "[{\"exchangeId\":\"" + exchangeId 137 | + "\",\"timezone\":\"GMT+08:00\",\"version\":\"" + version + "\"}]"; 138 | return RpcCall.invoke(loader, "alipay.charity.mobile.donate.exchange.success", args1); 139 | }catch(Throwable t) 140 | { 141 | Log.i(TAG, "rpcCall_exchange_success err:"); 142 | Log.printStackTrace(TAG, t); 143 | } 144 | return null; 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /app/src/main/java/pansong291/xposed/quickenergy/hook/ClassMember.java: -------------------------------------------------------------------------------- 1 | package pansong291.xposed.quickenergy.hook; 2 | 3 | public class ClassMember 4 | { 5 | public static final String 6 | com_eg_android_AlipayGphone = "com.eg.android.AlipayGphone", 7 | com_eg_android_AlipayGphone_AlipayLogin = "com.eg.android.AlipayGphone.AlipayLogin", 8 | com_alipay_android_launcher_service_LauncherService = "com.alipay.android.launcher.service.LauncherService", 9 | com_alipay_mobile_nebulaappproxy_api_rpc_H5AppRpcUpdate = "com.alipay.mobile.nebulaappproxy.api.rpc.H5AppRpcUpdate", 10 | matchVersion = "matchVersion", 11 | a = "a", h = "h", 12 | com_alipay_mobile_h5container_api_H5Page = "com.alipay.mobile.h5container.api.H5Page", 13 | com_alibaba_fastjson_JSONObject = "com.alibaba.fastjson.JSONObject", 14 | com_alipay_mobile_nebulaappproxy_api_rpc_H5RpcUtil = "com.alipay.mobile.nebulaappproxy.api.rpc.H5RpcUtil", 15 | rpcCall = "rpcCall", 16 | com_alipay_mobile_nebulacore_ui_H5FragmentManager = "com.alipay.mobile.nebulacore.ui.H5FragmentManager", 17 | com_alipay_mobile_nebulacore_ui_H5Fragment = "com.alipay.mobile.nebulacore.ui.H5Fragment", 18 | pushFragment = "pushFragment", 19 | com_alipay_mobile_nebulacore_ui_H5Activity = "com.alipay.mobile.nebulacore.ui.H5Activity", 20 | onCreate = "onCreate", onResume = "onResume", onDestroy = "onDestroy", 21 | getResponse = "getResponse"; 22 | 23 | public static final String 24 | com_alipay_mobile_nebulabiz_rpc_H5RpcUtil = "com.alipay.mobile.nebulabiz.rpc.H5RpcUtil"; 25 | } 26 | -------------------------------------------------------------------------------- /app/src/main/java/pansong291/xposed/quickenergy/hook/KBMemberRpcCall.java: -------------------------------------------------------------------------------- 1 | package pansong291.xposed.quickenergy.hook; 2 | 3 | import pansong291.xposed.quickenergy.util.Log; 4 | 5 | public class KBMemberRpcCall 6 | { 7 | private static final String TAG = KBMemberRpcCall.class.getCanonicalName(); 8 | private static final String version = "2.0"; 9 | 10 | public static String rpcCall_signIn(ClassLoader loader) 11 | { 12 | try 13 | { 14 | String args1 = "[{\"sceneCode\":\"KOUBEI_INTEGRAL\",\"source\":\"ALIPAY_TAB\",\"version\":\"" + version + "\"}]"; 15 | return RpcCall.invoke(loader, "alipay.kbmemberprod.action.signIn", args1); 16 | }catch(Throwable t) 17 | { 18 | Log.i(TAG, "rpcCall_signIn err:"); 19 | Log.printStackTrace(TAG, t); 20 | } 21 | return null; 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /app/src/main/java/pansong291/xposed/quickenergy/hook/RpcCall.java: -------------------------------------------------------------------------------- 1 | package pansong291.xposed.quickenergy.hook; 2 | 3 | import android.content.Intent; 4 | import java.lang.reflect.InvocationTargetException; 5 | import java.lang.reflect.Method; 6 | import pansong291.xposed.quickenergy.AntForestToast; 7 | import pansong291.xposed.quickenergy.util.Config; 8 | import pansong291.xposed.quickenergy.util.Log; 9 | 10 | public class RpcCall 11 | { 12 | private static final String TAG = RpcCall.class.getCanonicalName(); 13 | private static Method rpcCallMethod; 14 | private static Method getResponseMethod; 15 | private static Object curH5PageImpl; 16 | public static boolean sendXEdgeProBroadcast; 17 | 18 | public static String invoke(ClassLoader loader, String args0, String args1) 19 | { 20 | if(rpcCallMethod == null) 21 | { 22 | try 23 | { 24 | Class rpcClazz = loader.loadClass(ClassMember.com_alipay_mobile_nebulabiz_rpc_H5RpcUtil); 25 | Class h5PageClazz = loader.loadClass(ClassMember.com_alipay_mobile_h5container_api_H5Page); 26 | Class jsonClazz = loader.loadClass(ClassMember.com_alibaba_fastjson_JSONObject); 27 | rpcCallMethod = rpcClazz.getMethod( 28 | ClassMember.rpcCall, String.class, String.class, String.class, 29 | boolean.class, jsonClazz, String.class, boolean.class, h5PageClazz, 30 | int.class, String.class, boolean.class, int.class); 31 | Log.i(TAG, "get Old RpcCallMethod successfully"); 32 | }catch(Throwable t) 33 | { 34 | Log.i(TAG, "get Old RpcCallMethod err:"); 35 | //Log.printStackTrace(TAG, t); 36 | } 37 | 38 | if(rpcCallMethod == null) 39 | try 40 | { 41 | Class h5PageClazz = loader.loadClass(ClassMember.com_alipay_mobile_h5container_api_H5Page); 42 | Class jsonClazz = loader.loadClass(ClassMember.com_alibaba_fastjson_JSONObject); 43 | Class rpcClazz = loader.loadClass(ClassMember.com_alipay_mobile_nebulaappproxy_api_rpc_H5RpcUtil); 44 | rpcCallMethod = rpcClazz.getMethod( 45 | ClassMember.rpcCall, String.class, String.class, String.class, 46 | boolean.class, jsonClazz, String.class, boolean.class, h5PageClazz, 47 | int.class, String.class, boolean.class, int.class, String.class); 48 | Log.i(TAG, "get RpcCallMethod successfully"); 49 | }catch(Throwable t) 50 | { 51 | Log.i(TAG, "get RpcCallMethod err:"); 52 | //Log.printStackTrace(TAG, t); 53 | } 54 | } 55 | 56 | try 57 | { 58 | Object o = null; 59 | switch(rpcCallMethod.getParameterTypes().length) 60 | { 61 | case 12: 62 | o = rpcCallMethod.invoke( 63 | null, args0, args1, "", true, null, null, false, curH5PageImpl, 0, "", false, -1); 64 | break; 65 | default: 66 | o = rpcCallMethod.invoke( 67 | null, args0, args1, "", true, null, null, false, curH5PageImpl, 0, "", false, -1, ""); 68 | } 69 | String str = getResponse(o); 70 | Log.i(TAG, "argument: " + args0 + ", " + args1); 71 | Log.i(TAG, "response: " + str); 72 | return str; 73 | }catch(Throwable t) 74 | { 75 | Log.i(TAG, "invoke err:"); 76 | Log.printStackTrace(TAG, t); 77 | if(t instanceof InvocationTargetException) 78 | { 79 | if(AntForestToast.context != null && sendXEdgeProBroadcast) 80 | { 81 | sendXEdgeProBroadcast = false; 82 | Intent it = new Intent("com.jozein.xedgepro.PERFORM"); 83 | it.putExtra("data", Config.xedgeproData()); 84 | AntForestToast.context.sendBroadcast(it); 85 | Log.recordLog(t.getCause().getMessage() + ",发送XposedEdgePro广播", ""); 86 | } 87 | } 88 | } 89 | return null; 90 | } 91 | 92 | public static String getResponse(Object resp) 93 | { 94 | try 95 | { 96 | if(getResponseMethod == null) 97 | getResponseMethod = resp.getClass().getMethod(ClassMember.getResponse); 98 | 99 | return (String) getResponseMethod.invoke(resp); 100 | }catch(Throwable t) 101 | { 102 | Log.i(TAG, "getResponse err:"); 103 | Log.printStackTrace(TAG, t); 104 | } 105 | return null; 106 | } 107 | 108 | } 109 | -------------------------------------------------------------------------------- /app/src/main/java/pansong291/xposed/quickenergy/hook/XposedHook.java: -------------------------------------------------------------------------------- 1 | package pansong291.xposed.quickenergy.hook; 2 | 3 | import android.app.AlarmManager; 4 | import android.app.PendingIntent; 5 | import android.app.Service; 6 | import android.content.Intent; 7 | import android.os.Handler; 8 | import android.os.PowerManager; 9 | import de.robv.android.xposed.IXposedHookLoadPackage; 10 | import de.robv.android.xposed.XC_MethodHook; 11 | import de.robv.android.xposed.XC_MethodReplacement; 12 | import de.robv.android.xposed.XposedHelpers; 13 | import de.robv.android.xposed.callbacks.XC_LoadPackage; 14 | import java.util.Map; 15 | import pansong291.xposed.quickenergy.AntCooperate; 16 | import pansong291.xposed.quickenergy.AntFarm; 17 | import pansong291.xposed.quickenergy.AntForest; 18 | import pansong291.xposed.quickenergy.AntForestNotification; 19 | import pansong291.xposed.quickenergy.AntForestToast; 20 | import pansong291.xposed.quickenergy.AntMember; 21 | import pansong291.xposed.quickenergy.AntSports; 22 | import pansong291.xposed.quickenergy.KBMember; 23 | import pansong291.xposed.quickenergy.ui.MainActivity; 24 | import pansong291.xposed.quickenergy.util.Config; 25 | import pansong291.xposed.quickenergy.util.Log; 26 | import pansong291.xposed.quickenergy.util.Statistics; 27 | 28 | public class XposedHook implements IXposedHookLoadPackage 29 | { 30 | private static final String TAG = XposedHook.class.getCanonicalName(); 31 | private static PowerManager.WakeLock wakeLock; 32 | public static Handler handler; 33 | private static Runnable runnable; 34 | private static int times; 35 | 36 | @Override 37 | public void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) throws Throwable 38 | { 39 | if("pansong291.xposed.quickenergy".equals(lpparam.packageName)) 40 | { 41 | XposedHelpers.findAndHookMethod(MainActivity.class.getName(), lpparam.classLoader, "setModuleActive", boolean.class, new XC_MethodHook() 42 | { 43 | @Override 44 | protected void beforeHookedMethod(MethodHookParam param) throws Throwable 45 | { 46 | param.args[0] = true; 47 | } 48 | }); 49 | } 50 | 51 | if(ClassMember.com_eg_android_AlipayGphone.equals(lpparam.packageName)) 52 | { 53 | Log.i(TAG, lpparam.packageName); 54 | hookLauncherService(lpparam.classLoader); 55 | hookRpcCall(lpparam.classLoader); 56 | } 57 | } 58 | 59 | private void hookLauncherService(ClassLoader loader) 60 | { 61 | try 62 | { 63 | XposedHelpers.findAndHookMethod( 64 | ClassMember.com_alipay_android_launcher_service_LauncherService, loader, ClassMember.onCreate, new XC_MethodHook() 65 | { 66 | ClassLoader loader; 67 | 68 | public XC_MethodHook setData(ClassLoader cl) 69 | { 70 | loader = cl; 71 | return this; 72 | } 73 | 74 | @Override 75 | protected void afterHookedMethod(MethodHookParam param) throws Throwable 76 | { 77 | Service service = (Service) param.thisObject; 78 | AntForestToast.context = service.getApplicationContext(); 79 | times = 0; 80 | if(Config.stayAwake()) 81 | { 82 | PowerManager pm = (PowerManager) service.getSystemService(service.POWER_SERVICE); 83 | wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, service.getClass().getName()); 84 | wakeLock.acquire(); 85 | } 86 | if(handler == null) handler = new Handler(); 87 | if(runnable == null) runnable = new Runnable() 88 | { 89 | Service service; 90 | ClassLoader loader; 91 | 92 | public Runnable setData(Service s, ClassLoader cl) 93 | { 94 | service = s; 95 | loader = cl; 96 | return this; 97 | } 98 | 99 | @Override 100 | public void run() 101 | { 102 | Config.shouldReload = true; 103 | RpcCall.sendXEdgeProBroadcast = true; 104 | Statistics.resetToday(); 105 | AntForest.checkEnergyRanking(loader, times); 106 | AntCooperate.start(loader, times); 107 | AntFarm.start(loader); 108 | AntMember.receivePoint(loader, times); 109 | AntSports.start(loader, times); 110 | KBMember.start(loader); 111 | if(Config.collectEnergy() || Config.enableFarm()) 112 | handler.postDelayed(this, Config.checkInterval()); 113 | else AntForestNotification.stop(service, false); 114 | times = (times + 1) % (3600_000 / Config.checkInterval()); 115 | } 116 | }.setData(service, loader); 117 | if(Config.collectEnergy() || Config.enableFarm()) 118 | { 119 | AntForestNotification.start(service); 120 | handler.post(runnable); 121 | } 122 | } 123 | }.setData(loader)); 124 | Log.i(TAG, "hook " + ClassMember.onCreate + " successfully"); 125 | }catch(Throwable t) 126 | { 127 | Log.i(TAG, "hook " + ClassMember.onCreate + " err:"); 128 | Log.printStackTrace(TAG, t); 129 | } 130 | 131 | try 132 | { 133 | XposedHelpers.findAndHookMethod(ClassMember.com_alipay_android_launcher_service_LauncherService, loader, ClassMember.onDestroy, new XC_MethodHook() 134 | { 135 | @Override 136 | protected void afterHookedMethod(MethodHookParam param) throws Throwable 137 | { 138 | if(wakeLock != null) 139 | { 140 | wakeLock.release(); 141 | wakeLock = null; 142 | } 143 | Service service = (Service) param.thisObject; 144 | AntForestNotification.stop(service, false); 145 | AntForestNotification.setContentText("支付宝前台服务被销毁"); 146 | Log.recordLog("支付宝前台服务被销毁", ""); 147 | handler.removeCallbacks(runnable); 148 | if(Config.autoRestart()) 149 | { 150 | AlarmManager alarmManager = (AlarmManager) service.getSystemService(service.ALARM_SERVICE); 151 | Intent it = new Intent(); 152 | it.setClassName(ClassMember.com_eg_android_AlipayGphone, ClassMember.com_alipay_android_launcher_service_LauncherService); 153 | PendingIntent pi = PendingIntent.getService(service, 0, it, PendingIntent.FLAG_UPDATE_CURRENT); 154 | alarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + 1000, pi); 155 | } 156 | } 157 | }); 158 | Log.i(TAG, "hook " + ClassMember.onDestroy + " successfully"); 159 | }catch(Throwable t) 160 | { 161 | Log.i(TAG, "hook " + ClassMember.onDestroy + " err:"); 162 | Log.printStackTrace(TAG, t); 163 | } 164 | } 165 | 166 | private void hookRpcCall(ClassLoader loader) 167 | { 168 | try 169 | { 170 | Class clazz = loader.loadClass(ClassMember.com_alipay_mobile_nebulaappproxy_api_rpc_H5AppRpcUpdate); 171 | Class H5PageClazz = loader.loadClass(ClassMember.com_alipay_mobile_h5container_api_H5Page); 172 | XposedHelpers.findAndHookMethod( 173 | clazz, ClassMember.matchVersion, H5PageClazz, Map.class, String.class, 174 | XC_MethodReplacement.returnConstant(false)); 175 | Log.i(TAG, "hook " + ClassMember.matchVersion + " successfully"); 176 | }catch(Throwable t) 177 | { 178 | Log.i(TAG, "hook " + ClassMember.matchVersion + " err:"); 179 | Log.printStackTrace(TAG, t); 180 | } 181 | 182 | } 183 | 184 | 185 | } 186 | -------------------------------------------------------------------------------- /app/src/main/java/pansong291/xposed/quickenergy/ui/AlipayCooperate.java: -------------------------------------------------------------------------------- 1 | package pansong291.xposed.quickenergy.ui; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.Map; 6 | import java.util.Set; 7 | import pansong291.xposed.quickenergy.util.CooperationIdMap; 8 | 9 | public class AlipayCooperate extends AlipayId 10 | { 11 | private static List list; 12 | 13 | public AlipayCooperate(String i, String n) 14 | { 15 | id = i; 16 | name = n; 17 | } 18 | 19 | public static List getList() 20 | { 21 | if(list == null || CooperationIdMap.shouldReload) 22 | { 23 | list = new ArrayList(); 24 | Set idSet = CooperationIdMap.getIdMap().entrySet(); 25 | for(Map.Entry entry: idSet) 26 | { 27 | list.add(new AlipayCooperate(entry.getKey().toString(), entry.getValue().toString())); 28 | } 29 | } 30 | return list; 31 | } 32 | 33 | public static void remove(String id) 34 | { 35 | getList(); 36 | for(int i = 0; i < list.size(); i++) 37 | { 38 | if(list.get(i).id.equals(id)) 39 | { 40 | list.remove(i); 41 | break; 42 | } 43 | } 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /app/src/main/java/pansong291/xposed/quickenergy/ui/AlipayId.java: -------------------------------------------------------------------------------- 1 | package pansong291.xposed.quickenergy.ui; 2 | 3 | public class AlipayId 4 | { 5 | public String name; 6 | public String id; 7 | } 8 | -------------------------------------------------------------------------------- /app/src/main/java/pansong291/xposed/quickenergy/ui/AlipayUser.java: -------------------------------------------------------------------------------- 1 | package pansong291.xposed.quickenergy.ui; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.Map; 6 | import java.util.Set; 7 | import pansong291.xposed.quickenergy.util.FriendIdMap; 8 | 9 | public class AlipayUser extends AlipayId 10 | { 11 | private static List list; 12 | 13 | public AlipayUser(String i, String n) 14 | { 15 | id = i; 16 | name = n; 17 | } 18 | 19 | public static List getList() 20 | { 21 | if(list == null || FriendIdMap.shouldReload) 22 | { 23 | list = new ArrayList(); 24 | Set idSet = FriendIdMap.getIdMap().entrySet(); 25 | for(Map.Entry entry: idSet) 26 | { 27 | list.add(new AlipayUser(entry.getKey().toString(), entry.getValue().toString())); 28 | } 29 | } 30 | return list; 31 | } 32 | 33 | public static void remove(String id) 34 | { 35 | getList(); 36 | for(int i = 0; i < list.size(); i++) 37 | { 38 | if(list.get(i).id.equals(id)) 39 | { 40 | list.remove(i); 41 | break; 42 | } 43 | } 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /app/src/main/java/pansong291/xposed/quickenergy/ui/ChoiceDialog.java: -------------------------------------------------------------------------------- 1 | package pansong291.xposed.quickenergy.ui; 2 | 3 | import android.app.AlertDialog; 4 | import android.content.Context; 5 | import android.content.DialogInterface; 6 | import android.content.DialogInterface.OnClickListener; 7 | import pansong291.xposed.quickenergy.AntFarm.SendType; 8 | import pansong291.xposed.quickenergy.util.Config; 9 | import pansong291.xposed.quickenergy.util.Config.RecallAnimalType; 10 | 11 | public class ChoiceDialog 12 | { 13 | private static AlertDialog 14 | sendTypeDialog, recallAnimalTypeDialog; 15 | 16 | public static void showSendType(Context c, CharSequence title) 17 | { 18 | try 19 | { 20 | getSendTypeDialog(c, title).show(); 21 | }catch(Throwable t) 22 | { 23 | sendTypeDialog = null; 24 | getSendTypeDialog(c, title).show(); 25 | } 26 | } 27 | 28 | private static AlertDialog getSendTypeDialog(Context c, CharSequence title) 29 | { 30 | if(sendTypeDialog == null) 31 | sendTypeDialog = new AlertDialog.Builder(c) 32 | .setTitle(title) 33 | .setSingleChoiceItems(SendType.names, Config.sendType().ordinal(), 34 | new OnClickListener() 35 | { 36 | @Override 37 | public void onClick(DialogInterface p1, int p2) 38 | { 39 | Config.setSendType(p2); 40 | } 41 | }) 42 | .setPositiveButton("OK", null) 43 | .create(); 44 | return sendTypeDialog; 45 | } 46 | 47 | public static void showRecallAnimalType(Context c, CharSequence title) 48 | { 49 | try 50 | { 51 | getRecallAnimalTypeDialog(c, title).show(); 52 | }catch(Throwable t) 53 | { 54 | recallAnimalTypeDialog = null; 55 | getRecallAnimalTypeDialog(c, title).show(); 56 | } 57 | } 58 | 59 | private static AlertDialog getRecallAnimalTypeDialog(Context c, CharSequence title) 60 | { 61 | if(recallAnimalTypeDialog == null) 62 | recallAnimalTypeDialog = new AlertDialog.Builder(c) 63 | .setTitle(title) 64 | .setSingleChoiceItems(RecallAnimalType.names, Config.recallAnimalType().ordinal(), 65 | new OnClickListener() 66 | { 67 | @Override 68 | public void onClick(DialogInterface p1, int p2) 69 | { 70 | Config.setRecallAnimalType(p2); 71 | } 72 | }) 73 | .setPositiveButton("OK", null) 74 | .create(); 75 | return recallAnimalTypeDialog; 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /app/src/main/java/pansong291/xposed/quickenergy/ui/EditDialog.java: -------------------------------------------------------------------------------- 1 | package pansong291.xposed.quickenergy.ui; 2 | 3 | import android.app.AlertDialog; 4 | import android.content.Context; 5 | import android.content.DialogInterface; 6 | import android.content.DialogInterface.OnClickListener; 7 | import android.widget.EditText; 8 | import pansong291.xposed.quickenergy.util.Config; 9 | 10 | public class EditDialog 11 | { 12 | private static AlertDialog editDialog; 13 | private static EditText edt; 14 | public enum EditMode 15 | { CHECK_INTERVAL, THREAD_COUNT, ADVANCE_TIME, COLLECT_INTERVAL, 16 | COLLECT_TIMEOUT, RETURN_WATER_30, RETURN_WATER_20, RETURN_WATER_10, 17 | MIN_EXCHANGE_COUNT, LATEST_EXCHANGE_TIME } 18 | private static EditMode mode; 19 | 20 | public static void showEditDialog(Context c, CharSequence title, EditMode em) 21 | { 22 | mode = em; 23 | try 24 | { 25 | getEditDialog(c).show(); 26 | }catch(Throwable t) 27 | { 28 | editDialog = null; 29 | getEditDialog(c).show(); 30 | } 31 | editDialog.setTitle(title); 32 | } 33 | 34 | private static AlertDialog getEditDialog(Context c) 35 | { 36 | if(editDialog == null) 37 | { 38 | edt = new EditText(c); 39 | editDialog = new AlertDialog.Builder(c) 40 | .setTitle("title") 41 | .setView(edt) 42 | .setPositiveButton( 43 | "OK", 44 | new OnClickListener() 45 | { 46 | Context context; 47 | 48 | public OnClickListener setData(Context c) 49 | { 50 | context = c; 51 | return this; 52 | } 53 | 54 | @Override 55 | public void onClick(DialogInterface p1, int p2) 56 | { 57 | try 58 | { 59 | int i = Integer.parseInt(edt.getText().toString()); 60 | switch(mode) 61 | { 62 | case CHECK_INTERVAL: 63 | if(i > 0) 64 | Config.setCheckInterval(i * 60_000); 65 | break; 66 | 67 | case THREAD_COUNT: 68 | if(i >= 0) 69 | Config.setThreadCount(i); 70 | break; 71 | 72 | case ADVANCE_TIME: 73 | Config.setAdvanceTime(i); 74 | break; 75 | 76 | case COLLECT_INTERVAL: 77 | if(i >= 0) 78 | Config.setCollectInterval(i); 79 | break; 80 | 81 | case COLLECT_TIMEOUT: 82 | if(i > 0) 83 | Config.setCollectTimeout(i * 1_000); 84 | break; 85 | 86 | case RETURN_WATER_30: 87 | if(i >= 0) 88 | Config.setReturnWater30(i); 89 | break; 90 | 91 | case RETURN_WATER_20: 92 | 93 | if(i >= 0) 94 | Config.setReturnWater20(i); 95 | break; 96 | 97 | case RETURN_WATER_10: 98 | if(i >= 0) 99 | Config.setReturnWater10(i); 100 | break; 101 | 102 | case MIN_EXCHANGE_COUNT: 103 | if(i >= 0) 104 | Config.setMinExchangeCount(i); 105 | break; 106 | 107 | case LATEST_EXCHANGE_TIME: 108 | if(i >= 0 && i < 24) 109 | Config.setLatestExchangeTime(i); 110 | break; 111 | 112 | } 113 | }catch(Throwable t) 114 | {} 115 | } 116 | }.setData(c)) 117 | .create(); 118 | } 119 | String str = ""; 120 | switch(mode) 121 | { 122 | case CHECK_INTERVAL: 123 | str = String.valueOf(Config.checkInterval() / 60_000); 124 | break; 125 | 126 | case THREAD_COUNT: 127 | str = String.valueOf(Config.threadCount()); 128 | break; 129 | 130 | case ADVANCE_TIME: 131 | str = String.valueOf(Config.advanceTime()); 132 | break; 133 | 134 | case COLLECT_INTERVAL: 135 | str = String.valueOf(Config.collectInterval()); 136 | break; 137 | 138 | case COLLECT_TIMEOUT: 139 | str = String.valueOf(Config.collectTimeout() / 1_000); 140 | break; 141 | 142 | case RETURN_WATER_30: 143 | str = String.valueOf(Config.returnWater30()); 144 | break; 145 | 146 | case RETURN_WATER_20: 147 | str = String.valueOf(Config.returnWater20()); 148 | break; 149 | 150 | case RETURN_WATER_10: 151 | str = String.valueOf(Config.returnWater10()); 152 | break; 153 | 154 | case MIN_EXCHANGE_COUNT: 155 | str = String.valueOf(Config.minExchangeCount()); 156 | break; 157 | 158 | case LATEST_EXCHANGE_TIME: 159 | str = String.valueOf(Config.latestExchangeTime()); 160 | break; 161 | 162 | } 163 | edt.setText(str); 164 | return editDialog; 165 | } 166 | 167 | } 168 | -------------------------------------------------------------------------------- /app/src/main/java/pansong291/xposed/quickenergy/ui/HtmlViewerActivity.java: -------------------------------------------------------------------------------- 1 | package pansong291.xposed.quickenergy.ui; 2 | 3 | import android.app.Activity; 4 | import android.content.ClipboardManager; 5 | import android.content.Intent; 6 | import android.os.Bundle; 7 | import android.view.Menu; 8 | import android.view.MenuItem; 9 | import android.view.View; 10 | import android.webkit.WebChromeClient; 11 | import android.webkit.WebView; 12 | import android.widget.ProgressBar; 13 | import android.widget.Toast; 14 | import pansong291.xposed.quickenergy.R; 15 | 16 | public class HtmlViewerActivity extends Activity 17 | { 18 | MyWebView mWebView; 19 | ProgressBar pgb; 20 | 21 | @Override 22 | protected void onCreate(Bundle savedInstanceState) 23 | { 24 | super.onCreate(savedInstanceState); 25 | setContentView(R.layout.activity_html_viewer); 26 | 27 | mWebView = (MyWebView) findViewById(R.id.mwv_webview); 28 | pgb = (ProgressBar) findViewById(R.id.pgb_webview); 29 | 30 | mWebView.setWebChromeClient( 31 | new WebChromeClient() 32 | { 33 | @Override 34 | public void onProgressChanged(WebView view, int progress) 35 | { 36 | pgb.setProgress(progress); 37 | if(progress < 100) 38 | { 39 | setTitle("Loading..."); 40 | pgb.setVisibility(View.VISIBLE); 41 | }else 42 | { 43 | setTitle(mWebView.getTitle()); 44 | pgb.setVisibility(View.GONE); 45 | } 46 | } 47 | }); 48 | mWebView.loadUrl(getIntent().getData().toString()); 49 | } 50 | 51 | @Override 52 | public boolean onCreateOptionsMenu(Menu menu) 53 | { 54 | menu.add(0, 1, 0, "Open with other browser"); 55 | menu.add(0, 2, 0, "Copy the url"); 56 | menu.add(0, 3, 0, "Scroll to top"); 57 | menu.add(0, 4, 0, "Scroll to bottom"); 58 | return super.onCreateOptionsMenu(menu); 59 | } 60 | 61 | @Override 62 | public boolean onOptionsItemSelected(MenuItem item) 63 | { 64 | switch(item.getItemId()) 65 | { 66 | case 1: 67 | Intent it = new Intent(Intent.ACTION_VIEW); 68 | it.addCategory(Intent.CATEGORY_DEFAULT); 69 | it.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 70 | it.setDataAndType(getIntent().getData(), "text/html"); 71 | startActivity(Intent.createChooser(it, "Choose a browser")); 72 | break; 73 | 74 | case 2: 75 | ClipboardManager cm = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE); 76 | cm.setText(mWebView.getUrl()); 77 | Toast.makeText(this, "Copy success", 0).show(); 78 | break; 79 | 80 | case 3: 81 | mWebView.scrollTo(0, 0); 82 | break; 83 | 84 | case 4: 85 | mWebView.scrollToBottom(); 86 | break; 87 | } 88 | return true; 89 | } 90 | 91 | } 92 | -------------------------------------------------------------------------------- /app/src/main/java/pansong291/xposed/quickenergy/ui/ListAdapter.java: -------------------------------------------------------------------------------- 1 | package pansong291.xposed.quickenergy.ui; 2 | 3 | import android.content.Context; 4 | import android.graphics.Color; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.widget.BaseAdapter; 9 | import android.widget.CheckBox; 10 | import android.widget.TextView; 11 | import java.util.List; 12 | import pansong291.xposed.quickenergy.R; 13 | 14 | public class ListAdapter extends BaseAdapter 15 | { 16 | private static ListAdapter adapter; 17 | 18 | public static ListAdapter get(Context c) 19 | { 20 | if(adapter == null) 21 | adapter = new ListAdapter(c); 22 | return adapter; 23 | } 24 | 25 | Context context; 26 | List list; 27 | List selects; 28 | int findIndex = -1; 29 | CharSequence findWord = null; 30 | 31 | private ListAdapter(Context c) 32 | { 33 | context = c; 34 | } 35 | 36 | public void setBaseList(List l) 37 | { 38 | if(l != list) exitFind(); 39 | list = l; 40 | } 41 | 42 | public void setSelectedList(List l) 43 | { 44 | selects = l; 45 | } 46 | 47 | public int findLast(CharSequence cs) 48 | { 49 | if(list == null || list.size() == 0) return -1; 50 | if(!cs.equals(findWord)) 51 | { 52 | findIndex = -1; 53 | findWord = cs; 54 | } 55 | int i = findIndex; 56 | if(i < 0) i = list.size(); 57 | for(;;) 58 | { 59 | i = (i + list.size() - 1) % list.size(); 60 | AlipayId ai = (AlipayId) list.get(i); 61 | if(ai.name.contains(cs)) 62 | { 63 | findIndex = i; 64 | break; 65 | } 66 | if(findIndex < 0 && i == 0) 67 | break; 68 | } 69 | notifyDataSetChanged(); 70 | return findIndex; 71 | } 72 | 73 | public int findNext(CharSequence cs) 74 | { 75 | if(list == null || list.size() == 0) return -1; 76 | if(!cs.equals(findWord)) 77 | { 78 | findIndex = -1; 79 | findWord = cs; 80 | } 81 | for(int i = findIndex;;) 82 | { 83 | i = (i + 1) % list.size(); 84 | AlipayId ai = (AlipayId) list.get(i); 85 | if(ai.name.contains(cs)) 86 | { 87 | findIndex = i; 88 | break; 89 | } 90 | if(findIndex < 0 && i == list.size() - 1) 91 | break; 92 | } 93 | notifyDataSetChanged(); 94 | return findIndex; 95 | } 96 | 97 | public void exitFind() 98 | { 99 | findIndex = -1; 100 | } 101 | 102 | @Override 103 | public int getCount() 104 | { 105 | return list == null ? 0: list.size(); 106 | } 107 | 108 | @Override 109 | public Object getItem(int p1) 110 | { 111 | return list.get(p1); 112 | } 113 | 114 | @Override 115 | public long getItemId(int p1) 116 | { 117 | return p1; 118 | } 119 | 120 | @Override 121 | public View getView(int p1, View p2, ViewGroup p3) 122 | { 123 | ViewHolder vh; 124 | if(p2 == null) 125 | { 126 | vh = new ViewHolder(); 127 | p2 = LayoutInflater.from(context).inflate(R.layout.list_item, null); 128 | vh.tv = p2.findViewById(R.id.tv_idn); 129 | vh.cb = p2.findViewById(R.id.cb_list); 130 | p2.setTag(vh); 131 | }else 132 | { 133 | vh = (ViewHolder)p2.getTag(); 134 | } 135 | 136 | AlipayId ai = (AlipayId) list.get(p1); 137 | vh.tv.setText(ai.name); 138 | vh.tv.setTextColor(findIndex == p1 ? Color.RED: Color.BLACK); 139 | vh.cb.setChecked(selects == null ? false: selects.contains(ai.id)); 140 | return p2; 141 | } 142 | 143 | class ViewHolder 144 | { 145 | TextView tv; 146 | CheckBox cb; 147 | } 148 | 149 | } 150 | -------------------------------------------------------------------------------- /app/src/main/java/pansong291/xposed/quickenergy/ui/ListDialog.java: -------------------------------------------------------------------------------- 1 | package pansong291.xposed.quickenergy.ui; 2 | 3 | import android.app.AlertDialog; 4 | import android.content.Context; 5 | import android.content.DialogInterface; 6 | import android.content.DialogInterface.OnClickListener; 7 | import android.content.DialogInterface.OnShowListener; 8 | import android.content.Intent; 9 | import android.net.Uri; 10 | import android.view.LayoutInflater; 11 | import android.view.View; 12 | import android.widget.AdapterView; 13 | import android.widget.AdapterView.OnItemClickListener; 14 | import android.widget.AdapterView.OnItemLongClickListener; 15 | import android.widget.Button; 16 | import android.widget.EditText; 17 | import android.widget.ListView; 18 | import android.widget.Toast; 19 | import java.util.List; 20 | import pansong291.xposed.quickenergy.R; 21 | import pansong291.xposed.quickenergy.util.Config; 22 | import pansong291.xposed.quickenergy.util.CooperationIdMap; 23 | import pansong291.xposed.quickenergy.util.FriendIdMap; 24 | 25 | public class ListDialog 26 | { 27 | static AlertDialog listDialog; 28 | static Button btn_find_last, btn_find_next; 29 | static EditText edt_find; 30 | static ListView lv_list; 31 | static List selectedList; 32 | static List countList; 33 | static ListAdapter.ViewHolder curViewHolder; 34 | static AlipayId curAlipayId; 35 | 36 | static AlertDialog edtDialog; 37 | static EditText edt_count; 38 | 39 | static AlertDialog optionsDialog; 40 | static AlertDialog deleteDialog; 41 | 42 | public static void show(Context c, CharSequence title, List bl, List sl, List cl) 43 | { 44 | selectedList = sl; 45 | countList = cl; 46 | ListAdapter la = ListAdapter.get(c); 47 | la.setBaseList(bl); 48 | la.setSelectedList(selectedList); 49 | showListDialog(c, title); 50 | } 51 | 52 | private static void showListDialog(Context c, CharSequence title) 53 | { 54 | try 55 | { 56 | getListDialog(c).show(); 57 | }catch(Throwable t) 58 | { 59 | listDialog = null; 60 | getListDialog(c).show(); 61 | } 62 | listDialog.setTitle(title); 63 | } 64 | 65 | private static AlertDialog getListDialog(Context c) 66 | { 67 | if(listDialog == null) 68 | listDialog = new AlertDialog.Builder(c) 69 | .setTitle("title") 70 | .setView(getListView(c)) 71 | .setPositiveButton("OK", null) 72 | .create(); 73 | listDialog.setOnShowListener( 74 | new OnShowListener() 75 | { 76 | Context c; 77 | 78 | public OnShowListener setContext(Context c) 79 | { 80 | this.c = c; 81 | return this; 82 | } 83 | 84 | @Override 85 | public void onShow(DialogInterface p1) 86 | { 87 | ListAdapter.get(c).notifyDataSetChanged(); 88 | } 89 | }.setContext(c)); 90 | return listDialog; 91 | } 92 | 93 | private static View getListView(Context c) 94 | { 95 | View v = LayoutInflater.from(c).inflate(R.layout.dialog_list, null); 96 | OnBtnClickListener onBtnClickListener = new OnBtnClickListener(); 97 | btn_find_last = v.findViewById(R.id.btn_find_last); 98 | btn_find_next = v.findViewById(R.id.btn_find_next); 99 | btn_find_last.setOnClickListener(onBtnClickListener); 100 | btn_find_next.setOnClickListener(onBtnClickListener); 101 | edt_find = v.findViewById(R.id.edt_find); 102 | lv_list = v.findViewById(R.id.lv_list); 103 | lv_list.setAdapter(ListAdapter.get(c)); 104 | lv_list.setOnItemClickListener( 105 | new OnItemClickListener() 106 | { 107 | @Override 108 | public void onItemClick(AdapterView p1, View p2, int p3, long p4) 109 | { 110 | curViewHolder = (ListAdapter.ViewHolder) p2.getTag(); 111 | curAlipayId = (AlipayId) p1.getAdapter().getItem(p3); 112 | if(countList == null) 113 | { 114 | if(curViewHolder.cb.isChecked()) 115 | { 116 | if(selectedList.contains(curAlipayId.id)) 117 | selectedList.remove(curAlipayId.id); 118 | curViewHolder.cb.setChecked(false); 119 | }else 120 | { 121 | if(!selectedList.contains(curAlipayId.id)) 122 | selectedList.add(curAlipayId.id); 123 | curViewHolder.cb.setChecked(true); 124 | } 125 | Config.hasChanged = true; 126 | }else 127 | { 128 | showEdtDialog(p1.getContext()); 129 | } 130 | } 131 | }); 132 | lv_list.setOnItemLongClickListener( 133 | new OnItemLongClickListener() 134 | { 135 | @Override 136 | public boolean onItemLongClick(AdapterView p1, View p2, int p3, long p4) 137 | { 138 | curAlipayId = (AlipayId) p1.getAdapter().getItem(p3); 139 | if(curAlipayId instanceof AlipayCooperate) 140 | { 141 | showDeleteDialog(p1.getContext()); 142 | }else 143 | { 144 | showOptionsDialog(p1.getContext()); 145 | } 146 | return true; 147 | } 148 | }); 149 | return v; 150 | } 151 | 152 | private static void showEdtDialog(Context c) 153 | { 154 | try 155 | { 156 | getEdtDialog(c).show(); 157 | }catch(Throwable t) 158 | { 159 | edtDialog = null; 160 | getEdtDialog(c).show(); 161 | } 162 | edtDialog.setTitle(curAlipayId.name); 163 | if(curAlipayId instanceof AlipayCooperate) 164 | edt_count.setHint("grams"); 165 | else 166 | edt_count.setHint("count"); 167 | int i = selectedList.indexOf(curAlipayId.id); 168 | if(i >= 0) 169 | edt_count.setText(String.valueOf(countList.get(i))); 170 | else 171 | edt_count.getText().clear(); 172 | } 173 | 174 | private static AlertDialog getEdtDialog(Context c) 175 | { 176 | if(edtDialog == null) 177 | { 178 | OnClickListener listener = new OnClickListener() 179 | { 180 | Context c; 181 | 182 | public OnClickListener setContext(Context c) 183 | { 184 | this.c = c; 185 | return this; 186 | } 187 | 188 | @Override 189 | public void onClick(DialogInterface p1, int p2) 190 | { 191 | switch(p2) 192 | { 193 | case DialogInterface.BUTTON_POSITIVE: 194 | int count = 0; 195 | if(edt_count.length() > 0) 196 | try 197 | { 198 | count = Integer.parseInt(edt_count.getText().toString()); 199 | }catch(Throwable t) 200 | { 201 | return; 202 | } 203 | int index = selectedList.indexOf(curAlipayId.id); 204 | if(count > 0) 205 | { 206 | if(index < 0) 207 | { 208 | selectedList.add(curAlipayId.id); 209 | countList.add(count); 210 | }else 211 | { 212 | countList.set(index, count); 213 | } 214 | curViewHolder.cb.setChecked(true); 215 | }else 216 | { 217 | if(index >= 0) 218 | { 219 | selectedList.remove(index); 220 | countList.remove(index); 221 | } 222 | curViewHolder.cb.setChecked(false); 223 | } 224 | Config.hasChanged = true; 225 | break; 226 | } 227 | ListAdapter.get(c).notifyDataSetChanged(); 228 | } 229 | }.setContext(c); 230 | edt_count = new EditText(c); 231 | edtDialog = new AlertDialog.Builder(c) 232 | .setTitle("title") 233 | .setView(edt_count) 234 | .setPositiveButton("OK", listener) 235 | .setNegativeButton("CANCEL", null) 236 | .create(); 237 | } 238 | return edtDialog; 239 | } 240 | 241 | private static void showOptionsDialog(Context c) 242 | { 243 | try 244 | { 245 | getOptionsDailog(c).show(); 246 | }catch(Throwable t) 247 | { 248 | optionsDialog = null; 249 | getOptionsDailog(c).show(); 250 | } 251 | } 252 | 253 | private static AlertDialog getOptionsDailog(Context c) 254 | { 255 | if(optionsDialog == null) 256 | { 257 | optionsDialog = new AlertDialog.Builder(c) 258 | .setTitle("Options") 259 | .setAdapter( 260 | OptionsAdapter.get(c), new OnClickListener() 261 | { 262 | Context c; 263 | 264 | public OnClickListener setContext(Context c) 265 | { 266 | this.c = c; 267 | return this; 268 | } 269 | 270 | @Override 271 | public void onClick(DialogInterface p1, int p2) 272 | { 273 | String url = null; 274 | switch(p2) 275 | { 276 | case 0: 277 | url = "alipays://platformapi/startapp?saId=10000007&qrcode=https%3A%2F%2F60000002.h5app.alipay.com%2Fwww%2Fhome.html%3FuserId%3D"; 278 | break; 279 | 280 | case 1: 281 | url = "alipays://platformapi/startapp?saId=10000007&qrcode=https%3A%2F%2F66666674.h5app.alipay.com%2Fwww%2Findex.htm%3Fuid%3D"; 282 | break; 283 | 284 | case 2: 285 | showDeleteDialog(c); 286 | } 287 | if(url != null && !url.isEmpty()) 288 | { 289 | Intent it = new Intent(Intent.ACTION_VIEW, Uri.parse(url + curAlipayId.id)); 290 | c.startActivity(it); 291 | } 292 | } 293 | }.setContext(c)) 294 | .setNegativeButton("CANCEL", null) 295 | .create(); 296 | } 297 | return optionsDialog; 298 | } 299 | 300 | private static void showDeleteDialog(Context c) 301 | { 302 | try 303 | { 304 | getDeleteDialog(c).show(); 305 | }catch(Throwable t) 306 | { 307 | deleteDialog = null; 308 | getDeleteDialog(c).show(); 309 | } 310 | deleteDialog.setTitle("Delete " + curAlipayId.name); 311 | } 312 | 313 | private static AlertDialog getDeleteDialog(Context c) 314 | { 315 | if(deleteDialog == null) 316 | { 317 | OnClickListener listener = new OnClickListener() 318 | { 319 | Context c; 320 | 321 | public OnClickListener setContext(Context c) 322 | { 323 | this.c = c; 324 | return this; 325 | } 326 | 327 | @Override 328 | public void onClick(DialogInterface p1, int p2) 329 | { 330 | switch(p2) 331 | { 332 | case DialogInterface.BUTTON_POSITIVE: 333 | if(curAlipayId instanceof AlipayUser) 334 | { 335 | FriendIdMap.removeIdMap(curAlipayId.id); 336 | AlipayUser.remove(curAlipayId.id); 337 | }else if(curAlipayId instanceof AlipayCooperate) 338 | { 339 | CooperationIdMap.removeIdMap(curAlipayId.id); 340 | AlipayCooperate.remove(curAlipayId.id); 341 | } 342 | if(selectedList.contains(curAlipayId.id)) 343 | selectedList.remove(curAlipayId.id); 344 | ListAdapter.get(c).exitFind(); 345 | break; 346 | } 347 | ListAdapter.get(c).notifyDataSetChanged(); 348 | } 349 | }.setContext(c); 350 | deleteDialog = new AlertDialog.Builder(c) 351 | .setTitle("title") 352 | .setPositiveButton("OK", listener) 353 | .setNegativeButton("CANCEL", null) 354 | .create(); 355 | } 356 | return deleteDialog; 357 | } 358 | 359 | static class OnBtnClickListener implements View.OnClickListener 360 | { 361 | @Override 362 | public void onClick(View p1) 363 | { 364 | if(edt_find.length() <= 0) return; 365 | ListAdapter la = ListAdapter.get(p1.getContext()); 366 | int index = -1; 367 | switch(p1.getId()) 368 | { 369 | case R.id.btn_find_last: 370 | // 下面Text要转String,不然判断equals会出问题 371 | index = la.findLast(edt_find.getText().toString()); 372 | break; 373 | 374 | case R.id.btn_find_next: 375 | // 同上 376 | index = la.findNext(edt_find.getText().toString()); 377 | break; 378 | } 379 | if(index < 0) 380 | { 381 | Toast.makeText(p1.getContext(), "Not found", Toast.LENGTH_SHORT).show(); 382 | }else 383 | { 384 | lv_list.setSelection(index); 385 | } 386 | } 387 | } 388 | 389 | } 390 | -------------------------------------------------------------------------------- /app/src/main/java/pansong291/xposed/quickenergy/ui/MainActivity.java: -------------------------------------------------------------------------------- 1 | package pansong291.xposed.quickenergy.ui; 2 | 3 | import android.app.Activity; 4 | import android.content.ComponentName; 5 | import android.content.ContentResolver; 6 | import android.content.Context; 7 | import android.content.Intent; 8 | import android.content.pm.PackageManager; 9 | import android.net.Uri; 10 | import android.os.Bundle; 11 | import android.view.Menu; 12 | import android.view.MenuItem; 13 | import android.view.View; 14 | import android.widget.Button; 15 | import android.widget.TextView; 16 | import android.widget.Toast; 17 | import pansong291.xposed.quickenergy.R; 18 | import pansong291.xposed.quickenergy.util.FileUtils; 19 | import pansong291.xposed.quickenergy.util.RandomUtils; 20 | import pansong291.xposed.quickenergy.util.Statistics; 21 | 22 | public class MainActivity extends Activity 23 | { 24 | private static String[] strArray; 25 | TextView tv_statistics; 26 | Button btn_help; 27 | 28 | @Override 29 | protected void onCreate(Bundle savedInstanceState) 30 | { 31 | super.onCreate(savedInstanceState); 32 | setContentView(R.layout.activity_main); 33 | setModuleActive(false); 34 | 35 | tv_statistics = (TextView) findViewById(R.id.tv_statistics); 36 | btn_help = (Button) findViewById(R.id.btn_help); 37 | if(strArray == null) 38 | strArray = getResources().getStringArray(R.array.sentences); 39 | if(strArray != null) 40 | btn_help.setText(strArray[RandomUtils.nextInt(0, strArray.length)]); 41 | } 42 | 43 | @Override 44 | protected void onResume() 45 | { 46 | super.onResume(); 47 | tv_statistics.setText(Statistics.getText()); 48 | } 49 | 50 | public void onClick(View v) 51 | { 52 | String data = "file://"; 53 | switch(v.getId()) 54 | { 55 | case R.id.btn_forest_log: 56 | data += FileUtils.getForestLogFile().getAbsolutePath(); 57 | break; 58 | 59 | case R.id.btn_farm_log: 60 | data += FileUtils.getFarmLogFile().getAbsolutePath(); 61 | break; 62 | 63 | case R.id.btn_other_log: 64 | data += FileUtils.getOtherLogFile().getAbsolutePath(); 65 | break; 66 | 67 | case R.id.btn_help: 68 | data = "https://github.com/pansong291/XQuickEnergy/wiki"; 69 | break; 70 | } 71 | Intent it = new Intent(this, HtmlViewerActivity.class); 72 | it.setData(Uri.parse(data)); 73 | startActivity(it); 74 | } 75 | 76 | @Override 77 | public boolean onCreateOptionsMenu(Menu menu) 78 | { 79 | int state = getPackageManager() 80 | .getComponentEnabledSetting(new ComponentName(this, getClass().getCanonicalName() + "Alias")); 81 | menu.add(0, 1, 0, "Hide the application icon") 82 | .setCheckable(true) 83 | .setChecked(state > PackageManager.COMPONENT_ENABLED_STATE_ENABLED); 84 | menu.add(0, 2, 0, "Export the statistic file"); 85 | menu.add(0, 3, 0, "Import the statistic file"); 86 | menu.add(0, 4, 0, "Settings"); 87 | return super.onCreateOptionsMenu(menu); 88 | } 89 | 90 | @Override 91 | public boolean onOptionsItemSelected(MenuItem item) 92 | { 93 | switch(item.getItemId()) 94 | { 95 | case 1: 96 | int state = item.isChecked() ? PackageManager.COMPONENT_ENABLED_STATE_DEFAULT: PackageManager.COMPONENT_ENABLED_STATE_DISABLED; 97 | getPackageManager() 98 | .setComponentEnabledSetting(new ComponentName(this, getClass().getCanonicalName() + "Alias"), state, PackageManager.DONT_KILL_APP); 99 | item.setChecked(!item.isChecked()); 100 | break; 101 | 102 | case 2: 103 | if(FileUtils.copyTo(FileUtils.getStatisticsFile(), FileUtils.getExportedStatisticsFile())) 104 | Toast.makeText(this, "Export success", 0).show(); 105 | break; 106 | 107 | case 3: 108 | if(FileUtils.copyTo(FileUtils.getExportedStatisticsFile(), FileUtils.getStatisticsFile())) 109 | { 110 | tv_statistics.setText(Statistics.getText()); 111 | Toast.makeText(this, "Import success", 0).show(); 112 | } 113 | break; 114 | 115 | case 4: 116 | startActivity(new Intent(this, SettingsActivity.class)); 117 | break; 118 | } 119 | return super.onOptionsItemSelected(item); 120 | } 121 | 122 | private void setModuleActive(boolean b) 123 | { 124 | b = b || isExpModuleActive(this); 125 | TextView tv_unactive = (TextView) findViewById(R.id.tv_unactive); 126 | tv_unactive.setVisibility(b ? View.GONE : View.VISIBLE); 127 | } 128 | 129 | private static boolean isExpModuleActive(Context context) 130 | { 131 | boolean isExp = false; 132 | if(context == null) 133 | throw new IllegalArgumentException("context must not be null!!"); 134 | 135 | try 136 | { 137 | ContentResolver contentResolver = context.getContentResolver(); 138 | Uri uri = Uri.parse("content://me.weishu.exposed.CP/"); 139 | Bundle result = null; 140 | try 141 | { 142 | result = contentResolver.call(uri, "active", null, null); 143 | }catch(RuntimeException e) 144 | { 145 | // TaiChi is killed, try invoke 146 | try 147 | { 148 | Intent intent = new Intent("me.weishu.exp.ACTION_ACTIVE"); 149 | intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 150 | context.startActivity(intent); 151 | }catch(Throwable e1) 152 | { 153 | return false; 154 | } 155 | } 156 | if(result == null) 157 | result = contentResolver.call(uri, "active", null, null); 158 | 159 | if(result == null) 160 | return false; 161 | isExp = result.getBoolean("active", false); 162 | }catch(Throwable ignored) 163 | { 164 | } 165 | return isExp; 166 | } 167 | 168 | } 169 | -------------------------------------------------------------------------------- /app/src/main/java/pansong291/xposed/quickenergy/ui/MyWebView.java: -------------------------------------------------------------------------------- 1 | package pansong291.xposed.quickenergy.ui; 2 | 3 | import android.content.Context; 4 | import android.util.AttributeSet; 5 | import android.webkit.WebSettings; 6 | import android.webkit.WebView; 7 | import android.webkit.WebViewClient; 8 | 9 | public class MyWebView extends WebView 10 | { 11 | public MyWebView(Context c) 12 | { 13 | super(c); 14 | defInit(); 15 | } 16 | public MyWebView(Context context, AttributeSet attrs) 17 | { 18 | super(context, attrs); 19 | defInit(); 20 | } 21 | 22 | public MyWebView(Context context, AttributeSet attrs, int defStyleAttr) 23 | { 24 | super(context, attrs, defStyleAttr); 25 | defInit(); 26 | } 27 | 28 | public MyWebView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) 29 | { 30 | super(context, attrs, defStyleAttr, defStyleRes); 31 | defInit(); 32 | } 33 | 34 | private void defInit() 35 | { 36 | getSettings().setSupportZoom(true); 37 | getSettings().setBuiltInZoomControls(true); 38 | getSettings().setDisplayZoomControls(false); 39 | getSettings().setUseWideViewPort(false); 40 | getSettings().setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NARROW_COLUMNS); 41 | getSettings().setAllowFileAccess(true); 42 | getSettings().setJavaScriptEnabled(true); 43 | setWebViewClient( 44 | new WebViewClient() 45 | { 46 | public void onPageFinished(WebView view, String url) 47 | { 48 | if(url.endsWith(".log")) 49 | postDelayed( 50 | new Runnable() 51 | { 52 | @Override 53 | public void run() 54 | { 55 | if(Thread.interrupted()) return; 56 | if(getContentHeight() == 0) 57 | postDelayed(this, 100); 58 | else 59 | scrollToBottom(); 60 | } 61 | }, 500); 62 | } 63 | }); 64 | } 65 | 66 | public void scrollToBottom() 67 | { 68 | scrollTo(0, computeVerticalScrollRange()); 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /app/src/main/java/pansong291/xposed/quickenergy/ui/OptionsAdapter.java: -------------------------------------------------------------------------------- 1 | package pansong291.xposed.quickenergy.ui; 2 | 3 | import android.content.Context; 4 | import android.view.LayoutInflater; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | import android.widget.BaseAdapter; 8 | import android.widget.TextView; 9 | import java.util.ArrayList; 10 | 11 | public class OptionsAdapter extends BaseAdapter 12 | { 13 | private static OptionsAdapter adapter; 14 | 15 | public static OptionsAdapter get(Context c) 16 | { 17 | if(adapter == null) 18 | adapter = new OptionsAdapter(c); 19 | return adapter; 20 | } 21 | 22 | Context context; 23 | ArrayList list; 24 | 25 | private OptionsAdapter(Context c) 26 | { 27 | context = c; 28 | list = new ArrayList<>(); 29 | list.add("View the forest"); 30 | list.add("View the farm"); 31 | list.add("Delete"); 32 | } 33 | 34 | @Override 35 | public int getCount() 36 | { 37 | return list == null ? 0 : list.size(); 38 | } 39 | 40 | @Override 41 | public Object getItem(int p1) 42 | { 43 | return list.get(p1); 44 | } 45 | 46 | @Override 47 | public long getItemId(int p1) 48 | { 49 | return p1; 50 | } 51 | 52 | @Override 53 | public View getView(int p1, View p2, ViewGroup p3) 54 | { 55 | if(p2 == null) 56 | { 57 | p2 = LayoutInflater.from(context).inflate(android.R.layout.simple_list_item_1, null); 58 | } 59 | TextView txt = (TextView) p2; 60 | txt.setText(getItem(p1).toString()); 61 | return p2; 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /app/src/main/java/pansong291/xposed/quickenergy/ui/SettingsActivity.java: -------------------------------------------------------------------------------- 1 | package pansong291.xposed.quickenergy.ui; 2 | 3 | import android.app.Activity; 4 | import android.content.Intent; 5 | import android.net.Uri; 6 | import android.os.Bundle; 7 | import android.view.View; 8 | import android.widget.Button; 9 | import android.widget.CheckBox; 10 | import android.widget.Toast; 11 | import pansong291.xposed.quickenergy.R; 12 | import pansong291.xposed.quickenergy.util.Config; 13 | import pansong291.xposed.quickenergy.util.CooperationIdMap; 14 | import pansong291.xposed.quickenergy.util.FriendIdMap; 15 | 16 | public class SettingsActivity extends Activity 17 | { 18 | CheckBox cb_immediateEffect, cb_recordLog, cb_showToast, 19 | cb_stayAwake, cb_autoRestart, 20 | cb_collectEnergy, cb_helpFriendCollect, cb_receiveForestTaskAward, 21 | cb_cooperateWater, 22 | cb_enableFarm, cb_rewardFriend, cb_sendBackAnimal, 23 | cb_receiveFarmToolReward, cb_useNewEggTool, cb_harvestProduce, 24 | cb_donation, cb_answerQuestion, cb_receiveFarmTaskAward, 25 | cb_feedAnimal, cb_useAccelerateTool, cb_notifyFriend, 26 | cb_receivePoint, cb_openTreasureBox, cb_donateCharityCoin, 27 | cb_kbSignIn; 28 | 29 | @Override 30 | protected void onCreate(Bundle savedInstanceState) 31 | { 32 | super.onCreate(savedInstanceState); 33 | setContentView(R.layout.activity_settings); 34 | 35 | Config.shouldReload = true; 36 | FriendIdMap.shouldReload = true; 37 | CooperationIdMap.shouldReload = true; 38 | 39 | cb_immediateEffect = (CheckBox) findViewById(R.id.cb_immediateEffect); 40 | cb_recordLog = (CheckBox) findViewById(R.id.cb_recordLog); 41 | cb_showToast = (CheckBox) findViewById(R.id.cb_showToast); 42 | cb_stayAwake = (CheckBox) findViewById(R.id.cb_stayAwake); 43 | cb_autoRestart = (CheckBox) findViewById(R.id.cb_autoRestart); 44 | cb_collectEnergy = (CheckBox) findViewById(R.id.cb_collectEnergy); 45 | cb_helpFriendCollect = (CheckBox) findViewById(R.id.cb_helpFriendCollect); 46 | cb_receiveForestTaskAward = (CheckBox) findViewById(R.id.cb_receiveForestTaskAward); 47 | cb_cooperateWater = (CheckBox) findViewById(R.id.cb_cooperateWater); 48 | cb_enableFarm = (CheckBox) findViewById(R.id.cb_enableFarm); 49 | cb_rewardFriend = (CheckBox) findViewById(R.id.cb_rewardFriend); 50 | cb_sendBackAnimal = (CheckBox) findViewById(R.id.cb_sendBackAnimal); 51 | cb_receiveFarmToolReward = (CheckBox) findViewById(R.id.cb_receiveFarmToolReward); 52 | cb_useNewEggTool = (CheckBox) findViewById(R.id.cb_useNewEggTool); 53 | cb_harvestProduce = (CheckBox) findViewById(R.id.cb_harvestProduce); 54 | cb_donation = (CheckBox) findViewById(R.id.cb_donation); 55 | cb_answerQuestion = (CheckBox) findViewById(R.id.cb_answerQuestion); 56 | cb_receiveFarmTaskAward = (CheckBox) findViewById(R.id.cb_receiveFarmTaskAward); 57 | cb_feedAnimal = (CheckBox) findViewById(R.id.cb_feedAnimal); 58 | cb_useAccelerateTool = (CheckBox) findViewById(R.id.cb_useAccelerateTool); 59 | cb_notifyFriend = (CheckBox) findViewById(R.id.cb_notifyFriend); 60 | cb_receivePoint = (CheckBox) findViewById(R.id.cb_receivePoint); 61 | cb_openTreasureBox = (CheckBox) findViewById(R.id.cb_openTreasureBox); 62 | cb_donateCharityCoin = (CheckBox) findViewById(R.id.cb_donateCharityCoin); 63 | cb_kbSignIn = (CheckBox) findViewById(R.id.cb_kbSignIn); 64 | } 65 | 66 | @Override 67 | protected void onResume() 68 | { 69 | super.onResume(); 70 | cb_immediateEffect.setChecked(Config.immediateEffect()); 71 | cb_recordLog.setChecked(Config.recordLog()); 72 | cb_showToast.setChecked(Config.showToast()); 73 | cb_stayAwake.setChecked(Config.stayAwake()); 74 | cb_autoRestart.setChecked(Config.autoRestart()); 75 | cb_collectEnergy.setChecked(Config.collectEnergy()); 76 | cb_helpFriendCollect.setChecked(Config.helpFriendCollect()); 77 | cb_receiveForestTaskAward.setChecked(Config.receiveForestTaskAward()); 78 | cb_cooperateWater.setChecked(Config.cooperateWater()); 79 | cb_enableFarm.setChecked(Config.enableFarm()); 80 | cb_rewardFriend.setChecked(Config.rewardFriend()); 81 | cb_sendBackAnimal.setChecked(Config.sendBackAnimal()); 82 | cb_receiveFarmToolReward.setChecked(Config.receiveFarmToolReward()); 83 | cb_useNewEggTool.setChecked(Config.useNewEggTool()); 84 | cb_harvestProduce.setChecked(Config.harvestProduce()); 85 | cb_donation.setChecked(Config.donation()); 86 | cb_answerQuestion.setChecked(Config.answerQuestion()); 87 | cb_receiveFarmTaskAward.setChecked(Config.receiveFarmTaskAward()); 88 | cb_feedAnimal.setChecked(Config.feedAnimal()); 89 | cb_useAccelerateTool.setChecked(Config.useAccelerateTool()); 90 | cb_notifyFriend.setChecked(Config.notifyFriend()); 91 | cb_receivePoint.setChecked(Config.receivePoint()); 92 | cb_openTreasureBox.setChecked(Config.openTreasureBox()); 93 | cb_donateCharityCoin.setChecked(Config.donateCharityCoin()); 94 | cb_kbSignIn.setChecked(Config.kbSginIn()); 95 | } 96 | 97 | public void onClick(View v) 98 | { 99 | CheckBox cb = v instanceof CheckBox ? (CheckBox)v : null; 100 | Button btn = v instanceof Button ? (Button)v : null; 101 | switch(v.getId()) 102 | { 103 | case R.id.cb_immediateEffect: 104 | Config.setImmediateEffect(cb.isChecked()); 105 | break; 106 | 107 | case R.id.cb_recordLog: 108 | Config.setRecordLog(cb.isChecked()); 109 | break; 110 | 111 | case R.id.cb_showToast: 112 | Config.setShowToast(cb.isChecked()); 113 | break; 114 | 115 | case R.id.cb_stayAwake: 116 | Config.setStayAwake(cb.isChecked()); 117 | break; 118 | 119 | case R.id.cb_autoRestart: 120 | Config.setAutoRestart(cb.isChecked()); 121 | break; 122 | 123 | case R.id.cb_collectEnergy: 124 | Config.setCollectEnergy(cb.isChecked()); 125 | break; 126 | 127 | case R.id.btn_checkInterval: 128 | EditDialog.showEditDialog(this, btn.getText(), EditDialog.EditMode.CHECK_INTERVAL); 129 | break; 130 | 131 | case R.id.btn_threadCount: 132 | EditDialog.showEditDialog(this, btn.getText(), EditDialog.EditMode.THREAD_COUNT); 133 | break; 134 | 135 | case R.id.btn_advanceTime: 136 | EditDialog.showEditDialog(this, btn.getText(), EditDialog.EditMode.ADVANCE_TIME); 137 | break; 138 | 139 | case R.id.btn_collectInterval: 140 | EditDialog.showEditDialog(this, btn.getText(), EditDialog.EditMode.COLLECT_INTERVAL); 141 | break; 142 | 143 | case R.id.btn_collectTimeout: 144 | EditDialog.showEditDialog(this, btn.getText(), EditDialog.EditMode.COLLECT_TIMEOUT); 145 | break; 146 | 147 | case R.id.btn_returnWater30: 148 | EditDialog.showEditDialog(this, btn.getText(), EditDialog.EditMode.RETURN_WATER_30); 149 | break; 150 | 151 | case R.id.btn_returnWater20: 152 | EditDialog.showEditDialog(this, btn.getText(), EditDialog.EditMode.RETURN_WATER_20); 153 | break; 154 | 155 | case R.id.btn_returnWater10: 156 | EditDialog.showEditDialog(this, btn.getText(), EditDialog.EditMode.RETURN_WATER_10); 157 | break; 158 | 159 | case R.id.cb_helpFriendCollect: 160 | Config.setHelpFriendCollect(cb.isChecked()); 161 | break; 162 | 163 | case R.id.btn_dontCollectList: 164 | ListDialog.show(this, btn.getText(), AlipayUser.getList(), Config.getDontCollectList(), null); 165 | break; 166 | 167 | case R.id.btn_dontHelpCollectList: 168 | ListDialog.show(this, btn.getText(), AlipayUser.getList(), Config.getDontHelpCollectList(), null); 169 | break; 170 | 171 | case R.id.cb_receiveForestTaskAward: 172 | Config.setReceiveForestTaskAward(cb.isChecked()); 173 | break; 174 | 175 | case R.id.btn_waterFriendList: 176 | ListDialog.show(this, btn.getText(), AlipayUser.getList(), Config.getWaterFriendList(), Config.getWaterCountList()); 177 | break; 178 | 179 | case R.id.cb_cooperateWater: 180 | Config.setCooperateWater(cb.isChecked()); 181 | break; 182 | 183 | case R.id.btn_cooperateWaterList: 184 | ListDialog.show(this, btn.getText(), AlipayCooperate.getList(), Config.getCooperateWaterList(), Config.getcooperateWaterNumList()); 185 | break; 186 | 187 | case R.id.cb_enableFarm: 188 | Config.setEnableFarm(cb.isChecked()); 189 | break; 190 | 191 | case R.id.cb_rewardFriend: 192 | Config.setRewardFriend(cb.isChecked()); 193 | break; 194 | 195 | case R.id.cb_sendBackAnimal: 196 | Config.setSendBackAnimal(cb.isChecked()); 197 | break; 198 | 199 | case R.id.btn_sendType: 200 | ChoiceDialog.showSendType(this, btn.getText()); 201 | break; 202 | 203 | case R.id.btn_dontSendFriendList: 204 | ListDialog.show(this, btn.getText(), AlipayUser.getList(), Config.getDontSendFriendList(), null); 205 | break; 206 | 207 | case R.id.btn_recallAnimalType: 208 | ChoiceDialog.showRecallAnimalType(this, btn.getText()); 209 | break; 210 | 211 | case R.id.cb_receiveFarmToolReward: 212 | Config.setReceiveFarmToolReward(cb.isChecked()); 213 | break; 214 | 215 | case R.id.cb_useNewEggTool: 216 | Config.setUseNewEggTool(cb.isChecked()); 217 | break; 218 | 219 | case R.id.cb_harvestProduce: 220 | Config.setHarvestProduce(cb.isChecked()); 221 | break; 222 | 223 | case R.id.cb_donation: 224 | Config.setDonation(cb.isChecked()); 225 | break; 226 | 227 | case R.id.cb_answerQuestion: 228 | Config.setAnswerQuestion(cb.isChecked()); 229 | break; 230 | 231 | case R.id.cb_receiveFarmTaskAward: 232 | Config.setReceiveFarmTaskAward(cb.isChecked()); 233 | break; 234 | 235 | case R.id.cb_feedAnimal: 236 | Config.setFeedAnimal(cb.isChecked()); 237 | break; 238 | 239 | case R.id.cb_useAccelerateTool: 240 | Config.setUseAccelerateTool(cb.isChecked()); 241 | break; 242 | 243 | case R.id.btn_feedFriendAnimalList: 244 | ListDialog.show(this, btn.getText(), AlipayUser.getList(), Config.getFeedFriendAnimalList(), Config.getFeedFriendCountList()); 245 | break; 246 | 247 | case R.id.cb_notifyFriend: 248 | Config.setNotifyFriend(cb.isChecked()); 249 | break; 250 | 251 | case R.id.btn_dontNotifyFriendList: 252 | ListDialog.show(this, btn.getText(), AlipayUser.getList(), Config.getDontNotifyFriendList(), null); 253 | break; 254 | 255 | case R.id.cb_receivePoint: 256 | Config.setReceivePoint(cb.isChecked()); 257 | break; 258 | 259 | case R.id.btn_donation_developer: 260 | Intent it2 = new Intent(Intent.ACTION_VIEW, Uri.parse("alipays://platformapi/startapp?saId=10000007&qrcode=https%3A%2F%2Fqr.alipay.com%2Ftsx00339eflkuhhtfctcn48")); 261 | startActivity(it2); 262 | break; 263 | 264 | case R.id.cb_openTreasureBox: 265 | Config.setOpenTreasureBox(cb.isChecked()); 266 | break; 267 | 268 | case R.id.cb_donateCharityCoin: 269 | Config.setDonateCharityCoin(cb.isChecked()); 270 | break; 271 | 272 | case R.id.btn_minExchangeCount: 273 | EditDialog.showEditDialog(this, btn.getText(), EditDialog.EditMode.MIN_EXCHANGE_COUNT); 274 | break; 275 | 276 | case R.id.btn_latestExchangeTime: 277 | EditDialog.showEditDialog(this, btn.getText(), EditDialog.EditMode.LATEST_EXCHANGE_TIME); 278 | break; 279 | 280 | case R.id.cb_kbSignIn: 281 | Config.setKbSginIn(cb.isChecked()); 282 | break; 283 | } 284 | } 285 | 286 | @Override 287 | protected void onPause() 288 | { 289 | super.onPause(); 290 | if(Config.hasChanged) 291 | { 292 | Config.hasChanged = !Config.saveConfigFile(); 293 | Toast.makeText(this, "Configuration saved", 0).show(); 294 | } 295 | FriendIdMap.saveIdMap(); 296 | CooperationIdMap.saveIdMap(); 297 | } 298 | 299 | } 300 | 301 | -------------------------------------------------------------------------------- /app/src/main/java/pansong291/xposed/quickenergy/util/CooperationIdMap.java: -------------------------------------------------------------------------------- 1 | package pansong291.xposed.quickenergy.util; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.Map; 6 | import java.util.Set; 7 | import java.util.TreeMap; 8 | 9 | public class CooperationIdMap 10 | { 11 | private static final String TAG = CooperationIdMap.class.getCanonicalName(); 12 | 13 | public static boolean shouldReload = false; 14 | 15 | private static Map idMap; 16 | private static boolean hasChanged = false; 17 | 18 | public static void putIdMap(String key, String value) 19 | { 20 | if(key == null || key.isEmpty()) return; 21 | if(getIdMap().containsKey(key)) 22 | { 23 | if(!getIdMap().get(key).equals(value)) 24 | { 25 | getIdMap().remove(key); 26 | getIdMap().put(key, value); 27 | hasChanged = true; 28 | } 29 | }else 30 | { 31 | getIdMap().put(key, value); 32 | hasChanged = true; 33 | } 34 | } 35 | 36 | public static void removeIdMap(String key) 37 | { 38 | if(key == null || key.isEmpty()) return; 39 | if(getIdMap().containsKey(key)) 40 | { 41 | getIdMap().remove(key); 42 | hasChanged = true; 43 | } 44 | } 45 | 46 | public static void clearIdMap() 47 | { 48 | getIdMap().clear(); 49 | hasChanged = true; 50 | } 51 | 52 | public static boolean saveIdMap() 53 | { 54 | if(hasChanged) 55 | { 56 | StringBuilder sb = new StringBuilder(); 57 | Set idSet = getIdMap().entrySet(); 58 | for(Map.Entry entry: idSet) 59 | { 60 | sb.append(entry.getKey()); 61 | sb.append(':'); 62 | sb.append(entry.getValue()); 63 | sb.append('\n'); 64 | } 65 | hasChanged = !FileUtils.write2File(sb.toString(), FileUtils.getCooperationIdMapFile()); 66 | } 67 | return hasChanged; 68 | } 69 | 70 | public static String getNameById(String id) 71 | { 72 | if(id == null || id.isEmpty()) return id; 73 | if(getIdMap().containsKey(id)) 74 | { 75 | id = getIdMap().get(id).toString(); 76 | } 77 | return id; 78 | } 79 | 80 | public static Map getIdMap() 81 | { 82 | if(idMap == null || shouldReload) 83 | { 84 | shouldReload = false; 85 | idMap = new TreeMap<>(); 86 | String str = FileUtils.readFromFile(FileUtils.getCooperationIdMapFile()); 87 | if(str != null && str.length() > 0) 88 | { 89 | try 90 | { 91 | String[] idSet = str.split("\n"); 92 | for(String s: idSet) 93 | { 94 | Log.i(TAG, s); 95 | int ind = s.indexOf(":"); 96 | idMap.put(s.substring(0, ind), s.substring(ind + 1)); 97 | } 98 | }catch(Throwable t) 99 | { 100 | Log.printStackTrace(TAG, t); 101 | idMap.clear(); 102 | } 103 | } 104 | } 105 | return idMap; 106 | } 107 | 108 | } 109 | -------------------------------------------------------------------------------- /app/src/main/java/pansong291/xposed/quickenergy/util/FileUtils.java: -------------------------------------------------------------------------------- 1 | package pansong291.xposed.quickenergy.util; 2 | 3 | import android.os.Environment; 4 | import java.io.Closeable; 5 | import java.io.File; 6 | import java.io.FileReader; 7 | import java.io.FileWriter; 8 | 9 | public class FileUtils 10 | { 11 | private static final String TAG = FileUtils.class.getCanonicalName(); 12 | private static File androidDirectory; 13 | private static File configDirectory; 14 | private static File configFile; 15 | private static File friendIdMapFile; 16 | private static File cooperationIdMapFile; 17 | private static File statisticsFile; 18 | private static File exportedStatisticsFile; 19 | private static File forestLogFile; 20 | private static File farmLogFile; 21 | private static File otherLogFile; 22 | private static File simpleLogFile; 23 | private static File runtimeLogFile; 24 | 25 | public static File getAndroidDirectoryFile() 26 | { 27 | if(androidDirectory == null) 28 | { 29 | androidDirectory = new File(Environment.getExternalStorageDirectory(), "Android"); 30 | if(!androidDirectory.exists()) 31 | { 32 | androidDirectory.mkdirs(); 33 | } 34 | } 35 | return androidDirectory; 36 | } 37 | 38 | public static File getConfigDirectoryFile() 39 | { 40 | if(configDirectory == null) 41 | { 42 | configDirectory = new File(getAndroidDirectoryFile(), "data/pansong291.xposed.quickenergy"); 43 | if(configDirectory.exists()) 44 | { 45 | if(configDirectory.isFile()) 46 | { 47 | configDirectory.delete(); 48 | configDirectory.mkdirs(); 49 | } 50 | }else 51 | { 52 | configDirectory.mkdirs(); 53 | } 54 | } 55 | return configDirectory; 56 | } 57 | 58 | public static File getConfigFile() 59 | { 60 | if(configFile == null) 61 | { 62 | configFile = new File(getConfigDirectoryFile(), "config.json"); 63 | if(configFile.exists() && configFile.isDirectory()) 64 | configFile.delete(); 65 | } 66 | return configFile; 67 | } 68 | 69 | public static File getFriendIdMapFile() 70 | { 71 | if(friendIdMapFile == null) 72 | { 73 | friendIdMapFile = new File(getConfigDirectoryFile(), "friendId.list"); 74 | if(friendIdMapFile.exists() && friendIdMapFile.isDirectory()) 75 | friendIdMapFile.delete(); 76 | } 77 | return friendIdMapFile; 78 | } 79 | 80 | public static File getCooperationIdMapFile() 81 | { 82 | if(cooperationIdMapFile == null) 83 | { 84 | cooperationIdMapFile = new File(getConfigDirectoryFile(), "cooperationId.list"); 85 | if(cooperationIdMapFile.exists() && cooperationIdMapFile.isDirectory()) 86 | cooperationIdMapFile.delete(); 87 | } 88 | return cooperationIdMapFile; 89 | } 90 | 91 | public static File getStatisticsFile() 92 | { 93 | if(statisticsFile == null) 94 | { 95 | statisticsFile = new File(getConfigDirectoryFile(), "statistics.json"); 96 | if(statisticsFile.exists() && statisticsFile.isDirectory()) 97 | statisticsFile.delete(); 98 | } 99 | return statisticsFile; 100 | } 101 | 102 | public static File getExportedStatisticsFile() 103 | { 104 | if(exportedStatisticsFile == null) 105 | { 106 | exportedStatisticsFile = new File(getAndroidDirectoryFile(), "statistics.json"); 107 | if(exportedStatisticsFile.exists() && exportedStatisticsFile.isDirectory()) 108 | exportedStatisticsFile.delete(); 109 | } 110 | return exportedStatisticsFile; 111 | } 112 | 113 | public static File getForestLogFile() 114 | { 115 | if(forestLogFile == null) 116 | { 117 | forestLogFile = new File(getConfigDirectoryFile(), "forest.log"); 118 | if(forestLogFile.exists() && forestLogFile.isDirectory()) 119 | forestLogFile.delete(); 120 | if(!forestLogFile.exists()) 121 | try 122 | { 123 | forestLogFile.createNewFile(); 124 | }catch(Throwable t) 125 | {} 126 | } 127 | return forestLogFile; 128 | } 129 | 130 | public static File getFarmLogFile() 131 | { 132 | if(farmLogFile == null) 133 | { 134 | farmLogFile = new File(getConfigDirectoryFile(), "farm.log"); 135 | if(farmLogFile.exists() && farmLogFile.isDirectory()) 136 | farmLogFile.delete(); 137 | if(!farmLogFile.exists()) 138 | try 139 | { 140 | farmLogFile.createNewFile(); 141 | }catch(Throwable t) 142 | {} 143 | } 144 | return farmLogFile; 145 | } 146 | 147 | public static File getOtherLogFile() 148 | { 149 | if(otherLogFile == null) 150 | { 151 | otherLogFile = new File(getConfigDirectoryFile(), "other.log"); 152 | if(otherLogFile.exists() && otherLogFile.isDirectory()) 153 | otherLogFile.delete(); 154 | if(!otherLogFile.exists()) 155 | try 156 | { 157 | otherLogFile.createNewFile(); 158 | }catch(Throwable t) 159 | {} 160 | } 161 | return otherLogFile; 162 | } 163 | 164 | public static File getSimpleLogFile() 165 | { 166 | if(simpleLogFile == null) 167 | { 168 | simpleLogFile = new File(getConfigDirectoryFile(), "simple.log"); 169 | if(simpleLogFile.exists() && simpleLogFile.isDirectory()) 170 | simpleLogFile.delete(); 171 | } 172 | return simpleLogFile; 173 | } 174 | 175 | public static File getRuntimeLogFile() 176 | { 177 | if(runtimeLogFile == null) 178 | { 179 | runtimeLogFile = new File(getConfigDirectoryFile(), "runtime.log"); 180 | if(runtimeLogFile.exists() && runtimeLogFile.isDirectory()) 181 | runtimeLogFile.delete(); 182 | } 183 | return runtimeLogFile; 184 | } 185 | 186 | public static File getBackupFile(File f) 187 | { 188 | return new File(f.getAbsolutePath() + ".bak"); 189 | } 190 | 191 | public static String readFromFile(File f) 192 | { 193 | StringBuilder result = new StringBuilder(); 194 | FileReader fr = null; 195 | try 196 | { 197 | fr = new FileReader(f); 198 | char[] chs = new char[1024]; 199 | int len = 0; 200 | while((len = fr.read(chs)) >= 0) 201 | { 202 | result .append(chs, 0, len); 203 | } 204 | }catch(Throwable t) 205 | { 206 | Log.printStackTrace(TAG, t); 207 | } 208 | close(fr, f); 209 | return result.toString(); 210 | } 211 | 212 | public static boolean append2SimpleLogFile(String s) 213 | { 214 | if(getSimpleLogFile().length() > 31_457_280) // 30MB 215 | getSimpleLogFile().delete(); 216 | return append2File(Log.getFormatDateTime() + " " + s + "\n", getSimpleLogFile()); 217 | } 218 | 219 | public static boolean append2RuntimeLogFile(String s) 220 | { 221 | if(getRuntimeLogFile().length() > 31_457_280) // 30MB 222 | getRuntimeLogFile().delete(); 223 | return append2File(Log.getFormatDateTime() + " " + s + "\n", getRuntimeLogFile()); 224 | } 225 | 226 | public static boolean write2File(String s, File f) 227 | { 228 | boolean success = false; 229 | FileWriter fw = null; 230 | try 231 | { 232 | fw = new FileWriter(f); 233 | fw.write(s); 234 | fw.flush(); 235 | success = true; 236 | }catch(Throwable t) 237 | { 238 | if(!f.equals(getRuntimeLogFile())) 239 | Log.printStackTrace(TAG, t); 240 | } 241 | close(fw, f); 242 | return success; 243 | } 244 | 245 | public static boolean append2File(String s, File f) 246 | { 247 | boolean success = false; 248 | FileWriter fw = null; 249 | try 250 | { 251 | fw = new FileWriter(f, true); 252 | fw.append(s); 253 | fw.flush(); 254 | success = true; 255 | }catch(Throwable t) 256 | { 257 | if(!f.equals(getRuntimeLogFile())) 258 | Log.printStackTrace(TAG, t); 259 | } 260 | close(fw, f); 261 | return success; 262 | } 263 | 264 | public static boolean copyTo(File f1, File f2) 265 | { 266 | return write2File(readFromFile(f1), f2); 267 | } 268 | 269 | public static void close(Closeable c, File f) 270 | { 271 | try 272 | { 273 | if(c != null) c.close(); 274 | }catch(Throwable t) 275 | { 276 | if(!f.equals(getRuntimeLogFile())) 277 | Log.printStackTrace(TAG, t); 278 | } 279 | } 280 | 281 | } 282 | -------------------------------------------------------------------------------- /app/src/main/java/pansong291/xposed/quickenergy/util/FriendIdMap.java: -------------------------------------------------------------------------------- 1 | package pansong291.xposed.quickenergy.util; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.Map; 6 | import java.util.Set; 7 | import java.util.TreeMap; 8 | 9 | public class FriendIdMap 10 | { 11 | private static final String TAG = FriendIdMap.class.getCanonicalName(); 12 | 13 | public static boolean shouldReload = false; 14 | 15 | public static String currentUid; 16 | 17 | private static Map idMap; 18 | private static boolean hasChanged = false; 19 | private static String selfId; 20 | 21 | public static void putIdMap(String key, String value) 22 | { 23 | if(key == null || key.isEmpty()) return; 24 | if(getIdMap().containsKey(key)) 25 | { 26 | if(!getIdMap().get(key).equals(value)) 27 | { 28 | getIdMap().remove(key); 29 | getIdMap().put(key, value); 30 | hasChanged = true; 31 | } 32 | }else 33 | { 34 | getIdMap().put(key, value); 35 | hasChanged = true; 36 | } 37 | } 38 | 39 | public static void removeIdMap(String key) 40 | { 41 | if(key == null || key.isEmpty()) return; 42 | if(getIdMap().containsKey(key)) 43 | { 44 | getIdMap().remove(key); 45 | hasChanged = true; 46 | } 47 | } 48 | 49 | public static boolean saveIdMap() 50 | { 51 | if(hasChanged) 52 | { 53 | StringBuilder sb = new StringBuilder(); 54 | Set idSet = getIdMap().entrySet(); 55 | for(Map.Entry entry: idSet) 56 | { 57 | sb.append(entry.getKey()); 58 | sb.append(':'); 59 | sb.append(entry.getValue()); 60 | sb.append('\n'); 61 | } 62 | hasChanged = !FileUtils.write2File(sb.toString(), FileUtils.getFriendIdMapFile()); 63 | } 64 | return hasChanged; 65 | } 66 | 67 | private static String getSelfId() 68 | { 69 | if(selfId == null) 70 | { 71 | Set idSet = getIdMap().entrySet(); 72 | for(Map.Entry entry: idSet) 73 | if(!entry.getValue().toString().contains("*")) 74 | { 75 | selfId = entry.getKey().toString(); 76 | break; 77 | } 78 | } 79 | return selfId; 80 | } 81 | 82 | public static String getNameById(String id) 83 | { 84 | if(id == null || id.isEmpty()) return id; 85 | if(getIdMap().containsKey(id)) 86 | { 87 | String n = getIdMap().get(id).toString(); 88 | int ind = n.lastIndexOf('('); 89 | if(ind > 0) n = n.substring(0, ind); 90 | if(!n.equals("*")) return n; 91 | }else 92 | { 93 | putIdMap(id, "*(*)"); 94 | } 95 | return id; 96 | } 97 | 98 | public static String[] getUnknownIds() 99 | { 100 | List idList = new ArrayList(); 101 | Set idSet = getIdMap().entrySet(); 102 | for(Map.Entry entry: idSet) 103 | if(entry.getValue().toString().contains("(*)")) 104 | idList.add(entry.getKey().toString()); 105 | if(idList.size() > 0) 106 | { 107 | String[] ids = new String[idList.size()]; 108 | for(int i = 0; i < ids.length; i++) 109 | { 110 | ids[i] = idList.get(i); 111 | Log.i(TAG, "未知id: " + ids[i]); 112 | } 113 | return ids; 114 | } 115 | return null; 116 | } 117 | 118 | public static Map getIdMap() 119 | { 120 | if(idMap == null || shouldReload) 121 | { 122 | shouldReload = false; 123 | idMap = new TreeMap<>(); 124 | String str = FileUtils.readFromFile(FileUtils.getFriendIdMapFile()); 125 | if(str != null && str.length() > 0) 126 | { 127 | try 128 | { 129 | String[] idSet = str.split("\n"); 130 | for(String s: idSet) 131 | { 132 | Log.i(TAG, s); 133 | int ind = s.indexOf(":"); 134 | idMap.put(s.substring(0, ind), s.substring(ind + 1)); 135 | } 136 | }catch(Throwable t) 137 | { 138 | Log.printStackTrace(TAG, t); 139 | idMap.clear(); 140 | } 141 | } 142 | } 143 | return idMap; 144 | } 145 | 146 | } 147 | -------------------------------------------------------------------------------- /app/src/main/java/pansong291/xposed/quickenergy/util/Log.java: -------------------------------------------------------------------------------- 1 | package pansong291.xposed.quickenergy.util; 2 | 3 | import de.robv.android.xposed.XposedBridge; 4 | import java.text.SimpleDateFormat; 5 | import java.util.Date; 6 | 7 | public class Log 8 | { 9 | private static final String TAG = Log.class.getCanonicalName(); 10 | private static SimpleDateFormat sdf; 11 | 12 | public static void i(String tag, String s) 13 | { 14 | StringBuilder sb = new StringBuilder(tag + ", " + s); 15 | try 16 | { 17 | for(int i = 0; i < sb.length(); i += 2000) 18 | { 19 | if(sb.length() < i + 2000) 20 | XposedBridge.log(sb.substring(i, sb.length())); 21 | else 22 | XposedBridge.log(sb.substring(i, i + 2000)); 23 | } 24 | }catch(Throwable t) 25 | { 26 | // when hooking self, this XposedBridge.class will 27 | // not be found, ignore it. 28 | android.util.Log.i(tag, s); 29 | } 30 | FileUtils.append2RuntimeLogFile(sb.toString()); 31 | } 32 | 33 | public static void printStackTrace(String tag, Throwable t) 34 | { 35 | Log.i(tag, android.util.Log.getStackTraceString(t)); 36 | } 37 | 38 | public static boolean forest(String s) 39 | { 40 | recordLog(s, ""); 41 | return FileUtils.append2File(getFormatTime() + " " + s + "\n", FileUtils.getForestLogFile()); 42 | } 43 | 44 | public static boolean farm(String s) 45 | { 46 | recordLog(s, ""); 47 | return FileUtils.append2File(getFormatTime() + " " + s + "\n", FileUtils.getFarmLogFile()); 48 | } 49 | 50 | public static boolean other(String s) 51 | { 52 | recordLog(s, ""); 53 | return FileUtils.append2File(getFormatTime() + " " + s + "\n", FileUtils.getOtherLogFile()); 54 | } 55 | 56 | public static boolean recordLog(String str, String str2) 57 | { 58 | Log.i(TAG, str + str2); 59 | if(!Config.recordLog()) return false; 60 | return FileUtils.append2SimpleLogFile(str); 61 | } 62 | 63 | public static String getFormatDateTime() 64 | { 65 | if(sdf == null) sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 66 | return sdf.format(new Date()); 67 | } 68 | 69 | public static String getFormatDate() 70 | { 71 | return getFormatDateTime().split(" ")[0]; 72 | } 73 | 74 | public static String getFormatTime() 75 | { 76 | return getFormatDateTime().split(" ")[1]; 77 | } 78 | 79 | } 80 | -------------------------------------------------------------------------------- /app/src/main/java/pansong291/xposed/quickenergy/util/RandomUtils.java: -------------------------------------------------------------------------------- 1 | package pansong291.xposed.quickenergy.util; 2 | 3 | import java.util.Random; 4 | 5 | public class RandomUtils 6 | { 7 | private static final Random rnd = new Random(); 8 | 9 | public static int delay() 10 | { 11 | return nextInt(100, 300); 12 | } 13 | 14 | public static int nextInt(int min, int max) 15 | { 16 | return rnd.nextInt(max - min) + min; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /app/src/main/java/pansong291/xposed/quickenergy/util/Statistics.java: -------------------------------------------------------------------------------- 1 | package pansong291.xposed.quickenergy.util; 2 | 3 | import java.util.ArrayList; 4 | import org.json.JSONArray; 5 | import org.json.JSONObject; 6 | 7 | public class Statistics 8 | { 9 | public enum TimeType 10 | { YEAR, MONTH, DAY } 11 | 12 | public enum DataType 13 | { TIME, COLLECTED, HELPED, WATERED } 14 | 15 | private class TimeStatistics 16 | { 17 | int time; 18 | int collected, helped, watered; 19 | 20 | TimeStatistics(int i) 21 | { 22 | reset(i); 23 | } 24 | 25 | public void reset(int i) 26 | { 27 | time = i; 28 | collected = 0; 29 | helped = 0; 30 | watered = 0; 31 | } 32 | } 33 | 34 | private class WaterFriendLog 35 | { 36 | String userId; 37 | int waterCount = 0; 38 | public WaterFriendLog(String id) 39 | { 40 | userId = id; 41 | } 42 | } 43 | 44 | private class FeedFriendLog 45 | { 46 | String userId; 47 | int feedCount = 0; 48 | public FeedFriendLog(String id) 49 | { 50 | userId = id; 51 | } 52 | } 53 | 54 | private static final String TAG = Statistics.class.getCanonicalName(); 55 | private static final String 56 | jn_year = "year", jn_month = "month", jn_day = "day", 57 | jn_collected = "collected", jn_helped = "helped", jn_watered = "watered", 58 | jn_answerQuestionList = "answerQuestionList", 59 | jn_questionHint = "questionHint", jn_memberSignIn = "memberSignIn", 60 | jn_exchange = "exchange", jn_kbSignIn = "kbSignIn"; 61 | 62 | private TimeStatistics year; 63 | private TimeStatistics month; 64 | private TimeStatistics day; 65 | 66 | // forest 67 | private ArrayList waterFriendLogList; 68 | private ArrayList cooperateWaterList; 69 | 70 | // farm 71 | private ArrayList answerQuestionList; 72 | private String questionHint; 73 | private ArrayList feedFriendLogList; 74 | 75 | // other 76 | private int memberSignIn = 0; 77 | private int exchange = 0; 78 | private int kbSignIn = 0; 79 | 80 | private static Statistics statistics; 81 | 82 | public static void addData(DataType dt, int i) 83 | { 84 | Statistics stat = getStatistics(); 85 | resetToday(); 86 | switch(dt) 87 | { 88 | case COLLECTED: 89 | stat.day.collected += i; 90 | stat.month.collected += i; 91 | stat.year.collected += i; 92 | break; 93 | case HELPED: 94 | stat.day.helped += i; 95 | stat.month.helped += i; 96 | stat.year.helped += i; 97 | break; 98 | case WATERED: 99 | stat.day.watered += i; 100 | stat.month.watered += i; 101 | stat.year.watered += i; 102 | break; 103 | } 104 | save(); 105 | } 106 | 107 | public static int getData(TimeType tt, DataType dt) 108 | { 109 | Statistics stat = getStatistics(); 110 | int data = 0; 111 | TimeStatistics ts = null; 112 | switch(tt) 113 | { 114 | case YEAR: 115 | ts = stat.year; 116 | break; 117 | case MONTH: 118 | ts = stat.month; 119 | break; 120 | case DAY: 121 | ts = stat.day; 122 | break; 123 | } 124 | if(ts != null) 125 | switch(dt) 126 | { 127 | case TIME: 128 | data = ts.time; 129 | break; 130 | case COLLECTED: 131 | data = ts.collected; 132 | break; 133 | case HELPED: 134 | data = ts.helped; 135 | break; 136 | case WATERED: 137 | data = ts.watered; 138 | break; 139 | } 140 | return data; 141 | } 142 | 143 | public static String getText() 144 | { 145 | statistics = null; 146 | Statistics stat = getStatistics(); 147 | StringBuilder sb = new StringBuilder("year " + getData(TimeType.YEAR, DataType.TIME) + " : collect "); 148 | sb.append(getData(TimeType.YEAR, DataType.COLLECTED)); 149 | sb.append(", help " + getData(TimeType.YEAR, DataType.HELPED)); 150 | sb.append(", water " + getData(TimeType.YEAR, DataType.WATERED)); 151 | sb.append("\nmonth " + getData(TimeType.MONTH, DataType.TIME) + " : collect "); 152 | sb.append(getData(TimeType.MONTH, DataType.COLLECTED)); 153 | sb.append(", help " + getData(TimeType.MONTH, DataType.HELPED)); 154 | sb.append(", water " + getData(TimeType.MONTH, DataType.WATERED)); 155 | sb.append("\nday " + getData(TimeType.DAY, DataType.TIME) + " : collect "); 156 | sb.append(getData(TimeType.DAY, DataType.COLLECTED)); 157 | sb.append(", help " + getData(TimeType.DAY, DataType.HELPED)); 158 | sb.append(", water " + getData(TimeType.DAY, DataType.WATERED)); 159 | if(stat.questionHint != null && !stat.questionHint.isEmpty()) 160 | { 161 | sb.append("\nquestion hint : " + stat.questionHint); 162 | } 163 | return sb.toString(); 164 | } 165 | 166 | public static boolean canWaterFriendToday(String id, int count) 167 | { 168 | Statistics stat = getStatistics(); 169 | int index = -1; 170 | for(int i = 0; i < stat.waterFriendLogList.size(); i++) 171 | if(stat.waterFriendLogList.get(i).userId.equals(id)) 172 | { 173 | index = i; 174 | break; 175 | } 176 | if(index < 0) return true; 177 | WaterFriendLog wfl = stat.waterFriendLogList.get(index); 178 | return wfl.waterCount < count; 179 | } 180 | 181 | public static void waterFriendToday(String id, int count) 182 | { 183 | Statistics stat = getStatistics(); 184 | WaterFriendLog wfl; 185 | int index = -1; 186 | for(int i = 0; i < stat.waterFriendLogList.size(); i++) 187 | if(stat.waterFriendLogList.get(i).userId.equals(id)) 188 | { 189 | index = i; 190 | break; 191 | } 192 | if(index < 0) 193 | { 194 | wfl = stat.new WaterFriendLog(id); 195 | stat.waterFriendLogList.add(wfl); 196 | }else 197 | { 198 | wfl = stat.waterFriendLogList.get(index); 199 | } 200 | wfl.waterCount = count; 201 | save(); 202 | } 203 | 204 | public static boolean canCooperateWaterToday(String uid, String coopId) 205 | { 206 | Statistics stat = getStatistics(); 207 | return !stat.cooperateWaterList.contains(uid + "_" + coopId); 208 | } 209 | 210 | public static void cooperateWaterToday(String uid, String coopId) 211 | { 212 | Statistics stat = getStatistics(); 213 | String v = uid + "_" + coopId; 214 | if(!stat.cooperateWaterList.contains(v)) 215 | { 216 | stat.cooperateWaterList.add(v); 217 | save(); 218 | } 219 | } 220 | 221 | public static boolean canAnswerQuestionToday(String uid) 222 | { 223 | Statistics stat = getStatistics(); 224 | return !stat.answerQuestionList.contains(uid); 225 | } 226 | 227 | public static void answerQuestionToday(String uid) 228 | { 229 | Statistics stat = getStatistics(); 230 | if(!stat.answerQuestionList.contains(uid)) 231 | { 232 | stat.answerQuestionList.add(uid); 233 | save(); 234 | } 235 | } 236 | 237 | public static void setQuestionHint(String s) 238 | { 239 | Statistics stat = getStatistics(); 240 | if(stat.questionHint == null) 241 | { 242 | stat.questionHint = s; 243 | save(); 244 | } 245 | } 246 | 247 | public static boolean canFeedFriendToday(String id, int count) 248 | { 249 | Statistics stat = getStatistics(); 250 | int index = -1; 251 | for(int i = 0; i < stat.feedFriendLogList.size(); i++) 252 | if(stat.feedFriendLogList.get(i).userId.equals(id)) 253 | { 254 | index = i; 255 | break; 256 | } 257 | if(index < 0) return true; 258 | FeedFriendLog ffl = stat.feedFriendLogList.get(index); 259 | return ffl.feedCount < count; 260 | } 261 | 262 | public static void feedFriendToday(String id) 263 | { 264 | Statistics stat = getStatistics(); 265 | FeedFriendLog ffl; 266 | int index = -1; 267 | for(int i = 0; i < stat.feedFriendLogList.size(); i++) 268 | if(stat.feedFriendLogList.get(i).userId.equals(id)) 269 | { 270 | index = i; 271 | break; 272 | } 273 | if(index < 0) 274 | { 275 | ffl = stat.new FeedFriendLog(id); 276 | stat.feedFriendLogList.add(ffl); 277 | }else 278 | { 279 | ffl = stat.feedFriendLogList.get(index); 280 | } 281 | ffl.feedCount++; 282 | save(); 283 | } 284 | 285 | public static boolean canMemberSignInToday() 286 | { 287 | Statistics stat = getStatistics(); 288 | return stat.memberSignIn < stat.day.time; 289 | } 290 | 291 | public static void memberSignInToday() 292 | { 293 | Statistics stat = getStatistics(); 294 | if(stat.memberSignIn != stat.day.time) 295 | { 296 | stat.memberSignIn = stat.day.time; 297 | save(); 298 | } 299 | } 300 | 301 | public static boolean canExchangeToday() 302 | { 303 | Statistics stat = getStatistics(); 304 | return stat.exchange < stat.day.time; 305 | } 306 | 307 | public static void exchangeToday() 308 | { 309 | Statistics stat = getStatistics(); 310 | if(stat.exchange != stat.day.time) 311 | { 312 | stat.exchange = stat.day.time; 313 | save(); 314 | } 315 | } 316 | 317 | public static boolean canKbSignInToday() 318 | { 319 | Statistics stat = getStatistics(); 320 | return stat.kbSignIn < stat.day.time; 321 | } 322 | 323 | public static void KbSignInToday() 324 | { 325 | Statistics stat = getStatistics(); 326 | if(stat.kbSignIn != stat.day.time) 327 | { 328 | stat.kbSignIn = stat.day.time; 329 | save(); 330 | } 331 | } 332 | 333 | private static Statistics getStatistics() 334 | { 335 | if(statistics == null) 336 | { 337 | String statJson = null; 338 | if(FileUtils.getStatisticsFile().exists()) 339 | statJson = FileUtils.readFromFile(FileUtils.getStatisticsFile()); 340 | statistics = json2Statistics(statJson); 341 | } 342 | return statistics; 343 | } 344 | 345 | public static void resetToday() 346 | { 347 | Statistics stat = getStatistics(); 348 | String[] dateStr = Log.getFormatDate().split("-"); 349 | int ye = Integer.parseInt(dateStr[0]); 350 | int mo = Integer.parseInt(dateStr[1]); 351 | int da = Integer.parseInt(dateStr[2]); 352 | 353 | if(ye > stat.year.time) 354 | { 355 | stat.year.reset(ye); 356 | stat.month.reset(mo); 357 | stat.day.reset(da); 358 | dayClear(); 359 | }else if(mo > stat.month.time) 360 | { 361 | stat.month.reset(mo); 362 | stat.day.reset(da); 363 | dayClear(); 364 | }else if(da > stat.day.time) 365 | { 366 | stat.day.reset(da); 367 | dayClear(); 368 | } 369 | } 370 | 371 | private static void monthClear() 372 | { 373 | } 374 | 375 | private static void dayClear() 376 | { 377 | Statistics stat = getStatistics(); 378 | stat.waterFriendLogList.clear(); 379 | stat.cooperateWaterList.clear(); 380 | stat.answerQuestionList.clear(); 381 | stat.feedFriendLogList.clear(); 382 | stat.questionHint = null; 383 | stat.memberSignIn = 0; 384 | stat.exchange = 0; 385 | stat.kbSignIn = 0; 386 | save(); 387 | FileUtils.getForestLogFile().delete(); 388 | FileUtils.getFarmLogFile().delete(); 389 | FileUtils.getOtherLogFile().delete(); 390 | } 391 | 392 | private static Statistics defInit() 393 | { 394 | Statistics stat = new Statistics(); 395 | String[] date = Log.getFormatDate().split("-"); 396 | if(stat.year == null) 397 | stat.year = stat.new TimeStatistics(Integer.parseInt(date[0])); 398 | if(stat.month == null) 399 | stat.month = stat.new TimeStatistics(Integer.parseInt(date[1])); 400 | if(stat.day == null) 401 | stat.day = stat.new TimeStatistics(Integer.parseInt(date[2])); 402 | if(stat.cooperateWaterList == null) 403 | stat.cooperateWaterList = new ArrayList<>(); 404 | if(stat.answerQuestionList == null) 405 | stat.answerQuestionList = new ArrayList<>(); 406 | if(stat.feedFriendLogList == null) 407 | stat.feedFriendLogList = new ArrayList<>(); 408 | return stat; 409 | } 410 | 411 | private static Statistics json2Statistics(String json) 412 | { 413 | Statistics stat = null; 414 | try 415 | { 416 | JSONObject jo = new JSONObject(json); 417 | JSONObject joo = null; 418 | stat = new Statistics(); 419 | 420 | joo = jo.getJSONObject(jn_year); 421 | stat.year = stat.new TimeStatistics(joo.getInt(jn_year)); 422 | Log.i(TAG, jn_year + ":" + stat.year.time); 423 | stat.year.collected = joo.getInt(jn_collected); 424 | Log.i(TAG, " " + jn_collected + ":" + stat.year.collected); 425 | stat.year.helped = joo.getInt(jn_helped); 426 | Log.i(TAG, " " + jn_helped + ":" + stat.year.helped); 427 | stat.year.watered = joo.getInt(jn_watered); 428 | Log.i(TAG, " " + jn_watered + ":" + stat.year.watered); 429 | 430 | joo = jo.getJSONObject(jn_month); 431 | stat.month = stat.new TimeStatistics(joo.getInt(jn_month)); 432 | Log.i(TAG, jn_month + ":" + stat.month.time); 433 | stat.month.collected = joo.getInt(jn_collected); 434 | Log.i(TAG, " " + jn_collected + ":" + stat.month.collected); 435 | stat.month.helped = joo.getInt(jn_helped); 436 | Log.i(TAG, " " + jn_helped + ":" + stat.month.helped); 437 | stat.month.watered = joo.getInt(jn_watered); 438 | Log.i(TAG, " " + jn_watered + ":" + stat.month.watered); 439 | 440 | joo = jo.getJSONObject(jn_day); 441 | stat.day = stat.new TimeStatistics(joo.getInt(jn_day)); 442 | Log.i(TAG, jn_day + ":" + stat.day.time); 443 | stat.day.collected = joo.getInt(jn_collected); 444 | Log.i(TAG, " " + jn_collected + ":" + stat.day.collected); 445 | stat.day.helped = joo.getInt(jn_helped); 446 | Log.i(TAG, " " + jn_helped + ":" + stat.day.helped); 447 | stat.day.watered = joo.getInt(jn_watered); 448 | Log.i(TAG, " " + jn_watered + ":" + stat.day.watered); 449 | 450 | stat.waterFriendLogList = new ArrayList<>(); 451 | Log.i(TAG, Config.jn_waterFriendList + ":["); 452 | if(jo.has(Config.jn_waterFriendList)) 453 | { 454 | JSONArray ja = jo.getJSONArray(Config.jn_waterFriendList); 455 | for(int i = 0; i < ja.length(); i++) 456 | { 457 | JSONArray jaa = ja.getJSONArray(i); 458 | WaterFriendLog wfl = stat.new WaterFriendLog(jaa.getString(0)); 459 | wfl.waterCount = jaa.getInt(1); 460 | stat.waterFriendLogList.add(wfl); 461 | Log.i(TAG, " " + wfl.userId + "," + wfl.waterCount + ","); 462 | } 463 | } 464 | 465 | stat.cooperateWaterList = new ArrayList<>(); 466 | Log.i(TAG, Config.jn_cooperateWaterList + ":["); 467 | if(jo.has(Config.jn_cooperateWaterList)) 468 | { 469 | JSONArray ja = jo.getJSONArray(Config.jn_cooperateWaterList); 470 | for(int i = 0; i < ja.length(); i++) 471 | { 472 | stat.cooperateWaterList.add(ja.getString(i)); 473 | Log.i(TAG, stat.cooperateWaterList.get(i) + ","); 474 | } 475 | } 476 | 477 | stat.answerQuestionList = new ArrayList<>(); 478 | Log.i(TAG, jn_answerQuestionList + ":["); 479 | if(jo.has(jn_answerQuestionList)) 480 | { 481 | JSONArray ja = jo.getJSONArray(jn_answerQuestionList); 482 | for(int i = 0; i < ja.length(); i++) 483 | { 484 | stat.answerQuestionList.add(ja.getString(i)); 485 | Log.i(TAG, stat.answerQuestionList.get(i) + ","); 486 | } 487 | } 488 | 489 | if(jo.has(jn_questionHint)) 490 | stat.questionHint = jo.getString(jn_questionHint); 491 | Log.i(TAG, jn_questionHint + ":" + stat.questionHint); 492 | 493 | stat.feedFriendLogList = new ArrayList<>(); 494 | Log.i(TAG, Config.jn_feedFriendAnimalList + ":["); 495 | if(jo.has(Config.jn_feedFriendAnimalList)) 496 | { 497 | JSONArray ja = jo.getJSONArray(Config.jn_feedFriendAnimalList); 498 | for(int i = 0; i < ja.length(); i++) 499 | { 500 | JSONArray jaa = ja.getJSONArray(i); 501 | FeedFriendLog ffl = stat.new FeedFriendLog(jaa.getString(0)); 502 | ffl.feedCount = jaa.getInt(1); 503 | stat.feedFriendLogList.add(ffl); 504 | Log.i(TAG, " " + ffl.userId + "," + ffl.feedCount + ","); 505 | } 506 | } 507 | 508 | if(jo.has(jn_memberSignIn)) 509 | stat.memberSignIn = jo.getInt(jn_memberSignIn); 510 | Log.i(TAG, jn_memberSignIn + ":" + stat.memberSignIn); 511 | 512 | if(jo.has(jn_exchange)) 513 | stat.exchange = jo.getInt(jn_exchange); 514 | Log.i(TAG, jn_exchange + ":" + stat.exchange); 515 | 516 | if(jo.has(jn_kbSignIn)) 517 | stat.kbSignIn = jo.getInt(jn_kbSignIn); 518 | Log.i(TAG, jn_kbSignIn + ":" + stat.kbSignIn); 519 | 520 | }catch(Throwable t) 521 | { 522 | Log.printStackTrace(TAG, t); 523 | if(json != null) 524 | { 525 | Log.i(TAG, "统计文件格式有误,已重置统计文件并备份原文件"); 526 | FileUtils.write2File(json, FileUtils.getBackupFile(FileUtils.getStatisticsFile())); 527 | } 528 | stat = defInit(); 529 | } 530 | String formated = statistics2Json(stat); 531 | if(!formated.equals(json)) 532 | { 533 | Log.i(TAG, "重新格式化 statistics.json"); 534 | FileUtils.write2File(formated, FileUtils.getStatisticsFile()); 535 | } 536 | return stat; 537 | } 538 | 539 | private static String statistics2Json(Statistics stat) 540 | { 541 | JSONObject jo = new JSONObject(); 542 | JSONArray ja = null; 543 | try 544 | { 545 | if(stat == null) stat = Statistics.defInit(); 546 | JSONObject joo = new JSONObject(); 547 | joo.put(jn_year, stat.year.time); 548 | joo.put(jn_collected, stat.year.collected); 549 | joo.put(jn_helped, stat.year.helped); 550 | joo.put(jn_watered, stat.year.watered); 551 | jo.put(jn_year, joo); 552 | 553 | joo = new JSONObject(); 554 | joo.put(jn_month, stat.month.time); 555 | joo.put(jn_collected, stat.month.collected); 556 | joo.put(jn_helped, stat.month.helped); 557 | joo.put(jn_watered, stat.month.watered); 558 | jo.put(jn_month, joo); 559 | 560 | joo = new JSONObject(); 561 | joo.put(jn_day, stat.day.time); 562 | joo.put(jn_collected, stat.day.collected); 563 | joo.put(jn_helped, stat.day.helped); 564 | joo.put(jn_watered, stat.day.watered); 565 | jo.put(jn_day, joo); 566 | 567 | ja = new JSONArray(); 568 | for(int i = 0; i < stat.waterFriendLogList.size(); i++) 569 | { 570 | WaterFriendLog wfl = stat.waterFriendLogList.get(i); 571 | JSONArray jaa = new JSONArray(); 572 | jaa.put(wfl.userId); 573 | jaa.put(wfl.waterCount); 574 | ja.put(jaa); 575 | } 576 | jo.put(Config.jn_waterFriendList, ja); 577 | 578 | ja = new JSONArray(); 579 | for(int i = 0; i < stat.cooperateWaterList.size(); i++) 580 | { 581 | ja.put(stat.cooperateWaterList.get(i)); 582 | } 583 | jo.put(Config.jn_cooperateWaterList, ja); 584 | 585 | ja = new JSONArray(); 586 | for(int i = 0; i < stat.answerQuestionList.size(); i++) 587 | { 588 | ja.put(stat.answerQuestionList.get(i)); 589 | } 590 | jo.put(jn_answerQuestionList, ja); 591 | 592 | if(stat.questionHint != null) 593 | jo.put(jn_questionHint, stat.questionHint); 594 | 595 | ja = new JSONArray(); 596 | for(int i = 0; i < stat.feedFriendLogList.size(); i++) 597 | { 598 | FeedFriendLog ffl = stat.feedFriendLogList.get(i); 599 | JSONArray jaa = new JSONArray(); 600 | jaa.put(ffl.userId); 601 | jaa.put(ffl.feedCount); 602 | ja.put(jaa); 603 | } 604 | jo.put(Config.jn_feedFriendAnimalList, ja); 605 | 606 | jo.put(jn_memberSignIn, stat.memberSignIn); 607 | 608 | jo.put(jn_exchange, stat.exchange); 609 | 610 | jo.put(jn_kbSignIn, stat.kbSignIn); 611 | }catch(Throwable t) 612 | { 613 | Log.printStackTrace(TAG, t); 614 | } 615 | return Config.formatJson(jo, false); 616 | } 617 | 618 | private static boolean save() 619 | { 620 | return FileUtils.write2File(statistics2Json(getStatistics()), FileUtils.getStatisticsFile()); 621 | } 622 | 623 | } 624 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/button.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 10 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_html_viewer.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 11 | 12 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 16 | 17 | 23 | 24 |