[
  {
    "path": ".gitignore",
    "content": "*.iml\n.gradle\n/local.properties\n/.idea/workspace.xml\n/.idea/libraries\n.DS_Store\n/build\n/captures\n"
  },
  {
    "path": ".idea/.name",
    "content": "FakeGps"
  },
  {
    "path": ".idea/compiler.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"CompilerConfiguration\">\n    <resourceExtensions />\n    <wildcardResourcePatterns>\n      <entry name=\"!?*.java\" />\n      <entry name=\"!?*.form\" />\n      <entry name=\"!?*.class\" />\n      <entry name=\"!?*.groovy\" />\n      <entry name=\"!?*.scala\" />\n      <entry name=\"!?*.flex\" />\n      <entry name=\"!?*.kt\" />\n      <entry name=\"!?*.clj\" />\n      <entry name=\"!?*.aj\" />\n    </wildcardResourcePatterns>\n    <annotationProcessing>\n      <profile default=\"true\" name=\"Default\" enabled=\"false\">\n        <processorPath useClasspath=\"true\" />\n      </profile>\n    </annotationProcessing>\n  </component>\n</project>"
  },
  {
    "path": ".idea/copyright/profiles_settings.xml",
    "content": "<component name=\"CopyrightManager\">\n  <settings default=\"\" />\n</component>"
  },
  {
    "path": ".idea/encodings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"Encoding\">\n    <file url=\"PROJECT\" charset=\"UTF-8\" />\n  </component>\n</project>"
  },
  {
    "path": ".idea/gradle.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"GradleSettings\">\n    <option name=\"linkedExternalProjectsSettings\">\n      <GradleProjectSettings>\n        <option name=\"distributionType\" value=\"DEFAULT_WRAPPED\" />\n        <option name=\"externalProjectPath\" value=\"$PROJECT_DIR$\" />\n        <option name=\"modules\">\n          <set>\n            <option value=\"$PROJECT_DIR$\" />\n            <option value=\"$PROJECT_DIR$/app\" />\n          </set>\n        </option>\n        <option name=\"resolveModulePerSourceSet\" value=\"false\" />\n      </GradleProjectSettings>\n    </option>\n  </component>\n</project>"
  },
  {
    "path": ".idea/misc.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"EntryPointsManager\">\n    <entry_points version=\"2.0\" />\n  </component>\n  <component name=\"NullableNotNullManager\">\n    <option name=\"myDefaultNullable\" value=\"android.support.annotation.Nullable\" />\n    <option name=\"myDefaultNotNull\" value=\"android.support.annotation.NonNull\" />\n    <option name=\"myNullables\">\n      <value>\n        <list size=\"4\">\n          <item index=\"0\" class=\"java.lang.String\" itemvalue=\"org.jetbrains.annotations.Nullable\" />\n          <item index=\"1\" class=\"java.lang.String\" itemvalue=\"javax.annotation.Nullable\" />\n          <item index=\"2\" class=\"java.lang.String\" itemvalue=\"edu.umd.cs.findbugs.annotations.Nullable\" />\n          <item index=\"3\" class=\"java.lang.String\" itemvalue=\"android.support.annotation.Nullable\" />\n        </list>\n      </value>\n    </option>\n    <option name=\"myNotNulls\">\n      <value>\n        <list size=\"4\">\n          <item index=\"0\" class=\"java.lang.String\" itemvalue=\"org.jetbrains.annotations.NotNull\" />\n          <item index=\"1\" class=\"java.lang.String\" itemvalue=\"javax.annotation.Nonnull\" />\n          <item index=\"2\" class=\"java.lang.String\" itemvalue=\"edu.umd.cs.findbugs.annotations.NonNull\" />\n          <item index=\"3\" class=\"java.lang.String\" itemvalue=\"android.support.annotation.NonNull\" />\n        </list>\n      </value>\n    </option>\n  </component>\n  <component name=\"ProjectLevelVcsManager\" settingsEditedManually=\"false\">\n    <OptionsSetting value=\"true\" id=\"Add\" />\n    <OptionsSetting value=\"true\" id=\"Remove\" />\n    <OptionsSetting value=\"true\" id=\"Checkout\" />\n    <OptionsSetting value=\"true\" id=\"Update\" />\n    <OptionsSetting value=\"true\" id=\"Status\" />\n    <OptionsSetting value=\"true\" id=\"Edit\" />\n    <ConfirmationsSetting value=\"0\" id=\"Add\" />\n    <ConfirmationsSetting value=\"0\" id=\"Remove\" />\n  </component>\n  <component name=\"ProjectRootManager\" version=\"2\" languageLevel=\"JDK_1_7\" default=\"true\" assert-keyword=\"true\" jdk-15=\"true\" project-jdk-name=\"1.8\" project-jdk-type=\"JavaSDK\">\n    <output url=\"file://$PROJECT_DIR$/build/classes\" />\n  </component>\n  <component name=\"ProjectType\">\n    <option name=\"id\" value=\"Android\" />\n  </component>\n</project>"
  },
  {
    "path": ".idea/modules.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"ProjectModuleManager\">\n    <modules>\n      <module fileurl=\"file://$PROJECT_DIR$/FakeGps.iml\" filepath=\"$PROJECT_DIR$/FakeGps.iml\" />\n      <module fileurl=\"file://$PROJECT_DIR$/app/app.iml\" filepath=\"$PROJECT_DIR$/app/app.iml\" />\n    </modules>\n  </component>\n</project>"
  },
  {
    "path": ".idea/runConfigurations.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"RunConfigurationProducerService\">\n    <option name=\"ignoredProducers\">\n      <set>\n        <option value=\"org.jetbrains.plugins.gradle.execution.test.runner.AllInPackageGradleConfigurationProducer\" />\n        <option value=\"org.jetbrains.plugins.gradle.execution.test.runner.TestClassGradleConfigurationProducer\" />\n        <option value=\"org.jetbrains.plugins.gradle.execution.test.runner.TestMethodGradleConfigurationProducer\" />\n      </set>\n    </option>\n  </component>\n</project>"
  },
  {
    "path": ".idea/vcs.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"VcsDirectoryMappings\">\n    <mapping directory=\"$PROJECT_DIR$\" vcs=\"Git\" />\n  </component>\n</project>"
  },
  {
    "path": "app/.gitignore",
    "content": "/build\n"
  },
  {
    "path": "app/build.gradle",
    "content": "apply plugin: 'com.android.application'\n\nandroid {\n    compileSdkVersion 24\n    buildToolsVersion '24.0.2'\n\n    defaultConfig {\n        applicationId \"name.caiyao.fakegps\"\n        minSdkVersion 9\n        targetSdkVersion 22\n        versionCode 6\n        versionName \"1.2.2\"\n    }\n    buildTypes {\n        release {\n            minifyEnabled true\n            shrinkResources true\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n    }\n}\n\ndependencies {\n    provided 'de.robv.android.xposed:api:81'\n    compile files('libs/AMap_2DMap_V2.8.1_20160202.jar')\n    compile 'com.android.support:appcompat-v7:24.2.1'\n    compile 'com.android.support:design:24.2.1'\n    compile files('libs/AMap_Search_V3.2.1_20160308.jar')\n}\n"
  },
  {
    "path": "app/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# By default, the flags in this file are appended to flags specified\n# in D:\\Android\\sdk/tools/proguard/proguard-android.txt\n# You can edit the include path and order by changing the proguardFiles\n# directive in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# Add any project specific keep options here:\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n-keep public class name.caiyao.fakegps.hook.MainHook\n-keep class com.amap.api.maps2d.**{*;}\n-dontwarn com.amap.api.**\n-keep class com.amap.api.mapcore2d.**{*;}\n"
  },
  {
    "path": "app/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n          package=\"name.caiyao.fakegps\">\n\n    <application\n        android:icon=\"@drawable/gps\"\n        android:label=\"@string/app_name\"\n        android:theme=\"@style/AppTheme\">\n        <meta-data\n            android:name=\"xposedmodule\"\n            android:value=\"true\"/>\n        <meta-data\n            android:name=\"xposeddescription\"\n            android:value=\"模拟位置\"/>\n        <meta-data\n            android:name=\"xposedminversion\"\n            android:value=\"30\"/>\n\n        <activity\n            android:name=\".ui.MainActivity\"\n            android:label=\"@string/app_name\"\n            android:launchMode=\"singleTask\"\n            android:theme=\"@style/AppTheme.NoActionBar\">\n            <intent-filter>\n                <action android:name=\"android.intent.action.MAIN\"/>\n\n                <category android:name=\"android.intent.category.LAUNCHER\"/>\n            </intent-filter>\n        </activity>\n\n        <meta-data\n            android:name=\"com.amap.api.v2.apikey\"\n            android:value=\"e34a748230a8123b72fd71a6f1604946\"/>\n\n        <activity\n            android:name=\".ui.AMapActivity\"\n            android:theme=\"@style/AppTheme.NoActionBar\"\n            >\n        </activity>\n\n        <provider\n            android:authorities=\"name.caiyao.fakegps.data.AppInfoProvider\"\n            android:exported=\"true\"\n            android:name=\".data.AppInfoProvider\"/>\n    </application>\n\n</manifest>"
  },
  {
    "path": "app/src/main/assets/xposed_init",
    "content": "name.caiyao.fakegps.hook.MainHook\n"
  },
  {
    "path": "app/src/main/java/name/caiyao/fakegps/data/AppInfo.java",
    "content": "package name.caiyao.fakegps.data;\n\nimport android.graphics.drawable.Drawable;\n\n/**\n * Created by 蔡小木 on 2016/5/3 0003.\n */\npublic class AppInfo {\n    public String appName = \"\";\n    public String packageName = \"\";\n    public String versionName = \"\";\n    public int versionCode = 0;\n    public boolean isChecked = false;\n    public Drawable appIcon = null;\n\n    public String getAppName() {\n        return appName;\n    }\n\n    public void setAppName(String appName) {\n        this.appName = appName;\n    }\n\n    public String getPackageName() {\n        return packageName;\n    }\n\n    public void setPackageName(String packageName) {\n        this.packageName = packageName;\n    }\n\n    public String getVersionName() {\n        return versionName;\n    }\n\n    public void setVersionName(String versionName) {\n        this.versionName = versionName;\n    }\n\n    public int getVersionCode() {\n        return versionCode;\n    }\n\n    public void setVersionCode(int versionCode) {\n        this.versionCode = versionCode;\n    }\n\n    public Drawable getAppIcon() {\n        return appIcon;\n    }\n\n    public void setAppIcon(Drawable appIcon) {\n        this.appIcon = appIcon;\n    }\n\n    public boolean isChecked() {\n        return isChecked;\n    }\n\n    public void setChecked(boolean checked) {\n        isChecked = checked;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/name/caiyao/fakegps/data/AppInfoProvider.java",
    "content": "package name.caiyao.fakegps.data;\n\nimport android.content.ContentProvider;\nimport android.content.ContentValues;\nimport android.content.UriMatcher;\nimport android.database.Cursor;\nimport android.database.sqlite.SQLiteDatabase;\nimport android.net.Uri;\nimport android.support.annotation.NonNull;\nimport android.support.annotation.Nullable;\n\n/**\n * Created by 蔡小木 on 2016/5/4 0004.\n */\npublic class AppInfoProvider extends ContentProvider {\n    public static final String AUTHRITY = \"name.caiyao.fakegps.data.AppInfoProvider\";\n    public static final Uri APP_CONTENT_URI = Uri.parse(\"content://\" + AUTHRITY + \"/app\");\n    public static final int APP_URI_CODE = 0;\n    private static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);\n\n    static {\n        sUriMatcher.addURI(AUTHRITY, \"app\", APP_URI_CODE);\n    }\n\n    private SQLiteDatabase mSQLiteDatabase;\n\n    @Override\n    public boolean onCreate() {\n        mSQLiteDatabase = new DbHelper(getContext()).getWritableDatabase();\n        return true;\n    }\n\n    @Nullable\n    @Override\n    public Cursor query(@NonNull Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {\n        String table = getTableName(uri);\n        if (table == null)\n            throw new IllegalArgumentException(\"Unsupported URI:\" + uri);\n        return mSQLiteDatabase.query(table, projection, selection, selectionArgs, null, null, sortOrder, null);\n    }\n\n    @Nullable\n    @Override\n    public String getType(@NonNull Uri uri) {\n        return null;\n    }\n\n    @Nullable\n    @Override\n    public Uri insert(@NonNull Uri uri, ContentValues values) {\n        String table = getTableName(uri);\n        if (table == null)\n            throw new IllegalArgumentException(\"Unsupported URI:\" + uri);\n        mSQLiteDatabase.insert(table, null, values);\n        getContext().getContentResolver().notifyChange(uri, null);\n        return uri;\n    }\n\n    @Override\n    public int delete(@NonNull Uri uri, String selection, String[] selectionArgs) {\n        String table = getTableName(uri);\n        if (table == null)\n            throw new IllegalArgumentException(\"Unsupported URI:\" + uri);\n        int count = mSQLiteDatabase.delete(table, selection, selectionArgs);\n        if (count > 0) {\n            getContext().getContentResolver().notifyChange(uri, null);\n        }\n        return count;\n    }\n\n    @Override\n    public int update(@NonNull Uri uri, ContentValues values, String selection, String[] selectionArgs) {\n        String table = getTableName(uri);\n        if (table == null)\n            throw new IllegalArgumentException(\"Unsupported URI:\" + uri);\n        int row = mSQLiteDatabase.update(table,values,selection,selectionArgs);\n        if (row>0){\n            getContext().getContentResolver().notifyChange(uri, null);\n        }\n        return row;\n    }\n\n    private String getTableName(Uri uri) {\n        String tableName = null;\n        switch (sUriMatcher.match(uri)) {\n            case APP_URI_CODE:\n                tableName = DbHelper.APP_TABLE_NAME;\n                break;\n        }\n        return tableName;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/name/caiyao/fakegps/data/DbHelper.java",
    "content": "package name.caiyao.fakegps.data;\n\nimport android.content.Context;\nimport android.database.sqlite.SQLiteDatabase;\nimport android.database.sqlite.SQLiteOpenHelper;\n\n/**\n * Created by 蔡小木 on 2016/5/4 0004.\n */\npublic class DbHelper extends SQLiteOpenHelper {\n\n    private final static String DB_NAME = \"applist.db\";\n    public final static String APP_TABLE_NAME = \"app\";\n    private final static int DB_VERSION = 1;\n\n    public DbHelper(Context context) {\n        super(context, DB_NAME, null, DB_VERSION);\n    }\n\n    @Override\n    public void onCreate(SQLiteDatabase db) {\n        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)\";\n        db.execSQL(CREATE_APP_TABLE);\n    }\n\n    @Override\n    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {\n\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/name/caiyao/fakegps/hook/HookUtils.java",
    "content": "package name.caiyao.fakegps.hook;\n\nimport android.location.Criteria;\nimport android.location.GpsStatus;\nimport android.location.Location;\nimport android.location.LocationListener;\nimport android.location.LocationManager;\nimport android.os.Build;\nimport android.os.SystemClock;\nimport android.telephony.CellIdentityCdma;\nimport android.telephony.CellIdentityGsm;\nimport android.telephony.CellIdentityLte;\nimport android.telephony.CellIdentityWcdma;\nimport android.telephony.CellInfoCdma;\nimport android.telephony.CellInfoGsm;\nimport android.telephony.CellInfoLte;\nimport android.telephony.CellInfoWcdma;\nimport android.telephony.CellLocation;\nimport android.telephony.gsm.GsmCellLocation;\n\nimport java.lang.reflect.Method;\nimport java.lang.reflect.Modifier;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport de.robv.android.xposed.XC_MethodHook;\nimport de.robv.android.xposed.XposedBridge;\nimport de.robv.android.xposed.XposedHelpers;\n\n/**\n * Created by 蔡小木 on 2016/5/4 0004.\n */\nclass HookUtils {\n\n    static void HookAndChange(ClassLoader classLoader, final double latitude, final double longtitude, final int lac, final int cid) {\n\n//        XposedHelpers.findAndHookMethod(\"android.telephony.TelephonyManager\", classLoader,\n//                \"getNetworkOperatorName\", new XC_MethodHook() {\n//                    @Override\n//                    protected void afterHookedMethod(MethodHookParam param) throws Throwable {\n//                        param.setResult(\"\");\n//                    }\n//                });\n//\n//        XposedHelpers.findAndHookMethod(\"android.telephony.TelephonyManager\", classLoader,\n//                \"getNetworkOperator\", new XC_MethodHook() {\n//                    @Override\n//                    protected void afterHookedMethod(MethodHookParam param) throws Throwable {\n//                        param.setResult(\"\");\n//                    }\n//                });\n//\n//        XposedHelpers.findAndHookMethod(\"android.telephony.TelephonyManager\", classLoader,\n//                \"getSimOperatorName\", new XC_MethodHook() {\n//                    @Override\n//                    protected void afterHookedMethod(MethodHookParam param) throws Throwable {\n//                        param.setResult(\"\");\n//                    }\n//                });\n//\n//        XposedHelpers.findAndHookMethod(\"android.telephony.TelephonyManager\", classLoader,\n//                \"getSimOperator\", new XC_MethodHook() {\n//                    @Override\n//                    protected void afterHookedMethod(MethodHookParam param) throws Throwable {\n//                        param.setResult(null);\n//                    }\n//                });\n//\n//        XposedHelpers.findAndHookMethod(\"android.telephony.TelephonyManager\", classLoader,\n//                \"getSimCountryIso\", new XC_MethodHook() {\n//                    @Override\n//                    protected void afterHookedMethod(MethodHookParam param) throws Throwable {\n//                        param.setResult(\"\");\n//                    }\n//                });\n//\n//        XposedHelpers.findAndHookMethod(\"android.telephony.TelephonyManager\", classLoader,\n//                \"getNetworkCountryIso\", new XC_MethodHook() {\n//                    @Override\n//                    protected void afterHookedMethod(MethodHookParam param) throws Throwable {\n//                        param.setResult(\"\");\n//                    }\n//                });\n//        XposedHelpers.findAndHookMethod(\"android.telephony.TelephonyManager\", classLoader,\n//                \"getNetworkType\", new XC_MethodHook() {\n//                    @Override\n//                    protected void afterHookedMethod(MethodHookParam param) throws Throwable {\n//                        param.setResult(TelephonyManager.NETWORK_TYPE_UNKNOWN);\n//                    }\n//                });\n//\n//        XposedHelpers.findAndHookMethod(\"android.telephony.TelephonyManager\", classLoader,\n//                \"getPhoneType\", new XC_MethodHook() {\n//                    @Override\n//                    protected void afterHookedMethod(MethodHookParam param) throws Throwable {\n//                        param.setResult(TelephonyManager.PHONE_TYPE_NONE);\n//                    }\n//                });\n//\n//        XposedHelpers.findAndHookMethod(\"android.telephony.TelephonyManager\", classLoader,\n//                \"getCurrentPhoneType\", new XC_MethodHook() {\n//                    @Override\n//                    protected void afterHookedMethod(MethodHookParam param) throws Throwable {\n//                        param.setResult(0);\n//                    }\n//                });\n//\n//        XposedHelpers.findAndHookMethod(\"android.telephony.TelephonyManager\", classLoader,\n//                \"getDataState\", new XC_MethodHook() {\n//                    @Override\n//                    protected void afterHookedMethod(MethodHookParam param) throws Throwable {\n//                        param.setResult(TelephonyManager.DATA_DISCONNECTED);\n//                    }\n//                });\n//\n//        XposedHelpers.findAndHookMethod(\"android.telephony.TelephonyManager\", classLoader,\n//                \"getSimState\", new XC_MethodHook() {\n//                    @Override\n//                    protected void afterHookedMethod(MethodHookParam param) throws Throwable {\n//                        param.setResult(TelephonyManager.SIM_STATE_UNKNOWN);\n//                    }\n//                });\n\n        XposedHelpers.findAndHookMethod(\"android.telephony.TelephonyManager\", classLoader,\n                \"getCellLocation\", new XC_MethodHook() {\n                    @Override\n                    protected void afterHookedMethod(MethodHookParam param) throws Throwable {\n                        GsmCellLocation gsmCellLocation = new GsmCellLocation();\n                        gsmCellLocation.setLacAndCid(lac, cid);\n                        param.setResult(gsmCellLocation);\n                    }\n                });\n\n        XposedHelpers.findAndHookMethod(\"android.telephony.PhoneStateListener\", classLoader,\n                \"onCellLocationChanged\", CellLocation.class, new XC_MethodHook() {\n                    @Override\n                    protected void afterHookedMethod(MethodHookParam param) throws Throwable {\n                        GsmCellLocation gsmCellLocation = new GsmCellLocation();\n                        gsmCellLocation.setLacAndCid(lac, cid);\n                        param.setResult(gsmCellLocation);\n                    }\n                });\n\n        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP_MR1) {\n            XposedHelpers.findAndHookMethod(\"android.telephony.TelephonyManager\", classLoader,\n                    \"getPhoneCount\", new XC_MethodHook() {\n                        @Override\n                        protected void afterHookedMethod(MethodHookParam param) throws Throwable {\n                            param.setResult(1);\n                        }\n                    });\n        }\n\n        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {\n            XposedHelpers.findAndHookMethod(\"android.telephony.TelephonyManager\", classLoader,\n                    \"getNeighboringCellInfo\", new XC_MethodHook() {\n                        @Override\n                        protected void afterHookedMethod(MethodHookParam param) throws Throwable {\n                            param.setResult(new ArrayList<>());\n                        }\n                    });\n        }\n\n        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN) {\n            XposedHelpers.findAndHookMethod(\"android.telephony.TelephonyManager\", classLoader,\n                    \"getAllCellInfo\", new XC_MethodHook() {\n                        @Override\n                        protected void afterHookedMethod(MethodHookParam param) throws Throwable {\n                            param.setResult(getCell(460, 0, lac, cid, 0, 0));\n                        }\n                    });\n            XposedHelpers.findAndHookMethod(\"android.telephony.PhoneStateListener\", classLoader,\n                    \"onCellInfoChanged\", List.class, new XC_MethodHook() {\n                        @Override\n                        protected void beforeHookedMethod(MethodHookParam param) throws Throwable {\n                            param.setResult(getCell(460, 0, lac, cid, 0,0));\n                        }\n                    });\n        }\n\n        XposedHelpers.findAndHookMethod(\"android.net.wifi.WifiManager\", classLoader, \"getScanResults\", new XC_MethodHook() {\n            @Override\n            protected void afterHookedMethod(MethodHookParam param) throws Throwable {\n                param.setResult(new ArrayList<>());\n            }\n        });\n\n        XposedHelpers.findAndHookMethod(\"android.net.wifi.WifiManager\", classLoader, \"getWifiState\", new XC_MethodHook() {\n            @Override\n            protected void afterHookedMethod(MethodHookParam param) throws Throwable {\n                param.setResult(1);\n            }\n        });\n\n        XposedHelpers.findAndHookMethod(\"android.net.wifi.WifiManager\", classLoader, \"isWifiEnabled\", new XC_MethodHook() {\n            @Override\n            protected void afterHookedMethod(MethodHookParam param) throws Throwable {\n                param.setResult(true);\n            }\n        });\n\n        XposedHelpers.findAndHookMethod(\"android.net.wifi.WifiInfo\", classLoader, \"getMacAddress\", new XC_MethodHook() {\n            @Override\n            protected void afterHookedMethod(MethodHookParam param) throws Throwable {\n                param.setResult(\"00-00-00-00-00-00-00-00\");\n            }\n        });\n\n        XposedHelpers.findAndHookMethod(\"android.net.wifi.WifiInfo\", classLoader, \"getSSID\", new XC_MethodHook() {\n            @Override\n            protected void afterHookedMethod(MethodHookParam param) throws Throwable {\n                param.setResult(\"null\");\n            }\n        });\n\n        XposedHelpers.findAndHookMethod(\"android.net.wifi.WifiInfo\", classLoader, \"getBSSID\", new XC_MethodHook() {\n            @Override\n            protected void afterHookedMethod(MethodHookParam param) throws Throwable {\n                param.setResult(\"00-00-00-00-00-00-00-00\");\n            }\n        });\n\n\n        XposedHelpers.findAndHookMethod(\"android.net.NetworkInfo\", classLoader,\n                \"getTypeName\", new XC_MethodHook() {\n                    @Override\n                    protected void afterHookedMethod(MethodHookParam param) throws Throwable {\n                        param.setResult(\"WIFI\");\n                    }\n                });\n        XposedHelpers.findAndHookMethod(\"android.net.NetworkInfo\", classLoader,\n                \"isConnectedOrConnecting\", new XC_MethodHook() {\n                    @Override\n                    protected void afterHookedMethod(MethodHookParam param) throws Throwable {\n                        param.setResult(true);\n                    }\n                });\n\n        XposedHelpers.findAndHookMethod(\"android.net.NetworkInfo\", classLoader,\n                \"isConnected\", new XC_MethodHook() {\n                    @Override\n                    protected void afterHookedMethod(MethodHookParam param) throws Throwable {\n                        param.setResult(true);\n                    }\n                });\n\n        XposedHelpers.findAndHookMethod(\"android.net.NetworkInfo\", classLoader,\n                \"isAvailable\", new XC_MethodHook() {\n                    @Override\n                    protected void afterHookedMethod(MethodHookParam param) throws Throwable {\n                        param.setResult(true);\n                    }\n                });\n\n        XposedHelpers.findAndHookMethod(\"android.telephony.CellInfo\", classLoader,\n                \"isRegistered\", new XC_MethodHook() {\n                    @Override\n                    protected void afterHookedMethod(MethodHookParam param) throws Throwable {\n                        param.setResult(true);\n                    }\n                });\n\n        XposedHelpers.findAndHookMethod(LocationManager.class, \"getLastLocation\", new XC_MethodHook() {\n            @Override\n            protected void afterHookedMethod(MethodHookParam param) throws Throwable {\n                Location l = new Location(LocationManager.GPS_PROVIDER);\n                l.setLatitude(latitude);\n                l.setLongitude(longtitude);\n                l.setAccuracy(100f);\n                l.setTime(System.currentTimeMillis());\n                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {\n                    l.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());\n                }\n                param.setResult(l);\n            }\n        });\n\n        XposedHelpers.findAndHookMethod(LocationManager.class, \"getLastKnownLocation\", String.class, new XC_MethodHook() {\n            @Override\n            protected void afterHookedMethod(MethodHookParam param) throws Throwable {\n                Location l = new Location(LocationManager.GPS_PROVIDER);\n                l.setLatitude(latitude);\n                l.setLongitude(longtitude);\n                l.setAccuracy(100f);\n                l.setTime(System.currentTimeMillis());\n                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {\n                    l.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());\n                }\n                param.setResult(l);\n            }\n        });\n\n\n        XposedBridge.hookAllMethods(LocationManager.class, \"getProviders\", new XC_MethodHook() {\n            @Override\n            protected void afterHookedMethod(MethodHookParam param) throws Throwable {\n                ArrayList<String> arrayList = new ArrayList<>();\n                arrayList.add(\"gps\");\n                param.setResult(arrayList);\n            }\n        });\n\n        XposedHelpers.findAndHookMethod(LocationManager.class, \"getBestProvider\", Criteria.class, Boolean.TYPE, new XC_MethodHook() {\n            @Override\n            protected void afterHookedMethod(MethodHookParam param) throws Throwable {\n                param.setResult(\"gps\");\n            }\n        });\n\n        XposedHelpers.findAndHookMethod(LocationManager.class, \"addGpsStatusListener\", GpsStatus.Listener.class, new XC_MethodHook() {\n            @Override\n            protected void afterHookedMethod(MethodHookParam param) throws Throwable {\n                if (param.args[0] != null) {\n                    XposedHelpers.callMethod(param.args[0], \"onGpsStatusChanged\", 1);\n                    XposedHelpers.callMethod(param.args[0], \"onGpsStatusChanged\", 3);\n                }\n            }\n        });\n\n        XposedHelpers.findAndHookMethod(LocationManager.class, \"addNmeaListener\", GpsStatus.NmeaListener.class, new XC_MethodHook() {\n            @Override\n            protected void beforeHookedMethod(MethodHookParam param) throws Throwable {\n                param.setResult(false);\n            }\n        });\n\n        XposedHelpers.findAndHookMethod(\"android.location.LocationManager\", classLoader,\n                \"getGpsStatus\", GpsStatus.class, new XC_MethodHook() {\n                    @Override\n                    protected void afterHookedMethod(MethodHookParam param) throws Throwable {\n                        GpsStatus gss = (GpsStatus) param.getResult();\n                        if (gss == null)\n                            return;\n\n                        Class<?> clazz = GpsStatus.class;\n                        Method m = null;\n                        for (Method method : clazz.getDeclaredMethods()) {\n                            if (method.getName().equals(\"setStatus\")) {\n                                if (method.getParameterTypes().length > 1) {\n                                    m = method;\n                                    break;\n                                }\n                            }\n                        }\n                        if (m == null)\n                            return;\n\n                        //access the private setStatus function of GpsStatus\n                        m.setAccessible(true);\n\n                        //make the apps belive GPS works fine now\n                        int svCount = 5;\n                        int[] prns = {1, 2, 3, 4, 5};\n                        float[] snrs = {0, 0, 0, 0, 0};\n                        float[] elevations = {0, 0, 0, 0, 0};\n                        float[] azimuths = {0, 0, 0, 0, 0};\n                        int ephemerisMask = 0x1f;\n                        int almanacMask = 0x1f;\n\n                        //5 satellites are fixed\n                        int usedInFixMask = 0x1f;\n\n                        XposedHelpers.callMethod(gss, \"setStatus\", svCount, prns, snrs, elevations, azimuths, ephemerisMask, almanacMask, usedInFixMask);\n                        param.args[0] = gss;\n                        param.setResult(gss);\n                        try {\n                            m.invoke(gss, svCount, prns, snrs, elevations, azimuths, ephemerisMask, almanacMask, usedInFixMask);\n                            param.setResult(gss);\n                        } catch (Exception e) {\n                            XposedBridge.log(e);\n                        }\n                    }\n                });\n\n        for (Method method : LocationManager.class.getDeclaredMethods()) {\n            if (method.getName().equals(\"requestLocationUpdates\")\n                    && !Modifier.isAbstract(method.getModifiers())\n                    && Modifier.isPublic(method.getModifiers())) {\n                XposedBridge.hookMethod(method, new XC_MethodHook() {\n                    @Override\n                    protected void beforeHookedMethod(MethodHookParam param) throws Throwable {\n                        if (param.args.length >= 4 && (param.args[3] instanceof LocationListener)) {\n\n                            LocationListener ll = (LocationListener) param.args[3];\n\n                            Class<?> clazz = LocationListener.class;\n                            Method m = null;\n                            for (Method method : clazz.getDeclaredMethods()) {\n                                if (method.getName().equals(\"onLocationChanged\") && !Modifier.isAbstract(method.getModifiers())) {\n                                    m = method;\n                                    break;\n                                }\n                            }\n                            Location l = new Location(LocationManager.GPS_PROVIDER);\n                            l.setLatitude(latitude);\n                            l.setLongitude(longtitude);\n                            l.setAccuracy(10.00f);\n                            l.setTime(System.currentTimeMillis());\n                            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {\n                                l.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());\n                            }\n                            XposedHelpers.callMethod(ll, \"onLocationChanged\", l);\n                            try {\n                                if (m != null) {\n                                    m.invoke(ll, l);\n                                }\n                            } catch (Exception e) {\n                                XposedBridge.log(e);\n                            }\n                        }\n                    }\n                });\n            }\n\n            if (method.getName().equals(\"requestSingleUpdate \")\n                    && !Modifier.isAbstract(method.getModifiers())\n                    && Modifier.isPublic(method.getModifiers())) {\n                XposedBridge.hookMethod(method, new XC_MethodHook() {\n                    @Override\n                    protected void beforeHookedMethod(MethodHookParam param) throws Throwable {\n                        if (param.args.length >= 3 && (param.args[1] instanceof LocationListener)) {\n\n                            LocationListener ll = (LocationListener) param.args[3];\n\n                            Class<?> clazz = LocationListener.class;\n                            Method m = null;\n                            for (Method method : clazz.getDeclaredMethods()) {\n                                if (method.getName().equals(\"onLocationChanged\") && !Modifier.isAbstract(method.getModifiers())) {\n                                    m = method;\n                                    break;\n                                }\n                            }\n\n                            try {\n                                if (m != null) {\n                                    Location l = new Location(LocationManager.GPS_PROVIDER);\n                                    l.setLatitude(latitude);\n                                    l.setLongitude(longtitude);\n                                    l.setAccuracy(100f);\n                                    l.setTime(System.currentTimeMillis());\n                                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {\n                                        l.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());\n                                    }\n                                    m.invoke(ll, l);\n                                }\n                            } catch (Exception e) {\n                                XposedBridge.log(e);\n                            }\n                        }\n                    }\n                });\n            }\n        }\n    }\n\n    private static ArrayList getCell(int mcc, int mnc, int lac, int cid, int sid, int networkType) {\n        ArrayList arrayList = new ArrayList();\n        CellInfoGsm cellInfoGsm = (CellInfoGsm) XposedHelpers.newInstance(CellInfoGsm.class);\n        XposedHelpers.callMethod(cellInfoGsm, \"setCellIdentity\", XposedHelpers.newInstance(CellIdentityGsm.class, new Object[]{Integer.valueOf(mcc), Integer.valueOf(mnc), Integer.valueOf(\n                lac), Integer.valueOf(cid)}));\n        CellInfoCdma cellInfoCdma = (CellInfoCdma) XposedHelpers.newInstance(CellInfoCdma.class);\n        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)}));\n        CellInfoWcdma cellInfoWcdma = (CellInfoWcdma) XposedHelpers.newInstance(CellInfoWcdma.class);\n        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)}));\n        CellInfoLte cellInfoLte = (CellInfoLte) XposedHelpers.newInstance(CellInfoLte.class);\n        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)}));\n        if (networkType == 1 || networkType == 2) {\n            arrayList.add(cellInfoGsm);\n        } else if (networkType == 13) {\n            arrayList.add(cellInfoLte);\n        } else if (networkType == 4 || networkType == 5 || networkType == 6 || networkType == 7 || networkType == 12 || networkType == 14) {\n            arrayList.add(cellInfoCdma);\n        } else if (networkType == 3 || networkType == 8 || networkType == 9 || networkType == 10 || networkType == 15) {\n            arrayList.add(cellInfoWcdma);\n        }\n        return arrayList;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/name/caiyao/fakegps/hook/MainHook.java",
    "content": "package name.caiyao.fakegps.hook;\n\nimport android.content.Context;\nimport android.database.Cursor;\nimport android.net.Uri;\n\nimport java.util.Random;\n\nimport de.robv.android.xposed.IXposedHookLoadPackage;\nimport de.robv.android.xposed.XposedBridge;\nimport de.robv.android.xposed.XposedHelpers;\nimport de.robv.android.xposed.callbacks.XC_LoadPackage;\n\n/**\n * Created by 蔡小木 on 2016/4/17 0017.\n */\npublic class MainHook implements IXposedHookLoadPackage {\n\n    @Override\n    public void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {\n        final Object activityThread = XposedHelpers.callStaticMethod(XposedHelpers.findClass(\"android.app.ActivityThread\", null), \"currentActivityThread\");\n        final Context systemContext = (Context) XposedHelpers.callMethod(activityThread, \"getSystemContext\");\n        Uri uri = Uri.parse(\"content://name.caiyao.fakegps.data.AppInfoProvider/app\");\n        Cursor cursor = systemContext.getContentResolver().query(uri, new String[]{\"latitude\", \"longitude\",\"lac\",\"cid\"}, \"package_name=?\", new String[]{loadPackageParam.packageName}, null);\n        if (cursor != null && cursor.moveToNext()) {\n            //41019, 18511\n            double latitude = cursor.getDouble(cursor.getColumnIndex(\"latitude\")) + (double) new Random().nextInt(100) / 1000000 + ((double) new Random().nextInt(99999999)) / 100000000000000d;\n            double longitude = cursor.getDouble(cursor.getColumnIndex(\"longitude\")) + (double) new Random().nextInt(100) / 1000000 + ((double) new Random().nextInt(99999999)) / 100000000000000d;\n            int lac = cursor.getInt(cursor.getColumnIndex(\"lac\"));\n            int cid = cursor.getInt(cursor.getColumnIndex(\"cid\"));\n            XposedBridge.log(\"模拟位置:\" + loadPackageParam.packageName + \",\" + latitude + \",\" + longitude + \",\" + lac + \",\" + cid);\n            HookUtils.HookAndChange(loadPackageParam.classLoader, latitude, longitude, lac, cid);\n            cursor.close();\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/name/caiyao/fakegps/ui/AMapActivity.java",
    "content": "package name.caiyao.fakegps.ui;\n\nimport android.content.ContentValues;\nimport android.content.DialogInterface;\nimport android.database.Cursor;\nimport android.database.sqlite.SQLiteDatabase;\nimport android.os.Bundle;\nimport android.support.design.widget.TextInputEditText;\nimport android.support.v7.app.AlertDialog;\nimport android.support.v7.app.AppCompatActivity;\nimport android.support.v7.widget.Toolbar;\nimport android.text.TextUtils;\nimport android.view.LayoutInflater;\nimport android.view.Menu;\nimport android.view.MenuItem;\nimport android.view.View;\nimport android.widget.EditText;\nimport android.widget.Toast;\n\nimport com.amap.api.maps2d.AMap;\nimport com.amap.api.maps2d.CameraUpdateFactory;\nimport com.amap.api.maps2d.MapView;\nimport com.amap.api.maps2d.model.LatLng;\nimport com.amap.api.maps2d.model.MarkerOptions;\nimport com.amap.api.services.core.PoiItem;\nimport com.amap.api.services.poisearch.PoiResult;\nimport com.amap.api.services.poisearch.PoiSearch;\n\nimport java.lang.reflect.Field;\nimport java.util.ArrayList;\n\nimport name.caiyao.fakegps.R;\nimport name.caiyao.fakegps.data.DbHelper;\n\npublic class AMapActivity extends AppCompatActivity implements AMap.OnMapClickListener {\n\n    private MapView mv;\n    private AMap aMap;\n    private LatLng latLng;\n    private String pacakgeName;\n    private int lac = 0, cid = 0;\n    private SQLiteDatabase mSQLiteDatabase;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_amap);\n        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);\n        setSupportActionBar(toolbar);\n\n        pacakgeName = getIntent().getStringExtra(\"package_name\");\n\n        mv = (MapView) findViewById(R.id.mv);\n        assert mv != null;\n        mv.onCreate(savedInstanceState);\n        aMap = mv.getMap();\n        mSQLiteDatabase = new DbHelper(this).getWritableDatabase();\n        Cursor cursor = mSQLiteDatabase.query(DbHelper.APP_TABLE_NAME, new String[]{\"latitude,longitude\"}, \"package_name=?\", new String[]{pacakgeName}, null, null, null);\n        if (cursor != null && cursor.moveToNext()) {\n            double lat = cursor.getDouble(cursor.getColumnIndex(\"latitude\"));\n            double lon = cursor.getDouble(cursor.getColumnIndex(\"longitude\"));\n            LatLng latLng1 = new LatLng(lat, lon);\n            MarkerOptions markerOptions = new MarkerOptions();\n            markerOptions.position(latLng1);\n            markerOptions.draggable(true);\n            markerOptions.title(\"经度：\" + latLng1.longitude + \",纬度：\" + latLng1.latitude);\n            aMap.addMarker(markerOptions);\n            aMap.moveCamera(CameraUpdateFactory.changeLatLng(latLng1));\n            aMap.moveCamera(CameraUpdateFactory.zoomTo(aMap.getMaxZoomLevel()));\n            cursor.close();\n        }\n        aMap.setMapType(AMap.MAP_TYPE_NORMAL);\n        aMap.setOnMapClickListener(this);\n    }\n\n    @Override\n    protected void onResume() {\n        super.onResume();\n        mv.onResume();\n    }\n\n    @Override\n    public boolean onCreateOptionsMenu(Menu menu) {\n        getMenuInflater().inflate(R.menu.menu_map, menu);\n        return super.onCreateOptionsMenu(menu);\n    }\n\n    @Override\n    public boolean onOptionsItemSelected(MenuItem item) {\n        switch (item.getItemId()) {\n            case R.id.ok:\n                if (latLng == null) {\n                    Toast.makeText(this, \"请点击地图选择一个地点！\", Toast.LENGTH_SHORT).show();\n                    return true;\n                }\n                new AlertDialog.Builder(AMapActivity.this).setTitle(\"注意\").setMessage(\"部分应用的定位如qq附近的人，钉钉签到等使用的是基站定位，如需使用相关功能请同时填写基站信息\")\n                        .setPositiveButton(\"知道了\", new DialogInterface.OnClickListener() {\n                            @Override\n                            public void onClick(DialogInterface dialog, int which) {\n                                dialog.dismiss();\n                            }\n                        })\n                        .show();\n                ContentValues contentValues = new ContentValues();\n                contentValues.put(\"package_name\", pacakgeName);\n                contentValues.put(\"latitude\", latLng.latitude);\n                contentValues.put(\"longitude\", latLng.longitude);\n                contentValues.put(\"lac\", lac);\n                contentValues.put(\"cid\", cid);\n                mSQLiteDatabase.insertWithOnConflict(DbHelper.APP_TABLE_NAME, null, contentValues, SQLiteDatabase.CONFLICT_REPLACE);\n                break;\n            case R.id.search:\n                View view = LayoutInflater.from(this).inflate(R.layout.dialog_search, null, false);\n                final EditText et_key = (EditText) view.findViewById(R.id.key);\n                new AlertDialog.Builder(this).setView(view)\n                        .setTitle(\"搜索位置\")\n                        .setPositiveButton(\"搜索\", new DialogInterface.OnClickListener() {\n                            @Override\n                            public void onClick(DialogInterface dialog, int which) {\n                                search(et_key.getText().toString());\n                            }\n                        }).setNegativeButton(\"取消\", new DialogInterface.OnClickListener() {\n                    @Override\n                    public void onClick(DialogInterface dialog, int which) {\n                        dialog.dismiss();\n                    }\n                }).show();\n                break;\n            case R.id.lac:\n                View view1 = getLayoutInflater().inflate(R.layout.dialog_lac_cid, null, false);\n                final TextInputEditText etLac = (TextInputEditText) view1.findViewById(R.id.lac);\n                final TextInputEditText etCid = (TextInputEditText) view1.findViewById(R.id.cid);\n                new AlertDialog.Builder(AMapActivity.this).setTitle(\"填写基站信息\").setView(view1).setPositiveButton(\"确定\", new DialogInterface.OnClickListener() {\n                    @Override\n                    public void onClick(DialogInterface dialog, int which) {\n                        canCloseDialog(dialog, false);\n                        if (TextUtils.isEmpty(etLac.getText())) {\n                            etLac.setError(\"lac的值不应该为空\");\n                        }\n                        if (TextUtils.isEmpty(etCid.getText())) {\n                            etCid.setError(\"cid的值不应该为空\");\n                        }\n                        if (!TextUtils.isEmpty(etLac.getText()) && !TextUtils.isEmpty(etCid.getText())) {\n                            int lac1 = Integer.parseInt(etLac.getText().toString());\n                            int cid1 = Integer.parseInt(etCid.getText().toString());\n                            if (lac1 <= 0 || lac1 >= 65535) {\n                                etLac.setError(\"lac的值应该是0~65535\");\n                                lac1 = 0;\n                            }\n                            if (cid1 <= 0 || cid1 >= 65535) {\n                                etCid.setError(\"cid的值应该是0~65535\");\n                                cid1 = 0;\n                            }\n                            lac = lac1;\n                            cid = cid1;\n                        }\n                        ContentValues contentValues = new ContentValues();\n                        contentValues.put(\"package_name\", pacakgeName);\n                        contentValues.put(\"lac\", lac);\n                        contentValues.put(\"cid\", cid);\n                        mSQLiteDatabase.insertWithOnConflict(DbHelper.APP_TABLE_NAME, null, contentValues, SQLiteDatabase.CONFLICT_REPLACE);\n                    }\n                }).setNegativeButton(\"取消\", new DialogInterface.OnClickListener() {\n                    @Override\n                    public void onClick(DialogInterface dialog, int which) {\n                        dialog.dismiss();\n                    }\n                }).show();\n                break;\n        }\n        return super.onOptionsItemSelected(item);\n    }\n\n    private void canCloseDialog(DialogInterface dialogInterface, boolean close) {\n        try {\n            Field field = dialogInterface.getClass().getSuperclass().getDeclaredField(\"mShowing\");\n            field.setAccessible(true);\n            field.set(dialogInterface, close);\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n    }\n\n    @Override\n    protected void onPause() {\n        super.onPause();\n        mv.onPause();\n    }\n\n    private void search(final String key) {\n        PoiSearch.Query query = new PoiSearch.Query(key, null, null);\n        query.setPageSize(10);\n        query.setPageNum(0);\n        PoiSearch poiSearch = new PoiSearch(this, query);\n        poiSearch.setOnPoiSearchListener(new PoiSearch.OnPoiSearchListener() {\n            @Override\n            public void onPoiSearched(PoiResult poiResult, int i) {\n                if (i == 1000) {\n                    final ArrayList<PoiItem> poiItems = poiResult.getPois();\n                    if (poiItems.size() != 0) {\n                        String[] keyList = new String[poiItems.size()];\n                        for (int j = 0; j < poiItems.size(); j++) {\n                            keyList[j] = poiItems.get(j).getTitle();\n                        }\n                        new AlertDialog.Builder(AMapActivity.this)\n                                .setTitle(\"选择位置\")\n                                .setSingleChoiceItems(keyList, 0, new DialogInterface.OnClickListener() {\n                                    @Override\n                                    public void onClick(DialogInterface dialog, int which) {\n                                        aMap.moveCamera(CameraUpdateFactory.changeLatLng(new LatLng(poiItems.get(which).getLatLonPoint().getLatitude(), poiItems.get(which).getLatLonPoint().getLongitude())));\n                                        aMap.moveCamera(CameraUpdateFactory.zoomTo(aMap.getMaxZoomLevel()));\n                                        dialog.dismiss();\n                                    }\n                                }).show();\n                    } else {\n                        Toast.makeText(AMapActivity.this, \"没有搜索结果\", Toast.LENGTH_SHORT).show();\n                    }\n\n                }\n            }\n\n            @Override\n            public void onPoiItemSearched(PoiItem poiItem, int i) {\n\n            }\n        });\n        poiSearch.searchPOIAsyn();\n    }\n\n    @Override\n    protected void onSaveInstanceState(Bundle outState) {\n        super.onSaveInstanceState(outState);\n        mv.onSaveInstanceState(outState);\n    }\n\n    @Override\n    protected void onDestroy() {\n        super.onDestroy();\n        mv.onDestroy();\n        mSQLiteDatabase.close();\n    }\n\n    @Override\n    public void onMapClick(LatLng latLng) {\n        aMap.clear();\n        MarkerOptions markerOptions = new MarkerOptions();\n        markerOptions.position(latLng);\n        markerOptions.draggable(true);\n        markerOptions.title(\"经度：\" + latLng.longitude + \",纬度：\" + latLng.latitude);\n        aMap.addMarker(markerOptions);\n        this.latLng = latLng;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/name/caiyao/fakegps/ui/MainActivity.java",
    "content": "package name.caiyao.fakegps.ui;\n\nimport android.app.ProgressDialog;\nimport android.content.Intent;\nimport android.content.pm.PackageInfo;\nimport android.net.Uri;\nimport android.os.AsyncTask;\nimport android.os.Bundle;\nimport android.support.v7.app.AppCompatActivity;\nimport android.support.v7.widget.LinearLayoutManager;\nimport android.support.v7.widget.RecyclerView;\nimport android.support.v7.widget.Toolbar;\nimport android.view.Menu;\nimport android.view.MenuItem;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.ImageView;\nimport android.widget.TextView;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport name.caiyao.fakegps.BuildConfig;\nimport name.caiyao.fakegps.R;\nimport name.caiyao.fakegps.data.AppInfo;\n\npublic class MainActivity extends AppCompatActivity {\n\n    private ProgressDialog mProgressDialog;\n    private AppAdapter mAppAdapter;\n    private ArrayList<AppInfo> mAppInfos = new ArrayList<>();\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_main);\n\n        RecyclerView recyclerView = (RecyclerView) findViewById(R.id.rv_app);\n        assert recyclerView != null;\n        recyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));\n        recyclerView.setHasFixedSize(true);\n        mAppAdapter = new AppAdapter(mAppInfos);\n        recyclerView.setAdapter(mAppAdapter);\n\n        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);\n        setSupportActionBar(toolbar);\n\n        mProgressDialog = new ProgressDialog(this);\n        mProgressDialog.setMax(100);\n        mProgressDialog.setMessage(\"正在扫描应用程序\");\n        mProgressDialog.show();\n\n        GetAppInfoTask getAppInfoTask = new GetAppInfoTask();\n        getAppInfoTask.execute();\n    }\n\n    @Override\n    public boolean onCreateOptionsMenu(Menu menu) {\n        getMenuInflater().inflate(R.menu.menu_main,menu);\n        return super.onCreateOptionsMenu(menu);\n    }\n\n    @Override\n    public boolean onOptionsItemSelected(MenuItem item) {\n        switch (item.getItemId()){\n            case R.id.setting:\n\n                break;\n            case R.id.donate:\n                startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(\"https://qr.alipay.com/apoy1zw1o2xpc7915d\")));\n                break;\n            case R.id.about:\n                startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(\"http://caiyao.name/releases\")));\n                break;\n        }\n        return super.onOptionsItemSelected(item);\n    }\n\n    private class GetAppInfoTask extends AsyncTask<Integer, Integer, ArrayList<AppInfo>> {\n\n        @Override\n        protected ArrayList<AppInfo> doInBackground(Integer[] params) {\n            ArrayList<AppInfo> appList = new ArrayList<>();\n            List<PackageInfo> packages = getPackageManager().getInstalledPackages(0);\n            for (int i = 0; i < packages.size(); i++) {\n                PackageInfo packageInfo = packages.get(i);\n                AppInfo tmpInfo = new AppInfo();\n                tmpInfo.appName = packageInfo.applicationInfo.loadLabel(getPackageManager()).toString();\n                tmpInfo.packageName = packageInfo.packageName;\n                tmpInfo.versionName = packageInfo.versionName;\n                tmpInfo.versionCode = packageInfo.versionCode;\n                tmpInfo.appIcon = packageInfo.applicationInfo.loadIcon(getPackageManager());\n                if (!packageInfo.packageName.equals(BuildConfig.APPLICATION_ID))\n                    appList.add(tmpInfo);\n                publishProgress(i / packages.size() * 100);\n            }\n            return appList;\n        }\n\n        @Override\n        protected void onProgressUpdate(Integer... values) {\n            mProgressDialog.setProgress(values[0]);\n        }\n\n        @Override\n        protected void onPostExecute(ArrayList<AppInfo> o) {\n            mProgressDialog.dismiss();\n            mAppInfos.addAll(o);\n            mAppAdapter.notifyDataSetChanged();\n        }\n    }\n\n    class AppAdapter extends RecyclerView.Adapter<AppAdapter.AppViewHolder> {\n\n        ArrayList<AppInfo> mAppInfos;\n\n        AppAdapter(ArrayList<AppInfo> appInfos) {\n            this.mAppInfos = appInfos;\n        }\n\n        @Override\n        public AppViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {\n            return new AppViewHolder(getLayoutInflater().inflate(R.layout.app_item, parent, false));\n        }\n\n        @Override\n        public void onBindViewHolder(final AppViewHolder holder, int position) {\n            holder.ivIcon.setImageDrawable(mAppInfos.get(position).getAppIcon());\n            holder.tvName.setText(mAppInfos.get(position).getAppName());\n            holder.tvPackageName.setText(mAppInfos.get(position).getPackageName());\n            holder.itemView.setOnClickListener(new View.OnClickListener() {\n                @Override\n                public void onClick(View v) {\n                    startActivity(new Intent(MainActivity.this, AMapActivity.class).putExtra(\"package_name\", mAppInfos.get(holder.getAdapterPosition()).getPackageName()));\n                }\n            });\n        }\n\n        @Override\n        public int getItemCount() {\n            return mAppInfos.size();\n        }\n\n        class AppViewHolder extends RecyclerView.ViewHolder {\n\n            ImageView ivIcon;\n            TextView tvName;\n            TextView tvPackageName;\n\n            AppViewHolder(View itemView) {\n                super(itemView);\n                ivIcon = (ImageView) itemView.findViewById(R.id.iv_icon);\n                tvName = (TextView) itemView.findViewById(R.id.tv_name);\n                tvPackageName = (TextView) itemView.findViewById(R.id.tv_package_name);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/res/layout/activity_amap.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<android.support.design.widget.CoordinatorLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:fitsSystemWindows=\"true\"\n    tools:context=\".ui.MainActivity\">\n\n    <android.support.design.widget.AppBarLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:theme=\"@style/AppTheme.AppBarOverlay\">\n\n        <android.support.v7.widget.Toolbar\n            android:id=\"@+id/toolbar\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"?attr/actionBarSize\"\n            android:background=\"?attr/colorPrimary\"\n            app:popupTheme=\"@style/AppTheme.PopupOverlay\"/>\n\n    </android.support.design.widget.AppBarLayout>\n\n    <RelativeLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        app:layout_behavior=\"@string/appbar_scrolling_view_behavior\">\n\n        <com.amap.api.maps2d.MapView\n            android:id=\"@+id/mv\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"/>\n    </RelativeLayout>\n\n\n</android.support.design.widget.CoordinatorLayout>"
  },
  {
    "path": "app/src/main/res/layout/activity_main.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<android.support.design.widget.CoordinatorLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:fitsSystemWindows=\"true\"\n    tools:context=\".ui.MainActivity\">\n\n    <android.support.design.widget.AppBarLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:theme=\"@style/AppTheme.AppBarOverlay\">\n\n        <android.support.v7.widget.Toolbar\n            android:id=\"@+id/toolbar\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"?attr/actionBarSize\"\n            android:background=\"?attr/colorPrimary\"\n            app:popupTheme=\"@style/AppTheme.PopupOverlay\" />\n\n    </android.support.design.widget.AppBarLayout>\n\n    <include layout=\"@layout/content_main\" />\n\n</android.support.design.widget.CoordinatorLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/app_item.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<android.support.v7.widget.CardView\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:card_view=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/cv_main\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:layout_margin=\"5dp\"\n    android:clickable=\"true\"\n    android:foreground=\"?android:attr/selectableItemBackground\"\n    card_view:cardCornerRadius=\"5dp\"\n    card_view:cardElevation=\"5dp\">\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"horizontal\"\n        android:padding=\"5dp\">\n\n        <ImageView\n            android:id=\"@+id/iv_icon\"\n            android:layout_width=\"0dp\"\n            android:layout_height=\"40dp\"\n            android:layout_weight=\"1\"\n            android:scaleType=\"fitCenter\"\n            card_view:ignore=\"ContentDescription\"/>\n\n        <RelativeLayout\n            android:layout_width=\"0dp\"\n            android:layout_height=\"match_parent\"\n            android:layout_marginLeft=\"5dp\"\n            android:layout_marginStart=\"5dp\"\n            android:layout_weight=\"3\"\n            android:orientation=\"vertical\">\n\n            <TextView\n                android:id=\"@+id/tv_name\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_above=\"@+id/tv_package_name\"\n                android:layout_alignParentTop=\"true\"\n                android:lines=\"2\"\n                android:textColor=\"@android:color/black\"\n                android:textSize=\"18sp\"/>\n\n            <TextView\n                android:id=\"@+id/tv_package_name\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_alignParentBottom=\"true\"\n                android:layout_alignParentLeft=\"true\"\n                android:layout_alignParentStart=\"true\"\n                android:textAppearance=\"@android:style/TextAppearance.DeviceDefault.Small\"/>\n\n        </RelativeLayout>\n    </LinearLayout>\n\n</android.support.v7.widget.CardView>"
  },
  {
    "path": "app/src/main/res/layout/content_main.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n              xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n              xmlns:tools=\"http://schemas.android.com/tools\"\n              android:layout_width=\"match_parent\"\n              android:layout_height=\"wrap_content\"\n              android:orientation=\"vertical\"\n              app:layout_behavior=\"@string/appbar_scrolling_view_behavior\"\n              tools:context=\".ui.MainActivity\"\n              tools:showIn=\"@layout/activity_main\">\n\n    <android.support.v7.widget.RecyclerView\n        android:id=\"@+id/rv_app\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"/>\n</LinearLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/dialog_lac_cid.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n              android:layout_width=\"match_parent\"\n              android:layout_height=\"match_parent\"\n              android:orientation=\"vertical\">\n\n    <android.support.design.widget.TextInputLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\">\n\n        <android.support.design.widget.TextInputEditText\n            android:id=\"@+id/lac\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:hint=\"LAC(0-65535)\"\n            android:inputType=\"number\"/>\n\n    </android.support.design.widget.TextInputLayout>\n\n    <android.support.design.widget.TextInputLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\">\n\n        <android.support.design.widget.TextInputEditText\n            android:id=\"@+id/cid\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:hint=\"CID(0-65535)\"\n            android:inputType=\"number\"/>\n\n    </android.support.design.widget.TextInputLayout>\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/dialog_search.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<EditText xmlns:android=\"http://schemas.android.com/apk/res/android\"\n          xmlns:tools=\"http://schemas.android.com/tools\"\n          android:id=\"@+id/key\"\n          android:layout_width=\"match_parent\"\n          android:layout_height=\"match_parent\"\n          android:inputType=\"text\"\n          tools:ignore=\"LabelFor\">\n\n</EditText>"
  },
  {
    "path": "app/src/main/res/menu/menu_main.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<menu xmlns:android=\"http://schemas.android.com/apk/res/android\"\n      xmlns:app=\"http://schemas.android.com/apk/res-auto\">\n    <item\n        android:id=\"@+id/setting\"\n        android:title=\"设置\"\n        app:showAsAction=\"never\"/>\n\n    <item\n        android:id=\"@+id/donate\"\n        android:title=\"@string/donate\"\n        app:showAsAction=\"never\"/>\n    <item\n        android:id=\"@+id/about\"\n        android:title=\"@string/about\"\n        app:showAsAction=\"never\"/>\n</menu>"
  },
  {
    "path": "app/src/main/res/menu/menu_map.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<menu xmlns:android=\"http://schemas.android.com/apk/res/android\"\n      xmlns:app=\"http://schemas.android.com/apk/res-auto\">\n    <item\n        android:id=\"@+id/ok\"\n        android:title=\"确定\"\n        app:showAsAction=\"always\"/>\n\n    <item\n        android:id=\"@+id/search\"\n        android:title=\"搜索\"\n        app:showAsAction=\"always\"/>\n\n    <item\n        android:id=\"@+id/lac\"\n        app:showAsAction=\"ifRoom\"\n        android:title=\"填写基站\"\n        />\n</menu>"
  },
  {
    "path": "app/src/main/res/values/colors.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <color name=\"colorPrimary\">#3F51B5</color>\n    <color name=\"colorPrimaryDark\">#303F9F</color>\n    <color name=\"colorAccent\">#FF4081</color>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values/dimens.xml",
    "content": "<resources>\n    <!-- Default screen margins, per the Android Design guidelines. -->\n    <dimen name=\"activity_horizontal_margin\">16dp</dimen>\n    <dimen name=\"activity_vertical_margin\">16dp</dimen>\n    <dimen name=\"fab_margin\">16dp</dimen>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values/strings.xml",
    "content": "<resources>\n    <string name=\"app_name\">模拟位置</string>\n    <string name=\"start\">开始</string>\n    <string name=\"stop\">停止</string>\n    <string name=\"donate\">支付宝捐赠</string>\n    <string name=\"about\">关于</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values/styles.xml",
    "content": "<resources>\n\n    <!-- Base application theme. -->\n    <style name=\"AppTheme\" parent=\"Theme.AppCompat.Light.DarkActionBar\">\n        <!-- Customize your theme here. -->\n        <item name=\"colorPrimary\">@color/colorPrimary</item>\n        <item name=\"colorPrimaryDark\">@color/colorPrimaryDark</item>\n        <item name=\"colorAccent\">@color/colorAccent</item>\n    </style>\n\n    <style name=\"AppTheme.NoActionBar\">\n        <item name=\"windowActionBar\">false</item>\n        <item name=\"windowNoTitle\">true</item>\n    </style>\n\n    <style name=\"AppTheme.AppBarOverlay\" parent=\"ThemeOverlay.AppCompat.Dark.ActionBar\" />\n\n    <style name=\"AppTheme.PopupOverlay\" parent=\"ThemeOverlay.AppCompat.Light\" />\n\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-en/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"app_name\">FakeGps</string>\n    <string name=\"about\">about</string>\n    <string name=\"donate\">Alipay Donate</string>\n    <string name=\"start\">Start</string>\n    <string name=\"stop\">Stop</string>\n</resources>"
  },
  {
    "path": "app/src/main/res/values-v21/styles.xml",
    "content": "<resources>\n\n    <style name=\"AppTheme.NoActionBar\">\n        <item name=\"windowActionBar\">false</item>\n        <item name=\"windowNoTitle\">true</item>\n        <item name=\"android:windowDrawsSystemBarBackgrounds\">true</item>\n        <item name=\"android:statusBarColor\">@android:color/transparent</item>\n    </style>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-w820dp/dimens.xml",
    "content": "<resources>\n    <!-- Example customization of dimensions originally defined in res/values/dimens.xml\n         (such as screen margins) for screens with more than 820dp of available width. This\n         would include 7\" and 10\" devices in landscape (~960dp and ~1280dp respectively). -->\n    <dimen name=\"activity_horizontal_margin\">64dp</dimen>\n</resources>\n"
  },
  {
    "path": "build.gradle",
    "content": "// Top-level build file where you can add configuration options common to all sub-projects/modules.\n\nbuildscript {\n    repositories {\n        jcenter()\n    }\n    dependencies {\n        classpath 'com.android.tools.build:gradle:2.2.0'\n\n        // NOTE: Do not place your application dependencies here; they belong\n        // in the individual module build.gradle files\n    }\n}\n\nallprojects {\n    repositories {\n        jcenter()\n    }\n}\n\ntask clean(type: Delete) {\n    delete rootProject.buildDir\n}\n"
  },
  {
    "path": "gradle/wrapper/gradle-wrapper.properties",
    "content": "#Sat Oct 08 16:10:49 CST 2016\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-2.14.1-all.zip\n"
  },
  {
    "path": "gradle.properties",
    "content": "## Project-wide Gradle settings.\n#\n# For more details on how to configure your build environment visit\n# http://www.gradle.org/docs/current/userguide/build_environment.html\n#\n# Specifies the JVM arguments used for the daemon process.\n# The setting is particularly useful for tweaking memory settings.\n# Default value: -Xmx1024m -XX:MaxPermSize=256m\n# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8\n#\n# When configured, Gradle will run in incubating parallel mode.\n# This option should only be used with decoupled projects. More details, visit\n# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects\n# org.gradle.parallel=true\n#Sat Oct 08 16:07:45 CST 2016\nsystemProp.http.proxyHost=127.0.0.1\nsystemProp.http.proxyPort=1081\n"
  },
  {
    "path": "gradlew",
    "content": "#!/usr/bin/env bash\n\n##############################################################################\n##\n##  Gradle start up script for UN*X\n##\n##############################################################################\n\n# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nDEFAULT_JVM_OPTS=\"\"\n\nAPP_NAME=\"Gradle\"\nAPP_BASE_NAME=`basename \"$0\"`\n\n# Use the maximum available, or set MAX_FD != -1 to use that value.\nMAX_FD=\"maximum\"\n\nwarn ( ) {\n    echo \"$*\"\n}\n\ndie ( ) {\n    echo\n    echo \"$*\"\n    echo\n    exit 1\n}\n\n# OS specific support (must be 'true' or 'false').\ncygwin=false\nmsys=false\ndarwin=false\ncase \"`uname`\" in\n  CYGWIN* )\n    cygwin=true\n    ;;\n  Darwin* )\n    darwin=true\n    ;;\n  MINGW* )\n    msys=true\n    ;;\nesac\n\n# Attempt to set APP_HOME\n# Resolve links: $0 may be a link\nPRG=\"$0\"\n# Need this for relative symlinks.\nwhile [ -h \"$PRG\" ] ; do\n    ls=`ls -ld \"$PRG\"`\n    link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n    if expr \"$link\" : '/.*' > /dev/null; then\n        PRG=\"$link\"\n    else\n        PRG=`dirname \"$PRG\"`\"/$link\"\n    fi\ndone\nSAVED=\"`pwd`\"\ncd \"`dirname \\\"$PRG\\\"`/\" >/dev/null\nAPP_HOME=\"`pwd -P`\"\ncd \"$SAVED\" >/dev/null\n\nCLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar\n\n# Determine the Java command to use to start the JVM.\nif [ -n \"$JAVA_HOME\" ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n        # IBM's JDK on AIX uses strange locations for the executables\n        JAVACMD=\"$JAVA_HOME/jre/sh/java\"\n    else\n        JAVACMD=\"$JAVA_HOME/bin/java\"\n    fi\n    if [ ! -x \"$JAVACMD\" ] ; then\n        die \"ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nelse\n    JAVACMD=\"java\"\n    which java >/dev/null 2>&1 || die \"ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\nfi\n\n# Increase the maximum file descriptors if we can.\nif [ \"$cygwin\" = \"false\" -a \"$darwin\" = \"false\" ] ; then\n    MAX_FD_LIMIT=`ulimit -H -n`\n    if [ $? -eq 0 ] ; then\n        if [ \"$MAX_FD\" = \"maximum\" -o \"$MAX_FD\" = \"max\" ] ; then\n            MAX_FD=\"$MAX_FD_LIMIT\"\n        fi\n        ulimit -n $MAX_FD\n        if [ $? -ne 0 ] ; then\n            warn \"Could not set maximum file descriptor limit: $MAX_FD\"\n        fi\n    else\n        warn \"Could not query maximum file descriptor limit: $MAX_FD_LIMIT\"\n    fi\nfi\n\n# For Darwin, add options to specify how the application appears in the dock\nif $darwin; then\n    GRADLE_OPTS=\"$GRADLE_OPTS \\\"-Xdock:name=$APP_NAME\\\" \\\"-Xdock:icon=$APP_HOME/media/gradle.icns\\\"\"\nfi\n\n# For Cygwin, switch paths to Windows format before running java\nif $cygwin ; then\n    APP_HOME=`cygpath --path --mixed \"$APP_HOME\"`\n    CLASSPATH=`cygpath --path --mixed \"$CLASSPATH\"`\n    JAVACMD=`cygpath --unix \"$JAVACMD\"`\n\n    # We build the pattern for arguments to be converted via cygpath\n    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`\n    SEP=\"\"\n    for dir in $ROOTDIRSRAW ; do\n        ROOTDIRS=\"$ROOTDIRS$SEP$dir\"\n        SEP=\"|\"\n    done\n    OURCYGPATTERN=\"(^($ROOTDIRS))\"\n    # Add a user-defined pattern to the cygpath arguments\n    if [ \"$GRADLE_CYGPATTERN\" != \"\" ] ; then\n        OURCYGPATTERN=\"$OURCYGPATTERN|($GRADLE_CYGPATTERN)\"\n    fi\n    # Now convert the arguments - kludge to limit ourselves to /bin/sh\n    i=0\n    for arg in \"$@\" ; do\n        CHECK=`echo \"$arg\"|egrep -c \"$OURCYGPATTERN\" -`\n        CHECK2=`echo \"$arg\"|egrep -c \"^-\"`                                 ### Determine if an option\n\n        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition\n            eval `echo args$i`=`cygpath --path --ignore --mixed \"$arg\"`\n        else\n            eval `echo args$i`=\"\\\"$arg\\\"\"\n        fi\n        i=$((i+1))\n    done\n    case $i in\n        (0) set -- ;;\n        (1) set -- \"$args0\" ;;\n        (2) set -- \"$args0\" \"$args1\" ;;\n        (3) set -- \"$args0\" \"$args1\" \"$args2\" ;;\n        (4) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" ;;\n        (5) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" ;;\n        (6) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" ;;\n        (7) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" ;;\n        (8) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" ;;\n        (9) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" \"$args8\" ;;\n    esac\nfi\n\n# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules\nfunction splitJvmOpts() {\n    JVM_OPTS=(\"$@\")\n}\neval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS\nJVM_OPTS[${#JVM_OPTS[*]}]=\"-Dorg.gradle.appname=$APP_BASE_NAME\"\n\nexec \"$JAVACMD\" \"${JVM_OPTS[@]}\" -classpath \"$CLASSPATH\" org.gradle.wrapper.GradleWrapperMain \"$@\"\n"
  },
  {
    "path": "gradlew.bat",
    "content": "@if \"%DEBUG%\" == \"\" @echo off\n@rem ##########################################################################\n@rem\n@rem  Gradle startup script for Windows\n@rem\n@rem ##########################################################################\n\n@rem Set local scope for the variables with windows NT shell\nif \"%OS%\"==\"Windows_NT\" setlocal\n\n@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nset DEFAULT_JVM_OPTS=\n\nset DIRNAME=%~dp0\nif \"%DIRNAME%\" == \"\" set DIRNAME=.\nset APP_BASE_NAME=%~n0\nset APP_HOME=%DIRNAME%\n\n@rem Find java.exe\nif defined JAVA_HOME goto findJavaFromJavaHome\n\nset JAVA_EXE=java.exe\n%JAVA_EXE% -version >NUL 2>&1\nif \"%ERRORLEVEL%\" == \"0\" goto init\n\necho.\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\necho.\necho Please set the JAVA_HOME variable in your environment to match the\necho location of your Java installation.\n\ngoto fail\n\n:findJavaFromJavaHome\nset JAVA_HOME=%JAVA_HOME:\"=%\nset JAVA_EXE=%JAVA_HOME%/bin/java.exe\n\nif exist \"%JAVA_EXE%\" goto init\n\necho.\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%\necho.\necho Please set the JAVA_HOME variable in your environment to match the\necho location of your Java installation.\n\ngoto fail\n\n:init\n@rem Get command-line arguments, handling Windowz variants\n\nif not \"%OS%\" == \"Windows_NT\" goto win9xME_args\nif \"%@eval[2+2]\" == \"4\" goto 4NT_args\n\n:win9xME_args\n@rem Slurp the command line arguments.\nset CMD_LINE_ARGS=\nset _SKIP=2\n\n:win9xME_args_slurp\nif \"x%~1\" == \"x\" goto execute\n\nset CMD_LINE_ARGS=%*\ngoto execute\n\n:4NT_args\n@rem Get arguments from the 4NT Shell from JP Software\nset CMD_LINE_ARGS=%$\n\n:execute\n@rem Setup the command line\n\nset CLASSPATH=%APP_HOME%\\gradle\\wrapper\\gradle-wrapper.jar\n\n@rem Execute Gradle\n\"%JAVA_EXE%\" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% \"-Dorg.gradle.appname=%APP_BASE_NAME%\" -classpath \"%CLASSPATH%\" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%\n\n:end\n@rem End local scope for the variables with windows NT shell\nif \"%ERRORLEVEL%\"==\"0\" goto mainEnd\n\n:fail\nrem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\nrem the _cmd.exe /c_ return code!\nif  not \"\" == \"%GRADLE_EXIT_CONSOLE%\" exit 1\nexit /b 1\n\n:mainEnd\nif \"%OS%\"==\"Windows_NT\" endlocal\n\n:omega\n"
  },
  {
    "path": "settings.gradle",
    "content": "include ':app'\n"
  }
]