├── .gitignore ├── .idea ├── .name ├── compiler.xml ├── copyright │ └── profiles_settings.xml ├── encodings.xml ├── gradle.xml ├── misc.xml ├── modules.xml ├── runConfigurations.xml └── vcs.xml ├── app ├── .gitignore ├── build.gradle ├── libs │ ├── AMap_2DMap_V2.8.1_20160202.jar │ └── AMap_Search_V3.2.1_20160308.jar ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── assets │ └── xposed_init │ ├── java │ └── name │ │ └── caiyao │ │ └── fakegps │ │ ├── data │ │ ├── AppInfo.java │ │ ├── AppInfoProvider.java │ │ └── DbHelper.java │ │ ├── hook │ │ ├── HookUtils.java │ │ └── MainHook.java │ │ └── ui │ │ ├── AMapActivity.java │ │ └── MainActivity.java │ └── res │ ├── drawable │ └── gps.png │ ├── layout │ ├── activity_amap.xml │ ├── activity_main.xml │ ├── app_item.xml │ ├── content_main.xml │ ├── dialog_lac_cid.xml │ └── dialog_search.xml │ ├── menu │ ├── menu_main.xml │ └── menu_map.xml │ ├── values-en │ └── strings.xml │ ├── values-v21 │ └── styles.xml │ ├── values-w820dp │ └── dimens.xml │ └── values │ ├── colors.xml │ ├── dimens.xml │ ├── strings.xml │ └── styles.xml ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | -------------------------------------------------------------------------------- /.idea/.name: -------------------------------------------------------------------------------- 1 | FakeGps -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 18 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 19 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 46 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 24 5 | buildToolsVersion '24.0.2' 6 | 7 | defaultConfig { 8 | applicationId "name.caiyao.fakegps" 9 | minSdkVersion 9 10 | targetSdkVersion 22 11 | versionCode 6 12 | versionName "1.2.2" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled true 17 | shrinkResources true 18 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 19 | } 20 | } 21 | } 22 | 23 | dependencies { 24 | provided 'de.robv.android.xposed:api:81' 25 | compile files('libs/AMap_2DMap_V2.8.1_20160202.jar') 26 | compile 'com.android.support:appcompat-v7:24.2.1' 27 | compile 'com.android.support:design:24.2.1' 28 | compile files('libs/AMap_Search_V3.2.1_20160308.jar') 29 | } 30 | -------------------------------------------------------------------------------- /app/libs/AMap_2DMap_V2.8.1_20160202.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YiuChoi/FakeGps/7041d356204c59f06b3831f9d6164afba3420570/app/libs/AMap_2DMap_V2.8.1_20160202.jar -------------------------------------------------------------------------------- /app/libs/AMap_Search_V3.2.1_20160308.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YiuChoi/FakeGps/7041d356204c59f06b3831f9d6164afba3420570/app/libs/AMap_Search_V3.2.1_20160308.jar -------------------------------------------------------------------------------- /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 D:\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 | -keep public class name.caiyao.fakegps.hook.MainHook 19 | -keep class com.amap.api.maps2d.**{*;} 20 | -dontwarn com.amap.api.** 21 | -keep class com.amap.api.mapcore2d.**{*;} 22 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 9 | 12 | 15 | 18 | 19 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 34 | 35 | 39 | 40 | 41 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /app/src/main/assets/xposed_init: -------------------------------------------------------------------------------- 1 | name.caiyao.fakegps.hook.MainHook 2 | -------------------------------------------------------------------------------- /app/src/main/java/name/caiyao/fakegps/data/AppInfo.java: -------------------------------------------------------------------------------- 1 | package name.caiyao.fakegps.data; 2 | 3 | import android.graphics.drawable.Drawable; 4 | 5 | /** 6 | * Created by 蔡小木 on 2016/5/3 0003. 7 | */ 8 | public class AppInfo { 9 | public String appName = ""; 10 | public String packageName = ""; 11 | public String versionName = ""; 12 | public int versionCode = 0; 13 | public boolean isChecked = false; 14 | public Drawable appIcon = null; 15 | 16 | public String getAppName() { 17 | return appName; 18 | } 19 | 20 | public void setAppName(String appName) { 21 | this.appName = appName; 22 | } 23 | 24 | public String getPackageName() { 25 | return packageName; 26 | } 27 | 28 | public void setPackageName(String packageName) { 29 | this.packageName = packageName; 30 | } 31 | 32 | public String getVersionName() { 33 | return versionName; 34 | } 35 | 36 | public void setVersionName(String versionName) { 37 | this.versionName = versionName; 38 | } 39 | 40 | public int getVersionCode() { 41 | return versionCode; 42 | } 43 | 44 | public void setVersionCode(int versionCode) { 45 | this.versionCode = versionCode; 46 | } 47 | 48 | public Drawable getAppIcon() { 49 | return appIcon; 50 | } 51 | 52 | public void setAppIcon(Drawable appIcon) { 53 | this.appIcon = appIcon; 54 | } 55 | 56 | public boolean isChecked() { 57 | return isChecked; 58 | } 59 | 60 | public void setChecked(boolean checked) { 61 | isChecked = checked; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /app/src/main/java/name/caiyao/fakegps/data/AppInfoProvider.java: -------------------------------------------------------------------------------- 1 | package name.caiyao.fakegps.data; 2 | 3 | import android.content.ContentProvider; 4 | import android.content.ContentValues; 5 | import android.content.UriMatcher; 6 | import android.database.Cursor; 7 | import android.database.sqlite.SQLiteDatabase; 8 | import android.net.Uri; 9 | import android.support.annotation.NonNull; 10 | import android.support.annotation.Nullable; 11 | 12 | /** 13 | * Created by 蔡小木 on 2016/5/4 0004. 14 | */ 15 | public class AppInfoProvider extends ContentProvider { 16 | public static final String AUTHRITY = "name.caiyao.fakegps.data.AppInfoProvider"; 17 | public static final Uri APP_CONTENT_URI = Uri.parse("content://" + AUTHRITY + "/app"); 18 | public static final int APP_URI_CODE = 0; 19 | private static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH); 20 | 21 | static { 22 | sUriMatcher.addURI(AUTHRITY, "app", APP_URI_CODE); 23 | } 24 | 25 | private SQLiteDatabase mSQLiteDatabase; 26 | 27 | @Override 28 | public boolean onCreate() { 29 | mSQLiteDatabase = new DbHelper(getContext()).getWritableDatabase(); 30 | return true; 31 | } 32 | 33 | @Nullable 34 | @Override 35 | public Cursor query(@NonNull Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { 36 | String table = getTableName(uri); 37 | if (table == null) 38 | throw new IllegalArgumentException("Unsupported URI:" + uri); 39 | return mSQLiteDatabase.query(table, projection, selection, selectionArgs, null, null, sortOrder, null); 40 | } 41 | 42 | @Nullable 43 | @Override 44 | public String getType(@NonNull Uri uri) { 45 | return null; 46 | } 47 | 48 | @Nullable 49 | @Override 50 | public Uri insert(@NonNull Uri uri, ContentValues values) { 51 | String table = getTableName(uri); 52 | if (table == null) 53 | throw new IllegalArgumentException("Unsupported URI:" + uri); 54 | mSQLiteDatabase.insert(table, null, values); 55 | getContext().getContentResolver().notifyChange(uri, null); 56 | return uri; 57 | } 58 | 59 | @Override 60 | public int delete(@NonNull Uri uri, String selection, String[] selectionArgs) { 61 | String table = getTableName(uri); 62 | if (table == null) 63 | throw new IllegalArgumentException("Unsupported URI:" + uri); 64 | int count = mSQLiteDatabase.delete(table, selection, selectionArgs); 65 | if (count > 0) { 66 | getContext().getContentResolver().notifyChange(uri, null); 67 | } 68 | return count; 69 | } 70 | 71 | @Override 72 | public int update(@NonNull Uri uri, ContentValues values, String selection, String[] selectionArgs) { 73 | String table = getTableName(uri); 74 | if (table == null) 75 | throw new IllegalArgumentException("Unsupported URI:" + uri); 76 | int row = mSQLiteDatabase.update(table,values,selection,selectionArgs); 77 | if (row>0){ 78 | getContext().getContentResolver().notifyChange(uri, null); 79 | } 80 | return row; 81 | } 82 | 83 | private String getTableName(Uri uri) { 84 | String tableName = null; 85 | switch (sUriMatcher.match(uri)) { 86 | case APP_URI_CODE: 87 | tableName = DbHelper.APP_TABLE_NAME; 88 | break; 89 | } 90 | return tableName; 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /app/src/main/java/name/caiyao/fakegps/data/DbHelper.java: -------------------------------------------------------------------------------- 1 | package name.caiyao.fakegps.data; 2 | 3 | import android.content.Context; 4 | import android.database.sqlite.SQLiteDatabase; 5 | import android.database.sqlite.SQLiteOpenHelper; 6 | 7 | /** 8 | * Created by 蔡小木 on 2016/5/4 0004. 9 | */ 10 | public class DbHelper extends SQLiteOpenHelper { 11 | 12 | private final static String DB_NAME = "applist.db"; 13 | public final static String APP_TABLE_NAME = "app"; 14 | private final static int DB_VERSION = 1; 15 | 16 | public DbHelper(Context context) { 17 | super(context, DB_NAME, null, DB_VERSION); 18 | } 19 | 20 | @Override 21 | public void onCreate(SQLiteDatabase db) { 22 | String CREATE_APP_TABLE = "CREATE TABLE IF NOT EXISTS " + APP_TABLE_NAME + "(package_name TEXT PRIMARY KEY," + "latitude DOUBLE,longitude DOUBLE,lac Integer,cid Integer)"; 23 | db.execSQL(CREATE_APP_TABLE); 24 | } 25 | 26 | @Override 27 | public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { 28 | 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /app/src/main/java/name/caiyao/fakegps/hook/HookUtils.java: -------------------------------------------------------------------------------- 1 | package name.caiyao.fakegps.hook; 2 | 3 | import android.location.Criteria; 4 | import android.location.GpsStatus; 5 | import android.location.Location; 6 | import android.location.LocationListener; 7 | import android.location.LocationManager; 8 | import android.os.Build; 9 | import android.os.SystemClock; 10 | import android.telephony.CellIdentityCdma; 11 | import android.telephony.CellIdentityGsm; 12 | import android.telephony.CellIdentityLte; 13 | import android.telephony.CellIdentityWcdma; 14 | import android.telephony.CellInfoCdma; 15 | import android.telephony.CellInfoGsm; 16 | import android.telephony.CellInfoLte; 17 | import android.telephony.CellInfoWcdma; 18 | import android.telephony.CellLocation; 19 | import android.telephony.gsm.GsmCellLocation; 20 | 21 | import java.lang.reflect.Method; 22 | import java.lang.reflect.Modifier; 23 | import java.util.ArrayList; 24 | import java.util.List; 25 | 26 | import de.robv.android.xposed.XC_MethodHook; 27 | import de.robv.android.xposed.XposedBridge; 28 | import de.robv.android.xposed.XposedHelpers; 29 | 30 | /** 31 | * Created by 蔡小木 on 2016/5/4 0004. 32 | */ 33 | class HookUtils { 34 | 35 | static void HookAndChange(ClassLoader classLoader, final double latitude, final double longtitude, final int lac, final int cid) { 36 | 37 | // XposedHelpers.findAndHookMethod("android.telephony.TelephonyManager", classLoader, 38 | // "getNetworkOperatorName", new XC_MethodHook() { 39 | // @Override 40 | // protected void afterHookedMethod(MethodHookParam param) throws Throwable { 41 | // param.setResult(""); 42 | // } 43 | // }); 44 | // 45 | // XposedHelpers.findAndHookMethod("android.telephony.TelephonyManager", classLoader, 46 | // "getNetworkOperator", new XC_MethodHook() { 47 | // @Override 48 | // protected void afterHookedMethod(MethodHookParam param) throws Throwable { 49 | // param.setResult(""); 50 | // } 51 | // }); 52 | // 53 | // XposedHelpers.findAndHookMethod("android.telephony.TelephonyManager", classLoader, 54 | // "getSimOperatorName", new XC_MethodHook() { 55 | // @Override 56 | // protected void afterHookedMethod(MethodHookParam param) throws Throwable { 57 | // param.setResult(""); 58 | // } 59 | // }); 60 | // 61 | // XposedHelpers.findAndHookMethod("android.telephony.TelephonyManager", classLoader, 62 | // "getSimOperator", new XC_MethodHook() { 63 | // @Override 64 | // protected void afterHookedMethod(MethodHookParam param) throws Throwable { 65 | // param.setResult(null); 66 | // } 67 | // }); 68 | // 69 | // XposedHelpers.findAndHookMethod("android.telephony.TelephonyManager", classLoader, 70 | // "getSimCountryIso", new XC_MethodHook() { 71 | // @Override 72 | // protected void afterHookedMethod(MethodHookParam param) throws Throwable { 73 | // param.setResult(""); 74 | // } 75 | // }); 76 | // 77 | // XposedHelpers.findAndHookMethod("android.telephony.TelephonyManager", classLoader, 78 | // "getNetworkCountryIso", new XC_MethodHook() { 79 | // @Override 80 | // protected void afterHookedMethod(MethodHookParam param) throws Throwable { 81 | // param.setResult(""); 82 | // } 83 | // }); 84 | // XposedHelpers.findAndHookMethod("android.telephony.TelephonyManager", classLoader, 85 | // "getNetworkType", new XC_MethodHook() { 86 | // @Override 87 | // protected void afterHookedMethod(MethodHookParam param) throws Throwable { 88 | // param.setResult(TelephonyManager.NETWORK_TYPE_UNKNOWN); 89 | // } 90 | // }); 91 | // 92 | // XposedHelpers.findAndHookMethod("android.telephony.TelephonyManager", classLoader, 93 | // "getPhoneType", new XC_MethodHook() { 94 | // @Override 95 | // protected void afterHookedMethod(MethodHookParam param) throws Throwable { 96 | // param.setResult(TelephonyManager.PHONE_TYPE_NONE); 97 | // } 98 | // }); 99 | // 100 | // XposedHelpers.findAndHookMethod("android.telephony.TelephonyManager", classLoader, 101 | // "getCurrentPhoneType", new XC_MethodHook() { 102 | // @Override 103 | // protected void afterHookedMethod(MethodHookParam param) throws Throwable { 104 | // param.setResult(0); 105 | // } 106 | // }); 107 | // 108 | // XposedHelpers.findAndHookMethod("android.telephony.TelephonyManager", classLoader, 109 | // "getDataState", new XC_MethodHook() { 110 | // @Override 111 | // protected void afterHookedMethod(MethodHookParam param) throws Throwable { 112 | // param.setResult(TelephonyManager.DATA_DISCONNECTED); 113 | // } 114 | // }); 115 | // 116 | // XposedHelpers.findAndHookMethod("android.telephony.TelephonyManager", classLoader, 117 | // "getSimState", new XC_MethodHook() { 118 | // @Override 119 | // protected void afterHookedMethod(MethodHookParam param) throws Throwable { 120 | // param.setResult(TelephonyManager.SIM_STATE_UNKNOWN); 121 | // } 122 | // }); 123 | 124 | XposedHelpers.findAndHookMethod("android.telephony.TelephonyManager", classLoader, 125 | "getCellLocation", new XC_MethodHook() { 126 | @Override 127 | protected void afterHookedMethod(MethodHookParam param) throws Throwable { 128 | GsmCellLocation gsmCellLocation = new GsmCellLocation(); 129 | gsmCellLocation.setLacAndCid(lac, cid); 130 | param.setResult(gsmCellLocation); 131 | } 132 | }); 133 | 134 | XposedHelpers.findAndHookMethod("android.telephony.PhoneStateListener", classLoader, 135 | "onCellLocationChanged", CellLocation.class, new XC_MethodHook() { 136 | @Override 137 | protected void afterHookedMethod(MethodHookParam param) throws Throwable { 138 | GsmCellLocation gsmCellLocation = new GsmCellLocation(); 139 | gsmCellLocation.setLacAndCid(lac, cid); 140 | param.setResult(gsmCellLocation); 141 | } 142 | }); 143 | 144 | if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP_MR1) { 145 | XposedHelpers.findAndHookMethod("android.telephony.TelephonyManager", classLoader, 146 | "getPhoneCount", new XC_MethodHook() { 147 | @Override 148 | protected void afterHookedMethod(MethodHookParam param) throws Throwable { 149 | param.setResult(1); 150 | } 151 | }); 152 | } 153 | 154 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { 155 | XposedHelpers.findAndHookMethod("android.telephony.TelephonyManager", classLoader, 156 | "getNeighboringCellInfo", new XC_MethodHook() { 157 | @Override 158 | protected void afterHookedMethod(MethodHookParam param) throws Throwable { 159 | param.setResult(new ArrayList<>()); 160 | } 161 | }); 162 | } 163 | 164 | if (Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN) { 165 | XposedHelpers.findAndHookMethod("android.telephony.TelephonyManager", classLoader, 166 | "getAllCellInfo", new XC_MethodHook() { 167 | @Override 168 | protected void afterHookedMethod(MethodHookParam param) throws Throwable { 169 | param.setResult(getCell(460, 0, lac, cid, 0, 0)); 170 | } 171 | }); 172 | XposedHelpers.findAndHookMethod("android.telephony.PhoneStateListener", classLoader, 173 | "onCellInfoChanged", List.class, new XC_MethodHook() { 174 | @Override 175 | protected void beforeHookedMethod(MethodHookParam param) throws Throwable { 176 | param.setResult(getCell(460, 0, lac, cid, 0,0)); 177 | } 178 | }); 179 | } 180 | 181 | XposedHelpers.findAndHookMethod("android.net.wifi.WifiManager", classLoader, "getScanResults", new XC_MethodHook() { 182 | @Override 183 | protected void afterHookedMethod(MethodHookParam param) throws Throwable { 184 | param.setResult(new ArrayList<>()); 185 | } 186 | }); 187 | 188 | XposedHelpers.findAndHookMethod("android.net.wifi.WifiManager", classLoader, "getWifiState", new XC_MethodHook() { 189 | @Override 190 | protected void afterHookedMethod(MethodHookParam param) throws Throwable { 191 | param.setResult(1); 192 | } 193 | }); 194 | 195 | XposedHelpers.findAndHookMethod("android.net.wifi.WifiManager", classLoader, "isWifiEnabled", new XC_MethodHook() { 196 | @Override 197 | protected void afterHookedMethod(MethodHookParam param) throws Throwable { 198 | param.setResult(true); 199 | } 200 | }); 201 | 202 | XposedHelpers.findAndHookMethod("android.net.wifi.WifiInfo", classLoader, "getMacAddress", new XC_MethodHook() { 203 | @Override 204 | protected void afterHookedMethod(MethodHookParam param) throws Throwable { 205 | param.setResult("00-00-00-00-00-00-00-00"); 206 | } 207 | }); 208 | 209 | XposedHelpers.findAndHookMethod("android.net.wifi.WifiInfo", classLoader, "getSSID", new XC_MethodHook() { 210 | @Override 211 | protected void afterHookedMethod(MethodHookParam param) throws Throwable { 212 | param.setResult("null"); 213 | } 214 | }); 215 | 216 | XposedHelpers.findAndHookMethod("android.net.wifi.WifiInfo", classLoader, "getBSSID", new XC_MethodHook() { 217 | @Override 218 | protected void afterHookedMethod(MethodHookParam param) throws Throwable { 219 | param.setResult("00-00-00-00-00-00-00-00"); 220 | } 221 | }); 222 | 223 | 224 | XposedHelpers.findAndHookMethod("android.net.NetworkInfo", classLoader, 225 | "getTypeName", new XC_MethodHook() { 226 | @Override 227 | protected void afterHookedMethod(MethodHookParam param) throws Throwable { 228 | param.setResult("WIFI"); 229 | } 230 | }); 231 | XposedHelpers.findAndHookMethod("android.net.NetworkInfo", classLoader, 232 | "isConnectedOrConnecting", new XC_MethodHook() { 233 | @Override 234 | protected void afterHookedMethod(MethodHookParam param) throws Throwable { 235 | param.setResult(true); 236 | } 237 | }); 238 | 239 | XposedHelpers.findAndHookMethod("android.net.NetworkInfo", classLoader, 240 | "isConnected", new XC_MethodHook() { 241 | @Override 242 | protected void afterHookedMethod(MethodHookParam param) throws Throwable { 243 | param.setResult(true); 244 | } 245 | }); 246 | 247 | XposedHelpers.findAndHookMethod("android.net.NetworkInfo", classLoader, 248 | "isAvailable", new XC_MethodHook() { 249 | @Override 250 | protected void afterHookedMethod(MethodHookParam param) throws Throwable { 251 | param.setResult(true); 252 | } 253 | }); 254 | 255 | XposedHelpers.findAndHookMethod("android.telephony.CellInfo", classLoader, 256 | "isRegistered", new XC_MethodHook() { 257 | @Override 258 | protected void afterHookedMethod(MethodHookParam param) throws Throwable { 259 | param.setResult(true); 260 | } 261 | }); 262 | 263 | XposedHelpers.findAndHookMethod(LocationManager.class, "getLastLocation", new XC_MethodHook() { 264 | @Override 265 | protected void afterHookedMethod(MethodHookParam param) throws Throwable { 266 | Location l = new Location(LocationManager.GPS_PROVIDER); 267 | l.setLatitude(latitude); 268 | l.setLongitude(longtitude); 269 | l.setAccuracy(100f); 270 | l.setTime(System.currentTimeMillis()); 271 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { 272 | l.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos()); 273 | } 274 | param.setResult(l); 275 | } 276 | }); 277 | 278 | XposedHelpers.findAndHookMethod(LocationManager.class, "getLastKnownLocation", String.class, new XC_MethodHook() { 279 | @Override 280 | protected void afterHookedMethod(MethodHookParam param) throws Throwable { 281 | Location l = new Location(LocationManager.GPS_PROVIDER); 282 | l.setLatitude(latitude); 283 | l.setLongitude(longtitude); 284 | l.setAccuracy(100f); 285 | l.setTime(System.currentTimeMillis()); 286 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { 287 | l.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos()); 288 | } 289 | param.setResult(l); 290 | } 291 | }); 292 | 293 | 294 | XposedBridge.hookAllMethods(LocationManager.class, "getProviders", new XC_MethodHook() { 295 | @Override 296 | protected void afterHookedMethod(MethodHookParam param) throws Throwable { 297 | ArrayList arrayList = new ArrayList<>(); 298 | arrayList.add("gps"); 299 | param.setResult(arrayList); 300 | } 301 | }); 302 | 303 | XposedHelpers.findAndHookMethod(LocationManager.class, "getBestProvider", Criteria.class, Boolean.TYPE, new XC_MethodHook() { 304 | @Override 305 | protected void afterHookedMethod(MethodHookParam param) throws Throwable { 306 | param.setResult("gps"); 307 | } 308 | }); 309 | 310 | XposedHelpers.findAndHookMethod(LocationManager.class, "addGpsStatusListener", GpsStatus.Listener.class, new XC_MethodHook() { 311 | @Override 312 | protected void afterHookedMethod(MethodHookParam param) throws Throwable { 313 | if (param.args[0] != null) { 314 | XposedHelpers.callMethod(param.args[0], "onGpsStatusChanged", 1); 315 | XposedHelpers.callMethod(param.args[0], "onGpsStatusChanged", 3); 316 | } 317 | } 318 | }); 319 | 320 | XposedHelpers.findAndHookMethod(LocationManager.class, "addNmeaListener", GpsStatus.NmeaListener.class, new XC_MethodHook() { 321 | @Override 322 | protected void beforeHookedMethod(MethodHookParam param) throws Throwable { 323 | param.setResult(false); 324 | } 325 | }); 326 | 327 | XposedHelpers.findAndHookMethod("android.location.LocationManager", classLoader, 328 | "getGpsStatus", GpsStatus.class, new XC_MethodHook() { 329 | @Override 330 | protected void afterHookedMethod(MethodHookParam param) throws Throwable { 331 | GpsStatus gss = (GpsStatus) param.getResult(); 332 | if (gss == null) 333 | return; 334 | 335 | Class clazz = GpsStatus.class; 336 | Method m = null; 337 | for (Method method : clazz.getDeclaredMethods()) { 338 | if (method.getName().equals("setStatus")) { 339 | if (method.getParameterTypes().length > 1) { 340 | m = method; 341 | break; 342 | } 343 | } 344 | } 345 | if (m == null) 346 | return; 347 | 348 | //access the private setStatus function of GpsStatus 349 | m.setAccessible(true); 350 | 351 | //make the apps belive GPS works fine now 352 | int svCount = 5; 353 | int[] prns = {1, 2, 3, 4, 5}; 354 | float[] snrs = {0, 0, 0, 0, 0}; 355 | float[] elevations = {0, 0, 0, 0, 0}; 356 | float[] azimuths = {0, 0, 0, 0, 0}; 357 | int ephemerisMask = 0x1f; 358 | int almanacMask = 0x1f; 359 | 360 | //5 satellites are fixed 361 | int usedInFixMask = 0x1f; 362 | 363 | XposedHelpers.callMethod(gss, "setStatus", svCount, prns, snrs, elevations, azimuths, ephemerisMask, almanacMask, usedInFixMask); 364 | param.args[0] = gss; 365 | param.setResult(gss); 366 | try { 367 | m.invoke(gss, svCount, prns, snrs, elevations, azimuths, ephemerisMask, almanacMask, usedInFixMask); 368 | param.setResult(gss); 369 | } catch (Exception e) { 370 | XposedBridge.log(e); 371 | } 372 | } 373 | }); 374 | 375 | for (Method method : LocationManager.class.getDeclaredMethods()) { 376 | if (method.getName().equals("requestLocationUpdates") 377 | && !Modifier.isAbstract(method.getModifiers()) 378 | && Modifier.isPublic(method.getModifiers())) { 379 | XposedBridge.hookMethod(method, new XC_MethodHook() { 380 | @Override 381 | protected void beforeHookedMethod(MethodHookParam param) throws Throwable { 382 | if (param.args.length >= 4 && (param.args[3] instanceof LocationListener)) { 383 | 384 | LocationListener ll = (LocationListener) param.args[3]; 385 | 386 | Class clazz = LocationListener.class; 387 | Method m = null; 388 | for (Method method : clazz.getDeclaredMethods()) { 389 | if (method.getName().equals("onLocationChanged") && !Modifier.isAbstract(method.getModifiers())) { 390 | m = method; 391 | break; 392 | } 393 | } 394 | Location l = new Location(LocationManager.GPS_PROVIDER); 395 | l.setLatitude(latitude); 396 | l.setLongitude(longtitude); 397 | l.setAccuracy(10.00f); 398 | l.setTime(System.currentTimeMillis()); 399 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { 400 | l.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos()); 401 | } 402 | XposedHelpers.callMethod(ll, "onLocationChanged", l); 403 | try { 404 | if (m != null) { 405 | m.invoke(ll, l); 406 | } 407 | } catch (Exception e) { 408 | XposedBridge.log(e); 409 | } 410 | } 411 | } 412 | }); 413 | } 414 | 415 | if (method.getName().equals("requestSingleUpdate ") 416 | && !Modifier.isAbstract(method.getModifiers()) 417 | && Modifier.isPublic(method.getModifiers())) { 418 | XposedBridge.hookMethod(method, new XC_MethodHook() { 419 | @Override 420 | protected void beforeHookedMethod(MethodHookParam param) throws Throwable { 421 | if (param.args.length >= 3 && (param.args[1] instanceof LocationListener)) { 422 | 423 | LocationListener ll = (LocationListener) param.args[3]; 424 | 425 | Class clazz = LocationListener.class; 426 | Method m = null; 427 | for (Method method : clazz.getDeclaredMethods()) { 428 | if (method.getName().equals("onLocationChanged") && !Modifier.isAbstract(method.getModifiers())) { 429 | m = method; 430 | break; 431 | } 432 | } 433 | 434 | try { 435 | if (m != null) { 436 | Location l = new Location(LocationManager.GPS_PROVIDER); 437 | l.setLatitude(latitude); 438 | l.setLongitude(longtitude); 439 | l.setAccuracy(100f); 440 | l.setTime(System.currentTimeMillis()); 441 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { 442 | l.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos()); 443 | } 444 | m.invoke(ll, l); 445 | } 446 | } catch (Exception e) { 447 | XposedBridge.log(e); 448 | } 449 | } 450 | } 451 | }); 452 | } 453 | } 454 | } 455 | 456 | private static ArrayList getCell(int mcc, int mnc, int lac, int cid, int sid, int networkType) { 457 | ArrayList arrayList = new ArrayList(); 458 | CellInfoGsm cellInfoGsm = (CellInfoGsm) XposedHelpers.newInstance(CellInfoGsm.class); 459 | XposedHelpers.callMethod(cellInfoGsm, "setCellIdentity", XposedHelpers.newInstance(CellIdentityGsm.class, new Object[]{Integer.valueOf(mcc), Integer.valueOf(mnc), Integer.valueOf( 460 | lac), Integer.valueOf(cid)})); 461 | CellInfoCdma cellInfoCdma = (CellInfoCdma) XposedHelpers.newInstance(CellInfoCdma.class); 462 | XposedHelpers.callMethod(cellInfoCdma, "setCellIdentity", XposedHelpers.newInstance(CellIdentityCdma.class, new Object[]{Integer.valueOf(lac), Integer.valueOf(sid), Integer.valueOf(cid), Integer.valueOf(0), Integer.valueOf(0)})); 463 | CellInfoWcdma cellInfoWcdma = (CellInfoWcdma) XposedHelpers.newInstance(CellInfoWcdma.class); 464 | XposedHelpers.callMethod(cellInfoWcdma, "setCellIdentity", XposedHelpers.newInstance(CellIdentityWcdma.class, new Object[]{Integer.valueOf(mcc), Integer.valueOf(mnc), Integer.valueOf(lac), Integer.valueOf(cid), Integer.valueOf(300)})); 465 | CellInfoLte cellInfoLte = (CellInfoLte) XposedHelpers.newInstance(CellInfoLte.class); 466 | XposedHelpers.callMethod(cellInfoLte, "setCellIdentity", XposedHelpers.newInstance(CellIdentityLte.class, new Object[]{Integer.valueOf(mcc), Integer.valueOf(mnc), Integer.valueOf(cid), Integer.valueOf(300), Integer.valueOf(lac)})); 467 | if (networkType == 1 || networkType == 2) { 468 | arrayList.add(cellInfoGsm); 469 | } else if (networkType == 13) { 470 | arrayList.add(cellInfoLte); 471 | } else if (networkType == 4 || networkType == 5 || networkType == 6 || networkType == 7 || networkType == 12 || networkType == 14) { 472 | arrayList.add(cellInfoCdma); 473 | } else if (networkType == 3 || networkType == 8 || networkType == 9 || networkType == 10 || networkType == 15) { 474 | arrayList.add(cellInfoWcdma); 475 | } 476 | return arrayList; 477 | } 478 | } 479 | -------------------------------------------------------------------------------- /app/src/main/java/name/caiyao/fakegps/hook/MainHook.java: -------------------------------------------------------------------------------- 1 | package name.caiyao.fakegps.hook; 2 | 3 | import android.content.Context; 4 | import android.database.Cursor; 5 | import android.net.Uri; 6 | 7 | import java.util.Random; 8 | 9 | import de.robv.android.xposed.IXposedHookLoadPackage; 10 | import de.robv.android.xposed.XposedBridge; 11 | import de.robv.android.xposed.XposedHelpers; 12 | import de.robv.android.xposed.callbacks.XC_LoadPackage; 13 | 14 | /** 15 | * Created by 蔡小木 on 2016/4/17 0017. 16 | */ 17 | public class MainHook implements IXposedHookLoadPackage { 18 | 19 | @Override 20 | public void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable { 21 | final Object activityThread = XposedHelpers.callStaticMethod(XposedHelpers.findClass("android.app.ActivityThread", null), "currentActivityThread"); 22 | final Context systemContext = (Context) XposedHelpers.callMethod(activityThread, "getSystemContext"); 23 | Uri uri = Uri.parse("content://name.caiyao.fakegps.data.AppInfoProvider/app"); 24 | Cursor cursor = systemContext.getContentResolver().query(uri, new String[]{"latitude", "longitude","lac","cid"}, "package_name=?", new String[]{loadPackageParam.packageName}, null); 25 | if (cursor != null && cursor.moveToNext()) { 26 | //41019, 18511 27 | double latitude = cursor.getDouble(cursor.getColumnIndex("latitude")) + (double) new Random().nextInt(100) / 1000000 + ((double) new Random().nextInt(99999999)) / 100000000000000d; 28 | double longitude = cursor.getDouble(cursor.getColumnIndex("longitude")) + (double) new Random().nextInt(100) / 1000000 + ((double) new Random().nextInt(99999999)) / 100000000000000d; 29 | int lac = cursor.getInt(cursor.getColumnIndex("lac")); 30 | int cid = cursor.getInt(cursor.getColumnIndex("cid")); 31 | XposedBridge.log("模拟位置:" + loadPackageParam.packageName + "," + latitude + "," + longitude + "," + lac + "," + cid); 32 | HookUtils.HookAndChange(loadPackageParam.classLoader, latitude, longitude, lac, cid); 33 | cursor.close(); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /app/src/main/java/name/caiyao/fakegps/ui/AMapActivity.java: -------------------------------------------------------------------------------- 1 | package name.caiyao.fakegps.ui; 2 | 3 | import android.content.ContentValues; 4 | import android.content.DialogInterface; 5 | import android.database.Cursor; 6 | import android.database.sqlite.SQLiteDatabase; 7 | import android.os.Bundle; 8 | import android.support.design.widget.TextInputEditText; 9 | import android.support.v7.app.AlertDialog; 10 | import android.support.v7.app.AppCompatActivity; 11 | import android.support.v7.widget.Toolbar; 12 | import android.text.TextUtils; 13 | import android.view.LayoutInflater; 14 | import android.view.Menu; 15 | import android.view.MenuItem; 16 | import android.view.View; 17 | import android.widget.EditText; 18 | import android.widget.Toast; 19 | 20 | import com.amap.api.maps2d.AMap; 21 | import com.amap.api.maps2d.CameraUpdateFactory; 22 | import com.amap.api.maps2d.MapView; 23 | import com.amap.api.maps2d.model.LatLng; 24 | import com.amap.api.maps2d.model.MarkerOptions; 25 | import com.amap.api.services.core.PoiItem; 26 | import com.amap.api.services.poisearch.PoiResult; 27 | import com.amap.api.services.poisearch.PoiSearch; 28 | 29 | import java.lang.reflect.Field; 30 | import java.util.ArrayList; 31 | 32 | import name.caiyao.fakegps.R; 33 | import name.caiyao.fakegps.data.DbHelper; 34 | 35 | public class AMapActivity extends AppCompatActivity implements AMap.OnMapClickListener { 36 | 37 | private MapView mv; 38 | private AMap aMap; 39 | private LatLng latLng; 40 | private String pacakgeName; 41 | private int lac = 0, cid = 0; 42 | private SQLiteDatabase mSQLiteDatabase; 43 | 44 | @Override 45 | protected void onCreate(Bundle savedInstanceState) { 46 | super.onCreate(savedInstanceState); 47 | setContentView(R.layout.activity_amap); 48 | Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); 49 | setSupportActionBar(toolbar); 50 | 51 | pacakgeName = getIntent().getStringExtra("package_name"); 52 | 53 | mv = (MapView) findViewById(R.id.mv); 54 | assert mv != null; 55 | mv.onCreate(savedInstanceState); 56 | aMap = mv.getMap(); 57 | mSQLiteDatabase = new DbHelper(this).getWritableDatabase(); 58 | Cursor cursor = mSQLiteDatabase.query(DbHelper.APP_TABLE_NAME, new String[]{"latitude,longitude"}, "package_name=?", new String[]{pacakgeName}, null, null, null); 59 | if (cursor != null && cursor.moveToNext()) { 60 | double lat = cursor.getDouble(cursor.getColumnIndex("latitude")); 61 | double lon = cursor.getDouble(cursor.getColumnIndex("longitude")); 62 | LatLng latLng1 = new LatLng(lat, lon); 63 | MarkerOptions markerOptions = new MarkerOptions(); 64 | markerOptions.position(latLng1); 65 | markerOptions.draggable(true); 66 | markerOptions.title("经度:" + latLng1.longitude + ",纬度:" + latLng1.latitude); 67 | aMap.addMarker(markerOptions); 68 | aMap.moveCamera(CameraUpdateFactory.changeLatLng(latLng1)); 69 | aMap.moveCamera(CameraUpdateFactory.zoomTo(aMap.getMaxZoomLevel())); 70 | cursor.close(); 71 | } 72 | aMap.setMapType(AMap.MAP_TYPE_NORMAL); 73 | aMap.setOnMapClickListener(this); 74 | } 75 | 76 | @Override 77 | protected void onResume() { 78 | super.onResume(); 79 | mv.onResume(); 80 | } 81 | 82 | @Override 83 | public boolean onCreateOptionsMenu(Menu menu) { 84 | getMenuInflater().inflate(R.menu.menu_map, menu); 85 | return super.onCreateOptionsMenu(menu); 86 | } 87 | 88 | @Override 89 | public boolean onOptionsItemSelected(MenuItem item) { 90 | switch (item.getItemId()) { 91 | case R.id.ok: 92 | if (latLng == null) { 93 | Toast.makeText(this, "请点击地图选择一个地点!", Toast.LENGTH_SHORT).show(); 94 | return true; 95 | } 96 | new AlertDialog.Builder(AMapActivity.this).setTitle("注意").setMessage("部分应用的定位如qq附近的人,钉钉签到等使用的是基站定位,如需使用相关功能请同时填写基站信息") 97 | .setPositiveButton("知道了", new DialogInterface.OnClickListener() { 98 | @Override 99 | public void onClick(DialogInterface dialog, int which) { 100 | dialog.dismiss(); 101 | } 102 | }) 103 | .show(); 104 | ContentValues contentValues = new ContentValues(); 105 | contentValues.put("package_name", pacakgeName); 106 | contentValues.put("latitude", latLng.latitude); 107 | contentValues.put("longitude", latLng.longitude); 108 | contentValues.put("lac", lac); 109 | contentValues.put("cid", cid); 110 | mSQLiteDatabase.insertWithOnConflict(DbHelper.APP_TABLE_NAME, null, contentValues, SQLiteDatabase.CONFLICT_REPLACE); 111 | break; 112 | case R.id.search: 113 | View view = LayoutInflater.from(this).inflate(R.layout.dialog_search, null, false); 114 | final EditText et_key = (EditText) view.findViewById(R.id.key); 115 | new AlertDialog.Builder(this).setView(view) 116 | .setTitle("搜索位置") 117 | .setPositiveButton("搜索", new DialogInterface.OnClickListener() { 118 | @Override 119 | public void onClick(DialogInterface dialog, int which) { 120 | search(et_key.getText().toString()); 121 | } 122 | }).setNegativeButton("取消", new DialogInterface.OnClickListener() { 123 | @Override 124 | public void onClick(DialogInterface dialog, int which) { 125 | dialog.dismiss(); 126 | } 127 | }).show(); 128 | break; 129 | case R.id.lac: 130 | View view1 = getLayoutInflater().inflate(R.layout.dialog_lac_cid, null, false); 131 | final TextInputEditText etLac = (TextInputEditText) view1.findViewById(R.id.lac); 132 | final TextInputEditText etCid = (TextInputEditText) view1.findViewById(R.id.cid); 133 | new AlertDialog.Builder(AMapActivity.this).setTitle("填写基站信息").setView(view1).setPositiveButton("确定", new DialogInterface.OnClickListener() { 134 | @Override 135 | public void onClick(DialogInterface dialog, int which) { 136 | canCloseDialog(dialog, false); 137 | if (TextUtils.isEmpty(etLac.getText())) { 138 | etLac.setError("lac的值不应该为空"); 139 | } 140 | if (TextUtils.isEmpty(etCid.getText())) { 141 | etCid.setError("cid的值不应该为空"); 142 | } 143 | if (!TextUtils.isEmpty(etLac.getText()) && !TextUtils.isEmpty(etCid.getText())) { 144 | int lac1 = Integer.parseInt(etLac.getText().toString()); 145 | int cid1 = Integer.parseInt(etCid.getText().toString()); 146 | if (lac1 <= 0 || lac1 >= 65535) { 147 | etLac.setError("lac的值应该是0~65535"); 148 | lac1 = 0; 149 | } 150 | if (cid1 <= 0 || cid1 >= 65535) { 151 | etCid.setError("cid的值应该是0~65535"); 152 | cid1 = 0; 153 | } 154 | lac = lac1; 155 | cid = cid1; 156 | } 157 | ContentValues contentValues = new ContentValues(); 158 | contentValues.put("package_name", pacakgeName); 159 | contentValues.put("lac", lac); 160 | contentValues.put("cid", cid); 161 | mSQLiteDatabase.insertWithOnConflict(DbHelper.APP_TABLE_NAME, null, contentValues, SQLiteDatabase.CONFLICT_REPLACE); 162 | } 163 | }).setNegativeButton("取消", new DialogInterface.OnClickListener() { 164 | @Override 165 | public void onClick(DialogInterface dialog, int which) { 166 | dialog.dismiss(); 167 | } 168 | }).show(); 169 | break; 170 | } 171 | return super.onOptionsItemSelected(item); 172 | } 173 | 174 | private void canCloseDialog(DialogInterface dialogInterface, boolean close) { 175 | try { 176 | Field field = dialogInterface.getClass().getSuperclass().getDeclaredField("mShowing"); 177 | field.setAccessible(true); 178 | field.set(dialogInterface, close); 179 | } catch (Exception e) { 180 | e.printStackTrace(); 181 | } 182 | } 183 | 184 | @Override 185 | protected void onPause() { 186 | super.onPause(); 187 | mv.onPause(); 188 | } 189 | 190 | private void search(final String key) { 191 | PoiSearch.Query query = new PoiSearch.Query(key, null, null); 192 | query.setPageSize(10); 193 | query.setPageNum(0); 194 | PoiSearch poiSearch = new PoiSearch(this, query); 195 | poiSearch.setOnPoiSearchListener(new PoiSearch.OnPoiSearchListener() { 196 | @Override 197 | public void onPoiSearched(PoiResult poiResult, int i) { 198 | if (i == 1000) { 199 | final ArrayList poiItems = poiResult.getPois(); 200 | if (poiItems.size() != 0) { 201 | String[] keyList = new String[poiItems.size()]; 202 | for (int j = 0; j < poiItems.size(); j++) { 203 | keyList[j] = poiItems.get(j).getTitle(); 204 | } 205 | new AlertDialog.Builder(AMapActivity.this) 206 | .setTitle("选择位置") 207 | .setSingleChoiceItems(keyList, 0, new DialogInterface.OnClickListener() { 208 | @Override 209 | public void onClick(DialogInterface dialog, int which) { 210 | aMap.moveCamera(CameraUpdateFactory.changeLatLng(new LatLng(poiItems.get(which).getLatLonPoint().getLatitude(), poiItems.get(which).getLatLonPoint().getLongitude()))); 211 | aMap.moveCamera(CameraUpdateFactory.zoomTo(aMap.getMaxZoomLevel())); 212 | dialog.dismiss(); 213 | } 214 | }).show(); 215 | } else { 216 | Toast.makeText(AMapActivity.this, "没有搜索结果", Toast.LENGTH_SHORT).show(); 217 | } 218 | 219 | } 220 | } 221 | 222 | @Override 223 | public void onPoiItemSearched(PoiItem poiItem, int i) { 224 | 225 | } 226 | }); 227 | poiSearch.searchPOIAsyn(); 228 | } 229 | 230 | @Override 231 | protected void onSaveInstanceState(Bundle outState) { 232 | super.onSaveInstanceState(outState); 233 | mv.onSaveInstanceState(outState); 234 | } 235 | 236 | @Override 237 | protected void onDestroy() { 238 | super.onDestroy(); 239 | mv.onDestroy(); 240 | mSQLiteDatabase.close(); 241 | } 242 | 243 | @Override 244 | public void onMapClick(LatLng latLng) { 245 | aMap.clear(); 246 | MarkerOptions markerOptions = new MarkerOptions(); 247 | markerOptions.position(latLng); 248 | markerOptions.draggable(true); 249 | markerOptions.title("经度:" + latLng.longitude + ",纬度:" + latLng.latitude); 250 | aMap.addMarker(markerOptions); 251 | this.latLng = latLng; 252 | } 253 | } 254 | -------------------------------------------------------------------------------- /app/src/main/java/name/caiyao/fakegps/ui/MainActivity.java: -------------------------------------------------------------------------------- 1 | package name.caiyao.fakegps.ui; 2 | 3 | import android.app.ProgressDialog; 4 | import android.content.Intent; 5 | import android.content.pm.PackageInfo; 6 | import android.net.Uri; 7 | import android.os.AsyncTask; 8 | import android.os.Bundle; 9 | import android.support.v7.app.AppCompatActivity; 10 | import android.support.v7.widget.LinearLayoutManager; 11 | import android.support.v7.widget.RecyclerView; 12 | import android.support.v7.widget.Toolbar; 13 | import android.view.Menu; 14 | import android.view.MenuItem; 15 | import android.view.View; 16 | import android.view.ViewGroup; 17 | import android.widget.ImageView; 18 | import android.widget.TextView; 19 | 20 | import java.util.ArrayList; 21 | import java.util.List; 22 | 23 | import name.caiyao.fakegps.BuildConfig; 24 | import name.caiyao.fakegps.R; 25 | import name.caiyao.fakegps.data.AppInfo; 26 | 27 | public class MainActivity extends AppCompatActivity { 28 | 29 | private ProgressDialog mProgressDialog; 30 | private AppAdapter mAppAdapter; 31 | private ArrayList mAppInfos = new ArrayList<>(); 32 | 33 | @Override 34 | protected void onCreate(Bundle savedInstanceState) { 35 | super.onCreate(savedInstanceState); 36 | setContentView(R.layout.activity_main); 37 | 38 | RecyclerView recyclerView = (RecyclerView) findViewById(R.id.rv_app); 39 | assert recyclerView != null; 40 | recyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)); 41 | recyclerView.setHasFixedSize(true); 42 | mAppAdapter = new AppAdapter(mAppInfos); 43 | recyclerView.setAdapter(mAppAdapter); 44 | 45 | Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); 46 | setSupportActionBar(toolbar); 47 | 48 | mProgressDialog = new ProgressDialog(this); 49 | mProgressDialog.setMax(100); 50 | mProgressDialog.setMessage("正在扫描应用程序"); 51 | mProgressDialog.show(); 52 | 53 | GetAppInfoTask getAppInfoTask = new GetAppInfoTask(); 54 | getAppInfoTask.execute(); 55 | } 56 | 57 | @Override 58 | public boolean onCreateOptionsMenu(Menu menu) { 59 | getMenuInflater().inflate(R.menu.menu_main,menu); 60 | return super.onCreateOptionsMenu(menu); 61 | } 62 | 63 | @Override 64 | public boolean onOptionsItemSelected(MenuItem item) { 65 | switch (item.getItemId()){ 66 | case R.id.setting: 67 | 68 | break; 69 | case R.id.donate: 70 | startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://qr.alipay.com/apoy1zw1o2xpc7915d"))); 71 | break; 72 | case R.id.about: 73 | startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("http://caiyao.name/releases"))); 74 | break; 75 | } 76 | return super.onOptionsItemSelected(item); 77 | } 78 | 79 | private class GetAppInfoTask extends AsyncTask> { 80 | 81 | @Override 82 | protected ArrayList doInBackground(Integer[] params) { 83 | ArrayList appList = new ArrayList<>(); 84 | List packages = getPackageManager().getInstalledPackages(0); 85 | for (int i = 0; i < packages.size(); i++) { 86 | PackageInfo packageInfo = packages.get(i); 87 | AppInfo tmpInfo = new AppInfo(); 88 | tmpInfo.appName = packageInfo.applicationInfo.loadLabel(getPackageManager()).toString(); 89 | tmpInfo.packageName = packageInfo.packageName; 90 | tmpInfo.versionName = packageInfo.versionName; 91 | tmpInfo.versionCode = packageInfo.versionCode; 92 | tmpInfo.appIcon = packageInfo.applicationInfo.loadIcon(getPackageManager()); 93 | if (!packageInfo.packageName.equals(BuildConfig.APPLICATION_ID)) 94 | appList.add(tmpInfo); 95 | publishProgress(i / packages.size() * 100); 96 | } 97 | return appList; 98 | } 99 | 100 | @Override 101 | protected void onProgressUpdate(Integer... values) { 102 | mProgressDialog.setProgress(values[0]); 103 | } 104 | 105 | @Override 106 | protected void onPostExecute(ArrayList o) { 107 | mProgressDialog.dismiss(); 108 | mAppInfos.addAll(o); 109 | mAppAdapter.notifyDataSetChanged(); 110 | } 111 | } 112 | 113 | class AppAdapter extends RecyclerView.Adapter { 114 | 115 | ArrayList mAppInfos; 116 | 117 | AppAdapter(ArrayList appInfos) { 118 | this.mAppInfos = appInfos; 119 | } 120 | 121 | @Override 122 | public AppViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 123 | return new AppViewHolder(getLayoutInflater().inflate(R.layout.app_item, parent, false)); 124 | } 125 | 126 | @Override 127 | public void onBindViewHolder(final AppViewHolder holder, int position) { 128 | holder.ivIcon.setImageDrawable(mAppInfos.get(position).getAppIcon()); 129 | holder.tvName.setText(mAppInfos.get(position).getAppName()); 130 | holder.tvPackageName.setText(mAppInfos.get(position).getPackageName()); 131 | holder.itemView.setOnClickListener(new View.OnClickListener() { 132 | @Override 133 | public void onClick(View v) { 134 | startActivity(new Intent(MainActivity.this, AMapActivity.class).putExtra("package_name", mAppInfos.get(holder.getAdapterPosition()).getPackageName())); 135 | } 136 | }); 137 | } 138 | 139 | @Override 140 | public int getItemCount() { 141 | return mAppInfos.size(); 142 | } 143 | 144 | class AppViewHolder extends RecyclerView.ViewHolder { 145 | 146 | ImageView ivIcon; 147 | TextView tvName; 148 | TextView tvPackageName; 149 | 150 | AppViewHolder(View itemView) { 151 | super(itemView); 152 | ivIcon = (ImageView) itemView.findViewById(R.id.iv_icon); 153 | tvName = (TextView) itemView.findViewById(R.id.tv_name); 154 | tvPackageName = (TextView) itemView.findViewById(R.id.tv_package_name); 155 | } 156 | } 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/gps.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YiuChoi/FakeGps/7041d356204c59f06b3831f9d6164afba3420570/app/src/main/res/drawable/gps.png -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_amap.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 15 | 16 | 22 | 23 | 24 | 25 | 29 | 30 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 14 | 15 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /app/src/main/res/layout/app_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 | 19 | 20 | 27 | 28 | 35 | 36 | 45 | 46 | 54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /app/src/main/res/layout/content_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 16 | 17 | -------------------------------------------------------------------------------- /app/src/main/res/layout/dialog_lac_cid.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 10 | 11 | 17 | 18 | 19 | 20 | 23 | 24 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /app/src/main/res/layout/dialog_search.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 8 | 9 | 13 | 17 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_map.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 8 | 9 | 13 | 14 | 19 | -------------------------------------------------------------------------------- /app/src/main/res/values-en/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | FakeGps 4 | about 5 | Alipay Donate 6 | Start 7 | Stop 8 | -------------------------------------------------------------------------------- /app/src/main/res/values-v21/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/values-w820dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 64dp 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3F51B5 4 | #303F9F 5 | #FF4081 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 16dp 5 | 16dp 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 模拟位置 3 | 开始 4 | 停止 5 | 支付宝捐赠 6 | 关于 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 15 | 16 |