├── app
├── .gitignore
├── libs
│ └── lite-orm-1.9.2.jar
├── src
│ └── main
│ │ ├── res
│ │ ├── drawable
│ │ │ ├── icon_app.png
│ │ │ ├── ic_set_loc.xml
│ │ │ ├── ic_flight_land.xml
│ │ │ ├── ic_flight_takeoff.xml
│ │ │ └── ic_bookmark.xml
│ │ ├── drawable-xhdpi
│ │ │ ├── icon_app.png
│ │ │ ├── ic_keyboard_arrow_down_black_24dp.png
│ │ │ ├── ic_keyboard_arrow_left_black_24dp.png
│ │ │ ├── ic_keyboard_arrow_up_black_24dp.png
│ │ │ └── ic_keyboard_arrow_right_black_24dp.png
│ │ ├── values
│ │ │ ├── colors.xml
│ │ │ ├── dimens.xml
│ │ │ ├── attrs.xml
│ │ │ ├── strings.xml
│ │ │ └── styles.xml
│ │ ├── values-w820dp
│ │ │ └── dimens.xml
│ │ └── layout
│ │ │ ├── list_item_bookmark_layout.xml
│ │ │ ├── joystick_layout.xml
│ │ │ ├── joystick_arrow.xml
│ │ │ ├── activity_bookmark.xml
│ │ │ ├── activity_fly.xml
│ │ │ └── activity_main.xml
│ │ ├── java
│ │ └── com
│ │ │ └── github
│ │ │ └── fakegps
│ │ │ ├── BroadcastEvent.java
│ │ │ ├── IJoyStickPresenter.java
│ │ │ ├── model
│ │ │ ├── LocPoint.java
│ │ │ └── LocBookmark.java
│ │ │ ├── FakeGpsApp.java
│ │ │ ├── ui
│ │ │ ├── JoyStickButton.java
│ │ │ ├── BookmarkAdapter.java
│ │ │ ├── BookmarkActivity.java
│ │ │ ├── JoyStickView.java
│ │ │ ├── FlyToActivity.java
│ │ │ └── MainActivity.java
│ │ │ ├── ScreenUtils.java
│ │ │ ├── FakeGpsUtils.java
│ │ │ ├── DbUtils.java
│ │ │ ├── LocationThread.java
│ │ │ └── JoyStickManager.java
│ │ ├── aidl
│ │ └── android
│ │ │ └── location
│ │ │ └── ILocationManager.aidl
│ │ └── AndroidManifest.xml
├── proguard-rules.pro
└── build.gradle
├── settings.gradle
├── keystore.debug.jks
├── screenshot
├── Screenshot_1.png
├── Screenshot_2.png
└── Screenshot_3.png
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── .gitignore
├── gradle.properties
├── README_CN.md
├── README.md
├── gradlew.bat
└── gradlew
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------
/keystore.debug.jks:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YiuChoi/FakeGPS-1/master/keystore.debug.jks
--------------------------------------------------------------------------------
/app/libs/lite-orm-1.9.2.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YiuChoi/FakeGPS-1/master/app/libs/lite-orm-1.9.2.jar
--------------------------------------------------------------------------------
/screenshot/Screenshot_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YiuChoi/FakeGPS-1/master/screenshot/Screenshot_1.png
--------------------------------------------------------------------------------
/screenshot/Screenshot_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YiuChoi/FakeGPS-1/master/screenshot/Screenshot_2.png
--------------------------------------------------------------------------------
/screenshot/Screenshot_3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YiuChoi/FakeGPS-1/master/screenshot/Screenshot_3.png
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YiuChoi/FakeGPS-1/master/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/app/src/main/res/drawable/icon_app.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YiuChoi/FakeGPS-1/master/app/src/main/res/drawable/icon_app.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/icon_app.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YiuChoi/FakeGPS-1/master/app/src/main/res/drawable-xhdpi/icon_app.png
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | .idea/
4 | /local.properties
5 | /.idea/workspace.xml
6 | /.idea/libraries
7 | .DS_Store
8 | /build
9 | /captures
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_keyboard_arrow_down_black_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YiuChoi/FakeGPS-1/master/app/src/main/res/drawable-xhdpi/ic_keyboard_arrow_down_black_24dp.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_keyboard_arrow_left_black_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YiuChoi/FakeGPS-1/master/app/src/main/res/drawable-xhdpi/ic_keyboard_arrow_left_black_24dp.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_keyboard_arrow_up_black_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YiuChoi/FakeGPS-1/master/app/src/main/res/drawable-xhdpi/ic_keyboard_arrow_up_black_24dp.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_keyboard_arrow_right_black_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YiuChoi/FakeGPS-1/master/app/src/main/res/drawable-xhdpi/ic_keyboard_arrow_right_black_24dp.png
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Mon Dec 28 10:00:20 PST 2015
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-all.zip
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 |
7 | #66000000
8 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/java/com/github/fakegps/BroadcastEvent.java:
--------------------------------------------------------------------------------
1 | package com.github.fakegps;
2 |
3 | /**
4 | * Created by tiger on 7/28/16.
5 | */
6 | public class BroadcastEvent {
7 |
8 | public static final class BookMark {
9 | public static final String ACTION_BOOK_MARK_UPDATE = "action_book_mark_update";
10 |
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 | 150dp
6 | 200dp
7 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/java/com/github/fakegps/IJoyStickPresenter.java:
--------------------------------------------------------------------------------
1 | package com.github.fakegps;
2 |
3 | /**
4 | * Created by tiger on 7/23/16.
5 | */
6 | public interface IJoyStickPresenter {
7 | void onSetLocationClick();
8 |
9 | void onFlyClick();
10 |
11 | void onBookmarkLocationClick();
12 |
13 | void onCopyLocationClick();
14 |
15 | void onArrowUpClick();
16 |
17 | void onArrowDownClick();
18 |
19 | void onArrowLeftClick();
20 |
21 | void onArrowRightClick();
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_set_loc.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_flight_land.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_flight_takeoff.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_bookmark.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /Users/tiger/Androidsdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m
13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
14 |
15 | # When configured, Gradle will run in incubating parallel mode.
16 | # This option should only be used with decoupled projects. More details, visit
17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
18 | # org.gradle.parallel=true
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | FakeGPS
3 | Start
4 | Stop
5 | Delete
6 |
7 | Bookmark
8 | Start Fly
9 | Stop Fly
10 | Fly To Location
11 | Set New Location
12 | Bookmark
13 | Move Step
14 | Move Step
15 | Latitude , Longitude
16 | Location:
17 | Fly Time(s)
18 | Bookmark Name
19 | No Bookmarks
20 | Save
21 | Cancel
22 |
23 |
24 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
18 |
19 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/list_item_bookmark_layout.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
18 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/app/src/main/java/com/github/fakegps/model/LocPoint.java:
--------------------------------------------------------------------------------
1 | package com.github.fakegps.model;
2 |
3 | import java.io.Serializable;
4 |
5 | /**
6 | * Created by tiger on 7/23/16.
7 | */
8 | public class LocPoint implements Serializable {
9 | static final long serialVersionUID = -1770575152720897533L;
10 |
11 | private double mLatitude;
12 | private double mLongitude;
13 |
14 | public LocPoint(LocPoint locPoint) {
15 | mLatitude = locPoint.getLatitude();
16 | mLongitude = locPoint.getLongitude();
17 | }
18 |
19 | public LocPoint(double latitude, double longitude) {
20 | mLatitude = latitude;
21 | mLongitude = longitude;
22 | }
23 |
24 | public double getLatitude() {
25 | return mLatitude;
26 | }
27 |
28 | public double getLongitude() {
29 | return mLongitude;
30 | }
31 |
32 | public void setLatitude(double latitude) {
33 | mLatitude = latitude;
34 | }
35 |
36 | public void setLongitude(double longitude) {
37 | mLongitude = longitude;
38 | }
39 |
40 | @Override
41 | public String toString() {
42 | return "(" + mLatitude + " , " + mLongitude + ")";
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/app/src/main/java/com/github/fakegps/FakeGpsApp.java:
--------------------------------------------------------------------------------
1 | package com.github.fakegps;
2 |
3 | import android.app.Application;
4 | import android.content.Context;
5 |
6 | import com.litesuits.orm.LiteOrm;
7 |
8 | /**
9 | * Created by tiger on 7/23/16.
10 | */
11 | public class FakeGpsApp extends Application {
12 |
13 | private static Context sAppContext;
14 | private volatile static LiteOrm sLiteOrm;
15 |
16 | @Override
17 | protected void attachBaseContext(Context base) {
18 | super.attachBaseContext(base);
19 | sAppContext = base;
20 | }
21 |
22 | @Override
23 | public void onCreate() {
24 | super.onCreate();
25 | JoyStickManager.get().init(this);
26 | }
27 |
28 | public static Context get() {
29 | return sAppContext;
30 | }
31 |
32 | public static LiteOrm getLiteOrm() {
33 | if (sLiteOrm == null) {
34 | synchronized (FakeGpsApp.class) {
35 | if (sLiteOrm == null) {
36 | sLiteOrm = LiteOrm.newSingleInstance(sAppContext, "fake_gps.db");
37 | sLiteOrm.setDebugged(true);
38 | }
39 | }
40 | }
41 | return sLiteOrm;
42 | }
43 |
44 | }
45 |
--------------------------------------------------------------------------------
/README_CN.md:
--------------------------------------------------------------------------------
1 | #FakeGPS
2 |
3 | FakeGPS是一个GPS设备模拟器,能够根据给定的坐标,输出GPS定位信号,并且带有全局悬浮窗的手柄,通过手柄上的方向按键,能够模拟用户在地图上行走。
4 |
5 | 按照惯例,先放截图。
6 |
7 | 
8 |
9 | 
10 |
11 | 
12 |
13 | [下载地址](https://github.com/xiangtailiang/FakeGPS/releases/tag/1.0)
14 |
15 | #功能描述
16 | - 模拟真实的GPS设备,每秒输出GPS定位信号。
17 | - 具备两种运行模式:跳变模式和飞行模式。**跳变模式**:直接跳转到新的位置。**飞行模式**:根据给定的时间,以线性插值的方式慢慢飞行到新的位置。
18 | - 带有全局浮窗手柄,点击手柄上的方向按键会在当前位置上做一定的偏移(通过Move Step设置,单位为度数)。手柄单击一次移动一格,长按会连续移动。
19 | - 带有书签功能,点击使用,长按删除。
20 | - 长按书签按钮可以复制当前坐标到剪切板,方便分享给其他小伙伴。
21 |
22 | #安装说明
23 | 由于模拟位置需要借助系统的`INSTALL_LOCATION_PROVIDER`权限,因此FakeGPS 需要以system的权限,安装到system分区中。
24 |
25 | - 1、Root手机,获取system分区的读写权限。
26 | - 2、借助[Lucky Patcher](htt
27 | ps://lucky-patcher.netbew.com/) 把FakeGPS以系统应用的方式安装。
28 | - 3、打开Android系统设置开发者选项,取消“允许模拟位置”勾选。设置位置服务仅使用GPS设备。
29 | - 4、打开FakeGPS,点击Start,这个时候手柄会展示出来,如果没有弹出,请打开应用的悬浮窗显示权限(特别是MIUI和Flyme,权限默认是关闭的),然后打开地图应用(谷歌地图和高德地图测试可用)。查看是否能够定位到设置的坐标,点击手柄上的按键检查是否能够正常移动。
30 |
31 | #最后
32 | 时间比较匆忙,应用的体验还不是细致,有空再来完善。
33 |
34 | 欢迎各位同学发pull request来帮忙改进,谢谢大家。
35 |
36 | ## License
37 | [The MIT License (MIT)](http://opensource.org/licenses/MIT)
38 |
39 |
40 |
--------------------------------------------------------------------------------
/app/src/main/aidl/android/location/ILocationManager.aidl:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2007, The Android Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package android.location;
18 |
19 | import android.location.Location;
20 |
21 |
22 | /**
23 | * System private API for talking with the location service.
24 | *
25 | * @hide
26 | */
27 | interface ILocationManager
28 | {
29 | // --- internal ---
30 |
31 | // Used by location providers to tell the location manager when it has a new location.
32 | // Passive is true if the location is coming from the passive provider, in which case
33 | // it need not be shared with other providers.
34 | void reportLocation(in Location location, boolean passive);
35 |
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/joystick_layout.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
12 |
13 |
18 |
19 |
24 |
25 |
30 |
31 |
32 |
33 |
34 |
39 |
40 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 23
5 | buildToolsVersion "23.0.3"
6 |
7 | defaultConfig {
8 | applicationId "com.github.fakegps"
9 | minSdkVersion 14
10 | targetSdkVersion 23
11 | versionCode 1
12 | versionName "1.0"
13 | }
14 | buildTypes {
15 | release {
16 | minifyEnabled false
17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
18 | }
19 | }
20 |
21 | signingConfigs {
22 | debug {
23 | storeFile file('../keystore.debug.jks')
24 | storePassword project.hasProperty('STOREPASS') ? STOREPASS : 'apptest'
25 | keyAlias project.hasProperty('KEYALIAS') ? KEYALIAS : 'apptest'
26 | keyPassword project.hasProperty('KEYPASS') ? KEYPASS : 'apptest'
27 | }
28 | }
29 |
30 | applicationVariants.all { variant ->
31 | variant.outputs.each { output ->
32 | def outputFile = output.outputFile
33 | if (outputFile != null && outputFile.name.endsWith('.apk')) {
34 | def fileName = "FakeGPS_v${defaultConfig.versionName}.apk"
35 | output.outputFile = new File(outputFile.parent, fileName)
36 | }
37 | }
38 | }
39 |
40 | }
41 |
42 | dependencies {
43 | compile fileTree(include: ['*.jar'], dir: 'libs')
44 | testCompile 'junit:junit:4.12'
45 | compile files('libs/lite-orm-1.9.2.jar')
46 | compile 'com.android.support:appcompat-v7:23.4.0'
47 | compile 'com.android.support:support-v4:23.4.0'
48 | }
49 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/joystick_arrow.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
13 |
14 |
18 |
19 |
24 |
25 |
26 |
32 |
33 |
34 |
35 |
36 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/app/src/main/java/com/github/fakegps/model/LocBookmark.java:
--------------------------------------------------------------------------------
1 | package com.github.fakegps.model;
2 |
3 | import com.litesuits.orm.db.annotation.Column;
4 | import com.litesuits.orm.db.annotation.NotNull;
5 | import com.litesuits.orm.db.annotation.PrimaryKey;
6 | import com.litesuits.orm.db.annotation.Table;
7 | import com.litesuits.orm.db.enums.AssignType;
8 |
9 | import java.io.Serializable;
10 |
11 | /**
12 | * bookmark for location
13 | * Created by tiger on 7/23/16.
14 | */
15 | @Table("LocBookmark")
16 | public class LocBookmark implements Serializable{
17 | static final long serialVersionUID =-1770575152720897666L;
18 |
19 | @PrimaryKey(AssignType.AUTO_INCREMENT)
20 | @Column("_id")
21 | private int id;
22 |
23 | @NotNull
24 | private String mName;
25 |
26 | private LocPoint mLocPoint;
27 |
28 |
29 | public LocBookmark() {
30 | }
31 |
32 | public LocBookmark(String name, LocPoint locPoint) {
33 | mName = name;
34 | mLocPoint = locPoint;
35 | }
36 |
37 | public String getName() {
38 | return mName;
39 | }
40 |
41 | public void setName(String name) {
42 | mName = name;
43 | }
44 |
45 | public LocPoint getLocPoint() {
46 | return mLocPoint;
47 | }
48 |
49 | public void setLocPoint(LocPoint locPoint) {
50 | mLocPoint = locPoint;
51 | }
52 |
53 | public int getId() {
54 | return id;
55 | }
56 |
57 | @Override
58 | public String toString() {
59 | StringBuilder builder = new StringBuilder("LocBookmark: ");
60 | builder.append(mName);
61 | builder.append(" ");
62 | builder.append(mLocPoint != null ? mLocPoint.toString() : "loc null");
63 |
64 | return builder.toString();
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/app/src/main/java/com/github/fakegps/ui/JoyStickButton.java:
--------------------------------------------------------------------------------
1 | package com.github.fakegps.ui;
2 |
3 | import android.content.Context;
4 | import android.util.AttributeSet;
5 | import android.util.Log;
6 | import android.view.MotionEvent;
7 | import android.widget.ImageButton;
8 |
9 | /**
10 | * Button can keep invoke click event when keep pressed
11 | * Created by tiger on 7/23/16.
12 | */
13 | public class JoyStickButton extends ImageButton {
14 |
15 | private static final String TAG = "JoyStickButton";
16 |
17 | private boolean mIsPressDown = false;
18 |
19 | public JoyStickButton(Context context) {
20 | super(context);
21 | }
22 |
23 | public JoyStickButton(Context context, AttributeSet attrs) {
24 | super(context, attrs);
25 | }
26 |
27 | @Override
28 | public boolean onTouchEvent(MotionEvent event) {
29 | final int action = event.getAction();
30 | switch (action & MotionEvent.ACTION_MASK) {
31 | case MotionEvent.ACTION_DOWN:
32 | mIsPressDown = true;
33 | postDelayed(mLongPressDetectorRunnable, 1000);
34 | break;
35 |
36 | case MotionEvent.ACTION_UP:
37 | case MotionEvent.ACTION_CANCEL:
38 | removeCallbacks(mLongPressDetectorRunnable);
39 | mIsPressDown = false;
40 | break;
41 |
42 | }
43 |
44 | return super.onTouchEvent(event);
45 |
46 | }
47 |
48 |
49 | private Runnable mLongPressDetectorRunnable = new Runnable() {
50 | @Override
51 | public void run() {
52 | if (mIsPressDown) {
53 | Log.d(TAG, "invoke click");
54 | performClick();
55 | postDelayed(this, 500);
56 | }
57 | }
58 | };
59 | }
60 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_bookmark.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
16 |
17 |
25 |
26 |
30 |
37 |
38 |
45 |
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/app/src/main/java/com/github/fakegps/ScreenUtils.java:
--------------------------------------------------------------------------------
1 | package com.github.fakegps;
2 |
3 | import android.content.Context;
4 | import android.view.WindowManager;
5 |
6 | import java.lang.reflect.Field;
7 |
8 | /**
9 | * Created by tiger on 7/22/16.
10 | */
11 | public class ScreenUtils {
12 |
13 | public static int getStatusBarHeight(Context context) {
14 |
15 | try {
16 | Class> c = Class.forName("com.android.internal.R$dimen");
17 | Object o = c.newInstance();
18 | Field field = c.getField("status_bar_height");
19 | int x = (Integer) field.get(o);
20 | return context.getResources().getDimensionPixelSize(x);
21 | } catch (Exception e) {
22 | e.printStackTrace();
23 | }
24 |
25 | return 0;
26 | }
27 |
28 |
29 | @SuppressWarnings("deprecation")
30 | public static int getScreenWidth(Context context) {
31 | return ((WindowManager) context
32 | .getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay()
33 | .getWidth();
34 | }
35 |
36 | @SuppressWarnings("deprecation")
37 | public static int getScreenHeight(Context context) {
38 | return ((WindowManager) context
39 | .getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay()
40 | .getHeight();
41 | }
42 |
43 | /**
44 | * dp2px
45 | */
46 | public static int dip2px(Context context, float dpValue) {
47 | final float scale = context.getResources().getDisplayMetrics().density;
48 | return (int) (dpValue * scale + 0.5f);
49 | }
50 |
51 | /**
52 | * px2dp
53 | */
54 | public static int px2dip(Context context, float pxValue) {
55 | final float scale = context.getResources().getDisplayMetrics().density;
56 | return (int) (pxValue / scale + 0.5f);
57 | }
58 |
59 | }
60 |
--------------------------------------------------------------------------------
/app/src/main/java/com/github/fakegps/FakeGpsUtils.java:
--------------------------------------------------------------------------------
1 | package com.github.fakegps;
2 |
3 | import android.content.ClipboardManager;
4 | import android.content.Context;
5 | import android.util.Log;
6 | import android.widget.EditText;
7 |
8 | import com.github.fakegps.model.LocPoint;
9 |
10 | /**
11 | * Created by tiger on 7/23/16.
12 | */
13 | public final class FakeGpsUtils {
14 | private static final String TAG = "FakeGpsUtils";
15 |
16 | private FakeGpsUtils() {
17 | }
18 |
19 | public static void copyToClipboard(Context context, String content) {
20 | ClipboardManager cmb = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
21 | cmb.setText(content.trim());
22 | }
23 |
24 | public static LocPoint getLocPointFromInput(Context context, EditText editText) {
25 | LocPoint point = null;
26 | String text = editText.getText().toString().replace("(", "").replace(")", "");
27 | String[] split = text.split(",");
28 | if (split.length == 2) {
29 | try {
30 | double lat = Double.parseDouble(split[0].trim());
31 | double lon = Double.parseDouble(split[1].trim());
32 | point = new LocPoint(lat, lon);
33 | } catch (NumberFormatException e) {
34 | Log.e(TAG, "Parse loc point error!", e);
35 | }
36 | }
37 | return point;
38 | }
39 |
40 | public static double getMoveStepFromInput(Context context, EditText editText) {
41 | double step = 0;
42 | String stepStr = editText.getText().toString().trim();
43 | try {
44 | step = Double.valueOf(stepStr);
45 | } catch (NumberFormatException e) {
46 | Log.e(TAG, "Parse move step error!", e);
47 | }
48 |
49 | return step;
50 | }
51 |
52 | public static int getIntValueFromInput(Context context, EditText editText) {
53 | int value = 0;
54 | String stepStr = editText.getText().toString().trim();
55 | try {
56 | value = Integer.valueOf(stepStr);
57 | } catch (NumberFormatException e) {
58 | Log.e(TAG, "Parse move step error!", e);
59 | }
60 |
61 | return value;
62 | }
63 |
64 | }
65 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | #FakeGPS
2 |
3 | [中文Readme](https://github.com/xiangtailiang/FakeGPS/blob/master/README_CN.md)
4 |
5 | FakeGPS is a GPS device simulator. GPS location signal keep output according to the given coordinates. By the direction keys on the joystick, the user can simulate walking on the map.
6 |
7 | #Features
8 | - Simulate the real GPS devices, output GPS location per second.
9 | - Have two modes to set the new location: **Jump Mode** and **Flight Mode**. **Jump Mode**: jump to the new location in second. **Flight Mode**: fly to the new location according to the given time by linear interpolation.
10 | - With a global floating joystick, the direction button will do a certain offset at the current position (via Move Step, degrees unit). Click to move a step, long press will move continuously.
11 | - Bookmarks support. In the Bookmarks List, tap to use it, long press to Delete. Long Press Bookmark button on the joystick to copy the current coordinates to the clipboard, make it easy to share it with other people.
12 |
13 | #Screenshots.
14 |
15 | 
16 |
17 | 
18 |
19 | 
20 |
21 | # Download
22 | [FakeGPS V1.0](https://github.com/xiangtailiang/FakeGPS/releases/tag/1.0)
23 |
24 |
25 | #Installation
26 | Since the FakeGPS need the `INSTALL_LOCATION_PROVIDER` permissions, so it need to installed as system app.
27 |
28 | - 1, Root your phone.
29 | - 2, Download [Lucky Patcher](https: //lucky-patcher.netbew.com/) and install it. Launch Lucky Patcher and find "Rebuild & Install" at the bottom bar. Locate FakeGPS using the built-in exploerer in Lucky Patcher. Click the apk file and select "Install as a system app"
30 | - 3, Uncheck "Allow mock location" in Settings > Developer Options. Enable "Location Services" on your device. It is suggested that you choose "Locate by GPS" instead of "Locate by network and GPS".
31 | - 4, Launch FakeGPS, click Start button, the joystick will be displayed, if not pop up, turn on the applications floating window display authority (especially MIUI and Flyme, permission is off by default), and then Launch the Maps apps (Like Google Map)and check if it work.
32 |
33 | # Contribute
34 | If you would like to contribute code to FakeGPS, you can do so through GitHub by forking the repository and sending a pull request.
35 |
36 | # License
37 | [The MIT License (MIT)](http://opensource.org/licenses/MIT)
38 |
--------------------------------------------------------------------------------
/app/src/main/java/com/github/fakegps/DbUtils.java:
--------------------------------------------------------------------------------
1 | package com.github.fakegps;
2 |
3 | import android.content.Context;
4 | import android.content.Intent;
5 | import android.support.annotation.NonNull;
6 | import android.support.v4.content.LocalBroadcastManager;
7 |
8 | import com.litesuits.orm.db.model.ConflictAlgorithm;
9 | import com.github.fakegps.model.LocBookmark;
10 | import com.github.fakegps.model.LocPoint;
11 |
12 | import java.util.ArrayList;
13 | import java.util.Collection;
14 |
15 | /**
16 | * Created by tiger on 7/23/16.
17 | */
18 | public final class DbUtils {
19 |
20 | private static final String SHARED_PREF_NAME = "FakeGPS";
21 | private static final String KEY_LAST_LOC = "last_loc";
22 |
23 | private DbUtils() {
24 | }
25 |
26 |
27 | public static long insertBookmark(LocBookmark bookmark) {
28 | if (bookmark == null) {
29 | return -1;
30 | }
31 | long id = FakeGpsApp.getLiteOrm().insert(bookmark, ConflictAlgorithm.Replace);
32 | if (id != -1) {
33 | notifyBookmarkUpdate();
34 | }
35 | return id;
36 | }
37 |
38 | public static void deleteBookmark(LocBookmark bookmark) {
39 | if (bookmark == null) return;
40 | FakeGpsApp.getLiteOrm().delete(bookmark);
41 | notifyBookmarkUpdate();
42 | }
43 |
44 | public static void saveBookmark(Collection bookmarks) {
45 | FakeGpsApp.getLiteOrm().deleteAll(LocBookmark.class);
46 | FakeGpsApp.getLiteOrm().save(bookmarks);
47 | }
48 |
49 | public static ArrayList getAllBookmark() {
50 | return FakeGpsApp.getLiteOrm().query(LocBookmark.class);
51 | }
52 |
53 | public static void saveLastLocPoint(@NonNull Context context, @NonNull LocPoint locPoint) {
54 | context.getSharedPreferences(SHARED_PREF_NAME, Context.MODE_PRIVATE).edit()
55 | .putString(KEY_LAST_LOC, locPoint.toString())
56 | .apply();
57 | }
58 |
59 | public static String getLastLocPoint(@NonNull Context context) {
60 | return context.getSharedPreferences(SHARED_PREF_NAME, Context.MODE_PRIVATE)
61 | .getString(KEY_LAST_LOC, "");
62 | }
63 |
64 | public static void notifyBookmarkUpdate() {
65 | Intent intent = new Intent(BroadcastEvent.BookMark.ACTION_BOOK_MARK_UPDATE);
66 | LocalBroadcastManager.getInstance(FakeGpsApp.get()).sendBroadcast(intent);
67 | }
68 |
69 | }
70 |
--------------------------------------------------------------------------------
/app/src/main/java/com/github/fakegps/ui/BookmarkAdapter.java:
--------------------------------------------------------------------------------
1 | package com.github.fakegps.ui;
2 |
3 | import android.content.Context;
4 | import android.view.LayoutInflater;
5 | import android.view.View;
6 | import android.view.ViewGroup;
7 | import android.widget.BaseAdapter;
8 | import android.widget.TextView;
9 |
10 | import com.tencent.fakegps.R;
11 | import com.github.fakegps.model.LocBookmark;
12 |
13 | import java.util.ArrayList;
14 | import java.util.List;
15 |
16 | /**
17 | * Bookmark Adapter
18 | * Created by tiger on 7/23/16.
19 | */
20 | public class BookmarkAdapter extends BaseAdapter {
21 |
22 | private Context mContext;
23 | private List mLocBookmarkList = new ArrayList<>();
24 |
25 | public BookmarkAdapter(Context context) {
26 | mContext = context;
27 | }
28 |
29 | @Override
30 | public int getCount() {
31 | return mLocBookmarkList.size();
32 | }
33 |
34 | @Override
35 | public LocBookmark getItem(int position) {
36 | return mLocBookmarkList.get(position);
37 | }
38 |
39 | @Override
40 | public long getItemId(int position) {
41 | return position;
42 | }
43 |
44 | @Override
45 | public View getView(int position, View convertView, ViewGroup parent) {
46 | ViewHolder viewHolder;
47 | if (convertView == null) {
48 | convertView = LayoutInflater.from(mContext).inflate(R.layout.list_item_bookmark_layout, parent, false);
49 | viewHolder = new ViewHolder();
50 | viewHolder.name = (TextView) convertView.findViewById(R.id.tv_name);
51 | viewHolder.loc = (TextView) convertView.findViewById(R.id.tv_loc);
52 |
53 | convertView.setTag(viewHolder);
54 | } else {
55 | viewHolder = (ViewHolder) convertView.getTag();
56 | }
57 | LocBookmark item = getItem(position);
58 | viewHolder.name.setText(item.getName());
59 | viewHolder.loc.setText(item.getLocPoint().toString());
60 |
61 | return convertView;
62 | }
63 |
64 | public void setLocBookmarkList(List locBookmarkList) {
65 | if (locBookmarkList == null || locBookmarkList.size() <= 0) return;
66 | mLocBookmarkList.clear();
67 | mLocBookmarkList.addAll(locBookmarkList);
68 | notifyDataSetChanged();
69 | }
70 |
71 | public void addBookmark(LocBookmark bookmark) {
72 | mLocBookmarkList.add(bookmark);
73 | notifyDataSetChanged();
74 | }
75 |
76 | public void clearAll() {
77 | mLocBookmarkList.clear();
78 | }
79 |
80 |
81 | class ViewHolder {
82 | TextView name;
83 | TextView loc;
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
19 |
22 |
23 |
30 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
49 |
50 |
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/app/src/main/java/com/github/fakegps/ui/BookmarkActivity.java:
--------------------------------------------------------------------------------
1 | package com.github.fakegps.ui;
2 |
3 | import android.content.Context;
4 | import android.content.Intent;
5 | import android.os.Bundle;
6 | import android.support.v7.app.AppCompatActivity;
7 | import android.text.TextUtils;
8 | import android.view.View;
9 | import android.widget.EditText;
10 | import android.widget.Toast;
11 |
12 | import com.github.fakegps.DbUtils;
13 | import com.github.fakegps.FakeGpsUtils;
14 | import com.tencent.fakegps.R;
15 | import com.github.fakegps.model.LocBookmark;
16 | import com.github.fakegps.model.LocPoint;
17 |
18 | /**
19 | * BookmarkActivity
20 | * Created by tiger on 7/23/16.
21 | */
22 | public class BookmarkActivity extends AppCompatActivity implements View.OnClickListener {
23 |
24 | public static final String EXTRA_LOCATION = "extra_location";
25 | public static final String EXTRA_NAME = "extra_name";
26 |
27 | private EditText mNameEditText;
28 | private EditText mLocEditText;
29 |
30 |
31 | @Override
32 | protected void onCreate(Bundle savedInstanceState) {
33 | super.onCreate(savedInstanceState);
34 | setContentView(R.layout.activity_bookmark);
35 |
36 | Intent intent = getIntent();
37 | String name = intent.getStringExtra(EXTRA_NAME);
38 | LocPoint locPoint = (LocPoint) intent.getSerializableExtra(EXTRA_LOCATION);
39 | mNameEditText = (EditText) findViewById(R.id.inputName);
40 | mLocEditText = (EditText) findViewById(R.id.inputLoc);
41 |
42 | mNameEditText.setText(name);
43 | if (!TextUtils.isEmpty(name)) {
44 | mNameEditText.setSelection(name.length());
45 | }
46 | if (locPoint != null) {
47 | mLocEditText.setText(locPoint.toString());
48 | }
49 |
50 | findViewById(R.id.btn_ok).setOnClickListener(this);
51 | findViewById(R.id.btn_cancel).setOnClickListener(this);
52 | }
53 |
54 |
55 | @Override
56 | public void onClick(View view) {
57 | switch (view.getId()) {
58 | case R.id.btn_ok:
59 | saveBookmark();
60 | finish();
61 | break;
62 | case R.id.btn_cancel:
63 | finish();
64 | break;
65 | }
66 | }
67 |
68 | private void saveBookmark() {
69 | String name = mNameEditText.getText().toString().trim();
70 | if (TextUtils.isEmpty(name)) {
71 | Toast.makeText(this, "name cannot be empty!", Toast.LENGTH_SHORT).show();
72 | return;
73 | }
74 |
75 | LocPoint locPointFromInput = FakeGpsUtils.getLocPointFromInput(this, mLocEditText);
76 | if (locPointFromInput != null) {
77 | LocBookmark locBookmark = new LocBookmark(name, locPointFromInput);
78 | long id = DbUtils.insertBookmark(locBookmark);
79 | if (id != -1) {
80 | Toast.makeText(this, "bookmark saved!", Toast.LENGTH_SHORT).show();
81 | } else {
82 | Toast.makeText(this, "bookmark cannot save!", Toast.LENGTH_SHORT).show();
83 | }
84 | }
85 | }
86 |
87 | public static void startPage(Context context, String name, LocPoint locPoint) {
88 | Intent intent = new Intent(context, BookmarkActivity.class);
89 | intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
90 | intent.putExtra(EXTRA_NAME, name);
91 | intent.putExtra(EXTRA_LOCATION, locPoint);
92 | context.startActivity(intent);
93 | }
94 |
95 | }
96 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_fly.xml:
--------------------------------------------------------------------------------
1 |
2 |
12 |
13 |
14 |
19 |
20 |
25 |
26 |
27 |
33 |
34 |
35 |
36 |
37 |
38 |
44 |
45 |
50 |
57 |
58 |
59 |
60 |
69 |
70 |
77 |
82 |
83 |
90 |
91 |
92 |
98 |
99 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
12 |
13 |
14 |
19 |
20 |
25 |
26 |
27 |
33 |
34 |
35 |
36 |
37 |
38 |
44 |
45 |
50 |
57 |
58 |
59 |
60 |
69 |
70 |
77 |
82 |
83 |
90 |
91 |
92 |
98 |
104 |
105 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
--------------------------------------------------------------------------------
/app/src/main/java/com/github/fakegps/LocationThread.java:
--------------------------------------------------------------------------------
1 | package com.github.fakegps;
2 |
3 | import android.content.Context;
4 | import android.location.ILocationManager;
5 | import android.location.Location;
6 | import android.location.LocationManager;
7 | import android.os.Build;
8 | import android.os.Handler;
9 | import android.os.HandlerThread;
10 | import android.os.SystemClock;
11 | import android.provider.Settings;
12 | import android.util.Log;
13 |
14 | import com.github.fakegps.model.LocPoint;
15 |
16 | import java.lang.reflect.Field;
17 | import java.lang.reflect.InvocationTargetException;
18 | import java.lang.reflect.Method;
19 |
20 | /**
21 | * LocationThread
22 | * Created by tiger on 7/21/16.
23 | */
24 | public class LocationThread extends HandlerThread {
25 |
26 | private static final String TAG = "LocationThread";
27 |
28 |
29 | private Context mContext;
30 | private JoyStickManager mJoyStickManager;
31 | private LocationManager mLocationManager;
32 |
33 | private Handler mHandler;
34 | private LocPoint mLastLocPoint = new LocPoint(0, 0);
35 |
36 | private static Method mMethodMakeComplete;
37 | private static ILocationManager mILocationManager;
38 |
39 | public LocationThread(Context context, JoyStickManager joyStickManager) {
40 | super("LocationThread");
41 | mContext = context;
42 | mJoyStickManager = joyStickManager;
43 |
44 | mLocationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
45 | if (mMethodMakeComplete == null) {
46 | try {
47 | mMethodMakeComplete = Location.class.getMethod("makeComplete", new Class[0]);
48 | } catch (NoSuchMethodException e) {
49 | Log.e(TAG, "get Location.makeComplete method fail!", e);
50 | }
51 | }
52 |
53 | if (mILocationManager == null) {
54 | Field declaredField = null;
55 | try {
56 | declaredField = Class.forName(mLocationManager.getClass().getName()).getDeclaredField("mService");
57 | declaredField.setAccessible(true);
58 | mILocationManager = (ILocationManager) declaredField.get(mLocationManager);
59 | } catch (Exception e) {
60 | Log.e(TAG, "get LocationManager mService fail!", e);
61 | }
62 | }
63 |
64 |
65 | }
66 |
67 | @Override
68 | public synchronized void start() {
69 | super.start();
70 |
71 | mHandler = new Handler(getLooper());
72 | mHandler.post(mUpdateLocation);
73 | }
74 |
75 | public void startThread() {
76 | start();
77 | }
78 |
79 | public void stopThread() {
80 | mHandler.removeCallbacksAndMessages(null);
81 | try {
82 | quit();
83 | interrupt();
84 | } catch (Exception e) {
85 | Log.e(TAG, "stopThread fail!", e);
86 | }
87 |
88 | mJoyStickManager = null;
89 | }
90 |
91 |
92 | protected static boolean setMockLocation(int i, Context context) {
93 | Log.d(TAG, "setMockLocation " + i);
94 | try {
95 | return Settings.Secure.putInt(context.getContentResolver(), "mock_location", i);
96 | } catch (Exception e) {
97 | return false;
98 | }
99 | }
100 |
101 | Runnable mUpdateLocation = new Runnable() {
102 | @Override
103 | public void run() {
104 |
105 | LocPoint locPoint = mJoyStickManager.getUpdateLocPoint();
106 | Log.d(TAG, "UpdateLocation, " + locPoint);
107 | Location location = new Location("gps");
108 | try {
109 | location.setLatitude(locPoint.getLatitude());
110 | location.setLongitude(locPoint.getLongitude());
111 | location.setAltitude(50);
112 | if (Build.VERSION.SDK_INT > 16) {
113 | location.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
114 | }
115 | location.setAccuracy(10);
116 | if (mLastLocPoint.getLatitude() != locPoint.getLatitude()
117 | || mLastLocPoint.getLongitude() != locPoint.getLongitude()) {
118 | mLastLocPoint.setLatitude(locPoint.getLatitude());
119 | mLastLocPoint.setLongitude(locPoint.getLongitude());
120 | location.setSpeed(1);
121 | } else {
122 | location.setSpeed(0);
123 | }
124 | location.setTime(System.currentTimeMillis());
125 | if (mMethodMakeComplete != null) {
126 | try {
127 | mMethodMakeComplete.invoke(location, new Object[0]);
128 | } catch (IllegalArgumentException | IllegalAccessException | InvocationTargetException e) {
129 | e.printStackTrace();
130 | }
131 | }
132 |
133 | mILocationManager.reportLocation(location, false);
134 |
135 | } catch (Exception e) {
136 | Log.e(TAG, "add Location fail!", e);
137 | }
138 |
139 | mHandler.postDelayed(mUpdateLocation, 1000);
140 | }
141 |
142 | };
143 |
144 | public Handler getHandler() {
145 | return mHandler;
146 | }
147 |
148 | }
149 |
150 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/app/src/main/java/com/github/fakegps/ui/JoyStickView.java:
--------------------------------------------------------------------------------
1 | package com.github.fakegps.ui;
2 |
3 | import android.content.Context;
4 | import android.graphics.PixelFormat;
5 | import android.view.Gravity;
6 | import android.view.LayoutInflater;
7 | import android.view.MotionEvent;
8 | import android.view.View;
9 | import android.view.WindowManager;
10 | import android.widget.FrameLayout;
11 |
12 | import com.github.fakegps.IJoyStickPresenter;
13 | import com.tencent.fakegps.R;
14 | import com.github.fakegps.ScreenUtils;
15 |
16 | /**
17 | * Created by tiger on 7/22/16.
18 | */
19 | public class JoyStickView extends FrameLayout {
20 |
21 | private static int sStatusBarHeight;
22 |
23 | private int mViewWidth;
24 | private int mViewHeight;
25 | private WindowManager mWindowManager;
26 | private WindowManager.LayoutParams mWindowLayoutParams;
27 | // touch point x pos according to screen
28 | private float mXInScreen;
29 | // touch point y pos according to screen
30 | private float mYInScreen;
31 | // touch point x pos according to view
32 | private float mXInView;
33 | // touch point y pos according to view
34 | private float mYInView;
35 |
36 | private boolean isShowing = false;
37 |
38 | private IJoyStickPresenter mJoyStickPresenter;
39 |
40 | public JoyStickView(Context context) {
41 | super(context);
42 | mWindowManager = (WindowManager) context
43 | .getSystemService(Context.WINDOW_SERVICE);
44 | LayoutInflater.from(context).inflate(R.layout.joystick_layout, this);
45 |
46 | sStatusBarHeight = ScreenUtils.getStatusBarHeight(context);
47 | mViewWidth = context.getResources().getDimensionPixelSize(R.dimen.joystick_width);
48 | mViewHeight = context.getResources().getDimensionPixelSize(R.dimen.joystick_height);
49 |
50 | mWindowLayoutParams = new WindowManager.LayoutParams();
51 | mWindowLayoutParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
52 | mWindowLayoutParams.format = PixelFormat.RGBA_8888;
53 | mWindowLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
54 | | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
55 | mWindowLayoutParams.gravity = Gravity.LEFT | Gravity.TOP;
56 |
57 | //the real width and height is needed, or the view cannot be shown
58 | mWindowLayoutParams.width = mViewWidth;
59 | mWindowLayoutParams.height = mViewHeight;
60 | mWindowLayoutParams.x = ScreenUtils.getScreenWidth(context);
61 | mWindowLayoutParams.y = ScreenUtils.getScreenHeight(context) / 2;
62 |
63 | findViewById(R.id.btn_set_loc).setOnClickListener(mOnClickListener);
64 | findViewById(R.id.btn_fly_to).setOnClickListener(mOnClickListener);
65 | findViewById(R.id.btn_bookmark).setOnClickListener(mOnClickListener);
66 | findViewById(R.id.btn_bookmark).setOnLongClickListener(new OnLongClickListener() {
67 | @Override
68 | public boolean onLongClick(View v) {
69 | if (mJoyStickPresenter != null) {
70 | mJoyStickPresenter.onCopyLocationClick();
71 | }
72 | return true;
73 | }
74 | });
75 |
76 | findViewById(R.id.btn_up).setOnClickListener(mOnClickListener);
77 | findViewById(R.id.btn_left).setOnClickListener(mOnClickListener);
78 | findViewById(R.id.btn_right).setOnClickListener(mOnClickListener);
79 | findViewById(R.id.btn_down).setOnClickListener(mOnClickListener);
80 |
81 | }
82 |
83 | @Override
84 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
85 | super.onMeasure(widthMeasureSpec, heightMeasureSpec);
86 |
87 | }
88 |
89 | public void addToWindow() {
90 | mWindowManager.addView(this, mWindowLayoutParams);
91 | isShowing = true;
92 | }
93 |
94 | public void removeFromWindow() {
95 | mWindowManager.removeView(this);
96 | isShowing = false;
97 | }
98 |
99 | public boolean isShowing() {
100 | return isShowing;
101 | }
102 |
103 | private View.OnClickListener mOnClickListener = new OnClickListener() {
104 | @Override
105 | public void onClick(View v) {
106 | int id = v.getId();
107 | switch (id) {
108 | case R.id.btn_up:
109 | if (mJoyStickPresenter != null) mJoyStickPresenter.onArrowUpClick();
110 | break;
111 | case R.id.btn_down:
112 | if (mJoyStickPresenter != null) mJoyStickPresenter.onArrowDownClick();
113 | break;
114 | case R.id.btn_left:
115 | if (mJoyStickPresenter != null) mJoyStickPresenter.onArrowLeftClick();
116 | break;
117 | case R.id.btn_right:
118 | if (mJoyStickPresenter != null) mJoyStickPresenter.onArrowRightClick();
119 | break;
120 |
121 | case R.id.btn_set_loc:
122 | if (mJoyStickPresenter != null) mJoyStickPresenter.onSetLocationClick();
123 | break;
124 |
125 | case R.id.btn_fly_to:
126 | if (mJoyStickPresenter != null) mJoyStickPresenter.onFlyClick();
127 | break;
128 |
129 | case R.id.btn_bookmark:
130 | if (mJoyStickPresenter != null) mJoyStickPresenter.onBookmarkLocationClick();
131 | break;
132 |
133 | default:
134 | break;
135 |
136 | }
137 | }
138 | };
139 |
140 | public void setJoyStickPresenter(IJoyStickPresenter joyStickPresenter) {
141 | mJoyStickPresenter = joyStickPresenter;
142 | }
143 |
144 | @Override
145 | public boolean onTouchEvent(MotionEvent event) {
146 | switch (event.getAction()) {
147 | case MotionEvent.ACTION_DOWN:
148 | mXInView = event.getX();
149 | mYInView = event.getY();
150 | break;
151 | case MotionEvent.ACTION_MOVE:
152 | mXInScreen = event.getRawX();
153 | mYInScreen = event.getRawY() - sStatusBarHeight;
154 | updateViewPosition();
155 | break;
156 | }
157 | return true;
158 | }
159 |
160 |
161 | private void updateViewPosition() {
162 | mWindowLayoutParams.x = (int) (mXInScreen - mXInView);
163 | mWindowLayoutParams.y = (int) (mYInScreen - mYInView);
164 | mWindowManager.updateViewLayout(this, mWindowLayoutParams);
165 | }
166 | }
167 |
--------------------------------------------------------------------------------
/app/src/main/java/com/github/fakegps/JoyStickManager.java:
--------------------------------------------------------------------------------
1 | package com.github.fakegps;
2 |
3 | import android.content.Context;
4 | import android.support.annotation.NonNull;
5 | import android.util.Log;
6 | import android.widget.Toast;
7 |
8 | import com.github.fakegps.model.LocPoint;
9 | import com.github.fakegps.ui.BookmarkActivity;
10 | import com.github.fakegps.ui.FlyToActivity;
11 | import com.github.fakegps.ui.JoyStickView;
12 | import com.github.fakegps.ui.MainActivity;
13 |
14 | /**
15 | * Created by tiger on 7/22/16.
16 | */
17 | public class JoyStickManager implements IJoyStickPresenter {
18 |
19 | private static final String TAG = "JoyStickManager";
20 |
21 | public static double STEP_DEFAULT = 0.00002;
22 |
23 | private static JoyStickManager INSTANCE = new JoyStickManager();
24 |
25 | private Context mContext;
26 | private LocationThread mLocationThread;
27 | private boolean mIsStarted = false;
28 | private double mMoveStep = STEP_DEFAULT;
29 |
30 | private LocPoint mCurrentLocPoint;
31 |
32 | private LocPoint mTargetLocPoint;
33 | private int mFlyTime;
34 | private int mFlyTimeIndex;
35 | private boolean mIsFlyMode = false;
36 |
37 | private JoyStickView mJoyStickView;
38 |
39 | private JoyStickManager() {
40 | }
41 |
42 |
43 | public void init(Context context) {
44 | mContext = context;
45 | }
46 |
47 | public static JoyStickManager get() {
48 | return INSTANCE;
49 | }
50 |
51 | public void start(@NonNull LocPoint locPoint) {
52 | mCurrentLocPoint = locPoint;
53 | if (mLocationThread == null || !mLocationThread.isAlive()) {
54 | mLocationThread = new LocationThread(mContext.getApplicationContext(), this);
55 | mLocationThread.startThread();
56 | }
57 | showJoyStick();
58 | mIsStarted = true;
59 | }
60 |
61 | public void stop() {
62 | if (mLocationThread != null) {
63 | mLocationThread.stopThread();
64 | mLocationThread = null;
65 | }
66 |
67 | hideJoyStick();
68 | mIsStarted = false;
69 | }
70 |
71 | public boolean isStarted() {
72 | return mIsStarted;
73 | }
74 |
75 | public void showJoyStick() {
76 | if (mJoyStickView == null) {
77 | mJoyStickView = new JoyStickView(mContext);
78 | mJoyStickView.setJoyStickPresenter(this);
79 | }
80 |
81 | if (!mJoyStickView.isShowing()) {
82 | mJoyStickView.addToWindow();
83 | }
84 | }
85 |
86 | public void hideJoyStick() {
87 | if (mJoyStickView != null && mJoyStickView.isShowing()) {
88 | mJoyStickView.removeFromWindow();
89 | }
90 | }
91 |
92 | public LocPoint getCurrentLocPoint() {
93 | return mCurrentLocPoint;
94 | }
95 |
96 | public LocPoint getUpdateLocPoint() {
97 | if (!mIsFlyMode || mFlyTimeIndex > mFlyTime) {
98 | return mCurrentLocPoint;
99 | } else {
100 | float factor = (float) mFlyTimeIndex / (float) mFlyTime;
101 | double lat = mCurrentLocPoint.getLatitude() + (factor * (mTargetLocPoint.getLatitude() - mCurrentLocPoint.getLatitude()));
102 | double lon = mCurrentLocPoint.getLongitude() + (factor * (mTargetLocPoint.getLatitude() - mCurrentLocPoint.getLatitude()));
103 | mCurrentLocPoint.setLatitude(lat);
104 | mCurrentLocPoint.setLongitude(lon);
105 | mFlyTimeIndex++;
106 | return mCurrentLocPoint;
107 | }
108 | }
109 |
110 | public void jumpToLocation(@NonNull LocPoint location) {
111 | mIsFlyMode = false;
112 | mCurrentLocPoint = location;
113 | }
114 |
115 | public void flyToLocation(@NonNull LocPoint location, int flyTime) {
116 | mTargetLocPoint = location;
117 | mFlyTime = flyTime;
118 | mFlyTimeIndex = 0;
119 | mIsFlyMode = true;
120 | }
121 |
122 | public boolean isFlyMode() {
123 | return mIsFlyMode;
124 | }
125 |
126 | public void stopFlyMode() {
127 | mIsFlyMode = false;
128 | }
129 |
130 | public void setMoveStep(double moveStep) {
131 | mMoveStep = moveStep;
132 | }
133 |
134 | public double getMoveStep() {
135 | return mMoveStep;
136 | }
137 |
138 |
139 | @Override
140 | public void onSetLocationClick() {
141 | Log.d(TAG, "onSetLocationClick");
142 | MainActivity.startPage(mContext);
143 | }
144 |
145 | @Override
146 | public void onFlyClick() {
147 | Log.d(TAG, "onFlyClick");
148 | if (mIsFlyMode) {
149 | stopFlyMode();
150 | Toast.makeText(mContext, "Stop Fly", Toast.LENGTH_SHORT).show();
151 | } else {
152 | FlyToActivity.startPage(mContext);
153 | }
154 |
155 | }
156 |
157 | @Override
158 | public void onBookmarkLocationClick() {
159 | Log.d(TAG, "onBookmarkLocationClick");
160 | if (mCurrentLocPoint != null) {
161 | LocPoint locPoint = new LocPoint(mCurrentLocPoint);
162 | BookmarkActivity.startPage(mContext, "Bookmark", locPoint);
163 | Toast.makeText(mContext, "Current location is copied!" + "\n" + locPoint, Toast.LENGTH_LONG).show();
164 | } else {
165 | Toast.makeText(mContext, "Service is not start!", Toast.LENGTH_SHORT).show();
166 | }
167 | }
168 |
169 | @Override
170 | public void onCopyLocationClick() {
171 | Log.d(TAG, "onCopyLocationClick");
172 | if (mCurrentLocPoint != null) {
173 | FakeGpsUtils.copyToClipboard(mContext, mCurrentLocPoint.toString());
174 | Toast.makeText(mContext, "Current location is copied!" + "\n" + mCurrentLocPoint, Toast.LENGTH_LONG).show();
175 | }
176 | }
177 |
178 |
179 | @Override
180 | public void onArrowUpClick() {
181 | Log.d(TAG, "onArrowUpClick");
182 | mCurrentLocPoint.setLatitude(mCurrentLocPoint.getLatitude() + mMoveStep);
183 | }
184 |
185 | @Override
186 | public void onArrowDownClick() {
187 | Log.d(TAG, "onArrowDownClick");
188 | mCurrentLocPoint.setLatitude(mCurrentLocPoint.getLatitude() - mMoveStep);
189 | }
190 |
191 | @Override
192 | public void onArrowLeftClick() {
193 | Log.d(TAG, "onArrowLeftClick");
194 | mCurrentLocPoint.setLongitude(mCurrentLocPoint.getLongitude() - mMoveStep);
195 | }
196 |
197 | @Override
198 | public void onArrowRightClick() {
199 | Log.d(TAG, "onArrowRightClick");
200 | mCurrentLocPoint.setLongitude(mCurrentLocPoint.getLongitude() + mMoveStep);
201 | }
202 |
203 | }
204 |
--------------------------------------------------------------------------------
/app/src/main/java/com/github/fakegps/ui/FlyToActivity.java:
--------------------------------------------------------------------------------
1 | package com.github.fakegps.ui;
2 |
3 | import android.content.BroadcastReceiver;
4 | import android.content.Context;
5 | import android.content.DialogInterface;
6 | import android.content.Intent;
7 | import android.content.IntentFilter;
8 | import android.os.Bundle;
9 | import android.support.v4.content.LocalBroadcastManager;
10 | import android.support.v7.app.AlertDialog;
11 | import android.support.v7.app.AppCompatActivity;
12 | import android.text.TextUtils;
13 | import android.view.ContextMenu;
14 | import android.view.Menu;
15 | import android.view.MenuItem;
16 | import android.view.View;
17 | import android.widget.AdapterView;
18 | import android.widget.Button;
19 | import android.widget.EditText;
20 | import android.widget.ListView;
21 | import android.widget.Toast;
22 |
23 | import com.github.fakegps.BroadcastEvent;
24 | import com.github.fakegps.DbUtils;
25 | import com.github.fakegps.FakeGpsApp;
26 | import com.github.fakegps.FakeGpsUtils;
27 | import com.github.fakegps.JoyStickManager;
28 | import com.tencent.fakegps.R;
29 | import com.github.fakegps.model.LocBookmark;
30 | import com.github.fakegps.model.LocPoint;
31 |
32 | import java.util.ArrayList;
33 |
34 | public class FlyToActivity extends AppCompatActivity implements View.OnClickListener {
35 | // private final double LAT_DEFAULT = 37.802406;
36 | // private final double LON_DEFAULT = -122.401779;
37 | private final double LAT_DEFAULT = 23.151637;
38 | private final double LON_DEFAULT = 113.344721;
39 |
40 | private final int FLY_TIME_DEFAULT = 60;
41 |
42 | public static final int DELETE_ID = 1001;
43 |
44 | private EditText mLocEditText;
45 | private EditText mFlyTimeEditText;
46 | private ListView mListView;
47 | private Button mBtnStart;
48 | private BookmarkAdapter mAdapter;
49 |
50 |
51 | @Override
52 | protected void onCreate(Bundle savedInstanceState) {
53 | super.onCreate(savedInstanceState);
54 | setContentView(R.layout.activity_fly);
55 |
56 | //location input
57 | mLocEditText = (EditText) findViewById(R.id.inputLoc);
58 | LocPoint currentLocPoint = JoyStickManager.get().getCurrentLocPoint();
59 | if (currentLocPoint != null) {
60 | mLocEditText.setText(currentLocPoint.toString());
61 | } else {
62 | String lastLocPoint = DbUtils.getLastLocPoint(this);
63 | if (!TextUtils.isEmpty(lastLocPoint)) {
64 | mLocEditText.setText(lastLocPoint);
65 | } else {
66 | mLocEditText.setText(new LocPoint(LAT_DEFAULT, LON_DEFAULT).toString());
67 | }
68 | }
69 | //each move step delta
70 | mFlyTimeEditText = (EditText) findViewById(R.id.inputFlyTime);
71 | mFlyTimeEditText.setText(String.valueOf(FLY_TIME_DEFAULT));
72 |
73 | mListView = (ListView) findViewById(R.id.list_bookmark);
74 |
75 | mBtnStart = (Button) findViewById(R.id.btn_fly);
76 | mBtnStart.setOnClickListener(this);
77 | updateBtn();
78 |
79 | initListView();
80 |
81 | registerBroadcastReceiver();
82 | }
83 |
84 | @Override
85 | public void onClick(View view) {
86 | int flyTime = FakeGpsUtils.getIntValueFromInput(this, mFlyTimeEditText);
87 | LocPoint point = FakeGpsUtils.getLocPointFromInput(this, mLocEditText);
88 |
89 | switch (view.getId()) {
90 |
91 | case R.id.btn_fly:
92 | if (JoyStickManager.get().isStarted()) {
93 | if (JoyStickManager.get().isFlyMode()) {
94 | JoyStickManager.get().stopFlyMode();
95 | } else {
96 | if (point != null && flyTime > 0) {
97 | JoyStickManager.get().flyToLocation(point, flyTime);
98 | } else {
99 | Toast.makeText(this, "Input is not valid!", Toast.LENGTH_SHORT).show();
100 | }
101 | }
102 | }
103 | updateBtn();
104 | break;
105 | }
106 | }
107 |
108 | private void updateBtn() {
109 | if (JoyStickManager.get().isFlyMode()) {
110 | mBtnStart.setText(R.string.btn_fly_stop);
111 | } else {
112 | mBtnStart.setText(R.string.btn_fly_start);
113 | }
114 | }
115 |
116 | private void initListView() {
117 | mAdapter = new BookmarkAdapter(this);
118 | ArrayList allBookmark = DbUtils.getAllBookmark();
119 | mAdapter.setLocBookmarkList(allBookmark);
120 | mListView.setAdapter(mAdapter);
121 |
122 | View emptyView = findViewById(R.id.empty_view);
123 | mListView.setEmptyView(emptyView);
124 |
125 | mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
126 | @Override
127 | public void onItemClick(AdapterView> parent, View view, int position, long id) {
128 | LocPoint locPoint = mAdapter.getItem(position).getLocPoint();
129 | mLocEditText.setText(locPoint != null ? locPoint.toString() : "");
130 | }
131 | });
132 |
133 | registerForContextMenu(mListView);
134 |
135 | }
136 |
137 | @Override
138 | public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
139 | menu.add(Menu.NONE, DELETE_ID, Menu.NONE, R.string.menu_delete);
140 | super.onCreateContextMenu(menu, v, menuInfo);
141 | }
142 |
143 | public boolean onContextItemSelected(MenuItem item) {
144 | switch (item.getItemId()) {
145 | case DELETE_ID:
146 | AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
147 | delete(info.position);
148 | return true;
149 | default:
150 | break;
151 | }
152 | return super.onContextItemSelected(item);
153 | }
154 |
155 | private void delete(final int position) {
156 | if (position < 0) return;
157 | final LocBookmark bookmark = mAdapter.getItem(position);
158 | new AlertDialog.Builder(this)
159 | .setTitle("Delete " + bookmark.toString())
160 | .setPositiveButton("OK", new DialogInterface.OnClickListener() {
161 | public void onClick(DialogInterface dialog, int which) {
162 | DbUtils.deleteBookmark(bookmark);
163 | ArrayList allBookmark = DbUtils.getAllBookmark();
164 | mAdapter.setLocBookmarkList(allBookmark);
165 | }
166 | })
167 | .setNegativeButton("Cancel", null)
168 | .show();
169 | }
170 |
171 | private void registerBroadcastReceiver() {
172 | IntentFilter intentFilter = new IntentFilter(BroadcastEvent.BookMark.ACTION_BOOK_MARK_UPDATE);
173 | LocalBroadcastManager.getInstance(FakeGpsApp.get()).registerReceiver(mBroadcastReceiver, intentFilter);
174 | }
175 |
176 | private void unregisterBroadcastReceiver() {
177 | LocalBroadcastManager.getInstance(FakeGpsApp.get()).unregisterReceiver(mBroadcastReceiver);
178 | }
179 |
180 | private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
181 | @Override
182 | public void onReceive(Context context, Intent intent) {
183 | String action = intent.getAction();
184 | if (BroadcastEvent.BookMark.ACTION_BOOK_MARK_UPDATE.equals(action)) {
185 | ArrayList allBookmark = DbUtils.getAllBookmark();
186 | mAdapter.setLocBookmarkList(allBookmark);
187 | }
188 | }
189 | };
190 |
191 | @Override
192 | protected void onDestroy() {
193 | unregisterBroadcastReceiver();
194 | super.onDestroy();
195 | }
196 |
197 | public static void startPage(Context context) {
198 | Intent intent = new Intent(context, FlyToActivity.class);
199 | intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
200 | context.startActivity(intent);
201 | }
202 |
203 |
204 | }
205 |
--------------------------------------------------------------------------------
/app/src/main/java/com/github/fakegps/ui/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.github.fakegps.ui;
2 |
3 | import android.content.BroadcastReceiver;
4 | import android.content.Context;
5 | import android.content.DialogInterface;
6 | import android.content.Intent;
7 | import android.content.IntentFilter;
8 | import android.os.Bundle;
9 | import android.support.v4.content.LocalBroadcastManager;
10 | import android.support.v7.app.AlertDialog;
11 | import android.support.v7.app.AppCompatActivity;
12 | import android.text.TextUtils;
13 | import android.view.ContextMenu;
14 | import android.view.Menu;
15 | import android.view.MenuItem;
16 | import android.view.View;
17 | import android.widget.AdapterView;
18 | import android.widget.Button;
19 | import android.widget.EditText;
20 | import android.widget.ListView;
21 | import android.widget.Toast;
22 |
23 | import com.github.fakegps.BroadcastEvent;
24 | import com.github.fakegps.DbUtils;
25 | import com.github.fakegps.FakeGpsApp;
26 | import com.github.fakegps.FakeGpsUtils;
27 | import com.github.fakegps.JoyStickManager;
28 | import com.tencent.fakegps.R;
29 | import com.github.fakegps.model.LocBookmark;
30 | import com.github.fakegps.model.LocPoint;
31 |
32 | import java.util.ArrayList;
33 |
34 | public class MainActivity extends AppCompatActivity implements View.OnClickListener {
35 | private final double LAT_DEFAULT = 37.802406;
36 | private final double LON_DEFAULT = -122.401779;
37 | // private final double LAT_DEFAULT = 23.151637;
38 | // private final double LON_DEFAULT = 113.344721;
39 |
40 | public static final int DELETE_ID = 1001;
41 |
42 | private EditText mLocEditText;
43 | private EditText mMoveStepEditText;
44 | private ListView mListView;
45 | private Button mBtnStart;
46 | private Button mBtnSetNew;
47 | private BookmarkAdapter mAdapter;
48 |
49 |
50 | @Override
51 | protected void onCreate(Bundle savedInstanceState) {
52 | super.onCreate(savedInstanceState);
53 | setContentView(R.layout.activity_main);
54 |
55 | //location input
56 | mLocEditText = (EditText) findViewById(R.id.inputLoc);
57 | LocPoint currentLocPoint = JoyStickManager.get().getCurrentLocPoint();
58 | if (currentLocPoint != null) {
59 | mLocEditText.setText(currentLocPoint.toString());
60 | } else {
61 | String lastLocPoint = DbUtils.getLastLocPoint(this);
62 | if (!TextUtils.isEmpty(lastLocPoint)) {
63 | mLocEditText.setText(lastLocPoint);
64 | } else {
65 | mLocEditText.setText(new LocPoint(LAT_DEFAULT, LON_DEFAULT).toString());
66 | }
67 | }
68 |
69 | mLocEditText.setSelection(mLocEditText.getText().length());
70 |
71 | //each move step delta
72 | mMoveStepEditText = (EditText) findViewById(R.id.inputStep);
73 | double currentMoveStep = JoyStickManager.get().getMoveStep();
74 | mMoveStepEditText.setText(String.valueOf(currentMoveStep));
75 |
76 | mListView = (ListView) findViewById(R.id.list_bookmark);
77 |
78 | mBtnStart = (Button) findViewById(R.id.btn_start);
79 | mBtnStart.setOnClickListener(this);
80 | updateBtnStart();
81 |
82 | mBtnSetNew = (Button) findViewById(R.id.btn_set_loc);
83 | mBtnSetNew.setOnClickListener(this);
84 | updateBtnSetNew();
85 |
86 | initListView();
87 |
88 | registerBroadcastReceiver();
89 | }
90 |
91 | @Override
92 | public void onClick(View view) {
93 | double step = FakeGpsUtils.getMoveStepFromInput(this, mMoveStepEditText);
94 | LocPoint point = FakeGpsUtils.getLocPointFromInput(this, mLocEditText);
95 |
96 | switch (view.getId()) {
97 | case R.id.btn_start:
98 | if (!JoyStickManager.get().isStarted()) {
99 | JoyStickManager.get().setMoveStep(step);
100 | if (point != null) {
101 | JoyStickManager.get().start(point);
102 | finish();
103 | } else {
104 | Toast.makeText(this, "Input is not valid!", Toast.LENGTH_SHORT).show();
105 | }
106 | } else {
107 | LocPoint currentLocPoint = JoyStickManager.get().getCurrentLocPoint();
108 | if (currentLocPoint != null) {
109 | DbUtils.saveLastLocPoint(this, currentLocPoint);
110 | }
111 | JoyStickManager.get().stop();
112 | finish();
113 | }
114 | updateBtnStart();
115 | updateBtnSetNew();
116 | break;
117 |
118 | case R.id.btn_set_loc:
119 | if (step > 0 && point != null) {
120 | JoyStickManager.get().setMoveStep(step);
121 | JoyStickManager.get().jumpToLocation(point);
122 | } else {
123 | Toast.makeText(this, "Input is not valid!", Toast.LENGTH_SHORT).show();
124 | }
125 | break;
126 | }
127 | }
128 |
129 | private void updateBtnStart() {
130 | if (JoyStickManager.get().isStarted()) {
131 | mBtnStart.setText(R.string.btn_stop);
132 | } else {
133 | mBtnStart.setText(R.string.btn_start);
134 | }
135 | }
136 |
137 | private void updateBtnSetNew() {
138 | if (JoyStickManager.get().isStarted()) {
139 | mBtnSetNew.setEnabled(true);
140 | } else {
141 | mBtnSetNew.setEnabled(false);
142 | }
143 | }
144 |
145 | private void initListView() {
146 | mAdapter = new BookmarkAdapter(this);
147 | ArrayList allBookmark = DbUtils.getAllBookmark();
148 | mAdapter.setLocBookmarkList(allBookmark);
149 | mListView.setAdapter(mAdapter);
150 |
151 | View emptyView = findViewById(R.id.empty_view);
152 | mListView.setEmptyView(emptyView);
153 |
154 | mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
155 | @Override
156 | public void onItemClick(AdapterView> parent, View view, int position, long id) {
157 | LocPoint locPoint = mAdapter.getItem(position).getLocPoint();
158 | mLocEditText.setText(locPoint != null ? locPoint.toString() : "");
159 | }
160 | });
161 |
162 | registerForContextMenu(mListView);
163 |
164 | }
165 |
166 | @Override
167 | public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
168 | menu.add(Menu.NONE, DELETE_ID, Menu.NONE, R.string.menu_delete);
169 | super.onCreateContextMenu(menu, v, menuInfo);
170 | }
171 |
172 | public boolean onContextItemSelected(MenuItem item) {
173 | switch (item.getItemId()) {
174 | case DELETE_ID:
175 | AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
176 | delete(info.position);
177 | return true;
178 | default:
179 | break;
180 | }
181 | return super.onContextItemSelected(item);
182 | }
183 |
184 | private void delete(final int position) {
185 | if (position < 0) return;
186 | final LocBookmark bookmark = mAdapter.getItem(position);
187 | new AlertDialog.Builder(this)
188 | .setTitle("Delete " + bookmark.toString())
189 | .setPositiveButton("OK", new DialogInterface.OnClickListener() {
190 | public void onClick(DialogInterface dialog, int which) {
191 | DbUtils.deleteBookmark(bookmark);
192 | }
193 | })
194 | .setNegativeButton("Cancel", null)
195 | .show();
196 | }
197 |
198 | private void registerBroadcastReceiver() {
199 | IntentFilter intentFilter = new IntentFilter(BroadcastEvent.BookMark.ACTION_BOOK_MARK_UPDATE);
200 | LocalBroadcastManager.getInstance(FakeGpsApp.get()).registerReceiver(mBroadcastReceiver, intentFilter);
201 | }
202 |
203 | private void unregisterBroadcastReceiver() {
204 | LocalBroadcastManager.getInstance(FakeGpsApp.get()).unregisterReceiver(mBroadcastReceiver);
205 | }
206 |
207 | private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
208 | @Override
209 | public void onReceive(Context context, Intent intent) {
210 | String action = intent.getAction();
211 | if (BroadcastEvent.BookMark.ACTION_BOOK_MARK_UPDATE.equals(action)) {
212 | ArrayList allBookmark = DbUtils.getAllBookmark();
213 | mAdapter.setLocBookmarkList(allBookmark);
214 | }
215 | }
216 | };
217 |
218 |
219 | @Override
220 | protected void onDestroy() {
221 | unregisterBroadcastReceiver();
222 | super.onDestroy();
223 | }
224 |
225 | public static void startPage(Context context) {
226 | Intent intent = new Intent(context, MainActivity.class);
227 | intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
228 | intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
229 | context.startActivity(intent);
230 | }
231 |
232 |
233 | }
234 |
--------------------------------------------------------------------------------