├── .gitignore
├── CHANGELOG.md
├── LICENSE
├── README.md
├── README_zh_rTW.md
├── app
└── src
│ └── main
│ └── res
│ ├── values-zh-rCN
│ └── strings.xml
│ ├── values-zh-rTW
│ └── strings.xml
│ └── values
│ └── strings.xml
├── art
└── screenshots
│ ├── main_0_1_44.png
│ ├── map_select_amap_0_7_300.png
│ ├── per_app_settings_0_3_73.png
│ ├── settings_0_1_44.png
│ └── shortcut_list_0_7_300.png
├── mapsearchbar
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── rong
│ │ └── library
│ │ └── widget
│ │ ├── HighlightTextView.java
│ │ └── mapsearchbar
│ │ ├── MapSearchBar.java
│ │ ├── OnSearchResultItemClickListener.java
│ │ ├── SearchQueryThread.java
│ │ ├── SearchResult.java
│ │ └── SearchResultAdapter.java
│ └── res
│ ├── drawable-hdpi
│ ├── ic_arrow_back_white_24dp.png
│ ├── ic_close_white_24dp.png
│ ├── ic_history_white_24dp.png
│ ├── ic_more_vert_white_24dp.png
│ ├── ic_place_white_24dp.png
│ └── ic_search_white_24dp.png
│ ├── drawable-mdpi
│ ├── ic_arrow_back_white_24dp.png
│ ├── ic_close_white_24dp.png
│ ├── ic_history_white_24dp.png
│ ├── ic_more_vert_white_24dp.png
│ ├── ic_place_white_24dp.png
│ └── ic_search_white_24dp.png
│ ├── drawable-xhdpi
│ ├── ic_arrow_back_white_24dp.png
│ ├── ic_close_white_24dp.png
│ ├── ic_history_white_24dp.png
│ ├── ic_more_vert_white_24dp.png
│ ├── ic_place_white_24dp.png
│ └── ic_search_white_24dp.png
│ ├── drawable-xxhdpi
│ ├── ic_arrow_back_white_24dp.png
│ ├── ic_close_white_24dp.png
│ ├── ic_history_white_24dp.png
│ ├── ic_more_vert_white_24dp.png
│ ├── ic_place_white_24dp.png
│ └── ic_search_white_24dp.png
│ ├── drawable-xxxhdpi
│ ├── ic_arrow_back_white_24dp.png
│ ├── ic_close_white_24dp.png
│ ├── ic_history_white_24dp.png
│ ├── ic_more_vert_white_24dp.png
│ ├── ic_place_white_24dp.png
│ └── ic_search_white_24dp.png
│ ├── layout
│ ├── item_search_result.xml
│ └── search_bar.xml
│ └── values
│ ├── attr.xml
│ ├── colors.xml
│ ├── dimens.xml
│ └── strings.xml
└── markdownview
├── .gitignore
├── LICENSE
├── build.gradle
└── src
└── main
├── AndroidManifest.xml
├── assets
└── html
│ ├── css
│ ├── bootstrap.css
│ ├── github-gist.css
│ └── github.css
│ ├── js
│ ├── highlight.pack.js
│ ├── jquery-2.1.4.min.js
│ ├── marked.js
│ └── preview.js
│ └── preview.html
└── java
└── com
└── mukesh
└── MarkdownView.java
/.gitignore:
--------------------------------------------------------------------------------
1 | # Built application files
2 | *.apk
3 | *.ap_
4 |
5 | # Files for the Dalvik VM
6 | *.dex
7 |
8 | # Java class files
9 | *.class
10 |
11 | # Generated files
12 | bin/
13 | gen/
14 |
15 | # Gradle files
16 | .gradle/
17 | build/
18 |
19 | # Local configuration file (sdk path, etc)
20 | local.properties
21 |
22 | # Proguard folder generated by Eclipse
23 | proguard/
24 |
25 | # Log Files
26 | *.log
27 |
28 | # Android Studio Navigation editor temp files
29 | .navigation/
30 |
31 | # Android Studio captures folder
32 | captures/
33 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # 更新日志 (Changelogs)
2 |
3 | ## 1.2
4 | - 准备对Android 7的支持(部分)
5 | - 应用设置页恢复“更新”按钮
6 | - 尝试修复部分GPS定位问题
7 | - 其他一些改进
8 |
9 | - Prepare Android 7 support (partial)
10 | - Add "Notify" button back in `Per-app Settings` page
11 | - Try to fix some issues regarding to GPS mocking
12 | - Other improvements
13 |
14 |
15 | ## 1.1.646
16 | - 地图添加搜索支持
17 | - 完善当前基站信息获取
18 | - 帮助中的页面链接现在使用浏览器打开
19 | - 打开地图默认定位到应用之前设置的位置
20 | - UI细节调整
21 | - 修复错误
22 |
23 | - Add map search
24 | - Improve 'Current Cell Info'
25 | - Links in help now use browser to open
26 | - Map's initial location default to app's current settings
27 | - UI adjustments
28 | - Bug fixes
29 |
30 |
31 | ## 1.0.561
32 | - 完善对Gps状态的处理
33 | - 悬浮窗及应用设置页新增“更新”按钮,单独使用GPS时应用出现“正在定位”、“无法定位”等可尝试点击
34 | - 改进内存不足时悬浮窗服务可能被系统关闭的问题
35 |
36 | - Improve Gps status handling
37 | - Add a "Notify" button (overlay and per-app settings), try it when you use GPS Mocking alone and get "Locating", "Unable to locate", etc.
38 | - Improve that overlay may be killed by the system when low on memory
39 |
40 |
41 | ## 1.0.527
42 | - 新增`模板`-`当前基站信息`
43 | - 修复错误
44 | - 易用性改进
45 |
46 | - Add `Template` - `Current Cell Info`
47 | - Bug fixes
48 | - Improve usability
49 |
50 |
51 | ## 0.9.486
52 | - 新增自我隐藏
53 | - 应用列表根据应用是否启用模拟排序
54 | - GMS支持使用新的实现(现在无需单独设置com.google.android.gms,直接设置对应APP即可)
55 | - 修复可能跳转回真实地址的错误
56 | - 兼容跳转至Material Xposed Installer模块设置页面
57 | - 更新帮助内容
58 | - 更新间隔设置
59 | - 修复错误
60 |
61 | - Hide module from selected app(s)
62 | - Sort apps list by mocking status and settings
63 | - New approach for GMS support (Make the gps settings in App's per-app settings page, no longer need to set com.google.android.gms separately)
64 | - Fix location jumping back to real location
65 | - Fix a problem with Material Xposed Installer
66 | - Update help
67 | - Settings for update interval
68 | - Bug fixes
69 |
70 |
71 | ## 0.8.400
72 | - 现在无需打开GPS即可实时模拟新的位置
73 | - 优化捐赠方式
74 | - 如微信无法打开,在设置中打开兼容模式
75 | - 新增摇杆悬浮窗,根据方向、力量值更新位置信息,使用时先在对应App设置页面点击“关联悬浮窗”按钮。
76 | - 添加首选地图设置
77 | - 修复部分手机上启用模块后仍然显示模块未启用的错误
78 | - 修复列表为空时点击搜索闪退的错误
79 | - 修复一些错误
80 | - 请注意:新版使用了新的设置文件和格式,更新后部分设置需重新设置
81 |
82 | - Now you don't even need to turn on GPS to update new mocking location
83 | - Optimize donation
84 | - Add joystick overlay, mocking location will be updated according to the bearing and strength. To use it, go to the app setting page and click "Connect" first.
85 | - Add preferred map setting
86 | - Fix a bug that the module keeps saying that it's not active even it was enabled in Xposed Installer on some devices
87 | - Fix a crash cause by clicking search when the list is still loading
88 | - Other bug fixes
89 | - PLEASE NOTE that this update uses a new setting file and new format, some old settings will be lost after the update.
90 |
91 |
92 | ## 0.7.306
93 | - 修复点击应用列表闪退的错误
94 | - 修复加载应用列表可能导致的OOM错误
95 |
96 | - Fix a crash when selecting app from the list
97 | - Fix an OOM crash when loading a long list of apps
98 |
99 |
100 | ## 0.7.300
101 | - 自定义GPS状态
102 | - 新增地图选择
103 | - 地图选择历史(最近列表)
104 | - 修复一些错误
105 | - 开启“即时更新”后,地图点击、选择(点击)标记、使用最近列表中的地点将直接写入设置中,无需返回应用列表。
106 |
107 | - Custom GPS status support
108 | - Select GPS coordinates from map (play service 7.0.0+ is required)
109 | - Map select history (recent list)
110 | - Bug fixes
111 | - When "Instant Update" enabled, location settings made by map click, marker click, recent list selection will be saved immediately without going back to app list.
112 |
113 |
114 | ## 0.7.291
115 | - 测试版本 (Internal release)
116 |
117 |
118 | ## 0.6.195
119 | - 支持Android 4.3
120 | - 基站模拟增强
121 | - 完善部分函数的处理逻辑
122 | - 新增对Google Play services Location API的支持
123 | - 新增对腾讯定位SDK的支持
124 |
125 | - Support Android 4.3
126 | - Enhance cell location mocking
127 | - Improve the handling logic of several functions
128 | - Add support for the Location API of Google Play services
129 | - Add support for the Tencent Location SDK
130 |
131 |
132 | ## 0.5.161
133 | - 新增模板
134 | - 坐标偏移修正
135 | - 基站模拟增强
136 | - 修复一个可能导致崩溃的错误
137 | - 修复部分设置不能生效的错误
138 | - 新增的WRITE_EXTERNAL_STORAGE权限用于记录崩溃日志
139 |
140 | - Add template settings
141 | - Offset correction (coordinates in China)
142 | - Enhance cell location mocking
143 | - Fix a bug that may cause FC
144 | - Fix a bug that new settings won't take effect
145 | - New permission WRITE_EXTERNAL_STORAGE is used for saving crash logs
146 |
147 |
148 | ## 0.4.127
149 | - 新增应用搜索
150 | - 新增快速设置(最近列表)
151 | - 修复一些错误
152 | - 一些性能优化
153 |
154 | - Add app search
155 | - Add setting shortcut (recent list)
156 | - Bug fixes
157 | - Performance optimizations
158 |
159 |
160 | ## 0.3.78
161 | - 新增基站模拟
162 | - 新增繁体中文 (thanks to iamernie8199)
163 |
164 | - Add cell location mocking
165 | - Add Tradictional Chinese translation (thanks to iamernie8199)
166 |
167 |
168 | ## 0.2.48
169 | - 添加对4.4系统的支持
170 |
171 | - Add support for Android 4.4
172 |
173 |
174 | ## 0.1.44
175 | - 初始版本
176 |
177 | - First release
178 |
--------------------------------------------------------------------------------
/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 | # 模拟位置 (FakeLocation)
2 |
3 | - English description please refer to [here](https://github.com/j2rong/FakeLocation#english).
4 | - 繁體中文描述請參照[這裡](https://github.com/j2rong/FakeLocation/blob/master/README_zh_rTW.md)
5 | - 这是一个 ***Xposed*** 模块,用于模拟地理位置,世界在手天下我有。
6 | - 无需模拟位置权限
7 |
8 |
9 |
10 | ## 屏幕截图 (Screenshots)
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | ## 更新日志
24 | - [**CHANGELOG**](https://github.com/j2rong/FakeLocation/blob/master/CHANGELOG.md)
25 |
26 |
27 | ## 问题
28 |
29 | - 如使用过程中出现问题或功能建议,请至[此处](https://github.com/j2rong/FakeLocation/issues/new)提交。
30 | - 如位置设置无效,请在模块中打开日志,并将Xposed Installer中的日志提交至[此处](https://github.com/j2rong/FakeLocation/issues/new)。
31 |
32 |
33 |
34 | ## 致谢 (Credits)
35 |
36 | - [**Xposed Framework**](https://github.com/rovo89/Xposed)
37 |
38 | Original work Copyright (c) 2005-2008, The Android Open Source Project
39 | Modified work Copyright (c) 2013, rovo89 and Tungstwenty
40 |
41 | Licensed under the Apache License, Version 2.0 (the "License");
42 | you may not use this file except in compliance with the License.
43 |
44 | Unless required by applicable law or agreed to in writing, software
45 | distributed under the License is distributed on an "AS IS" BASIS,
46 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
47 | See the License for the specific language governing permissions and
48 | limitations under the License.
49 |
50 |
51 |
52 | ## English
53 |
54 | - This is an ***Xposed*** module for mocking locations per app
55 |
56 | - No need to turn on "Mock locations" permission
57 |
58 | - **Problems**
59 |
60 | Feel free to [open an issue](https://github.com/j2rong/FakeLocation/issues/new) if there is any problem or suggestion.
61 | If fake location don't work, you can turn on the logs and submit (you can find it in Xposed Installer) to help identify the issue.
62 |
63 | - [**Changelogs**](https://github.com/j2rong/FakeLocation/blob/master/CHANGELOG.md)
64 |
--------------------------------------------------------------------------------
/README_zh_rTW.md:
--------------------------------------------------------------------------------
1 | # 模擬位置 (FakeLocation)
2 |
3 | - English description please refer to [here](https://github.com/j2rong/FakeLocation#english).
4 | - 简体中文描述请参见[此处](https://github.com/j2rong/FakeLocation)
5 | - 這是一個 ***Xposed*** 模組,用於模擬地理位置,世界在手天下我有。
6 | - 無需模擬位置權限
7 |
8 |
9 |
10 | ## 螢幕截圖
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | ## 更新記錄檔
24 | - [**CHANGELOG**](https://github.com/j2rong/FakeLocation/blob/master/CHANGELOG.md)
25 |
26 |
27 | ## 問題
28 |
29 | - 若使用過程中出現問題或功能建議,請至[這裡](https://github.com/j2rong/FakeLocation/issues/new)送出。
30 | - 若位置設定無效,請在模組中啟用記錄檔,並把 Xposed Installer 裡的記錄檔送出至[這裡](https://github.com/j2rong/FakeLocation/issues/new)。
31 |
32 |
33 |
34 | ## 參與名單
35 |
36 | - [**Xposed Framework**](https://github.com/rovo89/Xposed)
37 |
38 | Original work Copyright (c) 2005-2008, The Android Open Source Project
39 | Modified work Copyright (c) 2013, rovo89 and Tungstwenty
40 |
41 | Licensed under the Apache License, Version 2.0 (the "License");
42 | you may not use this file except in compliance with the License.
43 |
44 | Unless required by applicable law or agreed to in writing, software
45 | distributed under the License is distributed on an "AS IS" BASIS,
46 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
47 | See the License for the specific language governing permissions and
48 | limitations under the License.
49 |
--------------------------------------------------------------------------------
/app/src/main/res/values-zh-rCN/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 模拟位置
4 | 模拟我的位置
5 |
6 | 位置设置
7 | 设置
8 | 捐赠
9 | 模板
10 | 关于
11 | 选择地点
12 | \"%1$s\"的搜索结果
13 |
14 |
15 |
16 | 设置
17 | 模板
18 | 搜索
19 | 捐赠
20 | 如何使用
21 | 关于
22 | 悬浮窗开启/关闭
23 |
24 | 模块“%1$s”尚未启用!首次使用请先在Xposed Installer中启用并重启。
25 | 我知道了
26 | 未知版本的Xposed Installer,请手动启用
27 |
28 | 本次更新中的部分新功能需要重启才能正常使用。
29 | 我知道了
30 |
31 | 搜索应用名或包名
32 | [隐藏]
33 | [关联]
34 |
35 |
36 |
37 | 很抱歉,%1$s已停止运行,崩溃日志已复制到剪贴板,请尝试重新启动或至GitHub反馈该问题。
38 | 调用堆栈:
39 | 崩溃日志已保存至%1$s
40 | 崩溃日志保存失败,保存日志需开启“写入外部存储 (WRITE_EXTERNAL_STORAGE)”权限
41 | 确定
42 | 提交问题
43 |
44 |
45 |
46 | 确定
47 | 不再显示
48 | 如果要模拟位置的App使用了谷歌服务来获取GPS信息,只需在设置中打开“谷歌服务API支持”并在对应App页面中设置即可,无需在此设置。
49 | 悬浮窗
50 | 关联一个应用以使悬浮窗正常工作,查看帮助获取更详细说明。(应用设置页面-GPS模拟-关联悬浮窗)
51 |
52 |
53 |
54 | 为保证下列功能正常运行:
55 | 保存自定义设置及崩溃日志
56 | 显示地图用于选择模拟的位置
57 | 显示悬浮窗
58 | 应用需要获取 %1$s、%2$s 和 %3$s 权限
59 | 在部分ROM上应用需要获取 %1$s 权限
60 | 写入外部存储 (WRITE_EXTERNAL_STORAGE)
61 | 读取手机状态 (READ_PHONE_STATE)
62 | 获取粗略位置 (ACCESS_COARSE_LOCATION)
63 | 显示系统窗口 (SYSTEM_ALERT_WINDOW)
64 |
65 | 以后再说
66 | 去设置
67 | 允许
68 | 拒绝
69 | 我知道了
70 |
71 |
72 |
73 | 搜索地点
74 | 历史记录
75 | 手气不错
76 | 切换地图
77 |
78 | 选择了 (%1$.6f, %2$.6f)
79 | 坐标获取失败
80 | 当前位置
81 | 正在获取地址…
82 | 选择地点
83 | (空)
84 |
85 |
86 |
87 | 没有找到与“%1$s”相关的地点
88 | 正在搜索
89 | 重试
90 | 正在加载
91 | 无法获取该地址对应坐标
92 |
93 |
94 |
95 | 最近
96 | 模板
97 | 应用包名称获取失败,请重试!
98 | 我知道了
99 | 模块已更新,该功能需重启后才能使用。
100 | 设置已保存
101 | 已更新
102 | 发生错误:%1$s
103 |
104 | 对该应用隐藏本模块
105 |
106 | 使用GPS模拟
107 | 不同应用的处理逻辑可能不同,如模拟的位置没有更新,使用悬浮窗手动更新
108 |
109 | 经度范围只能在-180与180之间
110 | 纬度范围只能在-90与90之间
111 | 纬度
112 | 经度
113 |
114 | 选择
115 | 关联悬浮窗
116 | 断开关联
117 | 更新
118 |
119 | 使用基站信息模拟
120 | GPS模拟失败时可尝试使用基站模拟
121 |
122 | 基站类型
123 | 最好与手机类型相同
124 |
125 |
126 |
127 | 新的设置尚未被保存,是否保存?
128 | 取消
129 | 否
130 | 保存
131 | 设置已保存
132 | 设置未被修改
133 | 设置未保存
134 |
135 |
136 |
137 | 快速填充
138 | 模板
139 | 最近
140 | (未设置)
141 | (未知)
142 | (空)
143 |
144 | 当前基站信息
145 | 使用手机当前所连接的基站的信息
146 | 自动获取基站信息失败 :(
147 | GPS模板
148 | 基站模板
149 | (无)
150 | 类型
151 |
152 |
153 |
154 |
155 | 通用
156 |
157 | 系统应用
158 | 显示
159 | 不显示
160 |
161 | 应用列表排序
162 | 根据应用设置及模拟状态排序(更耗时)
163 | 默认
164 |
165 |
166 | 地图
167 |
168 | 首选地图类型
169 |
170 | 自动(默认)
171 | 高德地图
172 | 谷歌地图
173 |
174 | 搜索范围(谷歌地图)
175 |
176 | 只搜索本地区
177 | 全球
178 |
179 |
180 |
181 | 定位
182 |
183 | 修正地图偏移
184 | 对中国地区坐标进行偏移修正,当定位失败、位置偏移时可尝试打开此项
185 | 不修正
186 |
187 | 谷歌服务API支持
188 |
189 |
190 |
191 | 反馈
192 |
193 | 输出日志
194 | 开启
195 | 提交问题前请先开启日志输出,并尝试重现该问题!
196 |
197 | 提交问题
198 | 请尽可能详细的描述该问题,并将Xposed Installer中的日志一起提交
199 |
200 |
201 |
202 | 高级
203 |
204 | 高级设置
205 | 如果你不能完全确定所进行的操作,建议不要更改这些设置,因为这可能会导致未知错误。
206 |
207 | GPS状态
208 | 默认为空,数字以逗号分隔
209 |
210 | 信噪比
211 | 卫星高度
212 | 卫星方位角
213 |
214 |
215 |
216 | 实验性功能
217 | 开启(需重启)
218 | 关闭(需重启)
219 |
220 | Tencent Location SDK 支持
221 |
222 |
223 |
224 | 悬浮窗
225 |
226 | 悬浮窗设置
227 | 相关设置
228 |
229 | 服务
230 |
231 | 自动停止
232 | 当主页面关闭时,如果悬浮窗未显示,停止后台服务
233 | 不自动停止
234 |
235 | 前台服务
236 | 启用以避免内存不足时系统自动停止服务
237 |
238 |
239 | 行为
240 |
241 | 切换间隔
242 | 在设置的时间内无操作时关闭摇杆返回小窗口(毫秒)
243 |
244 | 记住上次位置
245 | 悬浮窗将在上次关闭时的位置显示
246 | 悬浮窗将在默认位置显示
247 |
248 | 控制参数
249 |
250 | GPS坐标更新速度
251 | 更新间隔(毫秒)
252 | GPS坐标将根据摇杆所确定的方向和强度进行更新。
253 | 该值设置过小可能会影响设备性能,且如果设置的间隔小于关联应用所请求的位置更新间隔,新位置可能不被应用使用。
254 |
255 | 最小移动速度
256 | 摇杆强度值为0时使用该值(米/秒)
257 |
258 | 最大移动速度
259 | 摇杆强度最大时使用该值(米/秒)
260 |
261 |
262 |
263 | 格式错误,多个数字请用逗号分隔
264 | (默认)
265 | %1$d 毫秒
266 | 不能为空或小于%1$d
267 | 该数字必须是100的整数倍
268 | 速度值不能为空
269 | 格式错误,必须为一个数值
270 |
271 |
272 |
273 | 开始/停止更新
274 | 更新一次
275 |
276 |
277 |
278 | 开源项目
279 | 翻译
280 | 其他模块
281 | 禁用悬挂式(Heads-up)通知
282 |
283 | 如果喜欢,点击此处%1$s支持
284 | 捐赠
285 |
286 |
287 |
288 | 请注意
289 | 修改系统应用的位置设置可能会导致未知错误!
290 | 我知道了
291 | 不再提醒
292 |
293 |
294 |
295 | 测试版本仅支持设置最多8个应用
296 | 好的
297 | 取消
298 |
299 |
300 |
301 |
302 |
--------------------------------------------------------------------------------
/app/src/main/res/values-zh-rTW/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | FakeLocation
4 | 模擬目前的位置
5 |
6 | 位置設定
7 | 設定
8 | 捐贈
9 | 範本
10 | 關於
11 | 選擇一個位置
12 | \"%1$s\" 的搜尋結果
13 |
14 |
15 |
16 | 設定
17 | 範本
18 | 搜尋
19 | 捐贈
20 | 如何使用
21 | 關於
22 | 切換 Overlay
23 |
24 | "%1$s" 模組並未啟用!首次使用請先在 Xposed Installer 裡啟用並重新啟動。
25 | 我懂了
26 | 未知的 Xposed Installer,請手動啟用
27 |
28 | 此次更新包含一些新功能需要重新啟動才能正常運作。
29 | 我懂了
30 |
31 | 搜尋程式名稱或套件名稱
32 | [隱藏]
33 | [已連結]
34 |
35 |
36 |
37 | 很遺憾, "%1$s" 已停止執行,損毀記錄檔已複製至剪貼簿,請嘗試重新啟動此應用程式或在 GitHub 新開一個 issue。
38 | 追蹤堆疊:
39 | 損毀記錄檔已儲存至 %1$s
40 | 損毀記錄檔儲存失敗,儲存記錄檔需要「寫入外部儲存空間 (WRITE_EXTERNAL_STORAGE) 」權限
41 | 確定
42 | 在 GitHub 新開 issue
43 |
44 |
45 |
46 | 確定
47 | 不要再顯示
48 | 若您要模擬的應用程式使用 Google 服務取得GPS 位置,您應該在設定裡開啟「Google 服務 API 支援」並且在程式的每個程式設定頁面設定,而不是在此設定。
49 | Overlay
50 | 為了使 Overlay 能夠正常運作,您應該連結一個程式。(程式設定頁面- GPS 模擬-連結按鈕)參閱說明取得更多詳細資料。
51 |
52 |
53 |
54 | 為了使下列功能正常運作:
55 | 儲存損毀記錄檔與使用者設定
56 | 顯示地圖便於選擇位置
57 | 顯示 Overlay
58 | 需要 %1$s 與 %2$s 以及 %3$s 的權限
59 | 某些 ROM 需要 %1$s 權限
60 | 寫入外部儲存空間 (WRITE_EXTERNAL_STORAGE)
61 | 讀取電話狀態 (READ_PHONE_STATE)
62 | 存取約略位置 (ACCESS_COARSE_LOCATION)
63 | 系統警示視窗 (SYSTEM_ALERT_WINDOW)
64 |
65 | 稍後
66 | 前往設定
67 | 允許
68 | 拒絕
69 | 我懂了
70 |
71 |
72 |
73 | 搜尋地點
74 | 歷史
75 | 好手氣
76 | 切換地圖
77 |
78 | 已選擇位置 (%1$.6f, %2$.6f)
79 | 座標取得失敗
80 | 目前位置
81 | 擷取地址中…
82 | 選擇一個位置
83 | (空白)
84 |
85 |
86 |
87 | 找不到 "%1$s" 的結果
88 | 搜尋中…
89 | 重新嘗試
90 | 載入更多
91 | 找不到此地址的座標
92 |
93 |
94 |
95 | 最近
96 | 範本
97 | 取得套件名稱失敗,請再試一次!
98 | 我懂了
99 | 模組已更新,此功能需要重新啟動方能運作。
100 | 設定已儲存
101 | 已更新
102 | 發生錯誤:%1$s
103 |
104 | 對此程式隱藏此模組
105 |
106 | GPS 模擬
107 | 程式的位置處理可能不同,若此位置未更新,使用 Overlay 手動通知它
108 |
109 | 經度應大於 -180 小於 180
110 | 緯度應大於 -90 小於 90
111 | 緯度
112 | 經度
113 |
114 | 選擇
115 | 連結
116 | 中斷連結
117 | 通知
118 |
119 | 蜂窩資訊模擬
120 | 若 GPS 失敗,則嘗試使用蜂窩資訊
121 |
122 | 蜂窩類型
123 | 最好與手機類型一致
124 |
125 |
126 |
127 | 新設定未被儲存,是否先儲存之?
128 | 取消
129 | 捨棄
130 | 儲存
131 | 設定已儲存
132 | 未變更設定
133 | 設定已捨棄
134 |
135 |
136 |
137 | 捷徑
138 | 範本
139 | 最近
140 | (未設定)
141 | (不明)
142 | (空白)
143 |
144 | 目前的蜂窩資訊
145 | 使用手機目前的蜂窩資訊
146 | 不能自動擷取目前的蜂窩資訊:(
147 | GPS 範本
148 | 蜂窩範本
149 | (Null)
150 | 類型
151 |
152 |
153 |
154 |
155 | 一般
156 |
157 | 系統應用程式
158 | 顯示
159 | 不顯示
160 |
161 | 程式清單排序
162 | 根據程式的模擬狀態與設定排序(更耗時)
163 | 預設
164 |
165 |
166 | 地圖
167 |
168 | 偏好的地圖類型
169 |
170 | 自動(預設)
171 | 高德地圖
172 | Google 地圖
173 |
174 | 搜尋區域(Google 地圖)
175 |
176 | 僅目前地區
177 | 全球
178 |
179 |
180 |
181 | 定位
182 |
183 | 位移修正
184 | 嘗試修正位移(僅針對中國大陸座標)
185 | 不做任何事
186 |
187 | Google 服務 API 支援
188 |
189 |
190 |
191 | 回饋
192 |
193 | 詳細資訊記錄檔
194 | 啟用
195 | 在送出一條 issue 之前請先啟用此功能並且嘗試重現此 issue !
196 |
197 | Issue
198 | 請盡可能詳細描述此 issue,並且把 Xposed Installer 裡的記錄檔同時送出
199 |
200 |
201 |
202 | 進階
203 |
204 | 進階設定
205 | 若您無法完全確定進行的操作,建議不要變更這些設定,因為它或許會引起意外行為。
206 |
207 | GPS 狀態
208 | 預設為空白,數字用逗點分隔
209 |
210 | 訊號雜訊比
211 | 衛星高度
212 | 衛星方位
213 |
214 |
215 |
216 | 實驗性
217 | 啟用(需要重新啟動)
218 | 停用(需要重新啟動)
219 |
220 | 騰訊位置 SDK 支援
221 |
222 |
223 |
224 | Overlay
225 |
226 | Overlay 設定
227 | 相關設定
228 |
229 | 服務
230 |
231 | 自動停止
232 | 在主頁面關閉時,若 Overlay 未顯示,則停止服務
233 | 什麼都不做
234 |
235 | 前景服務
236 | 若開啟,在記憶體不足時,服務不會被系統終止
237 |
238 |
239 | 行為
240 |
241 | 切換間隔
242 | 在時間間隔內無操作時關閉搖桿視圖(毫秒)
243 |
244 | 記住上一次位置
245 | Overlay 視圖會在上一次關閉的位置顯示
246 | Overlay 視圖會在預設位置顯示
247 |
248 | 控制
249 |
250 | GPS 位置更新間隔
251 | 更新間隔(毫秒)
252 | GPS 位置會根據搖桿選擇的角度與強度更新。
253 | 若更新間隔太小,裝置效能或許會受到影響。
254 | 另外,若間隔小於已連結的程式要求的位置接收間隔,更新或許會被程式捨棄。
255 |
256 | 最小移動速度
257 | 在搖桿強度設定為零時使用此數值(公尺/秒)
258 |
259 | 最大移動速度
260 | 在搖桿強度設定為最大時使用此數值(公尺/秒)
261 |
262 |
263 |
264 | 輸入錯誤,多個數字用逗點分隔
265 | (預設)
266 | %1$d 毫秒
267 | 不可以空白或小於 %1$d
268 | 此數字只能是 100 的整數倍數
269 | 速度值不可以空白
270 | 速度值無效,應該為一個浮點數
271 |
272 |
273 |
274 | 開始/停止更新
275 | 通知一次
276 |
277 |
278 |
279 | 開放原始碼計畫
280 | 翻譯
281 | 其他模組
282 | 停用 heads-up 通知
283 |
284 | 覺得此程式好用嗎?\n透過 %1$s 來支持我們。
285 | 捐贈
286 |
287 |
288 |
289 | 注意事項
290 | 變更系統應用程式的位置設定可能會引起未知錯誤!
291 | 我懂了
292 | 不要再顯示
293 |
294 |
295 |
296 | 測試版本僅支援設定最多 8 個程式
297 | 好的
298 | 取消
299 |
300 |
301 |
302 |
303 |
304 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | FakeLocation
3 | Mock current location
4 |
5 |
6 | Location Settings
7 | Settings
8 | Donate
9 | Template
10 | About
11 | Select a location
12 | Results for \"%1$s\"
13 |
14 |
15 | Unfortunately, %1$s has stopped, crash log has been copied to the clipboard. Please try to restart the app or open an issue on GitHub.
16 | Stacktrace:
17 | Crash log has been saved to %1$s
18 | Failed to save the crash log, it requires \"Write External Storage\" permission.
19 | OK
20 | Open Issue
21 |
22 |
23 |
24 | Settings
25 | Template
26 | Search
27 | Donate
28 | How to Use
29 | About
30 | Toggle Overlay
31 |
32 | %1$s is not active! Please enable it first in Xposed Installer and restart the phone.
33 | OK
34 | Unknown Xposed Installer, please enable it manually.
35 |
36 | This update contains some new features that requires a reboot to work properly.
37 | OK
38 |
39 | Search app name or package name
40 | [Hidden]
41 | [Connected]
42 |
43 |
44 |
45 | OK
46 | Never Show Again
47 | If the app you want to mock uses Google service to obtain gps locations, you should turn on \'Google service API support\' in Settings and set in app\'s per-app settings page instead of setting here.
48 | Overlay
49 | In order for the overlay to work, you should connect an App to it (Per-app settings page, GPS Mocking, Connect button). See help for more details.
50 |
51 |
52 |
53 | In order for the following features to work properly:
54 | Save crash log and user settings
55 | Display map for location selection
56 | Display overlay
57 | Permissions %1$s, %2$s and %3$s are needed.
58 | Permission %1$s is needed on some ROMs.
59 | WRITE_EXTERNAL_STORAGE
60 | READ_PHONE_STATE
61 | ACCESS_COARSE_LOCATION
62 | SYSTEM_ALERT_WINDOW
63 |
64 | Later
65 | To Set
66 | Allow
67 | Deny
68 | GOT IT
69 |
70 |
71 |
72 | Search places
73 | History
74 | Feeling Lucky
75 | Switch Map
76 |
77 | Location (%1$.6f, %2$.6f) selected
78 | Failed to get coordinate
79 | Current location
80 | Retrieving address…
81 | Select a location
82 | (Empty)
83 |
84 |
85 |
86 | No results found for \"%1$s\"
87 | Searching
88 | Retry
89 | Loading more
90 | No coordinate found for this address
91 |
92 |
93 |
94 | Recent
95 | Templates
96 | Failed to get package name, please try again!
97 | GOT IT
98 | This feature requires a reboot to work since the module has been updated
99 | Settings saved
100 | Updated
101 | Error occurred: %1$s
102 |
103 | Hide Module from the App
104 |
105 |
106 | GPS Mocking
107 | App\'s location handling may be different. If the location is not updated, use overlay to notify it manually
108 |
109 | Latitude
110 | Longitude
111 | Longitude should be greater than -180 and less than 180
112 | Latitude should be greater than -90 and less than 90
113 |
114 | Select
115 | Connect
116 | Disconnect
117 | Notify
118 |
119 |
120 |
121 | Cell info Mocking
122 | Try use cell info if GPS failed
123 |
124 | Cell type
125 | preferably the same as phone type
126 |
127 |
128 |
129 | Settings have been changed, do you want to save it first?
130 | Cancel
131 | Discard
132 | Save
133 | Settings saved
134 | No settings changed
135 | Settings discarded
136 |
137 |
138 |
139 | Shortcut
140 | Template
141 | Recent
142 | (Not set)
143 | (Unknown)
144 | (Empty)
145 |
146 | Current Cell Info
147 | The phone currently using
148 | Cannot retrieve current cell info automatically :(
149 | GPS Template
150 | Cell Template
151 | (Null)
152 | Type
153 |
154 |
155 |
156 |
157 | General
158 |
159 | System apps
160 | Show
161 | Don\'t show
162 |
163 | App list sorting
164 | Sort according to app\'s mocking status and settings (more time-consuming)
165 | Default
166 |
167 |
168 | Map
169 |
170 | Preferred map type
171 |
172 | Auto (Default)
173 | AutoNavi Map
174 | Google Map
175 |
176 | Search area (Google Map)
177 |
178 | Only current locale
179 | Global
180 |
181 |
182 |
183 | Locate
184 |
185 | Offset correction
186 | Try to correct offset (only coordinates in China)
187 | Don\'t do anything
188 |
189 | Google Service API support
190 |
191 |
192 |
193 | Feedback
194 |
195 | Verbose log
196 | Enabled
197 | Before submitting an issue please enable this and try to reproduce the issue!
198 |
199 | Issue
200 | Please describe the issue as detailed as possible, and submit with the log in Xposed Installer together
201 |
202 |
203 |
204 |
205 | Advanced
206 |
207 | Advanced settings
208 | It is not advisable to change these settings if you are not completely sure of what you are doing, as it could cause unexpected behavior.
209 |
210 | GPS Status
211 | Default is empty, numbers separated by commas
212 |
213 | Signal to Noise Ratio
214 | Satellite Elevation
215 | Satellite Azimuths
216 |
217 |
218 |
219 | Experimental
220 | Enabled (Reboot required)
221 | Disabled (Reboot required)
222 |
223 | Tencent Location SDK support
224 |
225 |
226 |
227 | Overlay
228 |
229 | Overlay settings
230 | Related settings
231 |
232 | Service
233 |
234 | Auto stop
235 | Stop service when closing main page if overlay is not showing
236 | Do nothing
237 |
238 | Foreground service
239 | If on, the service will unlikely be killed by the system when low on memory.
240 |
241 | Behavior
242 |
243 | Switching interval
244 | Close joystick view when there is no operation during the time interval (ms)
245 |
246 | Remember last position
247 | Overlay view will be shown at last closed position
248 | Overlay view will be shown at default position
249 |
250 | Controls
251 |
252 | GPS location update interval
253 | Update Interval (ms)
254 | GPS location will be updated according to the angle and strength selected from the overlay joystick.
255 | Device performance may be affected if update interval is too small.
256 | Also the update may be discarded by the connected app if the interval is less than the location receiving interval that the app requested.
257 |
258 | Minimum moving speed
259 | The value is used when strength of the overlay joystick is set to 0 (meter/s)
260 |
261 | Maximum moving speed
262 | The value is used when strength of the overlay joystick is set to maximum (meter/s)
263 |
264 |
265 |
266 | Input error, numbers separated by commas
267 | (Default)
268 | %1$d ms
269 | Can not be empty or less than %1$d
270 | The number can only be a integer multiple of 100
271 | Speed can not be empty
272 | Invalid speed value, should be a float number
273 |
274 |
275 |
276 | Start/Stop Updates
277 | Notify Once
278 |
279 |
280 |
281 | Find this app useful?\nSupport by %1$s.
282 | making a donation
283 |
284 | Other modules
285 | Disable heads-up notifications
286 | Translations
287 | Open source projects
288 |
289 |
290 |
291 | Attention
292 | Change the location settings of system apps may cause unexpected behavior!
293 | GOT IT
294 | DON\'T SHOW AGAIN
295 |
296 |
297 |
298 | Only supports 8 apps in beta version.
299 | OK
300 | Cancel
301 |
302 |
303 |
304 |
--------------------------------------------------------------------------------
/art/screenshots/main_0_1_44.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/j2rong/FakeLocation/d8a2cb2d52ecee4cbd1b908e3d712029a6b8eee9/art/screenshots/main_0_1_44.png
--------------------------------------------------------------------------------
/art/screenshots/map_select_amap_0_7_300.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/j2rong/FakeLocation/d8a2cb2d52ecee4cbd1b908e3d712029a6b8eee9/art/screenshots/map_select_amap_0_7_300.png
--------------------------------------------------------------------------------
/art/screenshots/per_app_settings_0_3_73.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/j2rong/FakeLocation/d8a2cb2d52ecee4cbd1b908e3d712029a6b8eee9/art/screenshots/per_app_settings_0_3_73.png
--------------------------------------------------------------------------------
/art/screenshots/settings_0_1_44.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/j2rong/FakeLocation/d8a2cb2d52ecee4cbd1b908e3d712029a6b8eee9/art/screenshots/settings_0_1_44.png
--------------------------------------------------------------------------------
/art/screenshots/shortcut_list_0_7_300.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/j2rong/FakeLocation/d8a2cb2d52ecee4cbd1b908e3d712029a6b8eee9/art/screenshots/shortcut_list_0_7_300.png
--------------------------------------------------------------------------------
/mapsearchbar/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/mapsearchbar/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | android {
4 | compileSdkVersion 23
5 | buildToolsVersion "23.0.3"
6 |
7 | defaultConfig {
8 | minSdkVersion 17
9 | targetSdkVersion 23
10 | versionCode 1
11 | versionName "1.0"
12 | }
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 'com.android.support:appcompat-v7:23.4.0'
24 | compile 'com.android.support:design:23.4.0'
25 | compile 'com.android.support:recyclerview-v7:23.4.0'
26 | compile 'com.android.support:cardview-v7:23.4.0'
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/mapsearchbar/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:\Develop\Android\sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/mapsearchbar/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/mapsearchbar/src/main/java/com/rong/library/widget/HighlightTextView.java:
--------------------------------------------------------------------------------
1 | package com.rong.library.widget;
2 |
3 | import android.annotation.TargetApi;
4 | import android.content.Context;
5 | import android.content.res.TypedArray;
6 | import android.graphics.Color;
7 | import android.graphics.Typeface;
8 | import android.os.Build;
9 | import android.support.annotation.ColorInt;
10 | import android.text.Spannable;
11 | import android.text.SpannableString;
12 | import android.text.Spanned;
13 | import android.text.TextUtils;
14 | import android.text.style.BackgroundColorSpan;
15 | import android.text.style.ForegroundColorSpan;
16 | import android.text.style.StyleSpan;
17 | import android.util.AttributeSet;
18 | import android.widget.TextView;
19 |
20 | import com.rong.library.widget.mapsearchbar.R;
21 |
22 | /**
23 | * Copyright (c) 2016-2017, j2Rong
24 | *
25 | * Licensed under the Apache License, Version 2.0 (the "License");
26 | * you may not use this file except in compliance with the License.
27 | * You may obtain a copy of the License at
28 | *
29 | * http://www.apache.org/licenses/LICENSE-2.0
30 | *
31 | * Unless required by applicable law or agreed to in writing, software
32 | * distributed under the License is distributed on an "AS IS" BASIS,
33 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
34 | * See the License for the specific language governing permissions and
35 | * limitations under the License.
36 | */
37 | public class HighlightTextView extends android.support.v7.widget.AppCompatTextView {
38 |
39 | public HighlightTextView(Context context) {
40 | super(context);
41 | init(null, 0);
42 | }
43 |
44 | public HighlightTextView(Context context, AttributeSet attrs) {
45 | super(context, attrs);
46 | init(attrs, 0);
47 | }
48 |
49 | public HighlightTextView(Context context, AttributeSet attrs, int defStyle) {
50 | super(context, attrs, defStyle);
51 | init(attrs, defStyle);
52 | }
53 |
54 |
55 | private int mHighlightTextColor = Color.BLACK;
56 | private int mHighlightBackgroundColor = Color.TRANSPARENT;
57 | private boolean mCaseSensitive = false;
58 | private boolean mHighlightAllOccurrences = true;
59 | private boolean mHighlightTextBold = false;
60 |
61 | private void init(AttributeSet attrs, int defStyle) {
62 | final TypedArray a = getContext().obtainStyledAttributes(
63 | attrs, R.styleable.HighlightTextView, defStyle, 0);
64 |
65 | mHighlightTextColor = a.getColor(R.styleable.HighlightTextView_htv_textHighlightColor, getCurrentTextColor());
66 | mHighlightBackgroundColor = a.getColor(R.styleable.HighlightTextView_htv_textHighlightBackgroundColor, Color.TRANSPARENT);
67 | mCaseSensitive = a.getBoolean(R.styleable.HighlightTextView_htv_caseSensitive, false);
68 | mHighlightAllOccurrences = a.getBoolean(R.styleable.HighlightTextView_htv_highlightAllOccurrences, true);
69 | mHighlightTextBold = a.getBoolean(R.styleable.HighlightTextView_htv_highlightTextBold, false);
70 |
71 | a.recycle();
72 | }
73 |
74 | public void setHighlightTextColor(@ColorInt int color) {
75 | this.mHighlightTextColor = color;
76 | }
77 |
78 | public int getHighlightTextColor() {
79 | return mHighlightTextColor;
80 | }
81 |
82 | public void setHighlightBackgroundColor(@ColorInt int color) {
83 | this.mHighlightBackgroundColor = color;
84 | }
85 |
86 | public int getHighlightBackgroundColor() {
87 | return mHighlightBackgroundColor;
88 | }
89 |
90 | public boolean isCaseSensitive() {
91 | return mCaseSensitive;
92 | }
93 |
94 | public void setCaseSensitive(boolean mCaseSensitive) {
95 | this.mCaseSensitive = mCaseSensitive;
96 | }
97 |
98 | public boolean isHighlightAllOccurrences() {
99 | return mHighlightAllOccurrences;
100 | }
101 |
102 | public void setHighlightAllOccurrences(boolean mHighlightAllOccurrences) {
103 | this.mHighlightAllOccurrences = mHighlightAllOccurrences;
104 | }
105 |
106 | public void highlight(String textToHighlight) {
107 | if (textToHighlight == null) {
108 | // clear highlight
109 | String text = getText().toString();
110 | setText(text);
111 | return;
112 | }
113 |
114 | if (!TextUtils.isEmpty(getText()) && !textToHighlight.isEmpty()) {
115 | final String text = getText().toString();
116 | final Spannable spannableString = new SpannableString(text);
117 |
118 | String textCopy;
119 | String textHighlightCopy;
120 | if (!mCaseSensitive) {
121 | textCopy = text.toLowerCase();
122 | textHighlightCopy = textToHighlight.toLowerCase();
123 | } else {
124 | textCopy = text;
125 | textHighlightCopy = textToHighlight;
126 | }
127 |
128 | int matchStart = textCopy.indexOf(textHighlightCopy, 0);
129 | if (matchStart == -1) {
130 | // no match , return
131 | return;
132 | }
133 |
134 | int searchStart;
135 | do {
136 | searchStart = matchStart + textHighlightCopy.length();
137 |
138 | spannableString.setSpan(new ForegroundColorSpan(mHighlightTextColor),
139 | matchStart, searchStart, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
140 | spannableString.setSpan(new BackgroundColorSpan(mHighlightBackgroundColor),
141 | matchStart, searchStart, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
142 | if (mHighlightTextBold)
143 | spannableString.setSpan(new StyleSpan(Typeface.BOLD),
144 | matchStart, searchStart, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
145 |
146 | if (!mHighlightAllOccurrences) {
147 | break;
148 | }
149 | } while ((matchStart = textCopy.indexOf(textHighlightCopy, searchStart)) != -1);
150 |
151 | setText(spannableString);
152 | }
153 | }
154 |
155 | }
--------------------------------------------------------------------------------
/mapsearchbar/src/main/java/com/rong/library/widget/mapsearchbar/MapSearchBar.java:
--------------------------------------------------------------------------------
1 | package com.rong.library.widget.mapsearchbar;
2 |
3 | import android.animation.ValueAnimator;
4 | import android.annotation.TargetApi;
5 | import android.app.Activity;
6 | import android.content.Context;
7 | import android.content.res.TypedArray;
8 | import android.graphics.drawable.Drawable;
9 | import android.os.Build;
10 | import android.support.annotation.MenuRes;
11 | import android.support.v4.content.ContextCompat;
12 | import android.support.v7.widget.AppCompatEditText;
13 | import android.support.v7.widget.AppCompatImageView;
14 | import android.support.v7.widget.CardView;
15 | import android.support.v7.widget.LinearLayoutManager;
16 | import android.support.v7.widget.PopupMenu;
17 | import android.support.v7.widget.RecyclerView;
18 | import android.text.Editable;
19 | import android.text.TextUtils;
20 | import android.text.TextWatcher;
21 | import android.util.AttributeSet;
22 | import android.util.DisplayMetrics;
23 | import android.view.Gravity;
24 | import android.view.KeyEvent;
25 | import android.view.MenuItem;
26 | import android.view.View;
27 | import android.view.ViewGroup;
28 | import android.view.inputmethod.EditorInfo;
29 | import android.view.inputmethod.InputMethodManager;
30 | import android.widget.FrameLayout;
31 | import android.widget.RelativeLayout;
32 | import android.widget.TextView;
33 |
34 | import java.util.List;
35 |
36 | /**
37 | * Copyright (c) 2016-2017, j2Rong
38 | *
39 | * Licensed under the Apache License, Version 2.0 (the "License");
40 | * you may not use this file except in compliance with the License.
41 | * You may obtain a copy of the License at
42 | *
43 | * http://www.apache.org/licenses/LICENSE-2.0
44 | *
45 | * Unless required by applicable law or agreed to in writing, software
46 | * distributed under the License is distributed on an "AS IS" BASIS,
47 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
48 | * See the License for the specific language governing permissions and
49 | * limitations under the License.
50 | */
51 | public class MapSearchBar extends FrameLayout implements
52 | View.OnClickListener, PopupMenu.OnMenuItemClickListener,
53 | TextView.OnEditorActionListener, View.OnFocusChangeListener,
54 | SearchResultAdapter.OnSuggestionItemClickListener {
55 |
56 | public MapSearchBar(Context context, AttributeSet attrs) {
57 | super(context, attrs);
58 | init(attrs);
59 | }
60 |
61 | public MapSearchBar(Context context, AttributeSet attrs, int defStyleAttr) {
62 | super(context, attrs, defStyleAttr);
63 | init(attrs);
64 | }
65 |
66 | @TargetApi(Build.VERSION_CODES.LOLLIPOP)
67 | public MapSearchBar(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
68 | super(context, attrs, defStyleAttr, defStyleRes);
69 | init(attrs);
70 | }
71 |
72 | public interface MapSearchActionListener {
73 | boolean onSearchBarMenuItemClick(MenuItem item);
74 | void onNavigationClick(View v);
75 | void onHistoryClick(View v);
76 | void onSearchQuerySuggestionClick(SearchResult data);
77 |
78 | void onSearchConfirmedAsync(String query);
79 | void onSearchQueryChangedAsync(String query);
80 | }
81 |
82 |
83 | public static final int NAV_MAP_AUTO_NAV = 0;
84 | public static final int NAV_MAP_GOOGLE = 1;
85 |
86 |
87 | private CardView cardView = null;
88 | private AppCompatImageView btnMenu = null;
89 | private AppCompatImageView btnNavigation = null;
90 | private AppCompatImageView btnHistory = null;
91 | private AppCompatEditText searchEdit = null;
92 | private AppCompatImageView btnClear = null;
93 | private RelativeLayout containerSuggestion = null;
94 | private RecyclerView suggestionRecycler = null;
95 | private PopupMenu popupMenu = null;
96 |
97 | private SearchResultAdapter adapter;
98 | private MapSearchActionListener mListener = null;
99 | private SearchQueryThread queryThread = null;
100 |
101 | private int screenHeight = 0;
102 | private boolean isSearchEditFocused = false;
103 | private boolean focusCameFromHistory = false;
104 |
105 | private boolean suggestionsVisible;
106 |
107 |
108 | private String hint;
109 | private String emptyHistory;
110 | private int elevation;
111 | private int margin;
112 | private int navType;
113 |
114 |
115 | private void init(AttributeSet attrs) {
116 | inflate(getContext(), R.layout.search_bar, this);
117 |
118 | TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.MapSearchBar);
119 | hint = a.getString(R.styleable.MapSearchBar_ms_searchHint);
120 | emptyHistory = a.getString(R.styleable.MapSearchBar_ms_defaultHistoryEmptyString);
121 | elevation = a.getDimensionPixelSize(R.styleable.MapSearchBar_ms_elevation, -1);
122 | margin = a.getDimensionPixelSize(R.styleable.MapSearchBar_ms_margin, -1);
123 | navType = a.getInt(R.styleable.MapSearchBar_ms_mapType, -1);
124 |
125 | a.recycle();
126 |
127 | // default settings
128 | if (hint == null) hint = getContext().getString(R.string.ms_default_edit_hint);
129 | if (emptyHistory == null) emptyHistory = "";
130 | if (elevation == -1) elevation = getResources().getDimensionPixelSize(R.dimen.ms_default_search_bar_elevation);
131 | if (margin == -1) margin = getResources().getDimensionPixelSize(R.dimen.ms_default_search_bar_margin);
132 | if (navType == -1) navType = NAV_MAP_AUTO_NAV;
133 |
134 |
135 | findViews();
136 | setupViews();
137 |
138 | DisplayMetrics displaymetrics = new DisplayMetrics();
139 | ((Activity)getContext()).getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
140 | screenHeight = displaymetrics.heightPixels;
141 | }
142 |
143 | private void findViews() {
144 | cardView = findViewById(R.id.card);
145 | btnMenu = findViewById(R.id.btn_menu);
146 | btnNavigation = findViewById(R.id.btn_nav);
147 | btnHistory = findViewById(R.id.btn_history);
148 | searchEdit = findViewById(R.id.edit);
149 | btnClear = findViewById(R.id.btn_clear);
150 | containerSuggestion = findViewById(R.id.list_container);
151 | suggestionRecycler = findViewById(R.id.recycler);
152 | }
153 |
154 | private void setupViews() {
155 | cardView.setCardElevation(elevation);
156 |
157 | FrameLayout.LayoutParams lpCard = (FrameLayout.LayoutParams) cardView.getLayoutParams();
158 | lpCard.setMargins(margin, margin, margin, margin);
159 | cardView.setLayoutParams(lpCard);
160 |
161 | if (popupMenu == null)
162 | btnMenu.setVisibility(GONE);
163 |
164 | btnHistory.setOnClickListener(this);
165 |
166 | int navResId = (navType == NAV_MAP_AUTO_NAV) ? R.drawable.a_90 : R.drawable.gmap_24;
167 | Drawable d = ContextCompat.getDrawable(getContext(), navResId);
168 | btnNavigation.setImageDrawable(d);
169 | btnNavigation.setOnClickListener(this);
170 |
171 | searchEdit.setHint(hint);
172 | searchEdit.setOnEditorActionListener(this);
173 | searchEdit.setOnFocusChangeListener(this);
174 | searchEdit.addTextChangedListener(new SearchEditTextWatcher());
175 |
176 | btnClear.setVisibility(GONE);
177 | btnClear.setOnClickListener(this);
178 |
179 | adapter = new SearchResultAdapter(getContext(), this, emptyHistory);
180 | suggestionRecycler.setLayoutManager(new LinearLayoutManager(getContext()));
181 | suggestionRecycler.setAdapter(adapter);
182 | }
183 |
184 |
185 | //
186 | // animation
187 | //
188 | private int getSuggestionHeight() {
189 | // returns pixels
190 | int h = (int)(screenHeight * 0.45);
191 | return adapter.getSuggestedHeight(suggestionRecycler, h);
192 | }
193 |
194 | private void animateSuggestionList(int from, int to) {
195 | suggestionsVisible = (to > 0);
196 |
197 | final ViewGroup.LayoutParams lp = containerSuggestion.getLayoutParams();
198 | if (to == 0 && lp.height == 0)
199 | return; // already collapsed
200 |
201 | if (to == 0)
202 | from = lp.height;
203 |
204 | ValueAnimator animator = ValueAnimator.ofInt(from, to);
205 | animator.setDuration(200);
206 | animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
207 | @Override
208 | public void onAnimationUpdate(ValueAnimator animation) {
209 | lp.height = (int) animation.getAnimatedValue();
210 | containerSuggestion.setLayoutParams(lp);
211 | }
212 | });
213 |
214 | // if (adapter.getItemCount() > 0)
215 | animator.start();
216 | }
217 |
218 |
219 |
220 | @Override
221 | public void onClick(View v) {
222 | int id = v.getId(); // id == getId()
223 |
224 | if (id == R.id.btn_menu) {
225 | if (popupMenu != null) {
226 | popupMenu.show();
227 | searchEdit.clearFocus(); // clear focus and hide suggestion list
228 | }
229 | } else if (id == R.id.btn_clear) {
230 | searchEdit.setText(""); // auto trigger onTextChanged
231 | //searchEdit.requestFocus(); // hide
232 | } else if (id == R.id.btn_nav) {
233 | if (mListener != null)
234 | mListener.onNavigationClick(btnNavigation);
235 | } else if (id == R.id.btn_history) {
236 | if (mListener != null) {
237 | mListener.onHistoryClick(btnHistory);
238 | focusCameFromHistory = true;
239 | searchEdit.setText("");
240 | searchEdit.requestFocus();
241 | }
242 | }
243 | }
244 |
245 | @Override
246 | public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
247 | if (actionId == EditorInfo.IME_ACTION_SEARCH) {
248 |
249 | String q = searchEdit.getText().toString();
250 |
251 | // clear and hide suggestions
252 | searchEdit.setText("");
253 | searchEdit.clearFocus();
254 |
255 | if (mListener != null) {
256 | if (!TextUtils.isEmpty(q.trim()))
257 | mListener.onSearchConfirmedAsync(q);
258 | }
259 |
260 | return true;
261 | }
262 |
263 | return false;
264 | }
265 |
266 | private class SearchEditTextWatcher implements TextWatcher {
267 | @Override
268 | public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
269 |
270 | @Override
271 | public void afterTextChanged(Editable s) {}
272 |
273 | @Override
274 | public void onTextChanged(CharSequence s, int start, int before, int count) {
275 | if (TextUtils.isEmpty(s.toString())) {
276 | btnClear.setVisibility(GONE);
277 | } else {
278 | btnClear.setVisibility(VISIBLE);
279 | }
280 |
281 | if (queryThread != null) {
282 | queryThread.pushQuery(s.toString());
283 | }
284 | }
285 | }
286 |
287 | @Override
288 | public void onFocusChange(View v, boolean hasFocus) {
289 | InputMethodManager imm = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
290 |
291 | if (hasFocus) {
292 | if (!focusCameFromHistory && imm != null)
293 | imm.showSoftInput(v, InputMethodManager.SHOW_IMPLICIT);
294 | focusCameFromHistory = false;
295 |
296 | isSearchEditFocused = true;
297 | if (adapter.getItemCount() > 0 && !suggestionsVisible)
298 | animateSuggestionList(0, getSuggestionHeight());
299 |
300 | } else {
301 | if (imm != null)
302 | imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
303 |
304 | isSearchEditFocused = false;
305 | if (suggestionsVisible)
306 | animateSuggestionList(-1, 0);
307 | }
308 | }
309 |
310 | @SuppressWarnings("SimplifiableIfStatement")
311 | @Override
312 | public boolean onMenuItemClick(MenuItem item) {
313 | if (mListener != null)
314 | return mListener.onSearchBarMenuItemClick(item);
315 | else
316 | return false;
317 | }
318 |
319 | @Override
320 | public void onSuggestionItemClick(int position, View v, SearchResult data) {
321 | if (mListener != null)
322 | mListener.onSearchQuerySuggestionClick(data);
323 |
324 | searchEdit.setText("");
325 | searchEdit.clearFocus();
326 | }
327 |
328 |
329 | /**
330 | * update search result list
331 | * @param list new search result list, null if only content changed
332 | * @param theQuery query of this search
333 | *
334 | */
335 | public void updateSearchResult(List list, String theQuery) {
336 | int previous, current;
337 |
338 | previous = getSuggestionHeight();
339 |
340 | if (list != null)
341 | adapter.setList(list, theQuery);
342 |
343 | adapter.notifyDataSetChanged();
344 | current = getSuggestionHeight();
345 |
346 | if (isSearchEditFocused)
347 | animateSuggestionList(previous, current);
348 | }
349 |
350 |
351 | public void inflateMenu(@MenuRes int menuRes) {
352 | btnMenu.setVisibility(VISIBLE);
353 | btnMenu.setOnClickListener(this);
354 |
355 | popupMenu = new PopupMenu(getContext(), btnMenu);
356 | popupMenu.setOnMenuItemClickListener(this);
357 | popupMenu.inflate(menuRes);
358 | popupMenu.setGravity(Gravity.END);
359 | }
360 |
361 | public void setMapSearchActionListener(MapSearchActionListener l) {
362 | mListener = l;
363 | if (queryThread != null) {
364 | queryThread.updateListener(mListener);
365 | }
366 | }
367 |
368 | public void startQueryThread() {
369 | if (queryThread == null) {
370 | queryThread = new SearchQueryThread();
371 | queryThread.start();
372 | }
373 | }
374 |
375 | public void stopQueryThread() {
376 | if (queryThread != null) {
377 | queryThread.quit();
378 | queryThread = null;
379 | }
380 | }
381 |
382 | public void setNavigationType(int type) {
383 | navType = type;
384 | if (type != NAV_MAP_AUTO_NAV && type != NAV_MAP_GOOGLE)
385 | navType = NAV_MAP_AUTO_NAV;
386 |
387 | int navResId = (navType == NAV_MAP_AUTO_NAV) ? R.drawable.a_90 : R.drawable.gmap_24;
388 | Drawable d = ContextCompat.getDrawable(getContext(), navResId);
389 | btnNavigation.setImageDrawable(d);
390 | }
391 |
392 |
393 |
394 |
395 | }
396 |
--------------------------------------------------------------------------------
/mapsearchbar/src/main/java/com/rong/library/widget/mapsearchbar/OnSearchResultItemClickListener.java:
--------------------------------------------------------------------------------
1 | package com.rong.library.widget.mapsearchbar;
2 |
3 | import android.view.View;
4 |
5 | /**
6 | * Copyright (c) 2016-2017, j2Rong
7 | *
8 | * Licensed under the Apache License, Version 2.0 (the "License");
9 | * you may not use this file except in compliance with the License.
10 | * You may obtain a copy of the License at
11 | *
12 | * http://www.apache.org/licenses/LICENSE-2.0
13 | *
14 | * Unless required by applicable law or agreed to in writing, software
15 | * distributed under the License is distributed on an "AS IS" BASIS,
16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | * See the License for the specific language governing permissions and
18 | * limitations under the License.
19 | */
20 | public interface OnSearchResultItemClickListener {
21 | void onItemViewClick(int position, View v);
22 | }
23 |
--------------------------------------------------------------------------------
/mapsearchbar/src/main/java/com/rong/library/widget/mapsearchbar/SearchQueryThread.java:
--------------------------------------------------------------------------------
1 | package com.rong.library.widget.mapsearchbar;
2 |
3 | import java.lang.ref.WeakReference;
4 |
5 | /**
6 | * Copyright (c) 2016-2017, j2Rong
7 | *
8 | * Licensed under the Apache License, Version 2.0 (the "License");
9 | * you may not use this file except in compliance with the License.
10 | * You may obtain a copy of the License at
11 | *
12 | * http://www.apache.org/licenses/LICENSE-2.0
13 | *
14 | * Unless required by applicable law or agreed to in writing, software
15 | * distributed under the License is distributed on an "AS IS" BASIS,
16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | * See the License for the specific language governing permissions and
18 | * limitations under the License.
19 | */
20 | class SearchQueryThread extends Thread {
21 |
22 | private volatile boolean bStopping = false;
23 |
24 | private String cachedQuery = null;
25 | private String strQuerying = "";
26 | private WeakReference listener = null;
27 |
28 | void pushQuery(String query) {
29 | strQuerying = query;
30 | }
31 |
32 | void updateListener(MapSearchBar.MapSearchActionListener l) {
33 | if (l != null) {
34 | listener = new WeakReference<>(l);
35 | } else {
36 | listener = null;
37 | }
38 | }
39 |
40 | public void quit() {
41 | if (!bStopping) {
42 | bStopping = true;
43 | this.interrupt();
44 | }
45 | }
46 |
47 | @Override
48 | public void run() {
49 | while (!bStopping) {
50 | if (strQuerying != null) {
51 | if (!strQuerying.equals(cachedQuery)) {
52 | cachedQuery = strQuerying;
53 |
54 | if (listener != null) {
55 | MapSearchBar.MapSearchActionListener l = listener.get();
56 | if (l != null)
57 | l.onSearchQueryChangedAsync(cachedQuery);
58 | }
59 | }
60 | }
61 |
62 | try {
63 | Thread.sleep(500);
64 | } catch (InterruptedException ignored) {
65 | ignored.printStackTrace();
66 | }
67 | }
68 | }
69 |
70 | }
71 |
--------------------------------------------------------------------------------
/mapsearchbar/src/main/java/com/rong/library/widget/mapsearchbar/SearchResult.java:
--------------------------------------------------------------------------------
1 | package com.rong.library.widget.mapsearchbar;
2 |
3 | /**
4 | * Copyright (c) 2016-2017, j2Rong
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 | public class SearchResult {
19 |
20 | public Object real;
21 | public int type;
22 |
23 | public String displayFirst;
24 | public String displaySecond;
25 |
26 | public static final int TYPE_LOCATION_RECENT = 0;
27 | public static final int TYPE_MAP_SEARCH_PLACE = 1;
28 | public static final int TYPE_MAP_SEARCH_WITHOUT_LOCATION = 2;
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/mapsearchbar/src/main/java/com/rong/library/widget/mapsearchbar/SearchResultAdapter.java:
--------------------------------------------------------------------------------
1 | package com.rong.library.widget.mapsearchbar;
2 |
3 | import android.content.Context;
4 | import android.graphics.drawable.Drawable;
5 | import android.support.v4.content.ContextCompat;
6 | import android.support.v7.widget.AppCompatImageView;
7 | import android.support.v7.widget.RecyclerView;
8 | import android.text.TextUtils;
9 | import android.util.DisplayMetrics;
10 | import android.util.TypedValue;
11 | import android.view.LayoutInflater;
12 | import android.view.View;
13 | import android.view.ViewGroup;
14 |
15 | import com.rong.library.widget.HighlightTextView;
16 |
17 | import java.lang.ref.WeakReference;
18 | import java.util.List;
19 |
20 | /**
21 | * Copyright (c) 2016-2017, j2Rong
22 | *
23 | * Licensed under the Apache License, Version 2.0 (the "License");
24 | * you may not use this file except in compliance with the License.
25 | * You may obtain a copy of the License at
26 | *
27 | * http://www.apache.org/licenses/LICENSE-2.0
28 | *
29 | * Unless required by applicable law or agreed to in writing, software
30 | * distributed under the License is distributed on an "AS IS" BASIS,
31 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
32 | * See the License for the specific language governing permissions and
33 | * limitations under the License.
34 | */
35 | class SearchResultAdapter extends RecyclerView.Adapter implements
36 | OnSearchResultItemClickListener {
37 |
38 | interface OnSuggestionItemClickListener {
39 | void onSuggestionItemClick(int pos, View v, SearchResult data);
40 | }
41 |
42 | private List mList = null;
43 | private String currentQuery;
44 |
45 | private WeakReference mListener;
46 | private Context mContext;
47 | private View calcView = null;
48 |
49 | private String defEmptyStr;
50 | private Drawable iconHistory;
51 | private Drawable iconSearch;
52 | private Drawable iconPlace;
53 |
54 | SearchResultAdapter(Context c, OnSuggestionItemClickListener listener, String empty) {
55 | mContext = c;
56 | mListener = new WeakReference<>(listener);
57 | defEmptyStr = empty;
58 |
59 | iconHistory = ContextCompat.getDrawable(c, R.drawable.ic_history_white_24dp);
60 | iconSearch = ContextCompat.getDrawable(c, R.drawable.ic_search_white_24dp);
61 | iconPlace = ContextCompat.getDrawable(c, R.drawable.ic_place_white_24dp);
62 | }
63 |
64 |
65 | @Override
66 | public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
67 | View v = LayoutInflater.from(mContext).inflate(R.layout.item_search_result, parent, false);
68 | return new ViewHolder(v, this);
69 | }
70 |
71 | @Override
72 | public void onBindViewHolder(ViewHolder holder, int position) {
73 | SearchResult r = getItem(position);
74 |
75 | if (r != null) {
76 | holder.txt1st.setText(r.displayFirst);
77 | holder.txt2nd.setText(r.displaySecond);
78 |
79 | // highlight
80 | if (!TextUtils.isEmpty(currentQuery)) {
81 | holder.txt1st.highlight(currentQuery);
82 | holder.txt2nd.highlight(currentQuery);
83 | }
84 |
85 | switch (r.type) {
86 | case SearchResult.TYPE_LOCATION_RECENT: {
87 | if (TextUtils.isEmpty(r.displayFirst)) {
88 | holder.txt1st.setText(defEmptyStr);
89 | }
90 |
91 | holder.icon.setImageDrawable(iconHistory);
92 | break;
93 | }
94 | case SearchResult.TYPE_MAP_SEARCH_PLACE: {
95 | holder.icon.setImageDrawable(iconPlace);
96 | break;
97 | }
98 | case SearchResult.TYPE_MAP_SEARCH_WITHOUT_LOCATION: {
99 | holder.icon.setImageDrawable(iconSearch);
100 | }
101 | }
102 | }
103 | }
104 |
105 | private SearchResult getItem(int position) {
106 | if (mList == null || mList.size() == 0)
107 | return null;
108 | else
109 | return mList.get(position);
110 | }
111 |
112 | @Override
113 | public int getItemCount() {
114 | return (mList == null) ? 0 : mList.size();
115 | }
116 |
117 | void setList(List list, String query) {
118 | mList = list;
119 | currentQuery = query;
120 | }
121 |
122 | int getSuggestedHeight(RecyclerView parent, int max) {
123 | if (getItemCount() == 0)
124 | return 0;
125 |
126 | if (calcView == null)
127 | calcView = LayoutInflater.from(mContext).inflate(R.layout.item_search_result, parent, false);
128 |
129 | HighlightTextView txt1st = calcView.findViewById(R.id.txt_1st);
130 | HighlightTextView txt2nd = calcView.findViewById(R.id.txt_2nd);
131 |
132 | int total = 0;
133 |
134 | // 1dp separator
135 | DisplayMetrics metrics = mContext.getResources().getDisplayMetrics();
136 | total += ((int)(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 1, metrics)));
137 |
138 | for (int i = 0; i < getItemCount(); i++) {
139 | SearchResult r = getItem(i);
140 | if (r != null) {
141 | txt1st.setText(r.displayFirst);
142 | txt2nd.setText(r.displaySecond);
143 |
144 | calcView.measure(View.MeasureSpec.makeMeasureSpec(parent.getMeasuredWidth(), View.MeasureSpec.EXACTLY),
145 | View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
146 | total += calcView.getMeasuredHeight();
147 |
148 | if (total > max) {
149 | total = max;
150 | break;
151 | }
152 | }
153 | }
154 |
155 | return total;
156 | }
157 |
158 | @Override
159 | public void onItemViewClick(int position, View v) {
160 | if (mListener != null) {
161 | if (mListener.get() != null) {
162 | mListener.get().onSuggestionItemClick(position, v, getItem(position));
163 | }
164 | }
165 | }
166 |
167 | public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
168 |
169 | AppCompatImageView icon;
170 | HighlightTextView txt1st;
171 | HighlightTextView txt2nd;
172 |
173 | private WeakReference listener;
174 |
175 | ViewHolder(View itemView, OnSearchResultItemClickListener l) {
176 | super(itemView);
177 |
178 | icon = itemView.findViewById(R.id.image);
179 | txt1st = itemView.findViewById(R.id.txt_1st);
180 | txt2nd = itemView.findViewById(R.id.txt_2nd);
181 |
182 | listener = new WeakReference<>(l);
183 | itemView.setOnClickListener(this);
184 | }
185 |
186 | @Override
187 | public void onClick(View v) {
188 | if (listener != null) {
189 | if (listener.get() != null)
190 | listener.get().onItemViewClick(getAdapterPosition(), v);
191 | }
192 | }
193 | }
194 | }
195 |
--------------------------------------------------------------------------------
/mapsearchbar/src/main/res/drawable-hdpi/ic_arrow_back_white_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/j2rong/FakeLocation/d8a2cb2d52ecee4cbd1b908e3d712029a6b8eee9/mapsearchbar/src/main/res/drawable-hdpi/ic_arrow_back_white_24dp.png
--------------------------------------------------------------------------------
/mapsearchbar/src/main/res/drawable-hdpi/ic_close_white_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/j2rong/FakeLocation/d8a2cb2d52ecee4cbd1b908e3d712029a6b8eee9/mapsearchbar/src/main/res/drawable-hdpi/ic_close_white_24dp.png
--------------------------------------------------------------------------------
/mapsearchbar/src/main/res/drawable-hdpi/ic_history_white_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/j2rong/FakeLocation/d8a2cb2d52ecee4cbd1b908e3d712029a6b8eee9/mapsearchbar/src/main/res/drawable-hdpi/ic_history_white_24dp.png
--------------------------------------------------------------------------------
/mapsearchbar/src/main/res/drawable-hdpi/ic_more_vert_white_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/j2rong/FakeLocation/d8a2cb2d52ecee4cbd1b908e3d712029a6b8eee9/mapsearchbar/src/main/res/drawable-hdpi/ic_more_vert_white_24dp.png
--------------------------------------------------------------------------------
/mapsearchbar/src/main/res/drawable-hdpi/ic_place_white_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/j2rong/FakeLocation/d8a2cb2d52ecee4cbd1b908e3d712029a6b8eee9/mapsearchbar/src/main/res/drawable-hdpi/ic_place_white_24dp.png
--------------------------------------------------------------------------------
/mapsearchbar/src/main/res/drawable-hdpi/ic_search_white_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/j2rong/FakeLocation/d8a2cb2d52ecee4cbd1b908e3d712029a6b8eee9/mapsearchbar/src/main/res/drawable-hdpi/ic_search_white_24dp.png
--------------------------------------------------------------------------------
/mapsearchbar/src/main/res/drawable-mdpi/ic_arrow_back_white_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/j2rong/FakeLocation/d8a2cb2d52ecee4cbd1b908e3d712029a6b8eee9/mapsearchbar/src/main/res/drawable-mdpi/ic_arrow_back_white_24dp.png
--------------------------------------------------------------------------------
/mapsearchbar/src/main/res/drawable-mdpi/ic_close_white_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/j2rong/FakeLocation/d8a2cb2d52ecee4cbd1b908e3d712029a6b8eee9/mapsearchbar/src/main/res/drawable-mdpi/ic_close_white_24dp.png
--------------------------------------------------------------------------------
/mapsearchbar/src/main/res/drawable-mdpi/ic_history_white_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/j2rong/FakeLocation/d8a2cb2d52ecee4cbd1b908e3d712029a6b8eee9/mapsearchbar/src/main/res/drawable-mdpi/ic_history_white_24dp.png
--------------------------------------------------------------------------------
/mapsearchbar/src/main/res/drawable-mdpi/ic_more_vert_white_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/j2rong/FakeLocation/d8a2cb2d52ecee4cbd1b908e3d712029a6b8eee9/mapsearchbar/src/main/res/drawable-mdpi/ic_more_vert_white_24dp.png
--------------------------------------------------------------------------------
/mapsearchbar/src/main/res/drawable-mdpi/ic_place_white_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/j2rong/FakeLocation/d8a2cb2d52ecee4cbd1b908e3d712029a6b8eee9/mapsearchbar/src/main/res/drawable-mdpi/ic_place_white_24dp.png
--------------------------------------------------------------------------------
/mapsearchbar/src/main/res/drawable-mdpi/ic_search_white_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/j2rong/FakeLocation/d8a2cb2d52ecee4cbd1b908e3d712029a6b8eee9/mapsearchbar/src/main/res/drawable-mdpi/ic_search_white_24dp.png
--------------------------------------------------------------------------------
/mapsearchbar/src/main/res/drawable-xhdpi/ic_arrow_back_white_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/j2rong/FakeLocation/d8a2cb2d52ecee4cbd1b908e3d712029a6b8eee9/mapsearchbar/src/main/res/drawable-xhdpi/ic_arrow_back_white_24dp.png
--------------------------------------------------------------------------------
/mapsearchbar/src/main/res/drawable-xhdpi/ic_close_white_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/j2rong/FakeLocation/d8a2cb2d52ecee4cbd1b908e3d712029a6b8eee9/mapsearchbar/src/main/res/drawable-xhdpi/ic_close_white_24dp.png
--------------------------------------------------------------------------------
/mapsearchbar/src/main/res/drawable-xhdpi/ic_history_white_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/j2rong/FakeLocation/d8a2cb2d52ecee4cbd1b908e3d712029a6b8eee9/mapsearchbar/src/main/res/drawable-xhdpi/ic_history_white_24dp.png
--------------------------------------------------------------------------------
/mapsearchbar/src/main/res/drawable-xhdpi/ic_more_vert_white_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/j2rong/FakeLocation/d8a2cb2d52ecee4cbd1b908e3d712029a6b8eee9/mapsearchbar/src/main/res/drawable-xhdpi/ic_more_vert_white_24dp.png
--------------------------------------------------------------------------------
/mapsearchbar/src/main/res/drawable-xhdpi/ic_place_white_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/j2rong/FakeLocation/d8a2cb2d52ecee4cbd1b908e3d712029a6b8eee9/mapsearchbar/src/main/res/drawable-xhdpi/ic_place_white_24dp.png
--------------------------------------------------------------------------------
/mapsearchbar/src/main/res/drawable-xhdpi/ic_search_white_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/j2rong/FakeLocation/d8a2cb2d52ecee4cbd1b908e3d712029a6b8eee9/mapsearchbar/src/main/res/drawable-xhdpi/ic_search_white_24dp.png
--------------------------------------------------------------------------------
/mapsearchbar/src/main/res/drawable-xxhdpi/ic_arrow_back_white_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/j2rong/FakeLocation/d8a2cb2d52ecee4cbd1b908e3d712029a6b8eee9/mapsearchbar/src/main/res/drawable-xxhdpi/ic_arrow_back_white_24dp.png
--------------------------------------------------------------------------------
/mapsearchbar/src/main/res/drawable-xxhdpi/ic_close_white_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/j2rong/FakeLocation/d8a2cb2d52ecee4cbd1b908e3d712029a6b8eee9/mapsearchbar/src/main/res/drawable-xxhdpi/ic_close_white_24dp.png
--------------------------------------------------------------------------------
/mapsearchbar/src/main/res/drawable-xxhdpi/ic_history_white_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/j2rong/FakeLocation/d8a2cb2d52ecee4cbd1b908e3d712029a6b8eee9/mapsearchbar/src/main/res/drawable-xxhdpi/ic_history_white_24dp.png
--------------------------------------------------------------------------------
/mapsearchbar/src/main/res/drawable-xxhdpi/ic_more_vert_white_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/j2rong/FakeLocation/d8a2cb2d52ecee4cbd1b908e3d712029a6b8eee9/mapsearchbar/src/main/res/drawable-xxhdpi/ic_more_vert_white_24dp.png
--------------------------------------------------------------------------------
/mapsearchbar/src/main/res/drawable-xxhdpi/ic_place_white_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/j2rong/FakeLocation/d8a2cb2d52ecee4cbd1b908e3d712029a6b8eee9/mapsearchbar/src/main/res/drawable-xxhdpi/ic_place_white_24dp.png
--------------------------------------------------------------------------------
/mapsearchbar/src/main/res/drawable-xxhdpi/ic_search_white_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/j2rong/FakeLocation/d8a2cb2d52ecee4cbd1b908e3d712029a6b8eee9/mapsearchbar/src/main/res/drawable-xxhdpi/ic_search_white_24dp.png
--------------------------------------------------------------------------------
/mapsearchbar/src/main/res/drawable-xxxhdpi/ic_arrow_back_white_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/j2rong/FakeLocation/d8a2cb2d52ecee4cbd1b908e3d712029a6b8eee9/mapsearchbar/src/main/res/drawable-xxxhdpi/ic_arrow_back_white_24dp.png
--------------------------------------------------------------------------------
/mapsearchbar/src/main/res/drawable-xxxhdpi/ic_close_white_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/j2rong/FakeLocation/d8a2cb2d52ecee4cbd1b908e3d712029a6b8eee9/mapsearchbar/src/main/res/drawable-xxxhdpi/ic_close_white_24dp.png
--------------------------------------------------------------------------------
/mapsearchbar/src/main/res/drawable-xxxhdpi/ic_history_white_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/j2rong/FakeLocation/d8a2cb2d52ecee4cbd1b908e3d712029a6b8eee9/mapsearchbar/src/main/res/drawable-xxxhdpi/ic_history_white_24dp.png
--------------------------------------------------------------------------------
/mapsearchbar/src/main/res/drawable-xxxhdpi/ic_more_vert_white_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/j2rong/FakeLocation/d8a2cb2d52ecee4cbd1b908e3d712029a6b8eee9/mapsearchbar/src/main/res/drawable-xxxhdpi/ic_more_vert_white_24dp.png
--------------------------------------------------------------------------------
/mapsearchbar/src/main/res/drawable-xxxhdpi/ic_place_white_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/j2rong/FakeLocation/d8a2cb2d52ecee4cbd1b908e3d712029a6b8eee9/mapsearchbar/src/main/res/drawable-xxxhdpi/ic_place_white_24dp.png
--------------------------------------------------------------------------------
/mapsearchbar/src/main/res/drawable-xxxhdpi/ic_search_white_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/j2rong/FakeLocation/d8a2cb2d52ecee4cbd1b908e3d712029a6b8eee9/mapsearchbar/src/main/res/drawable-xxxhdpi/ic_search_white_24dp.png
--------------------------------------------------------------------------------
/mapsearchbar/src/main/res/layout/item_search_result.xml:
--------------------------------------------------------------------------------
1 |
2 |
14 |
15 |
22 |
23 |
28 |
29 |
39 |
40 |
52 |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/mapsearchbar/src/main/res/layout/search_bar.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
14 |
15 |
19 |
20 |
34 |
35 |
48 |
49 |
62 |
63 |
75 |
76 |
77 |
81 |
82 |
85 |
86 |
100 |
101 |
113 |
114 |
115 |
116 |
123 |
124 |
128 |
129 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
--------------------------------------------------------------------------------
/mapsearchbar/src/main/res/values/attr.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/mapsearchbar/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | #E6FFFFFF
5 | @color/ms_material_grey_600
6 | #9C27B0
7 |
8 | #ffe0e0e0
9 | #ff757575
10 |
11 |
--------------------------------------------------------------------------------
/mapsearchbar/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 4dp
5 | 8dp
6 |
7 | 8dp
8 |
9 |
--------------------------------------------------------------------------------
/mapsearchbar/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Search
4 |
5 |
6 |
--------------------------------------------------------------------------------
/markdownview/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/markdownview/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 |
--------------------------------------------------------------------------------
/markdownview/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | android {
4 | compileSdkVersion 23
5 | buildToolsVersion "23.0.3"
6 |
7 | defaultConfig {
8 | minSdkVersion 14
9 | targetSdkVersion 23
10 | versionCode 1
11 | versionName "1.0"
12 | }
13 |
14 | buildTypes {
15 | release {
16 | minifyEnabled false
17 | proguardFiles getDefaultProguardFile('proguard-android.txt')
18 | }
19 | }
20 | }
21 |
22 | dependencies {
23 | //provided 'com.android.support:appcompat-v7:23.4.0'
24 | }
25 |
--------------------------------------------------------------------------------
/markdownview/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/markdownview/src/main/assets/html/css/github-gist.css:
--------------------------------------------------------------------------------
1 | /**
2 | * GitHub Gist Theme
3 | * Author : Louis Barranqueiro - https://github.com/LouisBarranqueiro
4 | */
5 |
6 | .hljs {
7 | display: block;
8 | background: white;
9 | padding: 0.5em;
10 | color: #333333;
11 | overflow-x: auto;
12 | -webkit-text-size-adjust: none;
13 | }
14 |
15 | .hljs-comment,
16 | .bash .hljs-shebang,
17 | .java .hljs-javadoc,
18 | .javascript .hljs-javadoc,
19 | .rust .hljs-preprocessor {
20 | color: #969896;
21 | }
22 |
23 | .hljs-string,
24 | .apache .hljs-sqbracket,
25 | .coffeescript .hljs-subst,
26 | .coffeescript .hljs-regexp,
27 | .cpp .hljs-preprocessor,
28 | .c .hljs-preprocessor,
29 | .javascript .hljs-regexp,
30 | .json .hljs-attribute,
31 | .makefile .hljs-variable,
32 | .markdown .hljs-value,
33 | .markdown .hljs-link_label,
34 | .markdown .hljs-strong,
35 | .markdown .hljs-emphasis,
36 | .markdown .hljs-blockquote,
37 | .nginx .hljs-regexp,
38 | .nginx .hljs-number,
39 | .objectivec .hljs-preprocessor .hljs-title,
40 | .perl .hljs-regexp,
41 | .php .hljs-regexp,
42 | .xml .hljs-value,
43 | .less .hljs-built_in,
44 | .scss .hljs-built_in {
45 | color: #df5000;
46 | }
47 |
48 | .hljs-keyword,
49 | .css .hljs-at_rule,
50 | .css .hljs-important,
51 | .http .hljs-request,
52 | .ini .hljs-setting,
53 | .haskell .hljs-type,
54 | .java .hljs-javadoctag,
55 | .javascript .hljs-tag,
56 | .javascript .hljs-javadoctag,
57 | .nginx .hljs-title,
58 | .objectivec .hljs-preprocessor,
59 | .php .hljs-phpdoc,
60 | .sql .hljs-built_in,
61 | .less .hljs-tag,
62 | .less .hljs-at_rule,
63 | .scss .hljs-tag,
64 | .scss .hljs-at_rule,
65 | .scss .hljs-important,
66 | .stylus .hljs-at_rule,
67 | .go .hljs-typename,
68 | .swift .hljs-preprocessor {
69 | color: #a71d5d;
70 | }
71 |
72 | .apache .hljs-common,
73 | .apache .hljs-cbracket,
74 | .apache .hljs-keyword,
75 | .bash .hljs-literal,
76 | .bash .hljs-built_in,
77 | .coffeescript .hljs-literal,
78 | .coffeescript .hljs-built_in,
79 | .coffeescript .hljs-number,
80 | .cpp .hljs-number,
81 | .cpp .hljs-built_in,
82 | .c .hljs-number,
83 | .c .hljs-built_in,
84 | .cs .hljs-number,
85 | .cs .hljs-built_in,
86 | .css .hljs-attribute,
87 | .css .hljs-hexcolor,
88 | .css .hljs-number,
89 | .css .hljs-function,
90 | .haskell .hljs-number,
91 | .http .hljs-literal,
92 | .http .hljs-attribute,
93 | .java .hljs-number,
94 | .javascript .hljs-built_in,
95 | .javascript .hljs-literal,
96 | .javascript .hljs-number,
97 | .json .hljs-number,
98 | .makefile .hljs-keyword,
99 | .markdown .hljs-link_reference,
100 | .nginx .hljs-built_in,
101 | .objectivec .hljs-literal,
102 | .objectivec .hljs-number,
103 | .objectivec .hljs-built_in,
104 | .php .hljs-literal,
105 | .php .hljs-number,
106 | .python .hljs-number,
107 | .ruby .hljs-prompt,
108 | .ruby .hljs-constant,
109 | .ruby .hljs-number,
110 | .ruby .hljs-subst .hljs-keyword,
111 | .ruby .hljs-symbol,
112 | .rust .hljs-number,
113 | .sql .hljs-number,
114 | .puppet .hljs-function,
115 | .less .hljs-number,
116 | .less .hljs-hexcolor,
117 | .less .hljs-function,
118 | .less .hljs-attribute,
119 | .scss .hljs-preprocessor,
120 | .scss .hljs-number,
121 | .scss .hljs-hexcolor,
122 | .scss .hljs-function,
123 | .scss .hljs-attribute,
124 | .stylus .hljs-number,
125 | .stylus .hljs-hexcolor,
126 | .stylus .hljs-attribute,
127 | .stylus .hljs-params,
128 | .go .hljs-built_in,
129 | .go .hljs-constant,
130 | .swift .hljs-built_in,
131 | .swift .hljs-number {
132 | color: #0086b3;
133 | }
134 |
135 | .apache .hljs-tag,
136 | .cs .hljs-xmlDocTag,
137 | .css .hljs-tag,
138 | .xml .hljs-title,
139 | .stylus .hljs-tag {
140 | color: #63a35c;
141 | }
142 |
143 | .bash .hljs-variable,
144 | .cs .hljs-preprocessor,
145 | .cs .hljs-preprocessor .hljs-keyword,
146 | .css .hljs-attr_selector,
147 | .css .hljs-value,
148 | .ini .hljs-value,
149 | .ini .hljs-keyword,
150 | .javascript .hljs-tag .hljs-title,
151 | .makefile .hljs-constant,
152 | .nginx .hljs-variable,
153 | .xml .hljs-tag,
154 | .scss .hljs-variable {
155 | color: #333333;
156 | }
157 |
158 | .bash .hljs-title,
159 | .coffeescript .hljs-title,
160 | .cpp .hljs-title,
161 | .c .hljs-title,
162 | .cs .hljs-title,
163 | .css .hljs-id,
164 | .css .hljs-class,
165 | .css .hljs-pseudo,
166 | .ini .hljs-title,
167 | .haskell .hljs-title,
168 | .haskell .hljs-pragma,
169 | .java .hljs-title,
170 | .javascript .hljs-title,
171 | .makefile .hljs-title,
172 | .objectivec .hljs-title,
173 | .perl .hljs-sub,
174 | .php .hljs-title,
175 | .python .hljs-decorator,
176 | .python .hljs-title,
177 | .ruby .hljs-parent,
178 | .ruby .hljs-title,
179 | .rust .hljs-title,
180 | .xml .hljs-attribute,
181 | .puppet .hljs-title,
182 | .less .hljs-id,
183 | .less .hljs-pseudo,
184 | .less .hljs-class,
185 | .scss .hljs-id,
186 | .scss .hljs-pseudo,
187 | .scss .hljs-class,
188 | .stylus .hljs-class,
189 | .stylus .hljs-id,
190 | .stylus .hljs-pseudo,
191 | .stylus .hljs-title,
192 | .swift .hljs-title,
193 | .diff .hljs-chunk {
194 | color: #795da3;
195 | }
196 |
197 | .coffeescript .hljs-reserved,
198 | .coffeescript .hljs-attribute {
199 | color: #1d3e81;
200 | }
201 |
202 | .diff .hljs-chunk {
203 | font-weight: bold;
204 | }
205 |
206 | .diff .hljs-addition {
207 | color: #55a532;
208 | background-color: #eaffea;
209 | }
210 |
211 | .diff .hljs-deletion {
212 | color: #bd2c00;
213 | background-color: #ffecec;
214 | }
215 |
216 | .markdown .hljs-link_url {
217 | text-decoration: underline;
218 | }
219 |
--------------------------------------------------------------------------------
/markdownview/src/main/assets/html/css/github.css:
--------------------------------------------------------------------------------
1 | /*
2 | github.com style (c) Vasily Polovnyov
3 | */
4 |
5 | .hljs {
6 | display: block;
7 | overflow-x: auto;
8 | padding: 0.5em;
9 | color: #333;
10 | background: #f8f8f8;
11 | -webkit-text-size-adjust: none;
12 | }
13 |
14 | .hljs-comment,
15 | .diff .hljs-header {
16 | color: #998;
17 | font-style: italic;
18 | }
19 |
20 | .hljs-keyword,
21 | .css .rule .hljs-keyword,
22 | .hljs-winutils,
23 | .nginx .hljs-title,
24 | .hljs-subst,
25 | .hljs-request,
26 | .hljs-status {
27 | color: #333;
28 | font-weight: bold;
29 | }
30 |
31 | .hljs-number,
32 | .hljs-hexcolor,
33 | .ruby .hljs-constant {
34 | color: #008080;
35 | }
36 |
37 | .hljs-string,
38 | .hljs-tag .hljs-value,
39 | .hljs-doctag,
40 | .tex .hljs-formula {
41 | color: #d14;
42 | }
43 |
44 | .hljs-title,
45 | .hljs-id,
46 | .scss .hljs-preprocessor {
47 | color: #900;
48 | font-weight: bold;
49 | }
50 |
51 | .hljs-list .hljs-keyword,
52 | .hljs-subst {
53 | font-weight: normal;
54 | }
55 |
56 | .hljs-class .hljs-title,
57 | .hljs-type,
58 | .vhdl .hljs-literal,
59 | .tex .hljs-command {
60 | color: #458;
61 | font-weight: bold;
62 | }
63 |
64 | .hljs-tag,
65 | .hljs-tag .hljs-title,
66 | .hljs-rule .hljs-property,
67 | .django .hljs-tag .hljs-keyword {
68 | color: #000080;
69 | font-weight: normal;
70 | }
71 |
72 | .hljs-attribute,
73 | .hljs-variable,
74 | .lisp .hljs-body,
75 | .hljs-name {
76 | color: #008080;
77 | }
78 |
79 | .hljs-regexp {
80 | color: #009926;
81 | }
82 |
83 | .hljs-symbol,
84 | .ruby .hljs-symbol .hljs-string,
85 | .lisp .hljs-keyword,
86 | .clojure .hljs-keyword,
87 | .scheme .hljs-keyword,
88 | .tex .hljs-special,
89 | .hljs-prompt {
90 | color: #990073;
91 | }
92 |
93 | .hljs-built_in {
94 | color: #0086b3;
95 | }
96 |
97 | .hljs-preprocessor,
98 | .hljs-pragma,
99 | .hljs-pi,
100 | .hljs-doctype,
101 | .hljs-shebang,
102 | .hljs-cdata {
103 | color: #999;
104 | font-weight: bold;
105 | }
106 |
107 | .hljs-deletion {
108 | background: #fdd;
109 | }
110 |
111 | .hljs-addition {
112 | background: #dfd;
113 | }
114 |
115 | .diff .hljs-change {
116 | background: #0086b3;
117 | }
118 |
119 | .hljs-chunk {
120 | color: #aaa;
121 | }
122 |
--------------------------------------------------------------------------------
/markdownview/src/main/assets/html/js/marked.js:
--------------------------------------------------------------------------------
1 | /**
2 | * marked - a markdown parser
3 | * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
4 | * https://github.com/chjj/marked
5 | */
6 |
7 | ;(function() {
8 |
9 | /**
10 | * Block-Level Grammar
11 | */
12 |
13 | var block = {
14 | newline: /^\n+/,
15 | code: /^( {4}[^\n]+\n*)+/,
16 | fences: noop,
17 | hr: /^( *[-*_]){3,} *(?:\n+|$)/,
18 | heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
19 | nptable: noop,
20 | lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
21 | blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,
22 | list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
23 | html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,
24 | def: /^ *\[([^\]]+)\]: *([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
25 | table: noop,
26 | paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
27 | text: /^[^\n]+/
28 | };
29 |
30 | block.bullet = /(?:[*+-]|\d+\.)/;
31 | block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
32 | block.item = replace(block.item, 'gm')
33 | (/bull/g, block.bullet)
34 | ();
35 |
36 | block.list = replace(block.list)
37 | (/bull/g, block.bullet)
38 | ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
39 | ('def', '\\n+(?=' + block.def.source + ')')
40 | ();
41 |
42 | block.blockquote = replace(block.blockquote)
43 | ('def', block.def)
44 | ();
45 |
46 | block._tag = '(?!(?:'
47 | + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
48 | + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
49 | + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b';
50 |
51 | block.html = replace(block.html)
52 | ('comment', //)
53 | ('closed', /<(tag)[\s\S]+?<\/\1>/)
54 | ('closing', /])*?>/)
55 | (/tag/g, block._tag)
56 | ();
57 |
58 | block.paragraph = replace(block.paragraph)
59 | ('hr', block.hr)
60 | ('heading', block.heading)
61 | ('lheading', block.lheading)
62 | ('blockquote', block.blockquote)
63 | ('tag', '<' + block._tag)
64 | ('def', block.def)
65 | ();
66 |
67 | /**
68 | * Normal Block Grammar
69 | */
70 |
71 | block.normal = merge({}, block);
72 |
73 | /**
74 | * GFM Block Grammar
75 | */
76 |
77 | block.gfm = merge({}, block.normal, {
78 | fences: /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,
79 | paragraph: /^/,
80 | heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/
81 | });
82 |
83 | block.gfm.paragraph = replace(block.paragraph)
84 | ('(?!', '(?!'
85 | + block.gfm.fences.source.replace('\\1', '\\2') + '|'
86 | + block.list.source.replace('\\1', '\\3') + '|')
87 | ();
88 |
89 | /**
90 | * GFM + Tables Block Grammar
91 | */
92 |
93 | block.tables = merge({}, block.gfm, {
94 | nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
95 | table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
96 | });
97 |
98 | /**
99 | * Block Lexer
100 | */
101 |
102 | function Lexer(options) {
103 | this.tokens = [];
104 | this.tokens.links = {};
105 | this.options = options || marked.defaults;
106 | this.rules = block.normal;
107 |
108 | if (this.options.gfm) {
109 | if (this.options.tables) {
110 | this.rules = block.tables;
111 | } else {
112 | this.rules = block.gfm;
113 | }
114 | }
115 | }
116 |
117 | /**
118 | * Expose Block Rules
119 | */
120 |
121 | Lexer.rules = block;
122 |
123 | /**
124 | * Static Lex Method
125 | */
126 |
127 | Lexer.lex = function(src, options) {
128 | var lexer = new Lexer(options);
129 | return lexer.lex(src);
130 | };
131 |
132 | /**
133 | * Preprocessing
134 | */
135 |
136 | Lexer.prototype.lex = function(src) {
137 | src = src
138 | .replace(/\r\n|\r/g, '\n')
139 | .replace(/\t/g, ' ')
140 | .replace(/\u00a0/g, ' ')
141 | .replace(/\u2424/g, '\n');
142 |
143 | return this.token(src, true);
144 | };
145 |
146 | /**
147 | * Lexing
148 | */
149 |
150 | Lexer.prototype.token = function(src, top, bq) {
151 | var src = src.replace(/^ +$/gm, '')
152 | , next
153 | , loose
154 | , cap
155 | , bull
156 | , b
157 | , item
158 | , space
159 | , i
160 | , l;
161 |
162 | while (src) {
163 | // newline
164 | if (cap = this.rules.newline.exec(src)) {
165 | src = src.substring(cap[0].length);
166 | if (cap[0].length > 1) {
167 | this.tokens.push({
168 | type: 'space'
169 | });
170 | }
171 | }
172 |
173 | // code
174 | if (cap = this.rules.code.exec(src)) {
175 | src = src.substring(cap[0].length);
176 | cap = cap[0].replace(/^ {4}/gm, '');
177 | this.tokens.push({
178 | type: 'code',
179 | text: !this.options.pedantic
180 | ? cap.replace(/\n+$/, '')
181 | : cap
182 | });
183 | continue;
184 | }
185 |
186 | // fences (gfm)
187 | if (cap = this.rules.fences.exec(src)) {
188 | src = src.substring(cap[0].length);
189 | this.tokens.push({
190 | type: 'code',
191 | lang: cap[2],
192 | text: cap[3] || ''
193 | });
194 | continue;
195 | }
196 |
197 | // heading
198 | if (cap = this.rules.heading.exec(src)) {
199 | src = src.substring(cap[0].length);
200 | this.tokens.push({
201 | type: 'heading',
202 | depth: cap[1].length,
203 | text: cap[2]
204 | });
205 | continue;
206 | }
207 |
208 | // table no leading pipe (gfm)
209 | if (top && (cap = this.rules.nptable.exec(src))) {
210 | src = src.substring(cap[0].length);
211 |
212 | item = {
213 | type: 'table',
214 | header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
215 | align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
216 | cells: cap[3].replace(/\n$/, '').split('\n')
217 | };
218 |
219 | for (i = 0; i < item.align.length; i++) {
220 | if (/^ *-+: *$/.test(item.align[i])) {
221 | item.align[i] = 'right';
222 | } else if (/^ *:-+: *$/.test(item.align[i])) {
223 | item.align[i] = 'center';
224 | } else if (/^ *:-+ *$/.test(item.align[i])) {
225 | item.align[i] = 'left';
226 | } else {
227 | item.align[i] = null;
228 | }
229 | }
230 |
231 | for (i = 0; i < item.cells.length; i++) {
232 | item.cells[i] = item.cells[i].split(/ *\| */);
233 | }
234 |
235 | this.tokens.push(item);
236 |
237 | continue;
238 | }
239 |
240 | // lheading
241 | if (cap = this.rules.lheading.exec(src)) {
242 | src = src.substring(cap[0].length);
243 | this.tokens.push({
244 | type: 'heading',
245 | depth: cap[2] === '=' ? 1 : 2,
246 | text: cap[1]
247 | });
248 | continue;
249 | }
250 |
251 | // hr
252 | if (cap = this.rules.hr.exec(src)) {
253 | src = src.substring(cap[0].length);
254 | this.tokens.push({
255 | type: 'hr'
256 | });
257 | continue;
258 | }
259 |
260 | // blockquote
261 | if (cap = this.rules.blockquote.exec(src)) {
262 | src = src.substring(cap[0].length);
263 |
264 | this.tokens.push({
265 | type: 'blockquote_start'
266 | });
267 |
268 | cap = cap[0].replace(/^ *> ?/gm, '');
269 |
270 | // Pass `top` to keep the current
271 | // "toplevel" state. This is exactly
272 | // how markdown.pl works.
273 | this.token(cap, top, true);
274 |
275 | this.tokens.push({
276 | type: 'blockquote_end'
277 | });
278 |
279 | continue;
280 | }
281 |
282 | // list
283 | if (cap = this.rules.list.exec(src)) {
284 | src = src.substring(cap[0].length);
285 | bull = cap[2];
286 |
287 | this.tokens.push({
288 | type: 'list_start',
289 | ordered: bull.length > 1
290 | });
291 |
292 | // Get each top-level item.
293 | cap = cap[0].match(this.rules.item);
294 |
295 | next = false;
296 | l = cap.length;
297 | i = 0;
298 |
299 | for (; i < l; i++) {
300 | item = cap[i];
301 |
302 | // Remove the list item's bullet
303 | // so it is seen as the next token.
304 | space = item.length;
305 | item = item.replace(/^ *([*+-]|\d+\.) +/, '');
306 |
307 | // Outdent whatever the
308 | // list item contains. Hacky.
309 | if (~item.indexOf('\n ')) {
310 | space -= item.length;
311 | item = !this.options.pedantic
312 | ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
313 | : item.replace(/^ {1,4}/gm, '');
314 | }
315 |
316 | // Determine whether the next list item belongs here.
317 | // Backpedal if it does not belong in this list.
318 | if (this.options.smartLists && i !== l - 1) {
319 | b = block.bullet.exec(cap[i + 1])[0];
320 | if (bull !== b && !(bull.length > 1 && b.length > 1)) {
321 | src = cap.slice(i + 1).join('\n') + src;
322 | i = l - 1;
323 | }
324 | }
325 |
326 | // Determine whether item is loose or not.
327 | // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
328 | // for discount behavior.
329 | loose = next || /\n\n(?!\s*$)/.test(item);
330 | if (i !== l - 1) {
331 | next = item.charAt(item.length - 1) === '\n';
332 | if (!loose) loose = next;
333 | }
334 |
335 | this.tokens.push({
336 | type: loose
337 | ? 'loose_item_start'
338 | : 'list_item_start'
339 | });
340 |
341 | // Recurse.
342 | this.token(item, false, bq);
343 |
344 | this.tokens.push({
345 | type: 'list_item_end'
346 | });
347 | }
348 |
349 | this.tokens.push({
350 | type: 'list_end'
351 | });
352 |
353 | continue;
354 | }
355 |
356 | // html
357 | if (cap = this.rules.html.exec(src)) {
358 | src = src.substring(cap[0].length);
359 | this.tokens.push({
360 | type: this.options.sanitize
361 | ? 'paragraph'
362 | : 'html',
363 | pre: !this.options.sanitizer
364 | && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
365 | text: cap[0]
366 | });
367 | continue;
368 | }
369 |
370 | // def
371 | if ((!bq && top) && (cap = this.rules.def.exec(src))) {
372 | src = src.substring(cap[0].length);
373 | this.tokens.links[cap[1].toLowerCase()] = {
374 | href: cap[2],
375 | title: cap[3]
376 | };
377 | continue;
378 | }
379 |
380 | // table (gfm)
381 | if (top && (cap = this.rules.table.exec(src))) {
382 | src = src.substring(cap[0].length);
383 |
384 | item = {
385 | type: 'table',
386 | header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
387 | align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
388 | cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
389 | };
390 |
391 | for (i = 0; i < item.align.length; i++) {
392 | if (/^ *-+: *$/.test(item.align[i])) {
393 | item.align[i] = 'right';
394 | } else if (/^ *:-+: *$/.test(item.align[i])) {
395 | item.align[i] = 'center';
396 | } else if (/^ *:-+ *$/.test(item.align[i])) {
397 | item.align[i] = 'left';
398 | } else {
399 | item.align[i] = null;
400 | }
401 | }
402 |
403 | for (i = 0; i < item.cells.length; i++) {
404 | item.cells[i] = item.cells[i]
405 | .replace(/^ *\| *| *\| *$/g, '')
406 | .split(/ *\| */);
407 | }
408 |
409 | this.tokens.push(item);
410 |
411 | continue;
412 | }
413 |
414 | // top-level paragraph
415 | if (top && (cap = this.rules.paragraph.exec(src))) {
416 | src = src.substring(cap[0].length);
417 | this.tokens.push({
418 | type: 'paragraph',
419 | text: cap[1].charAt(cap[1].length - 1) === '\n'
420 | ? cap[1].slice(0, -1)
421 | : cap[1]
422 | });
423 | continue;
424 | }
425 |
426 | // text
427 | if (cap = this.rules.text.exec(src)) {
428 | // Top-level should never reach here.
429 | src = src.substring(cap[0].length);
430 | this.tokens.push({
431 | type: 'text',
432 | text: cap[0]
433 | });
434 | continue;
435 | }
436 |
437 | if (src) {
438 | throw new
439 | Error('Infinite loop on byte: ' + src.charCodeAt(0));
440 | }
441 | }
442 |
443 | return this.tokens;
444 | };
445 |
446 | /**
447 | * Inline-Level Grammar
448 | */
449 |
450 | var inline = {
451 | escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
452 | autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
453 | url: noop,
454 | tag: /^|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
455 | link: /^!?\[(inside)\]\(href\)/,
456 | reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
457 | nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
458 | strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
459 | em: /^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
460 | code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
461 | br: /^ {2,}\n(?!\s*$)/,
462 | del: noop,
463 | text: /^[\s\S]+?(?=[\\?(?:\s+['"]([\s\S]*?)['"])?\s*/;
468 |
469 | inline.link = replace(inline.link)
470 | ('inside', inline._inside)
471 | ('href', inline._href)
472 | ();
473 |
474 | inline.reflink = replace(inline.reflink)
475 | ('inside', inline._inside)
476 | ();
477 |
478 | /**
479 | * Normal Inline Grammar
480 | */
481 |
482 | inline.normal = merge({}, inline);
483 |
484 | /**
485 | * Pedantic Inline Grammar
486 | */
487 |
488 | inline.pedantic = merge({}, inline.normal, {
489 | strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
490 | em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
491 | });
492 |
493 | /**
494 | * GFM Inline Grammar
495 | */
496 |
497 | inline.gfm = merge({}, inline.normal, {
498 | escape: replace(inline.escape)('])', '~|])')(),
499 | url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
500 | del: /^~~(?=\S)([\s\S]*?\S)~~/,
501 | text: replace(inline.text)
502 | (']|', '~]|')
503 | ('|', '|https?://|')
504 | ()
505 | });
506 |
507 | /**
508 | * GFM + Line Breaks Inline Grammar
509 | */
510 |
511 | inline.breaks = merge({}, inline.gfm, {
512 | br: replace(inline.br)('{2,}', '*')(),
513 | text: replace(inline.gfm.text)('{2,}', '*')()
514 | });
515 |
516 | /**
517 | * Inline Lexer & Compiler
518 | */
519 |
520 | function InlineLexer(links, options) {
521 | this.options = options || marked.defaults;
522 | this.links = links;
523 | this.rules = inline.normal;
524 | this.renderer = this.options.renderer || new Renderer;
525 | this.renderer.options = this.options;
526 |
527 | if (!this.links) {
528 | throw new
529 | Error('Tokens array requires a `links` property.');
530 | }
531 |
532 | if (this.options.gfm) {
533 | if (this.options.breaks) {
534 | this.rules = inline.breaks;
535 | } else {
536 | this.rules = inline.gfm;
537 | }
538 | } else if (this.options.pedantic) {
539 | this.rules = inline.pedantic;
540 | }
541 | }
542 |
543 | /**
544 | * Expose Inline Rules
545 | */
546 |
547 | InlineLexer.rules = inline;
548 |
549 | /**
550 | * Static Lexing/Compiling Method
551 | */
552 |
553 | InlineLexer.output = function(src, links, options) {
554 | var inline = new InlineLexer(links, options);
555 | return inline.output(src);
556 | };
557 |
558 | /**
559 | * Lexing/Compiling
560 | */
561 |
562 | InlineLexer.prototype.output = function(src) {
563 | var out = ''
564 | , link
565 | , text
566 | , href
567 | , cap;
568 |
569 | while (src) {
570 | // escape
571 | if (cap = this.rules.escape.exec(src)) {
572 | src = src.substring(cap[0].length);
573 | out += cap[1];
574 | continue;
575 | }
576 |
577 | // autolink
578 | if (cap = this.rules.autolink.exec(src)) {
579 | src = src.substring(cap[0].length);
580 | if (cap[2] === '@') {
581 | text = cap[1].charAt(6) === ':'
582 | ? this.mangle(cap[1].substring(7))
583 | : this.mangle(cap[1]);
584 | href = this.mangle('mailto:') + text;
585 | } else {
586 | text = escape(cap[1]);
587 | href = text;
588 | }
589 | out += this.renderer.link(href, null, text);
590 | continue;
591 | }
592 |
593 | // url (gfm)
594 | if (!this.inLink && (cap = this.rules.url.exec(src))) {
595 | src = src.substring(cap[0].length);
596 | text = escape(cap[1]);
597 | href = text;
598 | out += this.renderer.link(href, null, text);
599 | continue;
600 | }
601 |
602 | // tag
603 | if (cap = this.rules.tag.exec(src)) {
604 | if (!this.inLink && /^/i.test(cap[0])) {
607 | this.inLink = false;
608 | }
609 | src = src.substring(cap[0].length);
610 | out += this.options.sanitize
611 | ? this.options.sanitizer
612 | ? this.options.sanitizer(cap[0])
613 | : escape(cap[0])
614 | : cap[0]
615 | continue;
616 | }
617 |
618 | // link
619 | if (cap = this.rules.link.exec(src)) {
620 | src = src.substring(cap[0].length);
621 | this.inLink = true;
622 | out += this.outputLink(cap, {
623 | href: cap[2],
624 | title: cap[3]
625 | });
626 | this.inLink = false;
627 | continue;
628 | }
629 |
630 | // reflink, nolink
631 | if ((cap = this.rules.reflink.exec(src))
632 | || (cap = this.rules.nolink.exec(src))) {
633 | src = src.substring(cap[0].length);
634 | link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
635 | link = this.links[link.toLowerCase()];
636 | if (!link || !link.href) {
637 | out += cap[0].charAt(0);
638 | src = cap[0].substring(1) + src;
639 | continue;
640 | }
641 | this.inLink = true;
642 | out += this.outputLink(cap, link);
643 | this.inLink = false;
644 | continue;
645 | }
646 |
647 | // strong
648 | if (cap = this.rules.strong.exec(src)) {
649 | src = src.substring(cap[0].length);
650 | out += this.renderer.strong(this.output(cap[2] || cap[1]));
651 | continue;
652 | }
653 |
654 | // em
655 | if (cap = this.rules.em.exec(src)) {
656 | src = src.substring(cap[0].length);
657 | out += this.renderer.em(this.output(cap[2] || cap[1]));
658 | continue;
659 | }
660 |
661 | // code
662 | if (cap = this.rules.code.exec(src)) {
663 | src = src.substring(cap[0].length);
664 | out += this.renderer.codespan(escape(cap[2], true));
665 | continue;
666 | }
667 |
668 | // br
669 | if (cap = this.rules.br.exec(src)) {
670 | src = src.substring(cap[0].length);
671 | out += this.renderer.br();
672 | continue;
673 | }
674 |
675 | // del (gfm)
676 | if (cap = this.rules.del.exec(src)) {
677 | src = src.substring(cap[0].length);
678 | out += this.renderer.del(this.output(cap[1]));
679 | continue;
680 | }
681 |
682 | // text
683 | if (cap = this.rules.text.exec(src)) {
684 | src = src.substring(cap[0].length);
685 | out += this.renderer.text(escape(this.smartypants(cap[0])));
686 | continue;
687 | }
688 |
689 | if (src) {
690 | throw new
691 | Error('Infinite loop on byte: ' + src.charCodeAt(0));
692 | }
693 | }
694 |
695 | return out;
696 | };
697 |
698 | /**
699 | * Compile Link
700 | */
701 |
702 | InlineLexer.prototype.outputLink = function(cap, link) {
703 | var href = escape(link.href)
704 | , title = link.title ? escape(link.title) : null;
705 |
706 | return cap[0].charAt(0) !== '!'
707 | ? this.renderer.link(href, title, this.output(cap[1]))
708 | : this.renderer.image(href, title, escape(cap[1]));
709 | };
710 |
711 | /**
712 | * Smartypants Transformations
713 | */
714 |
715 | InlineLexer.prototype.smartypants = function(text) {
716 | if (!this.options.smartypants) return text;
717 | return text
718 | // em-dashes
719 | .replace(/---/g, '\u2014')
720 | // en-dashes
721 | .replace(/--/g, '\u2013')
722 | // opening singles
723 | .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
724 | // closing singles & apostrophes
725 | .replace(/'/g, '\u2019')
726 | // opening doubles
727 | .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
728 | // closing doubles
729 | .replace(/"/g, '\u201d')
730 | // ellipses
731 | .replace(/\.{3}/g, '\u2026');
732 | };
733 |
734 | /**
735 | * Mangle Links
736 | */
737 |
738 | InlineLexer.prototype.mangle = function(text) {
739 | if (!this.options.mangle) return text;
740 | var out = ''
741 | , l = text.length
742 | , i = 0
743 | , ch;
744 |
745 | for (; i < l; i++) {
746 | ch = text.charCodeAt(i);
747 | if (Math.random() > 0.5) {
748 | ch = 'x' + ch.toString(16);
749 | }
750 | out += '' + ch + ';';
751 | }
752 |
753 | return out;
754 | };
755 |
756 | /**
757 | * Renderer
758 | */
759 |
760 | function Renderer(options) {
761 | this.options = options || {};
762 | }
763 |
764 | Renderer.prototype.code = function(code, lang, escaped) {
765 | if (this.options.highlight) {
766 | var out = this.options.highlight(code, lang);
767 | if (out != null && out !== code) {
768 | escaped = true;
769 | code = out;
770 | }
771 | }
772 |
773 | if (!lang) {
774 | return '