├── LICENSE
├── README.md
├── ShotScreen
├── app_index.gif
├── code_design.png
├── location_result.png
├── location_xianggang.png
└── location_xinjiang.png
├── virtuallocation-release.apk
├── virtuallocation
├── .gitignore
├── build.gradle
├── jar
│ └── XposedBridgeApi-54.jar
├── libs
│ └── BaiduLBS_Android.jar
├── proguard-rules.pro
├── src
│ ├── androidTest
│ │ └── java
│ │ │ └── top
│ │ │ └── littlerich
│ │ │ └── virtuallocation
│ │ │ └── ExampleInstrumentedTest.java
│ ├── main
│ │ ├── AndroidManifest.xml
│ │ ├── assets
│ │ │ └── xposed_init
│ │ ├── java
│ │ │ └── top
│ │ │ │ └── littlerich
│ │ │ │ └── virtuallocation
│ │ │ │ ├── XPosedPlugin.java
│ │ │ │ ├── activity
│ │ │ │ ├── AboutActivity.java
│ │ │ │ ├── AppsActivity.java
│ │ │ │ ├── MainActivity.java
│ │ │ │ └── PreciseLocationActivity.java
│ │ │ │ ├── adapter
│ │ │ │ └── AppAdapter.java
│ │ │ │ ├── base
│ │ │ │ ├── BaseActivity.java
│ │ │ │ └── BaseDialog.java
│ │ │ │ ├── common
│ │ │ │ ├── AppApplication.java
│ │ │ │ ├── Common.java
│ │ │ │ └── Config.java
│ │ │ │ ├── listener
│ │ │ │ ├── AsyncLocationResultListener.java
│ │ │ │ ├── GeoCoderListener.java
│ │ │ │ ├── MapClickListener.java
│ │ │ │ └── MarkerDragListener.java
│ │ │ │ ├── model
│ │ │ │ ├── Gps.java
│ │ │ │ └── MyAppInfo.java
│ │ │ │ ├── presenter
│ │ │ │ ├── HookApis.java
│ │ │ │ ├── JellyInterpolator.java
│ │ │ │ └── SdkHookManager.java
│ │ │ │ ├── util
│ │ │ │ ├── ApkTool.java
│ │ │ │ ├── LocationUtil.java
│ │ │ │ ├── SharePreferenceUtil.java
│ │ │ │ └── XposedUtil.java
│ │ │ │ └── view
│ │ │ │ ├── CircleWaveView.java
│ │ │ │ ├── CustomProgressDialog.java
│ │ │ │ └── TopBanner.java
│ │ ├── jniLibs
│ │ │ └── armeabi
│ │ │ │ ├── libBaiduMapSDK_v3_2_0_15.so
│ │ │ │ └── liblocSDK5.so
│ │ └── res
│ │ │ ├── anim
│ │ │ └── spinloaing.xml
│ │ │ ├── drawable
│ │ │ ├── bg_begin_location.xml
│ │ │ ├── bg_botton_shadow.xml
│ │ │ ├── bg_notice.xml
│ │ │ ├── bg_progressbar.xml
│ │ │ └── bg_with_round.xml
│ │ │ ├── layout
│ │ │ ├── activity_about.xml
│ │ │ ├── activity_apps.xml
│ │ │ ├── activity_main.xml
│ │ │ ├── activity_precise_location.xml
│ │ │ ├── dialog_customprogress.xml
│ │ │ ├── item_app_info.xml
│ │ │ ├── layout_drawer.xml
│ │ │ └── layout_schema.xml
│ │ │ ├── menu
│ │ │ └── menu_main.xml
│ │ │ ├── mipmap-hdpi
│ │ │ ├── ic_current_location.png
│ │ │ ├── ic_drawer_add.png
│ │ │ ├── ic_drawer_me.png
│ │ │ ├── ic_expand.png
│ │ │ ├── ic_filter.png
│ │ │ ├── ic_launcher_round.png
│ │ │ ├── ic_reback.png
│ │ │ ├── ic_right.png
│ │ │ ├── ic_stop_location.png
│ │ │ ├── ic_topbar_search.png
│ │ │ └── ic_virtual_addr.png
│ │ │ ├── mipmap-mdpi
│ │ │ ├── ic_launcher_round.png
│ │ │ └── icon_gcoding.png
│ │ │ ├── mipmap-xhdpi
│ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xxxhdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ │ └── values
│ │ │ ├── attrs_topbar.xml
│ │ │ ├── colors.xml
│ │ │ ├── strings.xml
│ │ │ └── styles.xml
│ └── test
│ │ └── java
│ │ └── top
│ │ └── littlerich
│ │ └── virtuallocation
│ │ └── ExampleUnitTest.java
└── virtuallocation.iml
└── 环境配置工具
└── Xposed框架2.6.1.apk
/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 |
2 |
3 |
VirtualLocation(UI仿共享单车OFO)
4 | 博客主页
5 | 对Android程序进行虚拟定位,可修改微信、QQ、陌陌以及一些打卡APP等软件,随意切换手机所处位置!(喜欢的给一个star, 有帮助的给一个fork, 欢迎Star和Fork ^_^)
6 | 下载 话不多说,试玩应用先。
7 |
8 | 效果预览
9 | 主页
10 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 | ----------
27 |
28 |
29 | 微信虚拟定位演示
30 |
31 | 1、打开本程序,选择好要穿越的地点,确认穿越即可!
32 |
33 |
34 | 2、再打开微信,这里演示在朋友圈发位置状态,如下:
35 |
36 |
37 | ----------
38 |
39 | 钉钉虚拟定位打卡演示
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 | ----------
67 |
68 |
69 | 原理
70 | 本程序有两种方式可以实现虚拟定位:
71 |
72 | 通过ADB模拟定位功能
73 | 通过Hook修改获取经纬度API的值 (必需安装Xposed以及ROOT)
74 |
75 |
76 | 程序代码设计流程图如下:
77 |
78 |
79 | 第一种方式主要是是通过ADB模拟定位功能,再开启线程,不断的更新LocationManager的经纬度值,即可是实现定位模拟定位
80 |
81 | ```java
82 | mMockThread = new Thread(new Runnable() {
83 | @Override
84 | public void run() {
85 | while (true) {
86 | try {
87 | Thread.sleep(500);
88 | if (!hasAddTestProvider) {
89 | Log.d("xqf", "针对Android6.0+系统,需要单独把程序调加到ADB模拟定位服务中");
90 | continue;
91 | }
92 | setLocation(LocationUtil.mLatitude, LocationUtil.mLongitude);
93 | Log.d("xqf", "setLocation240=latitude:" + mLatitude + "?longitude:" + mLongitude);
94 | } catch (Exception e) {
95 | e.printStackTrace();
96 | }
97 | }
98 | }
99 | });
100 | mMockThread.start();
101 | ```
102 |
103 | 第二种方式主要是采用Hook修改系统API。目前很多程序都调用了isFromMockProvider方法来检测用户是否打开了ADB模拟定位功能,所以我又采用了Hook方式,就不怕不能虚拟定位了,具体如何Hook,可以看我的一篇博客:基于Xposed框架Hook定位功能来破解QQ的LBS红包
104 |
105 | ----------
106 |
107 | 测试
108 | 在Android测试机 分别是 魅蓝2、华为、SCL-TL00、Vivo xs1、红米note运行正常
109 |
110 | 版本
111 | v1.0
112 | 完成了通过ADB模拟定位功能来虚拟定位,但是新版的一些程序都做了ADB模拟定位检测,所以现在很多新版本程序都不行了
113 | v1.1
114 | 完善了通过Hook修改虚拟定位API,提高程序的兼容性和可行性,但同时也必须Android设备要ROOT
115 |
116 | issue
117 | 如果程序运行有什么问题,可以先查看Issues中的问题回答,这样我就不用重复回答大家的问题了,之前太多人加QQ问问题,工作有点忙实在是来不及一一回复(注:Issues在本网页顶部菜单栏上)
118 | Email:bugbye@163.com
119 | License
120 | Copyright 2016 xuqingfu
121 |
122 | Licensed under the Apache License, Version 2.0 (the "License");
123 | you may not use this file except in compliance with the License.
124 | You may obtain a copy of the License at
125 |
126 | http://www.apache.org/licenses/LICENSE-2.0
127 |
128 | Unless required by applicable law or agreed to in writing, software
129 | distributed under the License is distributed on an "AS IS" BASIS,
130 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
131 | See the License for the specific language governing permissions and
132 | limitations under the License.
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
--------------------------------------------------------------------------------
/ShotScreen/app_index.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/drizzle888/VirtualLocation/7eda42b23c4162d0705b01ecc4f888007bd7b071/ShotScreen/app_index.gif
--------------------------------------------------------------------------------
/ShotScreen/code_design.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/drizzle888/VirtualLocation/7eda42b23c4162d0705b01ecc4f888007bd7b071/ShotScreen/code_design.png
--------------------------------------------------------------------------------
/ShotScreen/location_result.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/drizzle888/VirtualLocation/7eda42b23c4162d0705b01ecc4f888007bd7b071/ShotScreen/location_result.png
--------------------------------------------------------------------------------
/ShotScreen/location_xianggang.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/drizzle888/VirtualLocation/7eda42b23c4162d0705b01ecc4f888007bd7b071/ShotScreen/location_xianggang.png
--------------------------------------------------------------------------------
/ShotScreen/location_xinjiang.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/drizzle888/VirtualLocation/7eda42b23c4162d0705b01ecc4f888007bd7b071/ShotScreen/location_xinjiang.png
--------------------------------------------------------------------------------
/virtuallocation-release.apk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/drizzle888/VirtualLocation/7eda42b23c4162d0705b01ecc4f888007bd7b071/virtuallocation-release.apk
--------------------------------------------------------------------------------
/virtuallocation/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/virtuallocation/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 25
5 | buildToolsVersion "25.0.2"
6 | defaultConfig {
7 | applicationId "top.littlerich.virtuallocation"
8 | minSdkVersion 18
9 | targetSdkVersion 19
10 | versionCode 20170508
11 | versionName "v1.0.252"
12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
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(include: ['*.jar'], dir: 'libs')
24 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
25 | exclude group: 'com.android.support', module: 'support-annotations'
26 | })
27 | provided files('jar/XposedBridgeApi-54.jar')
28 | compile files('libs/BaiduLBS_Android.jar')
29 | // jniLibs.srcDir 'src/main/jniLibs'
30 | compile 'com.android.support:appcompat-v7:25.3.1'
31 | compile 'com.android.support.constraint:constraint-layout:1.0.0-alpha8'
32 | compile 'com.android.support:cardview-v7:25.3.1'
33 | compile 'com.android.support:recyclerview-v7:25.3.1'
34 | testCompile 'junit:junit:4.12'
35 | compile 'com.android.support:design:25.3.1'
36 | }
37 |
--------------------------------------------------------------------------------
/virtuallocation/jar/XposedBridgeApi-54.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/drizzle888/VirtualLocation/7eda42b23c4162d0705b01ecc4f888007bd7b071/virtuallocation/jar/XposedBridgeApi-54.jar
--------------------------------------------------------------------------------
/virtuallocation/libs/BaiduLBS_Android.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/drizzle888/VirtualLocation/7eda42b23c4162d0705b01ecc4f888007bd7b071/virtuallocation/libs/BaiduLBS_Android.jar
--------------------------------------------------------------------------------
/virtuallocation/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 D:\DevSoft\Android\AndroidSDK/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 |
19 | # Uncomment this to preserve the line number information for
20 | # debugging stack traces.
21 | #-keepattributes SourceFile,LineNumberTable
22 |
23 | # If you keep the line number information, uncomment this to
24 | # hide the original source file name.
25 | #-renamesourcefileattribute SourceFile
26 |
27 | -keep class com.baidu.** {*;}
28 | -keep class vi.com.** {*;}
29 | -dontwarn com.baidu.**
30 |
--------------------------------------------------------------------------------
/virtuallocation/src/androidTest/java/top/littlerich/virtuallocation/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package top.littlerich.virtuallocation;
2 |
3 | import android.content.Context;
4 | import android.support.test.InstrumentationRegistry;
5 | import android.support.test.runner.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | /**
13 | * Instrumentation test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext() throws Exception {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("top.littlerich.virtuallocation", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/virtuallocation/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
28 |
31 |
32 |
33 |
36 |
37 |
38 |
41 |
44 |
45 |
49 |
50 |
51 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/virtuallocation/src/main/assets/xposed_init:
--------------------------------------------------------------------------------
1 | top.littlerich.virtuallocation.XPosedPlugin
--------------------------------------------------------------------------------
/virtuallocation/src/main/java/top/littlerich/virtuallocation/XPosedPlugin.java:
--------------------------------------------------------------------------------
1 | package top.littlerich.virtuallocation;
2 |
3 | import android.content.Context;
4 | import android.util.Log;
5 |
6 | import de.robv.android.xposed.IXposedHookLoadPackage;
7 | import de.robv.android.xposed.XC_MethodHook;
8 | import de.robv.android.xposed.XposedHelpers;
9 | import de.robv.android.xposed.callbacks.XC_LoadPackage;
10 | import top.littlerich.virtuallocation.presenter.HookApis;
11 | import top.littlerich.virtuallocation.presenter.SdkHookManager;
12 | import top.littlerich.virtuallocation.util.XposedUtil;
13 |
14 | /**
15 | * Created by xuqingfu on 2017/4/15.
16 | */
17 |
18 | public class XPosedPlugin implements IXposedHookLoadPackage {
19 |
20 | private static final String TAG = "silence";
21 |
22 | @Override
23 | public void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {
24 |
25 | if (!XposedUtil.isNeedHook(loadPackageParam.packageName)) { //过滤程序
26 | return;
27 | }
28 | Log.i(TAG, "加载Hook程序:" + loadPackageParam.packageName);
29 |
30 | SdkHookManager.findMethodIsFromMockProvider();
31 |
32 | SdkHookManager.findMethodGetInt(loadPackageParam);
33 |
34 | XposedHelpers.findAndHookMethod("android.app.Application", loadPackageParam.classLoader, "attach", Context.class, new XC_MethodHook() {
35 | @Override
36 | protected void afterHookedMethod(XC_MethodHook.MethodHookParam param) throws Throwable {
37 | super.afterHookedMethod(param);
38 | Log.v(TAG, "启动程序:" + param.thisObject.toString());
39 | ClassLoader appClassLoader = ((Context)param.args[0]).getClassLoader();
40 | try {
41 | HookApis.findMethodAmapLongitudeAndLatitude(appClassLoader);
42 |
43 | }
44 | catch(Exception e) {
45 | Log.e(TAG, "Hook发生异常:" + e.toString());
46 | }
47 | }
48 | });
49 |
50 |
51 | }
52 |
53 |
54 | }
55 |
--------------------------------------------------------------------------------
/virtuallocation/src/main/java/top/littlerich/virtuallocation/activity/AboutActivity.java:
--------------------------------------------------------------------------------
1 | package top.littlerich.virtuallocation.activity;
2 |
3 | import android.content.Context;
4 | import android.content.Intent;
5 | import android.os.Bundle;
6 | import android.support.v7.app.AppCompatActivity;
7 | import android.view.View;
8 | import android.view.Window;
9 |
10 | import top.littlerich.virtuallocation.R;
11 | import top.littlerich.virtuallocation.view.TopBanner;
12 |
13 | public class AboutActivity extends AppCompatActivity {
14 |
15 | TopBanner mTopbanner;
16 |
17 | @Override
18 | protected void onCreate(Bundle savedInstanceState) {
19 | super.onCreate(savedInstanceState);
20 | requestWindowFeature(Window.FEATURE_NO_TITLE);
21 | setContentView(R.layout.activity_about);
22 | initViews();
23 | bindListener();
24 | }
25 |
26 | private void initViews() {
27 | mTopbanner = (TopBanner) findViewById(R.id.topbanner);
28 | }
29 |
30 | private void bindListener() {
31 | mTopbanner.setTopBannerListener(new TopBanner.OnTopBannerListener() {
32 | @Override
33 | public void leftClick(View v) {
34 | finish();
35 | }
36 |
37 | @Override
38 | public void rightClick(View v) {
39 |
40 | }
41 | });
42 | }
43 |
44 | public static void openActivity(Context conetxt){
45 | Intent intent = new Intent(conetxt, AboutActivity.class);
46 | conetxt.startActivity(intent);
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/virtuallocation/src/main/java/top/littlerich/virtuallocation/activity/AppsActivity.java:
--------------------------------------------------------------------------------
1 | package top.littlerich.virtuallocation.activity;
2 |
3 | import android.content.Context;
4 | import android.content.Intent;
5 | import android.os.Bundle;
6 | import android.os.Handler;
7 | import android.support.v7.app.AppCompatActivity;
8 | import android.support.v7.widget.LinearLayoutManager;
9 | import android.support.v7.widget.RecyclerView;
10 | import android.view.View;
11 | import android.widget.ProgressBar;
12 | import android.widget.Toast;
13 |
14 | import java.util.List;
15 |
16 | import top.littlerich.virtuallocation.R;
17 | import top.littlerich.virtuallocation.adapter.AppAdapter;
18 | import top.littlerich.virtuallocation.model.MyAppInfo;
19 | import top.littlerich.virtuallocation.util.ApkTool;
20 | import top.littlerich.virtuallocation.view.TopBanner;
21 |
22 | public class AppsActivity extends AppCompatActivity {
23 |
24 | private RecyclerView mRecyclerView;
25 | private LinearLayoutManager mLayoutManager;
26 | AppAdapter mAppAdapter;
27 | public Handler mHandler = new Handler();
28 | private ProgressBar mProgressBar;
29 | private TopBanner mTopbanner;
30 |
31 | @Override
32 | protected void onCreate(Bundle savedInstanceState) {
33 | super.onCreate(savedInstanceState);
34 | setContentView(R.layout.activity_apps);
35 |
36 | initView();
37 | bindListener();
38 |
39 | //创建默认的线性LayoutManager
40 | mLayoutManager = new LinearLayoutManager(this);
41 | mRecyclerView.setLayoutManager(mLayoutManager);
42 | //如果可以确定每个item的高度是固定的,设置这个选项可以提高性能
43 | mRecyclerView.setHasFixedSize(true);
44 | //创建并设置Adapter
45 | mAppAdapter = new AppAdapter(AppsActivity.this);
46 | mRecyclerView.setAdapter(mAppAdapter);
47 | initAppList(false);
48 | }
49 |
50 | private void bindListener() {
51 | mTopbanner.setTopBannerListener(new TopBanner.OnTopBannerListener() {
52 | @Override
53 | public void leftClick(View v) {
54 | finish();
55 | }
56 |
57 | @Override
58 | public void rightClick(View v) {
59 | if (mProgressBar.isShown()) {
60 | Toast.makeText(AppsActivity.this, "数据未加载完成,无法过滤!", Toast.LENGTH_SHORT).show();
61 | } else {
62 | mProgressBar.setVisibility(View.VISIBLE);
63 | initAppList(true);
64 | }
65 | }
66 | });
67 | }
68 |
69 | private void initView() {
70 | mTopbanner = (TopBanner) findViewById(R.id.topbanner);
71 | mRecyclerView = (RecyclerView) findViewById(R.id.my_recycler_view);
72 | mProgressBar = (ProgressBar) findViewById(R.id.pb_progressbar);
73 | mProgressBar.setVisibility(View.VISIBLE);
74 | }
75 |
76 | private void initAppList(final boolean isFilter) {
77 | new Thread() {
78 | @Override
79 | public void run() {
80 | super.run();
81 | //扫描得到APP列表
82 | final List appInfos = ApkTool.scanLocalInstallAppList(AppsActivity.this.getPackageManager(), isFilter);
83 | mHandler.post(new Runnable() {
84 | @Override
85 | public void run() {
86 | mAppAdapter.setData(appInfos);
87 | runOnUiThread(new Runnable() {
88 | @Override
89 | public void run() {
90 | mProgressBar.setVisibility(View.GONE);
91 | }
92 | });
93 | }
94 | });
95 | }
96 | }.start();
97 | }
98 |
99 | public static void openActivity(Context context) {
100 | Intent intent = new Intent(context, AppsActivity.class);
101 | context.startActivity(intent);
102 | }
103 |
104 | }
105 |
--------------------------------------------------------------------------------
/virtuallocation/src/main/java/top/littlerich/virtuallocation/activity/MainActivity.java:
--------------------------------------------------------------------------------
1 | package top.littlerich.virtuallocation.activity;
2 |
3 | import android.app.AlertDialog;
4 | import android.content.DialogInterface;
5 | import android.location.LocationManager;
6 | import android.os.Handler;
7 | import android.support.v4.widget.DrawerLayout;
8 | import android.view.Gravity;
9 | import android.view.View;
10 | import android.view.animation.Animation;
11 | import android.view.animation.AnimationUtils;
12 | import android.view.animation.LinearInterpolator;
13 | import android.widget.Button;
14 | import android.widget.ImageView;
15 | import android.widget.TextView;
16 | import android.widget.Toast;
17 |
18 | import com.baidu.location.LocationClient;
19 | import com.baidu.location.LocationClientOption;
20 | import com.baidu.mapapi.map.BaiduMap;
21 | import com.baidu.mapapi.map.BitmapDescriptor;
22 | import com.baidu.mapapi.map.BitmapDescriptorFactory;
23 | import com.baidu.mapapi.map.MapStatusUpdate;
24 | import com.baidu.mapapi.map.MapStatusUpdateFactory;
25 | import com.baidu.mapapi.map.MapView;
26 | import com.baidu.mapapi.map.Marker;
27 | import com.baidu.mapapi.map.MarkerOptions;
28 | import com.baidu.mapapi.map.MyLocationConfiguration;
29 | import com.baidu.mapapi.map.OverlayOptions;
30 | import com.baidu.mapapi.model.LatLng;
31 | import com.baidu.mapapi.search.geocode.GeoCoder;
32 | import com.baidu.mapapi.search.geocode.ReverseGeoCodeOption;
33 |
34 | import top.littlerich.virtuallocation.R;
35 | import top.littlerich.virtuallocation.base.BaseActivity;
36 | import top.littlerich.virtuallocation.common.AppApplication;
37 | import top.littlerich.virtuallocation.listener.AsyncLocationResultListener;
38 | import top.littlerich.virtuallocation.listener.GeoCoderListener;
39 | import top.littlerich.virtuallocation.listener.MapClickListener;
40 | import top.littlerich.virtuallocation.listener.MarkerDragListener;
41 | import top.littlerich.virtuallocation.util.LocationUtil;
42 | import top.littlerich.virtuallocation.view.TopBanner;
43 |
44 | import static top.littlerich.virtuallocation.util.LocationUtil.hasAddTestProvider;
45 |
46 | /**
47 | * Created by xuqingfu on 2017/4/15.
48 | */
49 | public class MainActivity extends BaseActivity implements View.OnClickListener{
50 |
51 | private String mMockProviderName = LocationManager.GPS_PROVIDER;
52 | private Button bt_Ok;
53 | private LocationManager locationManager;
54 | public static double latitude = 25.2358842413, longitude = 119.2035484314;
55 |
56 | private Thread thread;// 需要一个线程一直刷新
57 | private Boolean RUN = true;
58 | private TextView tv_location;
59 | boolean isFirstLoc = true;// 是否首次定位
60 | // 百度定位相关
61 | private LocationClient mLocClient;
62 | private MyLocationConfiguration.LocationMode mCurrentMode;// 定位模式
63 | private BitmapDescriptor mCurrentMarker;// 定位图标
64 | private MapView mMapView;
65 | private static BaiduMap mBaiduMap;
66 | // 初始化全局 bitmap 信息,不用时及时 recycle
67 | private BitmapDescriptor bd = BitmapDescriptorFactory.fromResource(R.mipmap.icon_gcoding);
68 | private static Marker mMarker;
69 | private static LatLng curLatlng;
70 | private static GeoCoder mSearch;
71 | public static double myGpslatitude, myGpslongitude;
72 | DrawerLayout mDrawerLayout;
73 | TopBanner mTopbanner;
74 | private TextView mAboutAuthor;
75 | private ImageView mCurrentLocation;
76 | private Animation mOperatingAnim;
77 | private TextView mPreciseLocation;
78 | private TextView mAddProcess;
79 | private ImageView mStopMock;
80 |
81 | @Override
82 | protected Object getContentViewId() {
83 | return R.layout.layout_schema;
84 | }
85 |
86 | @Override
87 | protected void IniView() {
88 | bt_Ok = (Button) findViewById(R.id.bt_Ok);
89 | tv_location = (TextView) findViewById(R.id.tv_location);
90 | mDrawerLayout = (DrawerLayout) findViewById(R.id.dl_left);
91 | mTopbanner = (TopBanner) findViewById(R.id.topbanner);
92 | mAboutAuthor = (TextView) findViewById(R.id.tv_about_me);
93 | mCurrentLocation = (ImageView)findViewById(R.id.iv_location);
94 | mStopMock = (ImageView)findViewById(R.id.iv_stop_location);
95 | mPreciseLocation = (TextView)findViewById(R.id.tv_precise);
96 | mAddProcess = (TextView) findViewById(R.id.tv_add_app);
97 | //加载旋转动画
98 | mOperatingAnim = AnimationUtils.loadAnimation(this, R.anim.spinloaing);
99 | LinearInterpolator lin = new LinearInterpolator();
100 |
101 | mOperatingAnim.setInterpolator(lin);
102 | // 地图初始化
103 | mMapView = (MapView) findViewById(R.id.bmapView);
104 | mBaiduMap = mMapView.getMap();
105 | // 开启定位图层
106 | mBaiduMap.setMyLocationEnabled(true);
107 | //隐藏地图比例尺
108 | mMapView.showScaleControl(false);
109 | //关闭缩放放大控件
110 | mMapView.showZoomControls(false);
111 | mMapView.removeViewAt(1);
112 | // 定位初始化
113 | mLocClient = new LocationClient(this);
114 | }
115 |
116 | @Override
117 | protected void IniLister() {
118 | bt_Ok.setOnClickListener(this);
119 | mLocClient.registerLocationListener(new AsyncLocationResultListener(mMapView, isFirstLoc));
120 | mBaiduMap.setOnMapClickListener(new MapClickListener(bt_Ok));
121 | mBaiduMap.setOnMarkerDragListener(new MarkerDragListener());
122 |
123 | // 初始化搜索模块,注册事件监听
124 | mSearch = GeoCoder.newInstance();
125 | mSearch.setOnGetGeoCodeResultListener(new GeoCoderListener(MainActivity.this, tv_location));
126 | mTopbanner.setTopBannerListener(new TopBanner.OnTopBannerListener() {
127 | @Override
128 | public void leftClick(View v) {
129 | if (mDrawerLayout.isDrawerOpen(Gravity.LEFT)){
130 | mDrawerLayout.closeDrawer(Gravity.LEFT);
131 | }else {
132 | mDrawerLayout.openDrawer(Gravity.LEFT);
133 | }
134 | }
135 |
136 | @Override
137 | public void rightClick(View v) {
138 |
139 | }
140 | });
141 | mAboutAuthor.setOnClickListener(new View.OnClickListener() {
142 | @Override
143 | public void onClick(View v) {
144 | AboutActivity.openActivity(MainActivity.this);
145 | }
146 | });
147 | mCurrentLocation.setOnClickListener(new View.OnClickListener() {
148 | @Override
149 | public void onClick(View v) {
150 | LatLng ll = new LatLng(myGpslatitude, myGpslongitude);
151 | setCurrentMapLatLng(ll);
152 | }
153 | });
154 | mBaiduMap.setOnMapLoadedCallback(new BaiduMap.OnMapLoadedCallback() {
155 | @Override
156 | public void onMapLoaded() {
157 | new Handler().postDelayed(new Runnable(){
158 |
159 | public void run() {
160 | mCurrentLocation.clearAnimation();
161 | }
162 |
163 | }, 1000 * 6);
164 | }
165 | });
166 | mPreciseLocation.setOnClickListener(new View.OnClickListener() {
167 | @Override
168 | public void onClick(View v) {
169 | PreciseLocationActivity.openActivity(MainActivity.this);
170 | }
171 | });
172 | mAddProcess.setOnClickListener(new View.OnClickListener() {
173 | @Override
174 | public void onClick(View v) {
175 | AppsActivity.openActivity(MainActivity.this);
176 | }
177 | });
178 | mStopMock.setOnClickListener(new View.OnClickListener() {
179 | @Override
180 | public void onClick(View v) {
181 | LocationUtil.stopMockLocation();
182 | Toast.makeText(MainActivity.this, "虚拟定位已暂停!", Toast.LENGTH_SHORT).show();
183 | bt_Ok.setText("立即穿越");
184 | }
185 | });
186 |
187 | }
188 |
189 | @Override
190 | protected void IniData() {
191 | inilocation();
192 | iniMap();
193 |
194 | if (mOperatingAnim != null) {
195 | mCurrentLocation.startAnimation(mOperatingAnim);
196 | }
197 |
198 | }
199 |
200 | /**
201 | * inilocation 初始化 位置模拟
202 | */
203 | private void inilocation() {
204 | try {
205 | if (LocationUtil.initLocation(MainActivity.this)) {
206 | LocationUtil.initLocationManager();
207 | } else {//未开启ADB模拟定位功能,则只能选择HOOK技术
208 |
209 | }
210 | } catch (Exception e) {
211 | Toast.makeText(MainActivity.this, "虚拟定位功能未打开!", Toast.LENGTH_SHORT).show();
212 | e.printStackTrace();
213 | }
214 | }
215 |
216 | /**
217 | * iniMap 初始化地图
218 | */
219 | private void iniMap() {
220 | LocationClientOption option = new LocationClientOption();
221 | option.setOpenGps(true);// 打开gps
222 | option.setCoorType("bd09ll"); // 设置坐标类型
223 | option.setScanSpan(3000);
224 | mCurrentMode = MyLocationConfiguration.LocationMode.NORMAL;
225 |
226 | // 缩放
227 | MapStatusUpdate msu = MapStatusUpdateFactory.zoomTo(14.0f);
228 | mBaiduMap.setMapStatus(msu);
229 |
230 | mBaiduMap.setMyLocationConfigeration(new MyLocationConfiguration(mCurrentMode, true, mCurrentMarker));
231 | mLocClient.setLocOption(option);
232 | mLocClient.start();
233 | initOverlay();
234 |
235 | // 开启线程,一直修改GPS坐标
236 | LocationUtil.startLocaton();
237 | }
238 |
239 | /**
240 | * initOverlay 设置覆盖物,这里就是地图上那个点
241 | */
242 | private void initOverlay() {
243 | LatLng ll = new LatLng(AppApplication.mMockGps.mLatitude, AppApplication.mMockGps.mLongitude);
244 | OverlayOptions oo = new MarkerOptions().position(ll).icon(bd).zIndex(9)
245 | .draggable(true);
246 | mMarker = (Marker) (mBaiduMap.addOverlay(oo));
247 | }
248 |
249 | /**
250 | * setCurrentMapLatLng 设置当前坐标
251 | */
252 | public static void setCurrentMapLatLng(LatLng arg0) {
253 | curLatlng = arg0;
254 | mMarker.setPosition(arg0);
255 |
256 | // 设置地图中心点为这是位置
257 | LatLng ll = new LatLng(arg0.latitude, arg0.longitude);
258 | MapStatusUpdate u = MapStatusUpdateFactory.newLatLng(ll);
259 | mBaiduMap.animateMapStatus(u);
260 |
261 | // 根据经纬度坐标 找到实地信息,会在接口onGetReverseGeoCodeResult中呈现结果
262 | mSearch.reverseGeoCode(new ReverseGeoCodeOption().location(arg0));
263 | }
264 |
265 | @Override
266 | protected void thisFinish() {
267 | AlertDialog.Builder build = new AlertDialog.Builder(this);
268 | build.setTitle("提示");
269 | build.setMessage("退出后,将不再提供定位服务,继续退出吗?");
270 | build.setPositiveButton("确认", new DialogInterface.OnClickListener() {
271 |
272 | @Override
273 | public void onClick(DialogInterface dialog, int which) {
274 | finish();
275 | }
276 | });
277 | build.setNeutralButton("最小化", new DialogInterface.OnClickListener() {
278 |
279 | @Override
280 | public void onClick(DialogInterface dialog, int which) {
281 | moveTaskToBack(true);
282 | }
283 | });
284 | build.setNegativeButton("取消", null);
285 | build.show();
286 | }
287 |
288 | @Override
289 | protected void onResume() {
290 | mMapView.onResume();
291 | super.onResume();
292 | }
293 |
294 | @Override
295 | protected void onPause() {
296 | mMapView.onPause();
297 | if (mDrawerLayout != null && mDrawerLayout.isDrawerOpen(Gravity.LEFT)){
298 | mDrawerLayout.closeDrawer(Gravity.LEFT);
299 | }
300 | super.onPause();
301 | }
302 |
303 | @Override
304 | public void onBackPressed() {
305 | thisFinish();
306 | }
307 |
308 | @Override
309 | protected void onDestroy() {
310 | RUN = false;
311 | thread = null;
312 | //清除旋转加载动画
313 | mCurrentLocation.clearAnimation();
314 |
315 | // 退出时销毁定位
316 | mLocClient.stop();
317 | // 关闭定位图层
318 | mBaiduMap.setMyLocationEnabled(false);
319 | mMapView.onDestroy();
320 | mMapView = null;
321 | bd.recycle();
322 | mSearch.destroy();
323 | super.onDestroy();
324 | }
325 |
326 | @Override
327 | public void onClick(View v) {
328 | switch (v.getId()) {
329 | case R.id.bt_Ok:
330 | latitude = curLatlng.latitude;
331 | longitude = curLatlng.longitude;
332 | try {
333 | if (!hasAddTestProvider){
334 | LocationUtil.initLocation(MainActivity.this);
335 | LocationUtil.initLocationManager();
336 | }
337 | LocationUtil.setLongitudeAndLatitude(curLatlng.longitude, curLatlng.latitude);
338 | AppApplication.mMockGps.mLatitude = curLatlng.latitude;
339 | AppApplication.mMockGps.mLongitude = curLatlng.longitude;
340 | bt_Ok.setText("穿越完成");
341 | } catch (Exception e) {
342 | e.printStackTrace();
343 | }
344 | break;
345 | }
346 | }
347 |
348 | }
--------------------------------------------------------------------------------
/virtuallocation/src/main/java/top/littlerich/virtuallocation/activity/PreciseLocationActivity.java:
--------------------------------------------------------------------------------
1 | package top.littlerich.virtuallocation.activity;
2 |
3 | import android.animation.Animator;
4 | import android.animation.AnimatorSet;
5 | import android.animation.ObjectAnimator;
6 | import android.animation.PropertyValuesHolder;
7 | import android.animation.ValueAnimator;
8 | import android.content.Context;
9 | import android.content.Intent;
10 | import android.os.Bundle;
11 | import android.support.v7.app.AppCompatActivity;
12 | import android.support.v7.widget.AppCompatButton;
13 | import android.view.View;
14 | import android.view.ViewGroup;
15 | import android.view.animation.AccelerateDecelerateInterpolator;
16 | import android.widget.EditText;
17 | import android.widget.ProgressBar;
18 | import android.widget.TextView;
19 | import android.widget.Toast;
20 |
21 | import top.littlerich.virtuallocation.R;
22 | import top.littlerich.virtuallocation.presenter.JellyInterpolator;
23 | import top.littlerich.virtuallocation.util.LocationUtil;
24 | import top.littlerich.virtuallocation.view.TopBanner;
25 |
26 | public class PreciseLocationActivity extends AppCompatActivity {
27 |
28 | private EditText mLongitudeValue;
29 | private EditText mLatitudeValue;
30 | private AppCompatButton mBeginLocation;
31 | private TopBanner mTopbanner;
32 | private ProgressBar mPbLocating;
33 | private TextView mTip;
34 | float width;
35 |
36 | @Override
37 | protected void onCreate(Bundle savedInstanceState) {
38 | super.onCreate(savedInstanceState);
39 | setContentView(R.layout.activity_precise_location);
40 | initViews();
41 | bindListener();
42 | }
43 |
44 | private void bindListener() {
45 | mBeginLocation.setOnClickListener(new View.OnClickListener() {
46 | @Override
47 | public void onClick(View v) {
48 | try {
49 | LocationUtil.setLongitudeAndLatitude(Double.valueOf(mLongitudeValue.getText().toString()),
50 | Double.valueOf(mLatitudeValue.getText().toString()));
51 | width = mBeginLocation.getMeasuredWidth();
52 | float height = mBeginLocation.getMeasuredHeight();
53 | inputAnimator(mBeginLocation, width, height);
54 | } catch (NumberFormatException e) {
55 | Toast.makeText(PreciseLocationActivity.this, "请输入正确的经纬度!", Toast.LENGTH_SHORT).show();
56 | }
57 | }
58 | });
59 | mTopbanner.setTopBannerListener(new TopBanner.OnTopBannerListener() {
60 | @Override
61 | public void leftClick(View v) {
62 | finish();
63 | }
64 |
65 | @Override
66 | public void rightClick(View v) {
67 |
68 | }
69 | });
70 | mPbLocating.setOnClickListener(new View.OnClickListener() {
71 | @Override
72 | public void onClick(View v) {
73 | showTip("精确定位", View.GONE);
74 | mPbLocating.setVisibility(View.GONE);
75 | mBeginLocation.setVisibility(View.VISIBLE);
76 | repaintView(mBeginLocation);
77 | }
78 | });
79 | }
80 |
81 | /**
82 | * 使组件变回原有形状
83 | * @param view
84 | */
85 | private void repaintView(final View view){
86 | AnimatorSet set = new AnimatorSet();
87 |
88 | ValueAnimator animator = ValueAnimator.ofFloat(width, 0);
89 | animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
90 |
91 | @Override
92 | public void onAnimationUpdate(ValueAnimator animation) {
93 | float value = (Float) animation.getAnimatedValue();
94 | ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) mBeginLocation
95 | .getLayoutParams();
96 | params.leftMargin = (int) value;
97 | params.rightMargin = (int) value;
98 | view.setLayoutParams(params);
99 | }
100 | });
101 |
102 | ObjectAnimator animator2 = ObjectAnimator.ofFloat(view,
103 | "scaleX", 0.5f, 1f);
104 | set.setDuration(1000);
105 | set.setInterpolator(new AccelerateDecelerateInterpolator());
106 | set.playTogether(animator, animator2);
107 | set.start();
108 | }
109 |
110 | private void initViews() {
111 | mLatitudeValue = (EditText)findViewById(R.id.et_latitude);
112 | mLongitudeValue = (EditText)findViewById(R.id.et_longitude);
113 | mBeginLocation = (AppCompatButton)findViewById(R.id.btn_precise_location);
114 | mTopbanner = (TopBanner) findViewById(R.id.topbanner);
115 | mPbLocating = (ProgressBar)findViewById(R.id.pb_locating);
116 | mTip = (TextView)findViewById(R.id.tv_tip);
117 | }
118 |
119 |
120 | private void inputAnimator(final View view, float w, float h) {
121 |
122 | AnimatorSet set = new AnimatorSet();
123 |
124 | ValueAnimator animator = ValueAnimator.ofFloat(0, w);
125 | animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
126 |
127 | @Override
128 | public void onAnimationUpdate(ValueAnimator animation) {
129 | float value = (Float) animation.getAnimatedValue();
130 | ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) mBeginLocation
131 | .getLayoutParams();
132 | params.leftMargin = (int) value;
133 | params.rightMargin = (int) value;
134 | view.setLayoutParams(params);
135 | }
136 | });
137 |
138 | ObjectAnimator animator2 = ObjectAnimator.ofFloat(view,
139 | "scaleX", 1f, 0.5f);
140 | set.setDuration(1000);
141 | set.setInterpolator(new AccelerateDecelerateInterpolator());
142 | set.playTogether(animator, animator2);
143 | set.start();
144 | set.addListener(new Animator.AnimatorListener() {
145 |
146 | @Override
147 | public void onAnimationStart(Animator animation) {
148 |
149 | }
150 |
151 | @Override
152 | public void onAnimationRepeat(Animator animation) {
153 | // TODO Auto-generated method stub
154 |
155 | }
156 |
157 | @Override
158 | public void onAnimationEnd(Animator animation) {
159 | showTip("穿越完成", View.VISIBLE);
160 | mBeginLocation.setVisibility(View.GONE);
161 | mPbLocating.setVisibility(View.VISIBLE);
162 | progressAnimator(mPbLocating);
163 | }
164 |
165 | @Override
166 | public void onAnimationCancel(Animator animation) {
167 | // TODO Auto-generated method stub
168 |
169 | }
170 | });
171 |
172 | }
173 |
174 | private void showTip(String title, int isVisible) {
175 | mTopbanner.setTitleText(title);
176 | mTip.setVisibility(isVisible);
177 | }
178 |
179 | private void progressAnimator(final View view) {
180 | PropertyValuesHolder animator = PropertyValuesHolder.ofFloat("scaleX",
181 | 0.5f, 1f);
182 | PropertyValuesHolder animator2 = PropertyValuesHolder.ofFloat("scaleY",
183 | 0.5f, 1f);
184 | ObjectAnimator animator3 = ObjectAnimator.ofPropertyValuesHolder(view,
185 | animator, animator2);
186 | animator3.setDuration(1000);
187 | animator3.setInterpolator(new JellyInterpolator());
188 | animator3.start();
189 | }
190 |
191 | public static void openActivity(Context context){
192 | Intent intent = new Intent(context, PreciseLocationActivity.class);
193 | context.startActivity(intent);
194 | }
195 |
196 | @Override
197 | protected void onDestroy() {
198 | super.onDestroy();
199 | mPbLocating.clearAnimation();
200 | mBeginLocation.clearAnimation();
201 | }
202 | }
203 |
--------------------------------------------------------------------------------
/virtuallocation/src/main/java/top/littlerich/virtuallocation/adapter/AppAdapter.java:
--------------------------------------------------------------------------------
1 | package top.littlerich.virtuallocation.adapter;
2 |
3 | import android.content.Context;
4 | import android.support.v7.widget.RecyclerView;
5 | import android.view.LayoutInflater;
6 | import android.view.View;
7 | import android.view.ViewGroup;
8 | import android.widget.ImageView;
9 | import android.widget.TextView;
10 |
11 | import java.util.ArrayList;
12 | import java.util.List;
13 |
14 | import top.littlerich.virtuallocation.R;
15 | import top.littlerich.virtuallocation.model.MyAppInfo;
16 |
17 | /**
18 | * Created by xuqingfu on 2017/4/24.
19 | */
20 |
21 | public class AppAdapter extends RecyclerView.Adapter {
22 |
23 | List mListData = new ArrayList();
24 | private Context mContext;
25 |
26 | public AppAdapter(Context context) {
27 | mContext = context;
28 | }
29 |
30 | @Override
31 | public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
32 | View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_app_info, parent, false);
33 | ViewHolder vh = new ViewHolder(view);
34 | return vh;
35 | }
36 |
37 | @Override
38 | public void onBindViewHolder(ViewHolder holder, int position) {
39 | MyAppInfo myAppInfo = mListData.get(position);
40 | holder.iv_app_icon.setImageDrawable(myAppInfo.getImage());
41 | holder.tx_app_name.setText(myAppInfo.getAppName());
42 | holder.tx_app_pkg.setText(myAppInfo.getPkgName());
43 | }
44 |
45 | @Override
46 | public int getItemCount() {
47 | return mListData != null ? mListData.size() : 0;
48 | }
49 |
50 | public void setData(List myAppInfos) {
51 | this.mListData = myAppInfos;
52 | notifyDataSetChanged();
53 | }
54 |
55 | /*
56 |
57 |
58 |
59 |
60 | @Override
61 | public View getView(int position, View convertView, ViewGroup parent) {
62 | ViewHolder mViewHolder;
63 | MyAppInfo myAppInfo = mListData.get(position);
64 | if (convertView == null) {
65 | mViewHolder = new ViewHolder();
66 | convertView = LayoutInflater.from(mContext).inflate(R.layout.item_app_info, null);
67 | mViewHolder.iv_app_icon = (ImageView) convertView.findViewById(R.id.iv_app_icon);
68 | mViewHolder.tx_app_name = (TextView) convertView.findViewById(R.id.tv_app_name);
69 | convertView.setTag(mViewHolder);
70 | } else {
71 | mViewHolder = (ViewHolder) convertView.getTag();
72 | }
73 | mViewHolder.iv_app_icon.setImageDrawable(myAppInfo.getImage());
74 | mViewHolder.tx_app_name.setText(myAppInfo.getAppName());
75 | return convertView;
76 | }*/
77 |
78 | public static class ViewHolder extends RecyclerView.ViewHolder {
79 |
80 | ImageView iv_app_icon;
81 | TextView tx_app_name;
82 | TextView tx_app_pkg;
83 |
84 | public ViewHolder(View itemView) {
85 | super(itemView);
86 | iv_app_icon = (ImageView) itemView.findViewById(R.id.iv_app_icon);
87 | tx_app_name = (TextView) itemView.findViewById(R.id.tv_app_name);
88 | tx_app_pkg = (TextView)itemView.findViewById(R.id.tv_app_pkg);
89 | }
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/virtuallocation/src/main/java/top/littlerich/virtuallocation/base/BaseActivity.java:
--------------------------------------------------------------------------------
1 | package top.littlerich.virtuallocation.base;
2 |
3 | import android.app.Activity;
4 | import android.os.Bundle;
5 | import android.support.v7.widget.Toolbar;
6 | import android.view.LayoutInflater;
7 | import android.view.View;
8 | import android.view.Window;
9 |
10 | import top.littlerich.virtuallocation.view.CustomProgressDialog;
11 |
12 |
13 | /**
14 | * Created by xuqingfu on 2017/4/15.
15 | */
16 | public abstract class BaseActivity extends Activity {
17 | protected View mView;
18 | protected CustomProgressDialog progressDialog;
19 | protected Toolbar toolbar;
20 |
21 | @Override
22 | protected void onCreate(Bundle savedInstanceState) {
23 | super.onCreate(savedInstanceState);
24 | requestWindowFeature(Window.FEATURE_NO_TITLE);
25 | Object object = getContentViewId();
26 | if (object instanceof Integer) {
27 | mView = LayoutInflater.from(this).inflate((Integer) object, null);
28 | } else if (object instanceof View) {
29 | mView = (View) object;
30 | }
31 | setContentView(mView);
32 | // toolbar = (Toolbar) findViewById(R.id.toolbar);
33 | IniView();
34 | progressDialog = new CustomProgressDialog(this);
35 | progressDialog.setCancelable(true);
36 | progressDialog.setCanceledOnTouchOutside(false);
37 | IniLister();
38 | IniData();
39 | }
40 |
41 | /**
42 | * @Title: getContentViewId
43 | * @Description: 布局文件Id
44 | */
45 | protected abstract Object getContentViewId();
46 |
47 | /**
48 | * @Title: IniView
49 | * @Description: 初始化View
50 | */
51 | protected abstract void IniView();
52 |
53 | /**
54 | * @Title: IniLister
55 | * @Description: 初始化接口
56 | */
57 | protected abstract void IniLister();
58 |
59 | /**
60 | * @Title: IniData
61 | * @Description: 初始化数据
62 | */
63 | protected abstract void IniData();
64 |
65 | /**
66 | * thisFinish 当前关闭
67 | */
68 | protected abstract void thisFinish();
69 |
70 | @Override
71 | public void onBackPressed() {
72 | thisFinish();
73 | }
74 |
75 | /**
76 | * showProgressDialog 显示等待框
77 | *
78 | * @param text 显示文字
79 | */
80 | public void showProgressDialog(String text) {
81 | if (progressDialog != null) {
82 | progressDialog.show();
83 | progressDialog.setMessage(text);
84 | }
85 | }
86 |
87 | /**
88 | * cancelProgressDialog 取消等待框
89 | */
90 | public void cancelProgressDialog() {
91 | if (progressDialog != null && progressDialog.isShowing()) {
92 | progressDialog.dismiss();
93 | }
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/virtuallocation/src/main/java/top/littlerich/virtuallocation/base/BaseDialog.java:
--------------------------------------------------------------------------------
1 | package top.littlerich.virtuallocation.base;
2 |
3 | import android.app.Dialog;
4 | import android.content.Context;
5 | import android.os.Bundle;
6 | import android.view.LayoutInflater;
7 | import android.view.View;
8 |
9 | import top.littlerich.virtuallocation.R;
10 |
11 |
12 | /**
13 | * Created by xuqingfu on 2017/4/15.
14 | */
15 | public abstract class BaseDialog extends Dialog {
16 | protected View mView;
17 | protected Context mContext;
18 |
19 | public BaseDialog(Context context) {
20 | this(context, R.style.clashDialog);
21 | }
22 |
23 | public BaseDialog(Context context, int theme) {
24 | super(context, theme);
25 | this.mContext = context;
26 | }
27 |
28 | @Override
29 | protected void onCreate(Bundle savedInstanceState) {
30 | super.onCreate(savedInstanceState);
31 | LayoutInflater mLayoutInflater = LayoutInflater.from(mContext);
32 | mView = mLayoutInflater.inflate(getContentViewId(), null);
33 | this.setContentView(mView);
34 | InitView();
35 | IniListener();
36 | InitData();
37 | }
38 |
39 | /**
40 | * 初始化view变量,用于显示
41 | */
42 | protected abstract int getContentViewId();
43 |
44 | /**
45 | * 初始化所有控件
46 | */
47 | protected abstract void InitView();
48 |
49 | /**
50 | * 设置事件
51 | */
52 | protected abstract void IniListener();
53 |
54 | /**
55 | * 初始化所有数据
56 | */
57 | protected abstract void InitData();
58 |
59 | }
60 |
--------------------------------------------------------------------------------
/virtuallocation/src/main/java/top/littlerich/virtuallocation/common/AppApplication.java:
--------------------------------------------------------------------------------
1 | package top.littlerich.virtuallocation.common;
2 |
3 | import android.app.Application;
4 |
5 | import com.baidu.mapapi.SDKInitializer;
6 |
7 | import top.littlerich.virtuallocation.model.Gps;
8 |
9 | /**
10 | * Created by xuqingfu on 2017/4/15.
11 | */
12 | public class AppApplication extends Application {
13 |
14 | /**全局GPS*/
15 | public static Gps mMockGps;
16 |
17 | static {
18 | mMockGps = Config.COMPANY;
19 | }
20 |
21 | @Override
22 | public void onCreate() {
23 | super.onCreate();
24 | // 在使用 SDK 各组间之前初始化 context 信息,传入 ApplicationContext
25 | SDKInitializer.initialize(this);
26 | }
27 |
28 | }
--------------------------------------------------------------------------------
/virtuallocation/src/main/java/top/littlerich/virtuallocation/common/Common.java:
--------------------------------------------------------------------------------
1 | package top.littlerich.virtuallocation.common;
2 |
3 | /**
4 | * Created by xuqingfu on 2017/5/31.
5 | */
6 |
7 | public class Common {
8 | public static final String SP_FILTER_APP_PKG_NAME = "hook_app_name";
9 | }
10 |
--------------------------------------------------------------------------------
/virtuallocation/src/main/java/top/littlerich/virtuallocation/common/Config.java:
--------------------------------------------------------------------------------
1 | package top.littlerich.virtuallocation.common;
2 |
3 | import top.littlerich.virtuallocation.model.Gps;
4 |
5 | /**
6 | * Created by xuqingfu on 2017/5/26.
7 | */
8 |
9 | public class Config {
10 |
11 | public static final Gps SWUN = new Gps(30.6386505171,104.0492391586);
12 | public static final Gps CAPITAL = new Gps(39.9127646676,116.3859844208);
13 | public static final Gps COMPANY = new Gps(30.5819505065,104.0539652109);
14 |
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/virtuallocation/src/main/java/top/littlerich/virtuallocation/listener/AsyncLocationResultListener.java:
--------------------------------------------------------------------------------
1 | package top.littlerich.virtuallocation.listener;
2 |
3 | import com.baidu.location.BDLocation;
4 | import com.baidu.location.BDLocationListener;
5 | import com.baidu.mapapi.map.MapView;
6 | import com.baidu.mapapi.model.LatLng;
7 |
8 | import top.littlerich.virtuallocation.activity.MainActivity;
9 |
10 | import static top.littlerich.virtuallocation.activity.MainActivity.myGpslatitude;
11 | import static top.littlerich.virtuallocation.activity.MainActivity.myGpslongitude;
12 | import static top.littlerich.virtuallocation.activity.MainActivity.setCurrentMapLatLng;
13 |
14 | /**
15 | * 定位结果回调
16 | * API: http://lbsyun.baidu.com/index.php?title=android-locsdk/guide/getloc
17 | * Created by xuqingfu on 2017/5/3.
18 | */
19 |
20 | public class AsyncLocationResultListener implements BDLocationListener {
21 |
22 | private MapView mMapView;
23 | boolean isFirstLoc = true;// 是否首次定位
24 | //private double myGpslatitude, myGpslongitude;
25 |
26 | public AsyncLocationResultListener(MapView mapView, boolean isFirstLoc) {
27 | mMapView = mapView;
28 | this.isFirstLoc = isFirstLoc;
29 | //this.myGpslatitude = myGpslatitude;
30 | // this.myGpslongitude = myGpslongitude;
31 | }
32 |
33 | @Override
34 | public void onReceiveLocation(BDLocation location) {
35 | // map view 销毁后不在处理新接收的位置
36 | if (location == null || mMapView == null) {
37 | return;
38 | }
39 |
40 | if (isFirstLoc) {
41 | isFirstLoc = false;
42 | MainActivity.myGpslatitude = location.getLatitude();
43 | MainActivity.myGpslongitude = location.getLongitude();
44 | LatLng ll = new LatLng(myGpslatitude, myGpslongitude);
45 | setCurrentMapLatLng(ll);
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/virtuallocation/src/main/java/top/littlerich/virtuallocation/listener/GeoCoderListener.java:
--------------------------------------------------------------------------------
1 | package top.littlerich.virtuallocation.listener;
2 |
3 | import android.content.Context;
4 | import android.widget.TextView;
5 | import android.widget.Toast;
6 |
7 | import com.baidu.mapapi.search.core.SearchResult;
8 | import com.baidu.mapapi.search.geocode.GeoCodeResult;
9 | import com.baidu.mapapi.search.geocode.OnGetGeoCoderResultListener;
10 | import com.baidu.mapapi.search.geocode.ReverseGeoCodeResult;
11 |
12 | /**
13 | * 地理编码:1、正向地图编码 2、反向地图编码
14 | * Created by xuqingfu on 2017/5/4.
15 | */
16 |
17 | public class GeoCoderListener implements OnGetGeoCoderResultListener {
18 |
19 | private Context mContext;
20 | private TextView mLocationTip;
21 |
22 | public GeoCoderListener(Context context, TextView locationTip) {
23 | mContext = context;
24 | mLocationTip = locationTip;
25 | }
26 |
27 | /**
28 | * 搜索(根据实地信息-->经纬坐标)
29 | * @param geoCodeResult
30 | */
31 | @Override
32 | public void onGetGeoCodeResult(GeoCodeResult geoCodeResult) {
33 |
34 | }
35 |
36 | /**
37 | * 搜索(根据坐标-->实地信息)
38 | * @param result
39 | */
40 | @Override
41 | public void onGetReverseGeoCodeResult(ReverseGeoCodeResult result) {
42 | if (result == null || result.error != SearchResult.ERRORNO.NO_ERROR) {
43 | Toast.makeText(mContext, "抱歉,未能找到结果", Toast.LENGTH_LONG).show();
44 | return;
45 | }
46 | mLocationTip.setText(String.format("伪造位置:%s", result.getAddress()));
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/virtuallocation/src/main/java/top/littlerich/virtuallocation/listener/MapClickListener.java:
--------------------------------------------------------------------------------
1 | package top.littlerich.virtuallocation.listener;
2 |
3 | import android.widget.Button;
4 |
5 | import com.baidu.mapapi.map.BaiduMap;
6 | import com.baidu.mapapi.map.MapPoi;
7 | import com.baidu.mapapi.model.LatLng;
8 |
9 | import static top.littlerich.virtuallocation.activity.MainActivity.setCurrentMapLatLng;
10 |
11 | /**
12 | * 地图单击事件监听接口
13 | * Created by xuqingfu on 2017/5/4.
14 | */
15 |
16 | public class MapClickListener implements BaiduMap.OnMapClickListener {
17 |
18 | private Button mLocOk;
19 |
20 | public MapClickListener(Button locOk) {
21 | mLocOk = locOk;
22 | }
23 |
24 | /**
25 | * 地图单击事件
26 | * @param latLng 点击的地理坐标
27 | */
28 | @Override
29 | public void onMapClick(LatLng latLng) {
30 | setCurrentMapLatLng(latLng);
31 | if ("穿越完成".equals(mLocOk.getText().toString())) {
32 | mLocOk.setText("修改位置");
33 | }
34 | }
35 |
36 | /**
37 | * 地图内 Poi 单击事件
38 | * @param mapPoi 点击的 poi 信息
39 | * @return
40 | */
41 | @Override
42 | public boolean onMapPoiClick(MapPoi mapPoi) {
43 | return false;
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/virtuallocation/src/main/java/top/littlerich/virtuallocation/listener/MarkerDragListener.java:
--------------------------------------------------------------------------------
1 | package top.littlerich.virtuallocation.listener;
2 |
3 | import com.baidu.mapapi.map.BaiduMap;
4 | import com.baidu.mapapi.map.Marker;
5 |
6 | import static top.littlerich.virtuallocation.activity.MainActivity.setCurrentMapLatLng;
7 |
8 | /**
9 | * Created by xuqingfu on 2017/5/4.
10 | */
11 |
12 | public class MarkerDragListener implements BaiduMap.OnMarkerDragListener {
13 | /**
14 | * 地图上标记拖动
15 | * @param marker
16 | */
17 | @Override
18 | public void onMarkerDrag(Marker marker) {
19 |
20 | }
21 |
22 | /**
23 | * 地图上标记拖动结束
24 | * @param marker
25 | */
26 | @Override
27 | public void onMarkerDragEnd(Marker marker) {
28 | setCurrentMapLatLng(marker.getPosition());
29 | }
30 |
31 | /**
32 | * 地图上标记拖动开始
33 | * @param marker
34 | */
35 | @Override
36 | public void onMarkerDragStart(Marker marker) {
37 |
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/virtuallocation/src/main/java/top/littlerich/virtuallocation/model/Gps.java:
--------------------------------------------------------------------------------
1 | package top.littlerich.virtuallocation.model;
2 |
3 | /**
4 | * Created by xuqingfu on 2017/5/26.
5 | */
6 |
7 | public class Gps {
8 | public double mLatitude;
9 | public double mLongitude;
10 |
11 | public Gps(double latitude, double longitude) {
12 | mLatitude = latitude;
13 | mLongitude = longitude;
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/virtuallocation/src/main/java/top/littlerich/virtuallocation/model/MyAppInfo.java:
--------------------------------------------------------------------------------
1 | package top.littlerich.virtuallocation.model;
2 |
3 | import android.graphics.drawable.Drawable;
4 | /**
5 | * Created by xuqingfu on 17/4/24.
6 | */
7 | public class MyAppInfo {
8 | private Drawable image;
9 | private String appName;
10 | private String pkgName;
11 |
12 | public MyAppInfo(Drawable image, String appName, String pkgName) {
13 | this.image = image;
14 | this.appName = appName;
15 | this.pkgName = pkgName;
16 | }
17 | public MyAppInfo() {
18 |
19 | }
20 |
21 | public Drawable getImage() {
22 | return image;
23 | }
24 |
25 | public void setImage(Drawable image) {
26 | this.image = image;
27 | }
28 |
29 | public String getAppName() {
30 | return appName;
31 | }
32 |
33 | public void setAppName(String appName) {
34 | this.appName = appName;
35 | }
36 |
37 | public String getPkgName() {
38 | return pkgName;
39 | }
40 |
41 | public void setPkgName(String pkgName) {
42 | this.pkgName = pkgName;
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/virtuallocation/src/main/java/top/littlerich/virtuallocation/presenter/HookApis.java:
--------------------------------------------------------------------------------
1 | package top.littlerich.virtuallocation.presenter;
2 |
3 | import android.util.Log;
4 |
5 | import de.robv.android.xposed.XC_MethodHook;
6 | import de.robv.android.xposed.XposedHelpers;
7 | import top.littlerich.virtuallocation.common.AppApplication;
8 |
9 | /**
10 | * Created by xuqingfu on 2017/5/26.
11 | */
12 |
13 | public class HookApis {
14 |
15 | private static final String TAG = "silence";
16 |
17 | /**
18 | * 修改高德地图的经纬度值
19 | * @param
20 | * @throws ClassNotFoundException
21 | */
22 | public static void findMethodAmapLongitudeAndLatitude(ClassLoader classLoader) {
23 | try {
24 | Class aMapLocationClazz = classLoader.loadClass("com.amap.api.location.AMapLocation");
25 | XposedHelpers.findAndHookMethod(aMapLocationClazz, "getLongitude", new Object[]{new XC_MethodHook() {
26 | protected void beforeHookedMethod(MethodHookParam arg3) throws Throwable {
27 | arg3.setResult(Double.valueOf(AppApplication.mMockGps.mLongitude));
28 | Log.d(TAG, "修改高德地图的经纬度值:" + AppApplication.mMockGps.mLongitude + ":" + AppApplication.mMockGps.mLatitude);
29 | }
30 | }});
31 |
32 | XposedHelpers.findAndHookMethod(aMapLocationClazz, "getLatitude", new Object[]{new XC_MethodHook() {
33 | protected void beforeHookedMethod(MethodHookParam arg3) throws Throwable {
34 | arg3.setResult(Double.valueOf(AppApplication.mMockGps.mLatitude));
35 | }
36 | }});
37 | } catch (Exception e) {
38 | Log.i(TAG, "该程序无高德地图模块,无法HOOK");
39 | }
40 | }
41 |
42 |
43 | }
44 |
--------------------------------------------------------------------------------
/virtuallocation/src/main/java/top/littlerich/virtuallocation/presenter/JellyInterpolator.java:
--------------------------------------------------------------------------------
1 | package top.littlerich.virtuallocation.presenter;
2 |
3 | import android.view.animation.LinearInterpolator;
4 |
5 | public class JellyInterpolator extends LinearInterpolator {
6 | private float factor;
7 |
8 | public JellyInterpolator() {
9 | this.factor = 0.15f;
10 | }
11 |
12 | @Override
13 | public float getInterpolation(float input) {
14 | return (float) (Math.pow(2, -10 * input)
15 | * Math.sin((input - factor / 4) * (2 * Math.PI) / factor) + 1);
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/virtuallocation/src/main/java/top/littlerich/virtuallocation/presenter/SdkHookManager.java:
--------------------------------------------------------------------------------
1 | package top.littlerich.virtuallocation.presenter;
2 |
3 | import android.content.ContentResolver;
4 | import android.location.Location;
5 | import android.provider.Settings;
6 |
7 | import de.robv.android.xposed.XC_MethodHook;
8 | import de.robv.android.xposed.XC_MethodReplacement;
9 | import de.robv.android.xposed.XposedHelpers;
10 | import de.robv.android.xposed.callbacks.XC_LoadPackage;
11 |
12 | import static android.provider.Settings.Secure.LOCATION_MODE_SENSORS_ONLY;
13 |
14 | /**
15 | * Created by xuqingfu on 2017/5/31.
16 | */
17 |
18 | public class SdkHookManager {
19 |
20 | /**
21 | * 判断是否开启允许ADB模拟定位功能
22 | */
23 | public static void findMethodIsFromMockProvider(){
24 | XposedHelpers.findAndHookMethod(Location.class, "isFromMockProvider", new XC_MethodHook() {
25 | @Override
26 | protected void afterHookedMethod(MethodHookParam param) throws Throwable {
27 | super.afterHookedMethod(param);
28 | param.setResult(false);
29 | }
30 | });
31 | }
32 |
33 | /**
34 | * 劫持判断是否使用虚拟定位
35 | * @param loadPackageParam
36 | */
37 | public static void findMethodGetInt(XC_LoadPackage.LoadPackageParam loadPackageParam){
38 | // boolean isOpen = Settings.Secure.getInt(getContentResolver(),Settings.Secure.ALLOW_MOCK_LOCATION, 0) != 0;
39 | XposedHelpers.findAndHookMethod("android.provider.Settings$Secure", loadPackageParam.classLoader, "getInt", ContentResolver.class, String.class, int.class, new XC_MethodHook() {
40 |
41 | /**
42 | * 设置返回值类型:
43 | * 1、gpsEnabled && networkEnabled:LOCATION_MODE_HIGH_ACCURACY
44 | * 2、gpsEnabled:LOCATION_MODE_SENSORS_ONLY
45 | * 3、networkEnabled:LOCATION_MODE_BATTERY_SAVING
46 | * 4、disable:LOCATION_MODE_OFF
47 | */
48 | @Override
49 | protected void afterHookedMethod(MethodHookParam param) throws Throwable {
50 | super.afterHookedMethod(param);
51 | param.setResult(LOCATION_MODE_SENSORS_ONLY);
52 | }
53 | });
54 |
55 | XposedHelpers.findAndHookMethod(Settings.Secure.class, "getInt", ContentResolver.class, String.class, int.class, new XC_MethodReplacement() {
56 | @Override
57 | protected Object replaceHookedMethod(MethodHookParam methodHookParam) throws Throwable {
58 | return LOCATION_MODE_SENSORS_ONLY;
59 | }
60 | });
61 | }
62 |
63 |
64 |
65 | }
66 |
--------------------------------------------------------------------------------
/virtuallocation/src/main/java/top/littlerich/virtuallocation/util/ApkTool.java:
--------------------------------------------------------------------------------
1 | package top.littlerich.virtuallocation.util;
2 |
3 | import android.content.pm.ApplicationInfo;
4 | import android.content.pm.PackageInfo;
5 | import android.content.pm.PackageManager;
6 | import android.util.Log;
7 |
8 | import java.util.ArrayList;
9 | import java.util.List;
10 |
11 | import top.littlerich.virtuallocation.model.MyAppInfo;
12 |
13 | /**
14 | * 扫描本地安装的应用,工具类
15 | *
16 | * Created by xuqingfu on 2017/4/24.
17 | */
18 | public class ApkTool {
19 | static String TAG = "ApkTool";
20 | public static List mLocalInstallApps = null;
21 |
22 | public static List scanLocalInstallAppList(PackageManager packageManager, boolean isFilter) {
23 | List myAppInfos = new ArrayList();
24 | try {
25 | List packageInfos = packageManager.getInstalledPackages(0);
26 | for (int i = 0; i < packageInfos.size(); i++) {
27 | PackageInfo packageInfo = packageInfos.get(i);
28 | //过滤掉系统app
29 | if (isFilter && (ApplicationInfo.FLAG_SYSTEM & packageInfo.applicationInfo.flags) != 0) {
30 | continue;
31 | }
32 | MyAppInfo myAppInfo = new MyAppInfo();
33 | myAppInfo.setPkgName(packageInfo.applicationInfo.loadLabel(packageManager).toString());
34 |
35 | myAppInfo.setAppName(packageInfo.packageName);
36 | if (packageInfo.applicationInfo.loadIcon(packageManager) == null) {
37 | continue;
38 | }
39 | myAppInfo.setImage(packageInfo.applicationInfo.loadIcon(packageManager));
40 | myAppInfos.add(myAppInfo);
41 | }
42 | } catch (Exception e) {
43 | Log.e(TAG, "===============获取应用包信息失败");
44 | }
45 | return myAppInfos;
46 | }
47 |
48 | }
49 |
--------------------------------------------------------------------------------
/virtuallocation/src/main/java/top/littlerich/virtuallocation/util/LocationUtil.java:
--------------------------------------------------------------------------------
1 | package top.littlerich.virtuallocation.util;
2 |
3 | import android.content.Context;
4 | import android.location.Criteria;
5 | import android.location.Location;
6 | import android.location.LocationListener;
7 | import android.location.LocationManager;
8 | import android.location.LocationProvider;
9 | import android.os.Build;
10 | import android.os.Bundle;
11 | import android.os.SystemClock;
12 | import android.provider.Settings;
13 | import android.util.Log;
14 |
15 | /**
16 | * Created by xuqingfu on 2017/4/24.
17 | */
18 |
19 | public class LocationUtil {
20 |
21 | private static final String TAG = "silence";
22 |
23 | private static Double mLatitude = 30.6363334898;
24 | private static Double mLongitude = 104.0486168861;
25 |
26 | private static LocationManager locationManager;
27 | private static boolean canMockPosition;
28 | /**
29 | * 判断在Android6.0+上是否将本程序添加到ADB模拟定位中
30 | */
31 | public static boolean hasAddTestProvider = false;
32 | private static Thread mMockThread;
33 |
34 |
35 | /**
36 | * 初始化模拟定位,并检测是否开启ADB模拟定位
37 | * @param context
38 | * @return
39 | */
40 | public static boolean initLocation(Context context) {
41 | locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
42 | canMockPosition = (Settings.Secure.getInt(context.getContentResolver(), Settings.Secure.ALLOW_MOCK_LOCATION, 0) != 0) || Build.VERSION.SDK_INT > 22;
43 | Log.d(TAG, "hasAddTestProvider:" + canMockPosition);
44 | return canMockPosition;
45 | }
46 |
47 | /**
48 | * 配置LocationManger参数
49 | */
50 | public static void initLocationManager() throws Exception{
51 | if (canMockPosition && !hasAddTestProvider) {
52 | try {
53 | String providerStr = LocationManager.GPS_PROVIDER;
54 | LocationProvider provider = locationManager.getProvider(providerStr);
55 | if (provider != null) {
56 | locationManager.addTestProvider(
57 | provider.getName()
58 | , provider.requiresNetwork()
59 | , provider.requiresSatellite()
60 | , provider.requiresCell()
61 | , provider.hasMonetaryCost()
62 | , provider.supportsAltitude()
63 | , provider.supportsSpeed()
64 | , provider.supportsBearing()
65 | , provider.getPowerRequirement()
66 | , provider.getAccuracy());
67 | } else {
68 | locationManager.addTestProvider(
69 | providerStr
70 | , true, true, false, false, true, true, true
71 | , Criteria.POWER_HIGH
72 | , Criteria.ACCURACY_FINE);
73 | }
74 | locationManager.setTestProviderEnabled(providerStr, true);
75 | locationManager.requestLocationUpdates(providerStr, 0, 0, new LocationStatuListener());
76 | locationManager.setTestProviderStatus(providerStr, LocationProvider.AVAILABLE, null, System.currentTimeMillis());
77 | Log.i(TAG,"already open GPS!");
78 | // 模拟位置可用
79 | hasAddTestProvider = true;
80 | Log.d(TAG, "hasAddTestProvider:" + hasAddTestProvider);
81 | canMockPosition = true;
82 | } catch (Exception e) {
83 | canMockPosition = false;
84 | Log.d(TAG, "初始化异常:" + e);
85 | throw e;
86 | }
87 | }
88 | }
89 |
90 | /**
91 | * 开启虚拟定位线程
92 | */
93 | public static void startLocaton(){
94 | if (mMockThread == null) {
95 | mMockThread = new Thread(new Runnable() {
96 | @Override
97 | public void run() {
98 | while (true) {
99 | try {
100 | Thread.sleep(500);
101 | if (!hasAddTestProvider) {
102 | Log.d("xqf", "定位服务未打开");
103 | continue;
104 | }
105 | setLocation(LocationUtil.mLatitude, LocationUtil.mLongitude);
106 | Log.d(TAG, "setLocation240=latitude:" + mLatitude + "?longitude:" + mLongitude);
107 | } catch (InterruptedException e) {
108 | e.printStackTrace();
109 | } catch (Exception e) {
110 | e.printStackTrace();
111 | }
112 | }
113 | }
114 | });
115 | mMockThread.start();
116 | }
117 | }
118 |
119 | /**
120 | * GPS定位需要不停的刷新经纬度值
121 | */
122 | private static void setLocation(double latitude, double longitude) throws Exception{
123 | try {
124 | String providerStr = LocationManager.GPS_PROVIDER;
125 | Location mockLocation = new Location(providerStr);
126 | mockLocation.setLatitude(latitude);
127 | mockLocation.setLongitude(longitude);
128 | mockLocation.setAltitude(0); // 高程(米)
129 | mockLocation.setBearing(0); // 方向(度)
130 | mockLocation.setSpeed(0); //速度(米/秒)
131 | mockLocation.setAccuracy(2); // 精度(米)
132 | mockLocation.setTime(System.currentTimeMillis()); // 本地时间
133 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
134 | //api 16以上的需要加上这一句才能模拟定位 , 也就是targetSdkVersion > 16
135 | mockLocation.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
136 | }
137 | locationManager.setTestProviderLocation(providerStr, mockLocation);
138 | } catch (Exception e) {
139 | // 防止用户在软件运行过程中关闭模拟位置或选择其他应用
140 | stopMockLocation();
141 | throw e;
142 | }
143 | }
144 |
145 | public static void stopMockLocation() {
146 | if (hasAddTestProvider) {
147 | try {
148 | locationManager.removeTestProvider(LocationManager.GPS_PROVIDER);
149 | } catch (Exception ex) {
150 | // 若未成功addTestProvider,或者系统模拟位置已关闭则必然会出错
151 | }
152 | hasAddTestProvider = false;
153 | }
154 | }
155 |
156 | /**
157 | * 设置地理经纬度值
158 | * @param mLongitude
159 | * @param mLatitude
160 | */
161 | public static void setLongitudeAndLatitude(Double mLongitude, Double mLatitude) {
162 | LocationUtil.mLatitude = mLatitude;
163 | LocationUtil.mLongitude = mLongitude;
164 | }
165 |
166 | /**
167 | * 监听Location经纬度值的修改状态
168 | */
169 | private static class LocationStatuListener implements LocationListener {
170 | @Override
171 | public void onLocationChanged(Location location) {
172 | double lat = location.getLatitude();
173 | double lng = location.getLongitude();
174 | Log.i(TAG, String.format("location: x=%s y=%s", lat, lng));
175 | }
176 |
177 | @Override
178 | public void onStatusChanged(String provider, int status, Bundle extras) {
179 |
180 | }
181 |
182 | @Override
183 | public void onProviderEnabled(String provider) {
184 |
185 | }
186 |
187 | @Override
188 | public void onProviderDisabled(String provider) {
189 |
190 | }
191 | }
192 |
193 | }
194 |
--------------------------------------------------------------------------------
/virtuallocation/src/main/java/top/littlerich/virtuallocation/util/SharePreferenceUtil.java:
--------------------------------------------------------------------------------
1 | package top.littlerich.virtuallocation.util;
2 |
3 | import android.content.Context;
4 | import android.content.SharedPreferences;
5 |
6 | import top.littlerich.virtuallocation.common.Common;
7 |
8 | import static android.content.Context.MODE_PRIVATE;
9 |
10 | /**
11 | * Created by xuqingfu on 2017/3/14.
12 | */
13 |
14 | public class SharePreferenceUtil {
15 |
16 | private static final String SP_FILENAME = "config";
17 |
18 | public static void saveData(Context context, String userName, String psd) {
19 | SharedPreferences sp = context.getSharedPreferences(SP_FILENAME, MODE_PRIVATE);
20 | SharedPreferences.Editor editor = sp.edit();
21 | editor.putString(Common.SP_FILTER_APP_PKG_NAME, userName);
22 | editor.commit();
23 | }
24 |
25 | public static boolean loadData(Context context) {
26 | SharedPreferences sp = context.getSharedPreferences(SP_FILENAME, MODE_PRIVATE);
27 | // Common.USER_NAME = sp.getString(Common.SP_FILTER_APP_PKG_NAME, "").toString();
28 | /*if (TextUtils.isEmpty(Common.USER_NAME) || TextUtils.isEmpty(Common.USER_PWD)) {
29 | return false;
30 | }*/
31 | return true;
32 | }
33 |
34 | public static void cleanData(Context context){
35 | saveData(context, "", "");
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/virtuallocation/src/main/java/top/littlerich/virtuallocation/util/XposedUtil.java:
--------------------------------------------------------------------------------
1 | package top.littlerich.virtuallocation.util;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 |
6 | /**
7 | * Created by xuqingfu on 2017/4/17.
8 | */
9 |
10 | public class XposedUtil {
11 |
12 | private static List pkgs = new ArrayList<>();
13 |
14 | static {
15 | pkgs.add("com.tencent.mm");
16 | pkgs.add("com.tencent.mobileqq");
17 | pkgs.add("com.alibaba.android.rimet");
18 | }
19 |
20 | public static void hookAndChange(ClassLoader classLoader){
21 |
22 | }
23 |
24 | public static boolean isNeedHook(String pkgName){
25 | return pkgs.contains(pkgName);
26 | }
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/virtuallocation/src/main/java/top/littlerich/virtuallocation/view/CircleWaveView.java:
--------------------------------------------------------------------------------
1 | package top.littlerich.virtuallocation.view;
2 |
3 | import android.view.View;
4 | import android.content.Context;
5 | import android.graphics.Canvas;
6 | import android.graphics.Color;
7 | import android.graphics.Paint;
8 | import android.util.AttributeSet;
9 |
10 | /**
11 | * Created by xuqingfu on 2017/5/2.
12 | */
13 |
14 | public class CircleWaveView extends View {
15 | private float mWidth;
16 | private float mHeight;
17 |
18 | private float centerX; // 圆心X
19 | private float centerY; // 圆心Y
20 | private float floatRadius; // 变化的半径
21 | private float maxRadius = -1; // 圆半径
22 | private volatile boolean started = false;
23 | private Paint mLinePaint;
24 | private Paint mSolidPaint;
25 | private int waveColor = Color.LTGRAY; // Color.argb(0, 0, 0, 0); //颜色
26 | private int waveInterval = 100; // 圆环的宽度
27 | private boolean centerAlign = true;// 居中
28 | private float bottomMargin = 0;// 底部margin
29 | private boolean fillCircle = true;// 是否填充成实心圆环
30 |
31 | public CircleWaveView(Context context, AttributeSet attrs) {
32 | this(context, attrs, 0);
33 | }
34 |
35 | public CircleWaveView(Context context) {
36 | this(context, null, 0);
37 | }
38 |
39 | public CircleWaveView(Context context, AttributeSet attrs, int defStyle) {
40 | super(context, attrs, defStyle);
41 | initView();
42 | }
43 |
44 | private void initView() {
45 | mLinePaint = new Paint();
46 | mSolidPaint = new Paint();
47 | }
48 |
49 | private void init() {
50 | mWidth = getWidth();
51 | mHeight = getHeight();
52 |
53 | mLinePaint.setAntiAlias(true);
54 | mLinePaint.setStrokeWidth(1.0F);
55 | mLinePaint.setStyle(Paint.Style.STROKE);
56 | mLinePaint.setColor(waveColor);
57 |
58 | if (fillCircle) {
59 | mSolidPaint.setStyle(Paint.Style.STROKE);
60 | mSolidPaint.setStrokeWidth(waveInterval);
61 | // 设置背景色的颜色
62 | mSolidPaint.setColor(Color.parseColor("#b37400"));
63 | }
64 |
65 | centerX = mWidth / 2.0F;
66 | if (centerAlign) {
67 | centerY = (mHeight / 2.0F);
68 |
69 | } else {
70 | centerY = mHeight - bottomMargin;
71 | }
72 |
73 | if (mWidth >= mHeight) {
74 | maxRadius = mHeight / 2.0F;
75 | } else {
76 | maxRadius = mWidth / 2.0F;
77 | }
78 |
79 | floatRadius = (maxRadius % waveInterval);
80 |
81 | start();
82 | }
83 |
84 | public void start() {
85 | if (!started) {
86 | started = true;
87 | new Thread(thread).start();
88 | }
89 | }
90 |
91 | public void stop() {
92 | // Thread.interrupted();
93 | started = true;
94 | }
95 |
96 | public void onDetachedFromWindow() {
97 | super.onDetachedFromWindow();
98 |
99 | stop();
100 | }
101 |
102 | protected void onDraw(Canvas canvas) {
103 | super.onDraw(canvas);
104 | if (maxRadius <= 0.0F) {
105 | return;
106 | }
107 | float radius = floatRadius % waveInterval;
108 | while (true) {
109 | int alpha = (int) (255.0F * (1.0F - radius / maxRadius));
110 | if (alpha <= 0) {
111 | break;
112 | }
113 | // 设置背景色
114 |
115 | if (fillCircle) {
116 | mSolidPaint.setAlpha(alpha >> 2);
117 | canvas.drawCircle(centerX, centerY, radius - waveInterval / 2,
118 | mSolidPaint);
119 | }
120 | mLinePaint.setAlpha(alpha);
121 | canvas.drawCircle(centerX, centerY, radius, mLinePaint);
122 | radius += waveInterval;
123 | }
124 | }
125 |
126 | public void onWindowFocusChanged(boolean hasWindowFocus) {
127 | super.onWindowFocusChanged(hasWindowFocus);
128 | if (hasWindowFocus) {
129 | init();
130 | } else {
131 | stop();
132 | }
133 | }
134 | //在外面定义一个方法把started设置为true就可以暂停了
135 | private Runnable thread = new Runnable() {
136 |
137 | @Override
138 | public void run() {
139 | // TODO Auto-generated method stub
140 | while (started) {
141 | floatRadius = 4.0F + floatRadius;
142 | if (floatRadius > maxRadius) {
143 | floatRadius = (maxRadius % waveInterval);
144 | postInvalidate();
145 | }
146 | postInvalidate();
147 | try {
148 | Thread.sleep(50L);
149 | } catch (InterruptedException localInterruptedException) {
150 | localInterruptedException.printStackTrace();
151 | }
152 | }
153 | }
154 | };
155 |
156 | public void setMaxRadius(float maxRadius) {
157 | this.maxRadius = maxRadius;
158 | }
159 |
160 | public void setWaveColor(int waveColor) {
161 | this.waveColor = waveColor;
162 | }
163 |
164 | public void setWaveInterval(int waveInterval) {
165 | this.waveInterval = waveInterval;
166 | }
167 |
168 | public void setCenterAlign(boolean centerAlign) {
169 | this.centerAlign = centerAlign;
170 | }
171 |
172 | }
--------------------------------------------------------------------------------
/virtuallocation/src/main/java/top/littlerich/virtuallocation/view/CustomProgressDialog.java:
--------------------------------------------------------------------------------
1 | package top.littlerich.virtuallocation.view;
2 |
3 | import android.content.Context;
4 | import android.widget.TextView;
5 |
6 | import top.littlerich.virtuallocation.R;
7 | import top.littlerich.virtuallocation.base.BaseDialog;
8 |
9 | /**
10 | * Created by xuqingfu on 2017/4/15.
11 | */
12 | public class CustomProgressDialog extends BaseDialog {
13 |
14 | private TextView tvMsg;
15 |
16 | public CustomProgressDialog(Context context) {
17 | super(context);
18 | }
19 |
20 | @Override
21 | protected int getContentViewId() {
22 | return R.layout.dialog_customprogress;
23 | }
24 |
25 | @Override
26 | protected void InitView() {
27 | tvMsg = (TextView) mView.findViewById(R.id.id_tv_loadingmsg);
28 | }
29 |
30 | @Override
31 | protected void IniListener() {
32 | // TODO Auto-generated method stub
33 |
34 | }
35 |
36 | @Override
37 | protected void InitData() {
38 |
39 | }
40 |
41 | public void setMessage(String strMessage) {
42 | if (tvMsg != null) {
43 | tvMsg.setText(strMessage);
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/virtuallocation/src/main/java/top/littlerich/virtuallocation/view/TopBanner.java:
--------------------------------------------------------------------------------
1 | package top.littlerich.virtuallocation.view;
2 |
3 | import android.content.Context;
4 | import android.content.res.TypedArray;
5 | import android.graphics.Color;
6 | import android.graphics.drawable.Drawable;
7 | import android.text.TextUtils.TruncateAt;
8 | import android.util.AttributeSet;
9 | import android.util.TypedValue;
10 | import android.view.Gravity;
11 | import android.view.View;
12 | import android.view.ViewGroup;
13 | import android.widget.ImageView;
14 | import android.widget.LinearLayout;
15 | import android.widget.RelativeLayout;
16 | import android.widget.TextView;
17 |
18 | import top.littlerich.virtuallocation.R;
19 |
20 |
21 | /**
22 | * 自定义Actionbar
23 | */
24 | public class TopBanner extends RelativeLayout {
25 | // private static int LEFT_BTN_ID = 1;
26 | // private static int TITLE_ID = 2;
27 | // private static int RIGHT_BTN_ID = 3;
28 |
29 | private ImageView leftButton;
30 | private ImageView rightButton;
31 | private TextView title;
32 | private LinearLayout leftLayout;
33 | private LinearLayout rightLayout;
34 |
35 | private OnTopBannerListener listener;
36 |
37 | @SuppressWarnings("deprecation")
38 | public TopBanner(Context context, AttributeSet attrs) {
39 | super(context, attrs);
40 | String leftButtonText;
41 | float leftButtonTextSize;
42 | Drawable leftButtonBackground;
43 | int leftButtonTextColor;
44 | boolean leftButtonVisiable;
45 | String rightButtonText;
46 | float rightButtonTextSize;
47 | Drawable rightButtonBackground;
48 | int rightButtonTextColor;
49 | boolean rightButtonVisiable;
50 | String titleText;
51 | float titleTextSize;
52 | int titleTextColor;
53 | float rightButtonHeight;
54 | float rightButtonWidth;
55 | float leftButtonHeight;
56 | float leftButtonWidth;
57 | LayoutParams leftButtonParams;
58 | LayoutParams rightButtonParams;
59 | LayoutParams titleButtonParams;
60 |
61 | LayoutParams leftParams;
62 | LayoutParams rightParams;
63 | // 获取属性
64 | TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.topBanner);
65 |
66 | leftButtonText = typedArray.getString(R.styleable.topBanner_leftButtonText);
67 | leftButtonTextSize = typedArray.getDimension(R.styleable.topBanner_leftButtonTextSize, 10);
68 | leftButtonBackground = typedArray.getDrawable(R.styleable.topBanner_leftButtonBackground);
69 | leftButtonTextColor = typedArray.getColor(R.styleable.topBanner_leftButtonTextColor, Color.BLACK);
70 | leftButtonVisiable = typedArray.getBoolean(R.styleable.topBanner_leftButtonVisiable, true);
71 | rightButtonText = typedArray.getString(R.styleable.topBanner_rightButtonText);
72 | rightButtonTextSize = typedArray.getDimension(R.styleable.topBanner_rightButtonTextSize, 10);
73 | rightButtonBackground = typedArray.getDrawable(R.styleable.topBanner_rightButtonBackground);
74 | rightButtonTextColor = typedArray.getColor(R.styleable.topBanner_rightButtonTextColor, Color.BLACK);
75 | rightButtonVisiable = typedArray.getBoolean(R.styleable.topBanner_rightButtonVisiable, true);
76 |
77 | titleText = typedArray.getString(R.styleable.topBanner_titleText);
78 | titleTextSize = typedArray.getDimension(R.styleable.topBanner_titleTextSize, 20);
79 | titleTextColor = typedArray.getColor(R.styleable.topBanner_titleTextColors, Color.WHITE);
80 |
81 | rightButtonHeight = typedArray.getDimension(R.styleable.topBanner_rightButtonHeight, ViewGroup.LayoutParams.WRAP_CONTENT);
82 | rightButtonWidth = typedArray.getDimension(R.styleable.topBanner_rightButtonWidth, ViewGroup.LayoutParams.WRAP_CONTENT);
83 | leftButtonHeight = typedArray.getDimension(R.styleable.topBanner_leftButtonHeight, ViewGroup.LayoutParams.WRAP_CONTENT);
84 | leftButtonWidth = typedArray.getDimension(R.styleable.topBanner_leftButtonWidth, ViewGroup.LayoutParams.WRAP_CONTENT);
85 |
86 | // 属性重用
87 | typedArray.recycle();
88 |
89 | leftButton = new ImageView(context);
90 | rightButton = new ImageView(context);
91 | title = new TextView(context);
92 |
93 | leftLayout = new LinearLayout(context);
94 | rightLayout = new LinearLayout(context);
95 |
96 | // leftLayout.setPadding(30, 30, 30, 30);
97 | // rightLayout.setPadding(30, 30, 30, 30);
98 |
99 | leftLayout.setBackgroundColor(0x2723bf);
100 | rightLayout.setBackgroundColor(0x2723bf);
101 |
102 | leftParams = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams
103 | .WRAP_CONTENT);
104 | rightParams = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams
105 | .WRAP_CONTENT);
106 |
107 | leftButtonParams = new LayoutParams((int) leftButtonWidth, (int) leftButtonHeight);
108 | rightButtonParams = new LayoutParams((int) rightButtonWidth, (int) rightButtonHeight);
109 | titleButtonParams = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
110 |
111 | leftParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT, RelativeLayout.TRUE);
112 | leftParams.addRule(RelativeLayout.CENTER_VERTICAL, RelativeLayout.TRUE);// 上下居中
113 | // lxh
114 | leftParams.setMargins(40, 0, 0, 0);// 左上右下
115 | // leftButton.setPadding(40, 10, 10, 10);
116 | leftButton.setPaddingRelative(40, 10, 10, 10);
117 |
118 | // leftButtonParams.addRule(RelativeLayout.CENTER_VERTICAL,
119 | // RelativeLayout.TRUE);
120 |
121 | rightParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT, RelativeLayout.TRUE);
122 | rightParams.addRule(RelativeLayout.CENTER_VERTICAL, RelativeLayout.TRUE);
123 | rightParams.setMargins(0, 0, 40, 0);// 左上右下
124 | rightButton.setPaddingRelative(10, 10, 40, 10);
125 | // rightButtonParams.addRule(RelativeLayout.CENTER_VERTICAL,
126 | // RelativeLayout.TRUE);
127 |
128 | titleButtonParams.addRule(RelativeLayout.CENTER_IN_PARENT, RelativeLayout.TRUE);
129 | // titleButtonParams.addRule(RelativeLayout.LEFT_OF, RIGHT_BTN_ID);
130 | // titleButtonParams.addRule(RelativeLayout.RIGHT_OF, LEFT_BTN_ID);
131 |
132 | leftLayout.addView(leftButton, leftButtonParams);
133 | rightLayout.addView(rightButton, rightButtonParams);
134 |
135 | addView(leftLayout, leftParams);
136 | addView(rightLayout, rightParams);
137 | addView(title, titleButtonParams);
138 |
139 | // 设置对应的属性值
140 | // leftButton.setGravity(Gravity.CENTER);
141 | // leftButton.setText(leftButtonText);
142 | // leftButton.setTextColor(leftButtonTextColor);
143 | // leftButton.setTextSize(TypedValue.COMPLEX_UNIT_DIP, leftButtonTextSize);
144 | leftButton.setBackgroundDrawable(leftButtonBackground);
145 | setLeftButtonVisibility(leftButtonVisiable);
146 |
147 | // rightButton.setGravity(Gravity.CENTER);
148 | // rightButton.setText(rightButtonText);
149 | // rightButton.setTextColor(rightButtonTextColor);
150 | // rightButton.setTextSize(TypedValue.COMPLEX_UNIT_DIP, rightButtonTextSize);
151 | rightButton.setBackgroundDrawable(rightButtonBackground);
152 | setRightButtonVisibility(rightButtonVisiable);
153 |
154 | title.setText(titleText);
155 | title.setTextSize(TypedValue.COMPLEX_UNIT_DIP, titleTextSize);
156 | title.setTextColor(titleTextColor);
157 | title.setEllipsize(TruncateAt.MARQUEE);
158 | title.setGravity(Gravity.CENTER);
159 | title.setSingleLine(true);
160 |
161 | leftLayout.setOnClickListener(new OnClickListener() {
162 | @Override
163 | public void onClick(View v) {
164 | if (null != listener) {
165 | listener.leftClick(v);
166 | }
167 | }
168 | });
169 |
170 | rightLayout.setOnClickListener(new OnClickListener() {
171 | @Override
172 | public void onClick(View v) {
173 | if (null != listener) {
174 | listener.rightClick(v);
175 | }
176 | }
177 | });
178 | }
179 |
180 |
181 | public void setTopBannerListener(OnTopBannerListener listener) {
182 | this.listener = listener;
183 | }
184 |
185 | private void setLeftButtonVisibility(Boolean isVisibility) {
186 | leftButton.setVisibility(isVisibility ? View.VISIBLE : View.GONE);
187 | }
188 |
189 | private void setRightButtonVisibility(Boolean isVisibility) {
190 | rightButton.setVisibility(isVisibility ? View.VISIBLE : View.GONE);
191 | }
192 |
193 | public String getTitleText() {
194 | return title.getText().toString().trim();
195 | }
196 |
197 | public void setTitleText(String titleText) {
198 | title.setText(titleText);
199 | }
200 |
201 | public ImageView getLeftButton() {
202 | return leftButton;
203 | }
204 |
205 | public ImageView getRightButton() {
206 | return rightButton;
207 | }
208 |
209 | public LinearLayout getLeftLayout() {
210 | return leftLayout;
211 | }
212 |
213 | public LinearLayout getRightLayout() {
214 | return rightLayout;
215 | }
216 |
217 | public interface OnTopBannerListener {
218 | void leftClick(View v);
219 |
220 | void rightClick(View v);
221 | }
222 |
223 | }
224 |
--------------------------------------------------------------------------------
/virtuallocation/src/main/jniLibs/armeabi/libBaiduMapSDK_v3_2_0_15.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/drizzle888/VirtualLocation/7eda42b23c4162d0705b01ecc4f888007bd7b071/virtuallocation/src/main/jniLibs/armeabi/libBaiduMapSDK_v3_2_0_15.so
--------------------------------------------------------------------------------
/virtuallocation/src/main/jniLibs/armeabi/liblocSDK5.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/drizzle888/VirtualLocation/7eda42b23c4162d0705b01ecc4f888007bd7b071/virtuallocation/src/main/jniLibs/armeabi/liblocSDK5.so
--------------------------------------------------------------------------------
/virtuallocation/src/main/res/anim/spinloaing.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
10 |
--------------------------------------------------------------------------------
/virtuallocation/src/main/res/drawable/bg_begin_location.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
12 |
15 |
17 |
--------------------------------------------------------------------------------
/virtuallocation/src/main/res/drawable/bg_botton_shadow.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
--------------------------------------------------------------------------------
/virtuallocation/src/main/res/drawable/bg_notice.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/virtuallocation/src/main/res/drawable/bg_progressbar.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
10 |
17 |
18 |
--------------------------------------------------------------------------------
/virtuallocation/src/main/res/drawable/bg_with_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
12 |
15 |
17 |
--------------------------------------------------------------------------------
/virtuallocation/src/main/res/layout/activity_about.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
24 |
32 |
39 |
46 |
47 |
48 |
55 |
62 |
70 |
71 |
72 |
79 |
86 |
94 |
95 |
96 |
103 |
111 |
112 |
113 |
120 |
128 |
129 |
130 |
140 |
141 |
142 |
143 |
144 |
--------------------------------------------------------------------------------
/virtuallocation/src/main/res/layout/activity_apps.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
22 |
23 |
26 |
31 |
37 | />
38 |
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/virtuallocation/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
13 |
14 |
19 |
20 |
25 |
26 |
37 |
38 |
39 |
40 |
56 |
57 |
58 |
59 |
60 |
71 |
72 |
73 |
79 |
87 |
96 |
97 |
98 |
104 |
114 |
115 |
116 |
117 |
123 |
132 |
141 |
142 |
143 |
144 |
150 |
151 |
--------------------------------------------------------------------------------
/virtuallocation/src/main/res/layout/activity_precise_location.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
12 |
22 |
23 |
32 |
33 |
34 |
41 |
42 |
50 |
51 |
52 |
59 |
60 |
69 |
70 |
71 |
81 |
93 |
94 |
105 |
106 |
--------------------------------------------------------------------------------
/virtuallocation/src/main/res/layout/dialog_customprogress.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
12 |
13 |
20 |
21 |
--------------------------------------------------------------------------------
/virtuallocation/src/main/res/layout/item_app_info.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
12 |
13 |
16 |
17 |
26 |
27 |
36 |
37 |
45 |
46 |
54 |
55 |
56 |
63 |
64 |
65 |
--------------------------------------------------------------------------------
/virtuallocation/src/main/res/layout/layout_drawer.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
17 |
27 |
37 |
38 |
--------------------------------------------------------------------------------
/virtuallocation/src/main/res/layout/layout_schema.xml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
13 |
14 |
17 |
18 |
19 |
20 |
21 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/virtuallocation/src/main/res/menu/menu_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
11 |
12 |
--------------------------------------------------------------------------------
/virtuallocation/src/main/res/mipmap-hdpi/ic_current_location.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/drizzle888/VirtualLocation/7eda42b23c4162d0705b01ecc4f888007bd7b071/virtuallocation/src/main/res/mipmap-hdpi/ic_current_location.png
--------------------------------------------------------------------------------
/virtuallocation/src/main/res/mipmap-hdpi/ic_drawer_add.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/drizzle888/VirtualLocation/7eda42b23c4162d0705b01ecc4f888007bd7b071/virtuallocation/src/main/res/mipmap-hdpi/ic_drawer_add.png
--------------------------------------------------------------------------------
/virtuallocation/src/main/res/mipmap-hdpi/ic_drawer_me.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/drizzle888/VirtualLocation/7eda42b23c4162d0705b01ecc4f888007bd7b071/virtuallocation/src/main/res/mipmap-hdpi/ic_drawer_me.png
--------------------------------------------------------------------------------
/virtuallocation/src/main/res/mipmap-hdpi/ic_expand.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/drizzle888/VirtualLocation/7eda42b23c4162d0705b01ecc4f888007bd7b071/virtuallocation/src/main/res/mipmap-hdpi/ic_expand.png
--------------------------------------------------------------------------------
/virtuallocation/src/main/res/mipmap-hdpi/ic_filter.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/drizzle888/VirtualLocation/7eda42b23c4162d0705b01ecc4f888007bd7b071/virtuallocation/src/main/res/mipmap-hdpi/ic_filter.png
--------------------------------------------------------------------------------
/virtuallocation/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/drizzle888/VirtualLocation/7eda42b23c4162d0705b01ecc4f888007bd7b071/virtuallocation/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/virtuallocation/src/main/res/mipmap-hdpi/ic_reback.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/drizzle888/VirtualLocation/7eda42b23c4162d0705b01ecc4f888007bd7b071/virtuallocation/src/main/res/mipmap-hdpi/ic_reback.png
--------------------------------------------------------------------------------
/virtuallocation/src/main/res/mipmap-hdpi/ic_right.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/drizzle888/VirtualLocation/7eda42b23c4162d0705b01ecc4f888007bd7b071/virtuallocation/src/main/res/mipmap-hdpi/ic_right.png
--------------------------------------------------------------------------------
/virtuallocation/src/main/res/mipmap-hdpi/ic_stop_location.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/drizzle888/VirtualLocation/7eda42b23c4162d0705b01ecc4f888007bd7b071/virtuallocation/src/main/res/mipmap-hdpi/ic_stop_location.png
--------------------------------------------------------------------------------
/virtuallocation/src/main/res/mipmap-hdpi/ic_topbar_search.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/drizzle888/VirtualLocation/7eda42b23c4162d0705b01ecc4f888007bd7b071/virtuallocation/src/main/res/mipmap-hdpi/ic_topbar_search.png
--------------------------------------------------------------------------------
/virtuallocation/src/main/res/mipmap-hdpi/ic_virtual_addr.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/drizzle888/VirtualLocation/7eda42b23c4162d0705b01ecc4f888007bd7b071/virtuallocation/src/main/res/mipmap-hdpi/ic_virtual_addr.png
--------------------------------------------------------------------------------
/virtuallocation/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/drizzle888/VirtualLocation/7eda42b23c4162d0705b01ecc4f888007bd7b071/virtuallocation/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/virtuallocation/src/main/res/mipmap-mdpi/icon_gcoding.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/drizzle888/VirtualLocation/7eda42b23c4162d0705b01ecc4f888007bd7b071/virtuallocation/src/main/res/mipmap-mdpi/icon_gcoding.png
--------------------------------------------------------------------------------
/virtuallocation/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/drizzle888/VirtualLocation/7eda42b23c4162d0705b01ecc4f888007bd7b071/virtuallocation/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/virtuallocation/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/drizzle888/VirtualLocation/7eda42b23c4162d0705b01ecc4f888007bd7b071/virtuallocation/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/virtuallocation/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/drizzle888/VirtualLocation/7eda42b23c4162d0705b01ecc4f888007bd7b071/virtuallocation/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/virtuallocation/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/drizzle888/VirtualLocation/7eda42b23c4162d0705b01ecc4f888007bd7b071/virtuallocation/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/virtuallocation/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/drizzle888/VirtualLocation/7eda42b23c4162d0705b01ecc4f888007bd7b071/virtuallocation/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/virtuallocation/src/main/res/values/attrs_topbar.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/virtuallocation/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 | #42ABC1
7 |
8 |
--------------------------------------------------------------------------------
/virtuallocation/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | 筋斗云
3 | 筋斗云是一款虚拟定位软件,适用于微信、微博、考勤签到等社交办公软件,让你随心所欲的改变手机地理位置!
4 | 当前版本:1.8.8(build 12035) \n@2017 littlerich.top All right reserved
5 | 应用程序名
6 |
7 |
--------------------------------------------------------------------------------
/virtuallocation/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
22 |
23 |
24 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/virtuallocation/src/test/java/top/littlerich/virtuallocation/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package top.littlerich.virtuallocation;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() throws Exception {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/virtuallocation/virtuallocation.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | generateDebugSources
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
--------------------------------------------------------------------------------
/环境配置工具/Xposed框架2.6.1.apk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/drizzle888/VirtualLocation/7eda42b23c4162d0705b01ecc4f888007bd7b071/环境配置工具/Xposed框架2.6.1.apk
--------------------------------------------------------------------------------